1f8829a4aSRandall Stewart /*-
251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni *
4b1006367SRandall Stewart * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
5807aad63SMichael Tuexen * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
6807aad63SMichael Tuexen * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
7f8829a4aSRandall Stewart *
8f8829a4aSRandall Stewart * Redistribution and use in source and binary forms, with or without
9f8829a4aSRandall Stewart * modification, are permitted provided that the following conditions are met:
10f8829a4aSRandall Stewart *
11f8829a4aSRandall Stewart * a) Redistributions of source code must retain the above copyright notice,
12f8829a4aSRandall Stewart * this list of conditions and the following disclaimer.
13f8829a4aSRandall Stewart *
14f8829a4aSRandall Stewart * b) Redistributions in binary form must reproduce the above copyright
15f8829a4aSRandall Stewart * notice, this list of conditions and the following disclaimer in
16f8829a4aSRandall Stewart * the documentation and/or other materials provided with the distribution.
17f8829a4aSRandall Stewart *
18f8829a4aSRandall Stewart * c) Neither the name of Cisco Systems, Inc. nor the names of its
19f8829a4aSRandall Stewart * contributors may be used to endorse or promote products derived
20f8829a4aSRandall Stewart * from this software without specific prior written permission.
21f8829a4aSRandall Stewart *
22f8829a4aSRandall Stewart * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23f8829a4aSRandall Stewart * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24f8829a4aSRandall Stewart * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25f8829a4aSRandall Stewart * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26f8829a4aSRandall Stewart * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27f8829a4aSRandall Stewart * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28f8829a4aSRandall Stewart * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29f8829a4aSRandall Stewart * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30f8829a4aSRandall Stewart * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31f8829a4aSRandall Stewart * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32f8829a4aSRandall Stewart * THE POSSIBILITY OF SUCH DAMAGE.
33f8829a4aSRandall Stewart */
34f8829a4aSRandall Stewart
35f8829a4aSRandall Stewart #include <netinet/sctp_os.h>
3644249214SRandall Stewart #include <sys/proc.h>
37f8829a4aSRandall Stewart #include <netinet/sctp_var.h>
3842551e99SRandall Stewart #include <netinet/sctp_sysctl.h>
39f8829a4aSRandall Stewart #include <netinet/sctp_header.h>
4044249214SRandall Stewart #include <netinet/sctp_pcb.h>
41f8829a4aSRandall Stewart #include <netinet/sctputil.h>
42f8829a4aSRandall Stewart #include <netinet/sctp_output.h>
43f8829a4aSRandall Stewart #include <netinet/sctp_uio.h>
4444249214SRandall Stewart #include <netinet/sctp_auth.h>
45f8829a4aSRandall Stewart #include <netinet/sctp_timer.h>
4644249214SRandall Stewart #include <netinet/sctp_asconf.h>
4744249214SRandall Stewart #include <netinet/sctp_indata.h>
4844249214SRandall Stewart #include <netinet/sctp_bsd_addr.h>
4944249214SRandall Stewart #include <netinet/sctp_input.h>
5044249214SRandall Stewart #include <netinet/sctp_crc32.h>
5144249214SRandall Stewart #include <netinet/sctp_lock_bsd.h>
52f8829a4aSRandall Stewart /*
53f8829a4aSRandall Stewart * NOTES: On the outbound side of things I need to check the sack timer to
54f8829a4aSRandall Stewart * see if I should generate a sack into the chunk queue (if I have data to
55f8829a4aSRandall Stewart * send that is and will be sending it .. for bundling.
56f8829a4aSRandall Stewart *
57f8829a4aSRandall Stewart * The callback in sctp_usrreq.c will get called when the socket is read from.
58f8829a4aSRandall Stewart * This will cause sctp_service_queues() to get called on the top entry in
59f8829a4aSRandall Stewart * the list.
60f8829a4aSRandall Stewart */
6128cd0699SMichael Tuexen static uint32_t
6244249214SRandall Stewart sctp_add_chk_to_control(struct sctp_queued_to_read *control,
6344249214SRandall Stewart struct sctp_stream_in *strm,
6444249214SRandall Stewart struct sctp_tcb *stcb,
6544249214SRandall Stewart struct sctp_association *asoc,
6644710431SMichael Tuexen struct sctp_tmit_chunk *chk, int hold_rlock);
6744249214SRandall Stewart
6872fb6fdbSRandall Stewart void
sctp_set_rwnd(struct sctp_tcb * stcb,struct sctp_association * asoc)69f8829a4aSRandall Stewart sctp_set_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc)
70f8829a4aSRandall Stewart {
71b3f1ea41SRandall Stewart asoc->my_rwnd = sctp_calc_rwnd(stcb, asoc);
72f8829a4aSRandall Stewart }
73f8829a4aSRandall Stewart
74f8829a4aSRandall Stewart /* Calculate what the rwnd would be */
7572fb6fdbSRandall Stewart uint32_t
sctp_calc_rwnd(struct sctp_tcb * stcb,struct sctp_association * asoc)76b0471b4bSMichael Tuexen sctp_calc_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc)
77b0471b4bSMichael Tuexen {
78b3f1ea41SRandall Stewart uint32_t calc = 0;
79f8829a4aSRandall Stewart
80f8829a4aSRandall Stewart /*
81f8829a4aSRandall Stewart * This is really set wrong with respect to a 1-2-m socket. Since
824e88d37aSMichael Tuexen * the sb_cc is the count that everyone as put up. When we re-write
83f8829a4aSRandall Stewart * sctp_soreceive then we will fix this so that ONLY this
84f8829a4aSRandall Stewart * associations data is taken into account.
85f8829a4aSRandall Stewart */
8644249214SRandall Stewart if (stcb->sctp_socket == NULL) {
87f8829a4aSRandall Stewart return (calc);
8844249214SRandall Stewart }
890053ed28SMichael Tuexen
90253a63b8SMichael Tuexen KASSERT(asoc->cnt_on_reasm_queue > 0 || asoc->size_on_reasm_queue == 0,
91253a63b8SMichael Tuexen ("size_on_reasm_queue is %u", asoc->size_on_reasm_queue));
92253a63b8SMichael Tuexen KASSERT(asoc->cnt_on_all_streams > 0 || asoc->size_on_all_streams == 0,
93253a63b8SMichael Tuexen ("size_on_all_streams is %u", asoc->size_on_all_streams));
944e88d37aSMichael Tuexen if (stcb->asoc.sb_cc == 0 &&
95253a63b8SMichael Tuexen asoc->cnt_on_reasm_queue == 0 &&
96253a63b8SMichael Tuexen asoc->cnt_on_all_streams == 0) {
97f8829a4aSRandall Stewart /* Full rwnd granted */
98b3f1ea41SRandall Stewart calc = max(SCTP_SB_LIMIT_RCV(stcb->sctp_socket), SCTP_MINIMAL_RWND);
99f8829a4aSRandall Stewart return (calc);
100f8829a4aSRandall Stewart }
101f8829a4aSRandall Stewart /* get actual space */
102f8829a4aSRandall Stewart calc = (uint32_t)sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv);
103f8829a4aSRandall Stewart /*
104f8829a4aSRandall Stewart * take out what has NOT been put on socket queue and we yet hold
105f8829a4aSRandall Stewart * for putting up.
106f8829a4aSRandall Stewart */
10744fbe462SRandall Stewart calc = sctp_sbspace_sub(calc, (uint32_t)(asoc->size_on_reasm_queue +
10844fbe462SRandall Stewart asoc->cnt_on_reasm_queue * MSIZE));
10944fbe462SRandall Stewart calc = sctp_sbspace_sub(calc, (uint32_t)(asoc->size_on_all_streams +
11044fbe462SRandall Stewart asoc->cnt_on_all_streams * MSIZE));
111f8829a4aSRandall Stewart if (calc == 0) {
112f8829a4aSRandall Stewart /* out of space */
113f8829a4aSRandall Stewart return (calc);
114f8829a4aSRandall Stewart }
1150053ed28SMichael Tuexen
116f8829a4aSRandall Stewart /* what is the overhead of all these rwnd's */
1172afb3e84SRandall Stewart calc = sctp_sbspace_sub(calc, stcb->asoc.my_rwnd_control_len);
118b3f1ea41SRandall Stewart /*
119b3f1ea41SRandall Stewart * If the window gets too small due to ctrl-stuff, reduce it to 1,
120b3f1ea41SRandall Stewart * even it is 0. SWS engaged
121f8829a4aSRandall Stewart */
122b3f1ea41SRandall Stewart if (calc < stcb->asoc.my_rwnd_control_len) {
123b3f1ea41SRandall Stewart calc = 1;
1242afb3e84SRandall Stewart }
125b3f1ea41SRandall Stewart return (calc);
126f8829a4aSRandall Stewart }
127f8829a4aSRandall Stewart
128f8829a4aSRandall Stewart /*
129f8829a4aSRandall Stewart * Build out our readq entry based on the incoming packet.
130f8829a4aSRandall Stewart */
131f8829a4aSRandall Stewart struct sctp_queued_to_read *
sctp_build_readq_entry(struct sctp_tcb * stcb,struct sctp_nets * net,uint32_t tsn,uint32_t ppid,uint32_t context,uint16_t sid,uint32_t mid,uint8_t flags,struct mbuf * dm)132f8829a4aSRandall Stewart sctp_build_readq_entry(struct sctp_tcb *stcb,
133f8829a4aSRandall Stewart struct sctp_nets *net,
134f8829a4aSRandall Stewart uint32_t tsn, uint32_t ppid,
13549656eefSMichael Tuexen uint32_t context, uint16_t sid,
13649656eefSMichael Tuexen uint32_t mid, uint8_t flags,
137f8829a4aSRandall Stewart struct mbuf *dm)
138f8829a4aSRandall Stewart {
139f8829a4aSRandall Stewart struct sctp_queued_to_read *read_queue_e = NULL;
140f8829a4aSRandall Stewart
141f8829a4aSRandall Stewart sctp_alloc_a_readq(stcb, read_queue_e);
142f8829a4aSRandall Stewart if (read_queue_e == NULL) {
143f8829a4aSRandall Stewart goto failed_build;
144f8829a4aSRandall Stewart }
14544249214SRandall Stewart memset(read_queue_e, 0, sizeof(struct sctp_queued_to_read));
14649656eefSMichael Tuexen read_queue_e->sinfo_stream = sid;
147f8829a4aSRandall Stewart read_queue_e->sinfo_flags = (flags << 8);
148f8829a4aSRandall Stewart read_queue_e->sinfo_ppid = ppid;
1497215cc1bSMichael Tuexen read_queue_e->sinfo_context = context;
150f8829a4aSRandall Stewart read_queue_e->sinfo_tsn = tsn;
151f8829a4aSRandall Stewart read_queue_e->sinfo_cumtsn = tsn;
152f8829a4aSRandall Stewart read_queue_e->sinfo_assoc_id = sctp_get_associd(stcb);
15349656eefSMichael Tuexen read_queue_e->mid = mid;
15444249214SRandall Stewart read_queue_e->top_fsn = read_queue_e->fsn_included = 0xffffffff;
15544249214SRandall Stewart TAILQ_INIT(&read_queue_e->reasm);
156f8829a4aSRandall Stewart read_queue_e->whoFrom = net;
157f8829a4aSRandall Stewart atomic_add_int(&net->ref_count, 1);
158f8829a4aSRandall Stewart read_queue_e->data = dm;
159f8829a4aSRandall Stewart read_queue_e->stcb = stcb;
160f8829a4aSRandall Stewart read_queue_e->port_from = stcb->rport;
161daf14341SMichael Tuexen if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
162daf14341SMichael Tuexen read_queue_e->do_not_ref_stcb = 1;
163daf14341SMichael Tuexen }
164f8829a4aSRandall Stewart failed_build:
165f8829a4aSRandall Stewart return (read_queue_e);
166f8829a4aSRandall Stewart }
167f8829a4aSRandall Stewart
168f8829a4aSRandall Stewart struct mbuf *
sctp_build_ctl_nchunk(struct sctp_inpcb * inp,struct sctp_sndrcvinfo * sinfo)169e2e7c62eSMichael Tuexen sctp_build_ctl_nchunk(struct sctp_inpcb *inp, struct sctp_sndrcvinfo *sinfo)
170f8829a4aSRandall Stewart {
171e2e7c62eSMichael Tuexen struct sctp_extrcvinfo *seinfo;
172f8829a4aSRandall Stewart struct sctp_sndrcvinfo *outinfo;
173e2e7c62eSMichael Tuexen struct sctp_rcvinfo *rcvinfo;
174e2e7c62eSMichael Tuexen struct sctp_nxtinfo *nxtinfo;
175f8829a4aSRandall Stewart struct cmsghdr *cmh;
176f8829a4aSRandall Stewart struct mbuf *ret;
177f8829a4aSRandall Stewart int len;
178e2e7c62eSMichael Tuexen int use_extended;
179e2e7c62eSMichael Tuexen int provide_nxt;
180f8829a4aSRandall Stewart
181e2e7c62eSMichael Tuexen if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT) &&
182e2e7c62eSMichael Tuexen sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO) &&
183e2e7c62eSMichael Tuexen sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) {
184e2e7c62eSMichael Tuexen /* user does not want any ancillary data */
185f8829a4aSRandall Stewart return (NULL);
186f8829a4aSRandall Stewart }
1870053ed28SMichael Tuexen
188e2e7c62eSMichael Tuexen len = 0;
189e2e7c62eSMichael Tuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO)) {
190e2e7c62eSMichael Tuexen len += CMSG_SPACE(sizeof(struct sctp_rcvinfo));
191e2e7c62eSMichael Tuexen }
192e2e7c62eSMichael Tuexen seinfo = (struct sctp_extrcvinfo *)sinfo;
193e2e7c62eSMichael Tuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO) &&
194b70b526dSMichael Tuexen (seinfo->serinfo_next_flags & SCTP_NEXT_MSG_AVAIL)) {
195e2e7c62eSMichael Tuexen provide_nxt = 1;
1960bfc52beSMichael Tuexen len += CMSG_SPACE(sizeof(struct sctp_nxtinfo));
197e2e7c62eSMichael Tuexen } else {
198e2e7c62eSMichael Tuexen provide_nxt = 0;
199e2e7c62eSMichael Tuexen }
200e2e7c62eSMichael Tuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) {
201f8829a4aSRandall Stewart if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO)) {
202f8829a4aSRandall Stewart use_extended = 1;
203e2e7c62eSMichael Tuexen len += CMSG_SPACE(sizeof(struct sctp_extrcvinfo));
204f8829a4aSRandall Stewart } else {
205e2e7c62eSMichael Tuexen use_extended = 0;
206e2e7c62eSMichael Tuexen len += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo));
207e2e7c62eSMichael Tuexen }
208e2e7c62eSMichael Tuexen } else {
209e2e7c62eSMichael Tuexen use_extended = 0;
210f8829a4aSRandall Stewart }
211f8829a4aSRandall Stewart
212eb1b1807SGleb Smirnoff ret = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA);
213f8829a4aSRandall Stewart if (ret == NULL) {
214f8829a4aSRandall Stewart /* No space */
215f8829a4aSRandall Stewart return (ret);
216f8829a4aSRandall Stewart }
217e2e7c62eSMichael Tuexen SCTP_BUF_LEN(ret) = 0;
218e2e7c62eSMichael Tuexen
219f8829a4aSRandall Stewart /* We need a CMSG header followed by the struct */
220f8829a4aSRandall Stewart cmh = mtod(ret, struct cmsghdr *);
221e432298aSXin LI /*
222e432298aSXin LI * Make sure that there is no un-initialized padding between the
223e432298aSXin LI * cmsg header and cmsg data and after the cmsg data.
224e432298aSXin LI */
225e432298aSXin LI memset(cmh, 0, len);
226e2e7c62eSMichael Tuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO)) {
227f8829a4aSRandall Stewart cmh->cmsg_level = IPPROTO_SCTP;
228e2e7c62eSMichael Tuexen cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_rcvinfo));
229e2e7c62eSMichael Tuexen cmh->cmsg_type = SCTP_RCVINFO;
230e2e7c62eSMichael Tuexen rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmh);
231e2e7c62eSMichael Tuexen rcvinfo->rcv_sid = sinfo->sinfo_stream;
232e2e7c62eSMichael Tuexen rcvinfo->rcv_ssn = sinfo->sinfo_ssn;
233e2e7c62eSMichael Tuexen rcvinfo->rcv_flags = sinfo->sinfo_flags;
234e2e7c62eSMichael Tuexen rcvinfo->rcv_ppid = sinfo->sinfo_ppid;
235e2e7c62eSMichael Tuexen rcvinfo->rcv_tsn = sinfo->sinfo_tsn;
236e2e7c62eSMichael Tuexen rcvinfo->rcv_cumtsn = sinfo->sinfo_cumtsn;
237e2e7c62eSMichael Tuexen rcvinfo->rcv_context = sinfo->sinfo_context;
238e2e7c62eSMichael Tuexen rcvinfo->rcv_assoc_id = sinfo->sinfo_assoc_id;
239e2e7c62eSMichael Tuexen cmh = (struct cmsghdr *)((caddr_t)cmh + CMSG_SPACE(sizeof(struct sctp_rcvinfo)));
240e2e7c62eSMichael Tuexen SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct sctp_rcvinfo));
241f8829a4aSRandall Stewart }
242e2e7c62eSMichael Tuexen if (provide_nxt) {
243e2e7c62eSMichael Tuexen cmh->cmsg_level = IPPROTO_SCTP;
244e2e7c62eSMichael Tuexen cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_nxtinfo));
245e2e7c62eSMichael Tuexen cmh->cmsg_type = SCTP_NXTINFO;
246e2e7c62eSMichael Tuexen nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmh);
247b70b526dSMichael Tuexen nxtinfo->nxt_sid = seinfo->serinfo_next_stream;
248e2e7c62eSMichael Tuexen nxtinfo->nxt_flags = 0;
249b70b526dSMichael Tuexen if (seinfo->serinfo_next_flags & SCTP_NEXT_MSG_IS_UNORDERED) {
250e2e7c62eSMichael Tuexen nxtinfo->nxt_flags |= SCTP_UNORDERED;
251e2e7c62eSMichael Tuexen }
252b70b526dSMichael Tuexen if (seinfo->serinfo_next_flags & SCTP_NEXT_MSG_IS_NOTIFICATION) {
253e2e7c62eSMichael Tuexen nxtinfo->nxt_flags |= SCTP_NOTIFICATION;
254e2e7c62eSMichael Tuexen }
255b70b526dSMichael Tuexen if (seinfo->serinfo_next_flags & SCTP_NEXT_MSG_ISCOMPLETE) {
256e2e7c62eSMichael Tuexen nxtinfo->nxt_flags |= SCTP_COMPLETE;
257e2e7c62eSMichael Tuexen }
258b70b526dSMichael Tuexen nxtinfo->nxt_ppid = seinfo->serinfo_next_ppid;
259b70b526dSMichael Tuexen nxtinfo->nxt_length = seinfo->serinfo_next_length;
260b70b526dSMichael Tuexen nxtinfo->nxt_assoc_id = seinfo->serinfo_next_aid;
261e2e7c62eSMichael Tuexen cmh = (struct cmsghdr *)((caddr_t)cmh + CMSG_SPACE(sizeof(struct sctp_nxtinfo)));
262e2e7c62eSMichael Tuexen SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct sctp_nxtinfo));
263e2e7c62eSMichael Tuexen }
264e2e7c62eSMichael Tuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) {
265e2e7c62eSMichael Tuexen cmh->cmsg_level = IPPROTO_SCTP;
266e2e7c62eSMichael Tuexen outinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmh);
267e2e7c62eSMichael Tuexen if (use_extended) {
268e2e7c62eSMichael Tuexen cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_extrcvinfo));
269e2e7c62eSMichael Tuexen cmh->cmsg_type = SCTP_EXTRCV;
270e2e7c62eSMichael Tuexen memcpy(outinfo, sinfo, sizeof(struct sctp_extrcvinfo));
271e2e7c62eSMichael Tuexen SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct sctp_extrcvinfo));
272e2e7c62eSMichael Tuexen } else {
273e2e7c62eSMichael Tuexen cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
274e2e7c62eSMichael Tuexen cmh->cmsg_type = SCTP_SNDRCV;
275e2e7c62eSMichael Tuexen *outinfo = *sinfo;
276e2e7c62eSMichael Tuexen SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo));
277e2e7c62eSMichael Tuexen }
278e2e7c62eSMichael Tuexen }
279f8829a4aSRandall Stewart return (ret);
280f8829a4aSRandall Stewart }
281f8829a4aSRandall Stewart
28277acdc25SRandall Stewart static void
sctp_mark_non_revokable(struct sctp_association * asoc,uint32_t tsn)28377acdc25SRandall Stewart sctp_mark_non_revokable(struct sctp_association *asoc, uint32_t tsn)
28477acdc25SRandall Stewart {
285d0ed75b3SMichael Tuexen uint32_t gap, i;
286d0ed75b3SMichael Tuexen int in_r, in_nr;
28777acdc25SRandall Stewart
28877acdc25SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_do_drain) == 0) {
28977acdc25SRandall Stewart return;
29077acdc25SRandall Stewart }
291d0ed75b3SMichael Tuexen if (SCTP_TSN_GE(asoc->cumulative_tsn, tsn)) {
2929b2e0767SRandall Stewart /*
293d0ed75b3SMichael Tuexen * This tsn is behind the cum ack and thus we don't need to
2949b2e0767SRandall Stewart * worry about it being moved from one to the other.
2959b2e0767SRandall Stewart */
2969b2e0767SRandall Stewart return;
2979b2e0767SRandall Stewart }
29877acdc25SRandall Stewart SCTP_CALC_TSN_TO_GAP(gap, tsn, asoc->mapping_array_base_tsn);
29944249214SRandall Stewart in_r = SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap);
30044249214SRandall Stewart in_nr = SCTP_IS_TSN_PRESENT(asoc->nr_mapping_array, gap);
3019f2d6263SMichael Tuexen KASSERT(in_r || in_nr, ("%s: Things are really messed up now", __func__));
302d0ed75b3SMichael Tuexen if (!in_nr) {
30377acdc25SRandall Stewart SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
30420b07a4dSMichael Tuexen if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
30577acdc25SRandall Stewart asoc->highest_tsn_inside_nr_map = tsn;
30677acdc25SRandall Stewart }
307d0ed75b3SMichael Tuexen }
308d0ed75b3SMichael Tuexen if (in_r) {
309d0ed75b3SMichael Tuexen SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
31077acdc25SRandall Stewart if (tsn == asoc->highest_tsn_inside_map) {
311d0ed75b3SMichael Tuexen /* We must back down to see what the new highest is. */
31220b07a4dSMichael Tuexen for (i = tsn - 1; SCTP_TSN_GE(i, asoc->mapping_array_base_tsn); i--) {
31377acdc25SRandall Stewart SCTP_CALC_TSN_TO_GAP(gap, i, asoc->mapping_array_base_tsn);
31477acdc25SRandall Stewart if (SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap)) {
31577acdc25SRandall Stewart asoc->highest_tsn_inside_map = i;
31677acdc25SRandall Stewart break;
31777acdc25SRandall Stewart }
31877acdc25SRandall Stewart }
319d0ed75b3SMichael Tuexen if (!SCTP_TSN_GE(i, asoc->mapping_array_base_tsn)) {
32077acdc25SRandall Stewart asoc->highest_tsn_inside_map = asoc->mapping_array_base_tsn - 1;
32177acdc25SRandall Stewart }
32277acdc25SRandall Stewart }
32377acdc25SRandall Stewart }
324d0ed75b3SMichael Tuexen }
32577acdc25SRandall Stewart
32644249214SRandall Stewart static int
sctp_place_control_in_stream(struct sctp_stream_in * strm,struct sctp_association * asoc,struct sctp_queued_to_read * control)32744249214SRandall Stewart sctp_place_control_in_stream(struct sctp_stream_in *strm,
32844249214SRandall Stewart struct sctp_association *asoc,
32944249214SRandall Stewart struct sctp_queued_to_read *control)
330f8829a4aSRandall Stewart {
33144249214SRandall Stewart struct sctp_queued_to_read *at;
33244249214SRandall Stewart struct sctp_readhead *q;
3338b9c95f4SMichael Tuexen uint8_t flags, unordered;
334f8829a4aSRandall Stewart
3358b9c95f4SMichael Tuexen flags = (control->sinfo_flags >> 8);
3368b9c95f4SMichael Tuexen unordered = flags & SCTP_DATA_UNORDERED;
33744249214SRandall Stewart if (unordered) {
33844249214SRandall Stewart q = &strm->uno_inqueue;
33944249214SRandall Stewart if (asoc->idata_supported == 0) {
34044249214SRandall Stewart if (!TAILQ_EMPTY(q)) {
341b7b84c0eSMichael Tuexen /*
342b7b84c0eSMichael Tuexen * Only one stream can be here in old style
343b7b84c0eSMichael Tuexen * -- abort
344b7b84c0eSMichael Tuexen */
34544249214SRandall Stewart return (-1);
34644249214SRandall Stewart }
34744249214SRandall Stewart TAILQ_INSERT_TAIL(q, control, next_instrm);
34844249214SRandall Stewart control->on_strm_q = SCTP_ON_UNORDERED;
34944249214SRandall Stewart return (0);
35044249214SRandall Stewart }
35144249214SRandall Stewart } else {
35244249214SRandall Stewart q = &strm->inqueue;
35344249214SRandall Stewart }
3548b9c95f4SMichael Tuexen if ((flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
3558b9c95f4SMichael Tuexen control->end_added = 1;
3568b9c95f4SMichael Tuexen control->first_frag_seen = 1;
3578b9c95f4SMichael Tuexen control->last_frag_seen = 1;
35844249214SRandall Stewart }
35944249214SRandall Stewart if (TAILQ_EMPTY(q)) {
36044249214SRandall Stewart /* Empty queue */
36144249214SRandall Stewart TAILQ_INSERT_HEAD(q, control, next_instrm);
36244249214SRandall Stewart if (unordered) {
36344249214SRandall Stewart control->on_strm_q = SCTP_ON_UNORDERED;
36444249214SRandall Stewart } else {
36544249214SRandall Stewart control->on_strm_q = SCTP_ON_ORDERED;
36644249214SRandall Stewart }
36744249214SRandall Stewart return (0);
36844249214SRandall Stewart } else {
36944249214SRandall Stewart TAILQ_FOREACH(at, q, next_instrm) {
37049656eefSMichael Tuexen if (SCTP_MID_GT(asoc->idata_supported, at->mid, control->mid)) {
37144249214SRandall Stewart /*
37244249214SRandall Stewart * one in queue is bigger than the new one,
37344249214SRandall Stewart * insert before this one
37444249214SRandall Stewart */
37544249214SRandall Stewart TAILQ_INSERT_BEFORE(at, control, next_instrm);
37644249214SRandall Stewart if (unordered) {
37744249214SRandall Stewart control->on_strm_q = SCTP_ON_UNORDERED;
37844249214SRandall Stewart } else {
37944249214SRandall Stewart control->on_strm_q = SCTP_ON_ORDERED;
38044249214SRandall Stewart }
38144249214SRandall Stewart break;
38249656eefSMichael Tuexen } else if (SCTP_MID_EQ(asoc->idata_supported, at->mid, control->mid)) {
38344249214SRandall Stewart /*
38444249214SRandall Stewart * Gak, He sent me a duplicate msg id
38544249214SRandall Stewart * number?? return -1 to abort.
38644249214SRandall Stewart */
38744249214SRandall Stewart return (-1);
38844249214SRandall Stewart } else {
38944249214SRandall Stewart if (TAILQ_NEXT(at, next_instrm) == NULL) {
39044249214SRandall Stewart /*
39144249214SRandall Stewart * We are at the end, insert it
39244249214SRandall Stewart * after this one
39344249214SRandall Stewart */
39444249214SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
39544249214SRandall Stewart sctp_log_strm_del(control, at,
39644249214SRandall Stewart SCTP_STR_LOG_FROM_INSERT_TL);
39744249214SRandall Stewart }
3988b9c95f4SMichael Tuexen TAILQ_INSERT_AFTER(q, 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
sctp_abort_in_reasm(struct sctp_tcb * stcb,struct sctp_queued_to_read * control,struct sctp_tmit_chunk * chk,int * abort_flag,int opspot)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) {
422999f86d6SMichael Tuexen SCTP_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,
42649656eefSMichael Tuexen chk->rec.data.tsn,
42749656eefSMichael Tuexen chk->rec.data.sid,
428821bae7cSMichael Tuexen chk->rec.data.fsn, chk->rec.data.mid);
42944249214SRandall Stewart } else {
430999f86d6SMichael Tuexen SCTP_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,
43449656eefSMichael Tuexen chk->rec.data.tsn,
43549656eefSMichael Tuexen chk->rec.data.sid,
43649656eefSMichael Tuexen chk->rec.data.fsn,
437821bae7cSMichael Tuexen (uint16_t)chk->rec.data.mid);
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;
444105b68b4SMichael Tuexen sctp_abort_an_association(stcb->sctp_ep, stcb, oper, false, SCTP_SO_NOT_LOCKED);
44544249214SRandall Stewart *abort_flag = 1;
446f8829a4aSRandall Stewart }
447f8829a4aSRandall Stewart
44844249214SRandall Stewart static void
sctp_clean_up_control(struct sctp_tcb * stcb,struct sctp_queued_to_read * control)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 }
4632b861c15SMichael Tuexen sctp_free_remote_addr(control->whoFrom);
4642b861c15SMichael Tuexen if (control->data) {
4652b861c15SMichael Tuexen sctp_m_freem(control->data);
4662b861c15SMichael Tuexen control->data = NULL;
4672b861c15SMichael Tuexen }
46844249214SRandall Stewart sctp_free_a_readq(stcb, control);
469f8829a4aSRandall Stewart }
470f8829a4aSRandall Stewart
471f8829a4aSRandall Stewart /*
472f8829a4aSRandall Stewart * Queue the chunk either right into the socket buffer if it is the next one
473f8829a4aSRandall Stewart * to go OR put it in the correct place in the delivery queue. If we do
47444249214SRandall Stewart * append to the so_buf, keep doing so until we are out of order as
47544249214SRandall Stewart * long as the control's entered are non-fragmented.
476f8829a4aSRandall Stewart */
477f8829a4aSRandall Stewart static void
sctp_queue_data_to_stream(struct sctp_tcb * stcb,struct sctp_association * asoc,struct sctp_queued_to_read * control,int * abort_flag,int * need_reasm)47844249214SRandall Stewart sctp_queue_data_to_stream(struct sctp_tcb *stcb,
47944249214SRandall Stewart struct sctp_association *asoc,
48044249214SRandall Stewart struct sctp_queued_to_read *control, int *abort_flag, int *need_reasm)
481f8829a4aSRandall Stewart {
482f8829a4aSRandall Stewart /*
483f8829a4aSRandall Stewart * FIX-ME maybe? What happens when the ssn wraps? If we are getting
484f8829a4aSRandall Stewart * all the data in one stream this could happen quite rapidly. One
485f8829a4aSRandall Stewart * could use the TSN to keep track of things, but this scheme breaks
486cd0a4ff6SPedro F. Giffuni * down in the other type of stream usage that could occur. Send a
487f8829a4aSRandall Stewart * single msg to stream 0, send 4Billion messages to stream 1, now
488f8829a4aSRandall Stewart * send a message to stream 0. You have a situation where the TSN
489f8829a4aSRandall Stewart * has wrapped but not in the stream. Is this worth worrying about
490f8829a4aSRandall Stewart * or should we just change our queue sort at the bottom to be by
491f8829a4aSRandall Stewart * TSN.
492f8829a4aSRandall Stewart *
4935b495f17SMichael Tuexen * Could it also be legal for a peer to send ssn 1 with TSN 2 and
4945b495f17SMichael Tuexen * ssn 2 with TSN 1? If the peer is doing some sort of funky TSN/SSN
495f8829a4aSRandall Stewart * assignment this could happen... and I don't see how this would be
496f8829a4aSRandall Stewart * a violation. So for now I am undecided an will leave the sort by
497e7e65008SMichael Tuexen * SSN alone. Maybe a hybrid approach is the answer
498f8829a4aSRandall Stewart *
499f8829a4aSRandall Stewart */
500f8829a4aSRandall Stewart struct sctp_queued_to_read *at;
501f8829a4aSRandall Stewart int queue_needed;
50244249214SRandall Stewart uint32_t nxt_todel;
503ff1ffd74SMichael Tuexen struct mbuf *op_err;
5043d6fe5d8SMichael Tuexen struct sctp_stream_in *strm;
505ff1ffd74SMichael Tuexen char msg[SCTP_DIAG_INFO_LEN];
506f8829a4aSRandall Stewart
5073d6fe5d8SMichael Tuexen strm = &asoc->strmin[control->sinfo_stream];
508b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
509f8829a4aSRandall Stewart sctp_log_strm_del(control, NULL, SCTP_STR_LOG_FROM_INTO_STRD);
51080fefe0aSRandall Stewart }
51149656eefSMichael Tuexen if (SCTP_MID_GT((asoc->idata_supported), strm->last_mid_delivered, control->mid)) {
512f8829a4aSRandall Stewart /* The incoming sseq is behind where we last delivered? */
513f2ea2a2dSMichael Tuexen SCTPDBG(SCTP_DEBUG_INDATA1, "Duplicate S-SEQ: %u delivered: %u from peer, Abort association\n",
5143d6fe5d8SMichael Tuexen strm->last_mid_delivered, control->mid);
515f8829a4aSRandall Stewart /*
516f8829a4aSRandall Stewart * throw it in the stream so it gets cleaned up in
517f8829a4aSRandall Stewart * association destruction
518f8829a4aSRandall Stewart */
51944249214SRandall Stewart TAILQ_INSERT_HEAD(&strm->inqueue, control, next_instrm);
52049656eefSMichael Tuexen if (asoc->idata_supported) {
521999f86d6SMichael Tuexen SCTP_SNPRINTF(msg, sizeof(msg), "Delivered MID=%8.8x, got TSN=%8.8x, SID=%4.4x, MID=%8.8x",
52249656eefSMichael Tuexen strm->last_mid_delivered, control->sinfo_tsn,
523821bae7cSMichael Tuexen control->sinfo_stream, control->mid);
52449656eefSMichael Tuexen } else {
525999f86d6SMichael Tuexen SCTP_SNPRINTF(msg, sizeof(msg), "Delivered SSN=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
52649656eefSMichael Tuexen (uint16_t)strm->last_mid_delivered,
52749656eefSMichael Tuexen control->sinfo_tsn,
52849656eefSMichael Tuexen control->sinfo_stream,
529821bae7cSMichael Tuexen (uint16_t)control->mid);
53049656eefSMichael Tuexen }
531ff1ffd74SMichael Tuexen op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
53244249214SRandall Stewart stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_2;
533105b68b4SMichael Tuexen sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED);
534f8829a4aSRandall Stewart *abort_flag = 1;
535f8829a4aSRandall Stewart return;
536f8829a4aSRandall Stewart }
53744249214SRandall Stewart queue_needed = 1;
53844249214SRandall Stewart asoc->size_on_all_streams += control->length;
53944249214SRandall Stewart sctp_ucount_incr(asoc->cnt_on_all_streams);
54049656eefSMichael Tuexen nxt_todel = strm->last_mid_delivered + 1;
54149656eefSMichael Tuexen if (SCTP_MID_EQ(asoc->idata_supported, nxt_todel, control->mid)) {
542f8829a4aSRandall Stewart /* can be delivered right away? */
543b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
544f8829a4aSRandall Stewart sctp_log_strm_del(control, NULL, SCTP_STR_LOG_FROM_IMMED_DEL);
54580fefe0aSRandall Stewart }
546830d754dSRandall Stewart /* EY it wont be queued if it could be delivered directly */
547f8829a4aSRandall Stewart queue_needed = 0;
54828cd0699SMichael Tuexen if (asoc->size_on_all_streams >= control->length) {
549f8829a4aSRandall Stewart asoc->size_on_all_streams -= control->length;
55028cd0699SMichael Tuexen } else {
55128cd0699SMichael Tuexen #ifdef INVARIANTS
55228cd0699SMichael Tuexen panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
55328cd0699SMichael Tuexen #else
55428cd0699SMichael Tuexen asoc->size_on_all_streams = 0;
55528cd0699SMichael Tuexen #endif
55628cd0699SMichael Tuexen }
557f8829a4aSRandall Stewart sctp_ucount_decr(asoc->cnt_on_all_streams);
55849656eefSMichael Tuexen strm->last_mid_delivered++;
559b5c16493SMichael Tuexen sctp_mark_non_revokable(asoc, control->sinfo_tsn);
560f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb,
561f8829a4aSRandall Stewart control,
562cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1,
563574679afSMichael Tuexen SCTP_READ_LOCK_NOT_HELD, SCTP_SO_LOCKED);
56444249214SRandall Stewart TAILQ_FOREACH_SAFE(control, &strm->inqueue, next_instrm, at) {
565f8829a4aSRandall Stewart /* all delivered */
56649656eefSMichael Tuexen nxt_todel = strm->last_mid_delivered + 1;
56749656eefSMichael Tuexen if (SCTP_MID_EQ(asoc->idata_supported, nxt_todel, control->mid) &&
56844249214SRandall Stewart (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG)) {
56944249214SRandall Stewart if (control->on_strm_q == SCTP_ON_ORDERED) {
57044249214SRandall Stewart TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
57128cd0699SMichael Tuexen if (asoc->size_on_all_streams >= control->length) {
57228cd0699SMichael Tuexen asoc->size_on_all_streams -= control->length;
57328cd0699SMichael Tuexen } else {
57428cd0699SMichael Tuexen #ifdef INVARIANTS
57528cd0699SMichael Tuexen panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
57628cd0699SMichael Tuexen #else
57728cd0699SMichael Tuexen asoc->size_on_all_streams = 0;
57828cd0699SMichael Tuexen #endif
57928cd0699SMichael Tuexen }
58028cd0699SMichael Tuexen sctp_ucount_decr(asoc->cnt_on_all_streams);
58198d5fd97SMichael Tuexen #ifdef INVARIANTS
58244249214SRandall Stewart } else {
58344249214SRandall Stewart panic("Huh control: %p is on_strm_q: %d",
58444249214SRandall Stewart control, control->on_strm_q);
58598d5fd97SMichael Tuexen #endif
58644249214SRandall Stewart }
58744249214SRandall Stewart control->on_strm_q = 0;
58849656eefSMichael Tuexen strm->last_mid_delivered++;
589f8829a4aSRandall Stewart /*
590f8829a4aSRandall Stewart * We ignore the return of deliver_data here
591f8829a4aSRandall Stewart * since we always can hold the chunk on the
592f8829a4aSRandall Stewart * d-queue. And we have a finite number that
593f8829a4aSRandall Stewart * can be delivered from the strq.
594f8829a4aSRandall Stewart */
595b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
596f8829a4aSRandall Stewart sctp_log_strm_del(control, NULL,
597f8829a4aSRandall Stewart SCTP_STR_LOG_FROM_IMMED_DEL);
59880fefe0aSRandall Stewart }
599b5c16493SMichael Tuexen sctp_mark_non_revokable(asoc, control->sinfo_tsn);
600f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb,
601f8829a4aSRandall Stewart control,
602cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1,
603cfde3ff7SRandall Stewart SCTP_READ_LOCK_NOT_HELD,
604574679afSMichael Tuexen SCTP_SO_LOCKED);
605f8829a4aSRandall Stewart continue;
60649656eefSMichael Tuexen } else if (SCTP_MID_EQ(asoc->idata_supported, nxt_todel, control->mid)) {
60744249214SRandall Stewart *need_reasm = 1;
608f8829a4aSRandall Stewart }
609f8829a4aSRandall Stewart break;
610f8829a4aSRandall Stewart }
611f8829a4aSRandall Stewart }
612f8829a4aSRandall Stewart if (queue_needed) {
613f8829a4aSRandall Stewart /*
614f8829a4aSRandall Stewart * Ok, we did not deliver this guy, find the correct place
615f8829a4aSRandall Stewart * to put it on the queue.
616f8829a4aSRandall Stewart */
61744249214SRandall Stewart if (sctp_place_control_in_stream(strm, asoc, control)) {
618999f86d6SMichael Tuexen SCTP_SNPRINTF(msg, sizeof(msg),
619999f86d6SMichael Tuexen "Queue to str MID: %u duplicate", control->mid);
620d1ea5fa9SMichael Tuexen sctp_clean_up_control(stcb, control);
621b1deed45SMichael Tuexen op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
62244249214SRandall Stewart stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_3;
623105b68b4SMichael Tuexen sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED);
62444249214SRandall Stewart *abort_flag = 1;
625f8829a4aSRandall Stewart }
626f8829a4aSRandall Stewart }
627f8829a4aSRandall Stewart }
628f8829a4aSRandall Stewart
62944249214SRandall Stewart static void
sctp_setup_tail_pointer(struct sctp_queued_to_read * control)63044249214SRandall Stewart sctp_setup_tail_pointer(struct sctp_queued_to_read *control)
631f8829a4aSRandall Stewart {
63244249214SRandall Stewart struct mbuf *m, *prev = NULL;
63344249214SRandall Stewart struct sctp_tcb *stcb;
634f8829a4aSRandall Stewart
63544249214SRandall Stewart stcb = control->stcb;
63644249214SRandall Stewart control->held_length = 0;
63744249214SRandall Stewart control->length = 0;
63844249214SRandall Stewart m = control->data;
63944249214SRandall Stewart while (m) {
64044249214SRandall Stewart if (SCTP_BUF_LEN(m) == 0) {
64144249214SRandall Stewart /* Skip mbufs with NO length */
64244249214SRandall Stewart if (prev == NULL) {
64344249214SRandall Stewart /* First one */
64444249214SRandall Stewart control->data = sctp_m_free(m);
64544249214SRandall Stewart m = control->data;
64644249214SRandall Stewart } else {
64744249214SRandall Stewart SCTP_BUF_NEXT(prev) = sctp_m_free(m);
64844249214SRandall Stewart m = SCTP_BUF_NEXT(prev);
649f8829a4aSRandall Stewart }
65044249214SRandall Stewart if (m == NULL) {
65144249214SRandall Stewart control->tail_mbuf = prev;
652f8829a4aSRandall Stewart }
65344249214SRandall Stewart continue;
654f8829a4aSRandall Stewart }
65544249214SRandall Stewart prev = m;
65644249214SRandall Stewart atomic_add_int(&control->length, SCTP_BUF_LEN(m));
65744249214SRandall Stewart if (control->on_read_q) {
65844249214SRandall Stewart /*
65944249214SRandall Stewart * On read queue so we must increment the SB stuff,
66044249214SRandall Stewart * we assume caller has done any locks of SB.
66144249214SRandall Stewart */
66244249214SRandall Stewart sctp_sballoc(stcb, &stcb->sctp_socket->so_rcv, m);
663f8829a4aSRandall Stewart }
66444249214SRandall Stewart m = SCTP_BUF_NEXT(m);
665f8829a4aSRandall Stewart }
66644249214SRandall Stewart if (prev) {
66744249214SRandall Stewart control->tail_mbuf = prev;
66844249214SRandall Stewart }
669f8829a4aSRandall Stewart }
670f8829a4aSRandall Stewart
671f8829a4aSRandall Stewart static void
sctp_add_to_tail_pointer(struct sctp_queued_to_read * control,struct mbuf * m,uint32_t * added)67228cd0699SMichael Tuexen sctp_add_to_tail_pointer(struct sctp_queued_to_read *control, struct mbuf *m, uint32_t *added)
673f8829a4aSRandall Stewart {
67444249214SRandall Stewart struct mbuf *prev = NULL;
67544249214SRandall Stewart struct sctp_tcb *stcb;
676f8829a4aSRandall Stewart
67744249214SRandall Stewart stcb = control->stcb;
67844249214SRandall Stewart if (stcb == NULL) {
67998d5fd97SMichael Tuexen #ifdef INVARIANTS
68044249214SRandall Stewart panic("Control broken");
68198d5fd97SMichael Tuexen #else
68298d5fd97SMichael Tuexen return;
68398d5fd97SMichael Tuexen #endif
68444249214SRandall Stewart }
68544249214SRandall Stewart if (control->tail_mbuf == NULL) {
68644249214SRandall Stewart /* TSNH */
68763fb39baSMichael Tuexen sctp_m_freem(control->data);
68844249214SRandall Stewart control->data = m;
68944249214SRandall Stewart sctp_setup_tail_pointer(control);
690f8829a4aSRandall Stewart return;
691f8829a4aSRandall Stewart }
69244249214SRandall Stewart control->tail_mbuf->m_next = m;
69344249214SRandall Stewart while (m) {
69444249214SRandall Stewart if (SCTP_BUF_LEN(m) == 0) {
69544249214SRandall Stewart /* Skip mbufs with NO length */
69644249214SRandall Stewart if (prev == NULL) {
69744249214SRandall Stewart /* First one */
69844249214SRandall Stewart control->tail_mbuf->m_next = sctp_m_free(m);
69944249214SRandall Stewart m = control->tail_mbuf->m_next;
70044249214SRandall Stewart } else {
70144249214SRandall Stewart SCTP_BUF_NEXT(prev) = sctp_m_free(m);
70244249214SRandall Stewart m = SCTP_BUF_NEXT(prev);
70344249214SRandall Stewart }
70444249214SRandall Stewart if (m == NULL) {
70544249214SRandall Stewart control->tail_mbuf = prev;
70644249214SRandall Stewart }
70744249214SRandall Stewart continue;
70844249214SRandall Stewart }
70944249214SRandall Stewart prev = m;
71044249214SRandall Stewart if (control->on_read_q) {
711f8829a4aSRandall Stewart /*
71244249214SRandall Stewart * On read queue so we must increment the SB stuff,
71344249214SRandall Stewart * we assume caller has done any locks of SB.
714f8829a4aSRandall Stewart */
71544249214SRandall Stewart sctp_sballoc(stcb, &stcb->sctp_socket->so_rcv, m);
71644249214SRandall Stewart }
71728cd0699SMichael Tuexen *added += SCTP_BUF_LEN(m);
71844249214SRandall Stewart atomic_add_int(&control->length, SCTP_BUF_LEN(m));
71944249214SRandall Stewart m = SCTP_BUF_NEXT(m);
72044249214SRandall Stewart }
72144249214SRandall Stewart if (prev) {
72244249214SRandall Stewart control->tail_mbuf = prev;
72344249214SRandall Stewart }
72444249214SRandall Stewart }
72544249214SRandall Stewart
72644249214SRandall Stewart static void
sctp_build_readq_entry_from_ctl(struct sctp_queued_to_read * nc,struct sctp_queued_to_read * control)72744249214SRandall Stewart sctp_build_readq_entry_from_ctl(struct sctp_queued_to_read *nc, struct sctp_queued_to_read *control)
72844249214SRandall Stewart {
72944249214SRandall Stewart memset(nc, 0, sizeof(struct sctp_queued_to_read));
73044249214SRandall Stewart nc->sinfo_stream = control->sinfo_stream;
73149656eefSMichael Tuexen nc->mid = control->mid;
73244249214SRandall Stewart TAILQ_INIT(&nc->reasm);
73344249214SRandall Stewart nc->top_fsn = control->top_fsn;
73449656eefSMichael Tuexen nc->mid = control->mid;
73544249214SRandall Stewart nc->sinfo_flags = control->sinfo_flags;
73644249214SRandall Stewart nc->sinfo_ppid = control->sinfo_ppid;
73744249214SRandall Stewart nc->sinfo_context = control->sinfo_context;
73844249214SRandall Stewart nc->fsn_included = 0xffffffff;
73944249214SRandall Stewart nc->sinfo_tsn = control->sinfo_tsn;
74044249214SRandall Stewart nc->sinfo_cumtsn = control->sinfo_cumtsn;
74144249214SRandall Stewart nc->sinfo_assoc_id = control->sinfo_assoc_id;
74244249214SRandall Stewart nc->whoFrom = control->whoFrom;
74344249214SRandall Stewart atomic_add_int(&nc->whoFrom->ref_count, 1);
74444249214SRandall Stewart nc->stcb = control->stcb;
74544249214SRandall Stewart nc->port_from = control->port_from;
746daf14341SMichael Tuexen nc->do_not_ref_stcb = control->do_not_ref_stcb;
74744249214SRandall Stewart }
74844249214SRandall Stewart
74944249214SRandall Stewart static int
sctp_handle_old_unordered_data(struct sctp_tcb * stcb,struct sctp_association * asoc,struct sctp_stream_in * strm,struct sctp_queued_to_read * control,uint32_t pd_point,int inp_read_lock_held)750d1ea5fa9SMichael Tuexen sctp_handle_old_unordered_data(struct sctp_tcb *stcb,
751d1ea5fa9SMichael Tuexen struct sctp_association *asoc,
752d1ea5fa9SMichael Tuexen struct sctp_stream_in *strm,
753d1ea5fa9SMichael Tuexen struct sctp_queued_to_read *control,
754d1ea5fa9SMichael Tuexen uint32_t pd_point,
755d1ea5fa9SMichael Tuexen int inp_read_lock_held)
75644249214SRandall Stewart {
75744249214SRandall Stewart /*
75844249214SRandall Stewart * Special handling for the old un-ordered data chunk. All the
75949656eefSMichael Tuexen * chunks/TSN's go to mid 0. So we have to do the old style watching
76049656eefSMichael Tuexen * to see if we have it all. If you return one, no other control
76149656eefSMichael Tuexen * entries on the un-ordered queue will be looked at. In theory
76249656eefSMichael Tuexen * there should be no others entries in reality, unless the guy is
76349656eefSMichael Tuexen * sending both unordered NDATA and unordered DATA...
76444249214SRandall Stewart */
76544249214SRandall Stewart struct sctp_tmit_chunk *chk, *lchk, *tchk;
76644249214SRandall Stewart uint32_t fsn;
767643fd575SMichael Tuexen struct sctp_queued_to_read *nc;
76844249214SRandall Stewart int cnt_added;
76944249214SRandall Stewart
77044249214SRandall Stewart if (control->first_frag_seen == 0) {
77144249214SRandall Stewart /* Nothing we can do, we have not seen the first piece yet */
77244249214SRandall Stewart return (1);
77344249214SRandall Stewart }
77444249214SRandall Stewart /* Collapse any we can */
77544249214SRandall Stewart cnt_added = 0;
77644249214SRandall Stewart restart:
77744249214SRandall Stewart fsn = control->fsn_included + 1;
77844249214SRandall Stewart /* Now what can we add? */
77944249214SRandall Stewart TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, lchk) {
78049656eefSMichael Tuexen if (chk->rec.data.fsn == fsn) {
78144249214SRandall Stewart /* Ok lets add it */
782643fd575SMichael Tuexen sctp_alloc_a_readq(stcb, nc);
783643fd575SMichael Tuexen if (nc == NULL) {
784643fd575SMichael Tuexen break;
785643fd575SMichael Tuexen }
786643fd575SMichael Tuexen memset(nc, 0, sizeof(struct sctp_queued_to_read));
78744249214SRandall Stewart TAILQ_REMOVE(&control->reasm, chk, sctp_next);
7888dc6a1edSMichael Tuexen sctp_add_chk_to_control(control, strm, stcb, asoc, chk, inp_read_lock_held);
78944249214SRandall Stewart fsn++;
79044249214SRandall Stewart cnt_added++;
79144249214SRandall Stewart chk = NULL;
79244249214SRandall Stewart if (control->end_added) {
79344249214SRandall Stewart /* We are done */
79444249214SRandall Stewart if (!TAILQ_EMPTY(&control->reasm)) {
79544249214SRandall Stewart /*
79644249214SRandall Stewart * Ok we have to move anything left
79744249214SRandall Stewart * on the control queue to a new
79844249214SRandall Stewart * control.
79944249214SRandall Stewart */
80044249214SRandall Stewart sctp_build_readq_entry_from_ctl(nc, control);
80144249214SRandall Stewart tchk = TAILQ_FIRST(&control->reasm);
80244249214SRandall Stewart if (tchk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
80344249214SRandall Stewart TAILQ_REMOVE(&control->reasm, tchk, sctp_next);
80428cd0699SMichael Tuexen if (asoc->size_on_reasm_queue >= tchk->send_size) {
8055cb91655SMichael Tuexen asoc->size_on_reasm_queue -= tchk->send_size;
80628cd0699SMichael Tuexen } else {
80728cd0699SMichael Tuexen #ifdef INVARIANTS
80828cd0699SMichael Tuexen panic("size_on_reasm_queue = %u smaller than chunk length %u", asoc->size_on_reasm_queue, tchk->send_size);
80928cd0699SMichael Tuexen #else
81028cd0699SMichael Tuexen asoc->size_on_reasm_queue = 0;
81128cd0699SMichael Tuexen #endif
81228cd0699SMichael Tuexen }
8135cb91655SMichael Tuexen sctp_ucount_decr(asoc->cnt_on_reasm_queue);
81444249214SRandall Stewart nc->first_frag_seen = 1;
81549656eefSMichael Tuexen nc->fsn_included = tchk->rec.data.fsn;
81644249214SRandall Stewart nc->data = tchk->data;
81749656eefSMichael Tuexen nc->sinfo_ppid = tchk->rec.data.ppid;
81849656eefSMichael Tuexen nc->sinfo_tsn = tchk->rec.data.tsn;
81949656eefSMichael Tuexen sctp_mark_non_revokable(asoc, tchk->rec.data.tsn);
82044249214SRandall Stewart tchk->data = NULL;
82144249214SRandall Stewart sctp_free_a_chunk(stcb, tchk, SCTP_SO_NOT_LOCKED);
82244249214SRandall Stewart sctp_setup_tail_pointer(nc);
82344249214SRandall Stewart tchk = TAILQ_FIRST(&control->reasm);
82444249214SRandall Stewart }
82544249214SRandall Stewart /* Spin the rest onto the queue */
82644249214SRandall Stewart while (tchk) {
82744249214SRandall Stewart TAILQ_REMOVE(&control->reasm, tchk, sctp_next);
82844249214SRandall Stewart TAILQ_INSERT_TAIL(&nc->reasm, tchk, sctp_next);
82944249214SRandall Stewart tchk = TAILQ_FIRST(&control->reasm);
83044249214SRandall Stewart }
831b7b84c0eSMichael Tuexen /*
832b7b84c0eSMichael Tuexen * Now lets add it to the queue
833b7b84c0eSMichael Tuexen * after removing control
834b7b84c0eSMichael Tuexen */
83544249214SRandall Stewart TAILQ_INSERT_TAIL(&strm->uno_inqueue, nc, next_instrm);
83644249214SRandall Stewart nc->on_strm_q = SCTP_ON_UNORDERED;
83744249214SRandall Stewart if (control->on_strm_q) {
83844249214SRandall Stewart TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
83944249214SRandall Stewart control->on_strm_q = 0;
84044249214SRandall Stewart }
84144249214SRandall Stewart }
84244249214SRandall Stewart if (control->pdapi_started) {
84344249214SRandall Stewart strm->pd_api_started = 0;
84444249214SRandall Stewart control->pdapi_started = 0;
84544249214SRandall Stewart }
84644249214SRandall Stewart if (control->on_strm_q) {
84744249214SRandall Stewart TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
84844249214SRandall Stewart control->on_strm_q = 0;
84926f0250aSMichael Tuexen SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
85044249214SRandall Stewart }
851c09a1534SMichael Tuexen if (control->on_read_q == 0) {
852c09a1534SMichael Tuexen sctp_add_to_readq(stcb->sctp_ep, stcb, control,
853c09a1534SMichael Tuexen &stcb->sctp_socket->so_rcv, control->end_added,
854d1ea5fa9SMichael Tuexen inp_read_lock_held, SCTP_SO_NOT_LOCKED);
855c09a1534SMichael Tuexen }
856b1deed45SMichael Tuexen sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
8570fa7377aSMichael Tuexen if ((nc->first_frag_seen) && !TAILQ_EMPTY(&nc->reasm)) {
858b7b84c0eSMichael Tuexen /*
859b7b84c0eSMichael Tuexen * Switch to the new guy and
860b7b84c0eSMichael Tuexen * continue
861b7b84c0eSMichael Tuexen */
86244249214SRandall Stewart control = nc;
86344249214SRandall Stewart goto restart;
864643fd575SMichael Tuexen } else {
865d1ea5fa9SMichael Tuexen if (nc->on_strm_q == 0) {
866643fd575SMichael Tuexen sctp_free_a_readq(stcb, nc);
86744249214SRandall Stewart }
868d1ea5fa9SMichael Tuexen }
86944249214SRandall Stewart return (1);
870643fd575SMichael Tuexen } else {
871643fd575SMichael Tuexen sctp_free_a_readq(stcb, nc);
87244249214SRandall Stewart }
87344249214SRandall Stewart } else {
87444249214SRandall Stewart /* Can't add more */
87544249214SRandall Stewart break;
87644249214SRandall Stewart }
87744249214SRandall Stewart }
878f1903dc0SMichael Tuexen if (cnt_added && strm->pd_api_started) {
879f1903dc0SMichael Tuexen sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
880f1903dc0SMichael Tuexen }
88144249214SRandall Stewart if ((control->length > pd_point) && (strm->pd_api_started == 0)) {
882c09a1534SMichael Tuexen strm->pd_api_started = 1;
883c09a1534SMichael Tuexen control->pdapi_started = 1;
88444249214SRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, control,
88544249214SRandall Stewart &stcb->sctp_socket->so_rcv, control->end_added,
886d1ea5fa9SMichael Tuexen inp_read_lock_held, SCTP_SO_NOT_LOCKED);
887b1deed45SMichael Tuexen sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
88844249214SRandall Stewart return (0);
88944249214SRandall Stewart } else {
89044249214SRandall Stewart return (1);
89144249214SRandall Stewart }
89244249214SRandall Stewart }
89344249214SRandall Stewart
89444249214SRandall Stewart static void
sctp_inject_old_unordered_data(struct sctp_tcb * stcb,struct sctp_association * asoc,struct sctp_queued_to_read * control,struct sctp_tmit_chunk * chk,int * abort_flag)895d1ea5fa9SMichael Tuexen sctp_inject_old_unordered_data(struct sctp_tcb *stcb,
896d1ea5fa9SMichael Tuexen struct sctp_association *asoc,
89744249214SRandall Stewart struct sctp_queued_to_read *control,
89844249214SRandall Stewart struct sctp_tmit_chunk *chk,
89944249214SRandall Stewart int *abort_flag)
90044249214SRandall Stewart {
90144249214SRandall Stewart struct sctp_tmit_chunk *at;
902d1ea5fa9SMichael Tuexen int inserted;
90344249214SRandall Stewart
90444249214SRandall Stewart /*
90544249214SRandall Stewart * Here we need to place the chunk into the control structure sorted
90644249214SRandall Stewart * in the correct order.
90744249214SRandall Stewart */
90844249214SRandall Stewart if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
90944249214SRandall Stewart /* Its the very first one. */
91044249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX,
911f2ea2a2dSMichael Tuexen "chunk is a first fsn: %u becomes fsn_included\n",
91249656eefSMichael Tuexen chk->rec.data.fsn);
9132de5b904SMichael Tuexen at = TAILQ_FIRST(&control->reasm);
9142de5b904SMichael Tuexen if (at && SCTP_TSN_GT(chk->rec.data.fsn, at->rec.data.fsn)) {
9152de5b904SMichael Tuexen /*
9162de5b904SMichael Tuexen * The first chunk in the reassembly is a smaller
9172de5b904SMichael Tuexen * TSN than this one, even though this has a first,
9182de5b904SMichael Tuexen * it must be from a subsequent msg.
9192de5b904SMichael Tuexen */
9202de5b904SMichael Tuexen goto place_chunk;
9212de5b904SMichael Tuexen }
92244249214SRandall Stewart if (control->first_frag_seen) {
92344249214SRandall Stewart /*
92444249214SRandall Stewart * In old un-ordered we can reassembly on one
92544249214SRandall Stewart * control multiple messages. As long as the next
92644249214SRandall Stewart * FIRST is greater then the old first (TSN i.e. FSN
92744249214SRandall Stewart * wise)
92844249214SRandall Stewart */
92944249214SRandall Stewart struct mbuf *tdata;
93044249214SRandall Stewart uint32_t tmp;
93144249214SRandall Stewart
93249656eefSMichael Tuexen if (SCTP_TSN_GT(chk->rec.data.fsn, control->fsn_included)) {
933b7b84c0eSMichael Tuexen /*
934b7b84c0eSMichael Tuexen * Easy way the start of a new guy beyond
935b7b84c0eSMichael Tuexen * the lowest
936b7b84c0eSMichael Tuexen */
93744249214SRandall Stewart goto place_chunk;
93844249214SRandall Stewart }
93949656eefSMichael Tuexen if ((chk->rec.data.fsn == control->fsn_included) ||
94044249214SRandall Stewart (control->pdapi_started)) {
94144249214SRandall Stewart /*
94244249214SRandall Stewart * Ok this should not happen, if it does we
94344249214SRandall Stewart * started the pd-api on the higher TSN
94444249214SRandall Stewart * (since the equals part is a TSN failure
94544249214SRandall Stewart * it must be that).
94644249214SRandall Stewart *
947e7e65008SMichael Tuexen * We are completely hosed in that case
948e7e65008SMichael Tuexen * since I have no way to recover. This
949e7e65008SMichael Tuexen * really will only happen if we can get
950e7e65008SMichael Tuexen * more TSN's higher before the
951e7e65008SMichael Tuexen * pd-api-point.
95244249214SRandall Stewart */
953b1deed45SMichael Tuexen sctp_abort_in_reasm(stcb, control, chk,
95444249214SRandall Stewart abort_flag,
95544249214SRandall Stewart SCTP_FROM_SCTP_INDATA + SCTP_LOC_4);
95644249214SRandall Stewart
95744249214SRandall Stewart return;
95844249214SRandall Stewart }
95944249214SRandall Stewart /*
96044249214SRandall Stewart * Ok we have two firsts and the one we just got is
96144249214SRandall Stewart * smaller than the one we previously placed.. yuck!
96244249214SRandall Stewart * We must swap them out.
96344249214SRandall Stewart */
96444249214SRandall Stewart /* swap the mbufs */
96544249214SRandall Stewart tdata = control->data;
96644249214SRandall Stewart control->data = chk->data;
96744249214SRandall Stewart chk->data = tdata;
968d1ea5fa9SMichael Tuexen /* Save the lengths */
969d1ea5fa9SMichael Tuexen chk->send_size = control->length;
970d1ea5fa9SMichael Tuexen /* Recompute length of control and tail pointer */
971d1ea5fa9SMichael Tuexen sctp_setup_tail_pointer(control);
97244249214SRandall Stewart /* Fix the FSN included */
97344249214SRandall Stewart tmp = control->fsn_included;
97449656eefSMichael Tuexen control->fsn_included = chk->rec.data.fsn;
97549656eefSMichael Tuexen chk->rec.data.fsn = tmp;
976d1ea5fa9SMichael Tuexen /* Fix the TSN included */
977d1ea5fa9SMichael Tuexen tmp = control->sinfo_tsn;
97849656eefSMichael Tuexen control->sinfo_tsn = chk->rec.data.tsn;
97949656eefSMichael Tuexen chk->rec.data.tsn = tmp;
980d1ea5fa9SMichael Tuexen /* Fix the PPID included */
981d1ea5fa9SMichael Tuexen tmp = control->sinfo_ppid;
98249656eefSMichael Tuexen control->sinfo_ppid = chk->rec.data.ppid;
98349656eefSMichael Tuexen chk->rec.data.ppid = tmp;
984d1ea5fa9SMichael Tuexen /* Fix tail pointer */
98544249214SRandall Stewart goto place_chunk;
98644249214SRandall Stewart }
98744249214SRandall Stewart control->first_frag_seen = 1;
9888b9c95f4SMichael Tuexen control->fsn_included = chk->rec.data.fsn;
9898b9c95f4SMichael Tuexen control->top_fsn = chk->rec.data.fsn;
99049656eefSMichael Tuexen control->sinfo_tsn = chk->rec.data.tsn;
99149656eefSMichael Tuexen control->sinfo_ppid = chk->rec.data.ppid;
99244249214SRandall Stewart control->data = chk->data;
99349656eefSMichael Tuexen sctp_mark_non_revokable(asoc, chk->rec.data.tsn);
99444249214SRandall Stewart chk->data = NULL;
99544249214SRandall Stewart sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
99644249214SRandall Stewart sctp_setup_tail_pointer(control);
99744249214SRandall Stewart return;
99844249214SRandall Stewart }
99944249214SRandall Stewart place_chunk:
1000d1ea5fa9SMichael Tuexen inserted = 0;
100144249214SRandall Stewart TAILQ_FOREACH(at, &control->reasm, sctp_next) {
100249656eefSMichael Tuexen if (SCTP_TSN_GT(at->rec.data.fsn, chk->rec.data.fsn)) {
100344249214SRandall Stewart /*
100444249214SRandall Stewart * This one in queue is bigger than the new one,
100544249214SRandall Stewart * insert the new one before at.
100644249214SRandall Stewart */
100744249214SRandall Stewart asoc->size_on_reasm_queue += chk->send_size;
100844249214SRandall Stewart sctp_ucount_incr(asoc->cnt_on_reasm_queue);
100944249214SRandall Stewart inserted = 1;
101044249214SRandall Stewart TAILQ_INSERT_BEFORE(at, chk, sctp_next);
101144249214SRandall Stewart break;
101249656eefSMichael Tuexen } else if (at->rec.data.fsn == chk->rec.data.fsn) {
101344249214SRandall Stewart /*
101444249214SRandall Stewart * They sent a duplicate fsn number. This really
101544249214SRandall Stewart * should not happen since the FSN is a TSN and it
101644249214SRandall Stewart * should have been dropped earlier.
101744249214SRandall Stewart */
1018b1deed45SMichael Tuexen sctp_abort_in_reasm(stcb, control, chk,
101944249214SRandall Stewart abort_flag,
102044249214SRandall Stewart SCTP_FROM_SCTP_INDATA + SCTP_LOC_5);
102144249214SRandall Stewart return;
102244249214SRandall Stewart }
102344249214SRandall Stewart }
102444249214SRandall Stewart if (inserted == 0) {
102544249214SRandall Stewart /* Its at the end */
102644249214SRandall Stewart asoc->size_on_reasm_queue += chk->send_size;
102744249214SRandall Stewart sctp_ucount_incr(asoc->cnt_on_reasm_queue);
102849656eefSMichael Tuexen control->top_fsn = chk->rec.data.fsn;
102944249214SRandall Stewart TAILQ_INSERT_TAIL(&control->reasm, chk, sctp_next);
103044249214SRandall Stewart }
103144249214SRandall Stewart }
103244249214SRandall Stewart
103344249214SRandall Stewart static int
sctp_deliver_reasm_check(struct sctp_tcb * stcb,struct sctp_association * asoc,struct sctp_stream_in * strm,int inp_read_lock_held)1034d1ea5fa9SMichael Tuexen sctp_deliver_reasm_check(struct sctp_tcb *stcb, struct sctp_association *asoc,
1035d1ea5fa9SMichael Tuexen struct sctp_stream_in *strm, int inp_read_lock_held)
103644249214SRandall Stewart {
103744249214SRandall Stewart /*
103844249214SRandall Stewart * Given a stream, strm, see if any of the SSN's on it that are
103944249214SRandall Stewart * fragmented are ready to deliver. If so go ahead and place them on
104044249214SRandall Stewart * the read queue. In so placing if we have hit the end, then we
104144249214SRandall Stewart * need to remove them from the stream's queue.
104244249214SRandall Stewart */
104344249214SRandall Stewart struct sctp_queued_to_read *control, *nctl = NULL;
104444249214SRandall Stewart uint32_t next_to_del;
104544249214SRandall Stewart uint32_t pd_point;
104644249214SRandall Stewart int ret = 0;
104744249214SRandall Stewart
1048810ec536SMichael Tuexen if (stcb->sctp_socket) {
1049d4d23375SMichael Tuexen pd_point = min(SCTP_SB_LIMIT_RCV(stcb->sctp_socket) >> SCTP_PARTIAL_DELIVERY_SHIFT,
1050810ec536SMichael Tuexen stcb->sctp_ep->partial_delivery_point);
1051810ec536SMichael Tuexen } else {
1052810ec536SMichael Tuexen pd_point = stcb->sctp_ep->partial_delivery_point;
1053810ec536SMichael Tuexen }
105444249214SRandall Stewart control = TAILQ_FIRST(&strm->uno_inqueue);
1055d1ea5fa9SMichael Tuexen
10563d6fe5d8SMichael Tuexen if ((control != NULL) &&
105744249214SRandall Stewart (asoc->idata_supported == 0)) {
105844249214SRandall Stewart /* Special handling needed for "old" data format */
1059d1ea5fa9SMichael Tuexen if (sctp_handle_old_unordered_data(stcb, asoc, strm, control, pd_point, inp_read_lock_held)) {
106044249214SRandall Stewart goto done_un;
1061f8829a4aSRandall Stewart }
1062f8829a4aSRandall Stewart }
106344249214SRandall Stewart if (strm->pd_api_started) {
106444249214SRandall Stewart /* Can't add more */
106544249214SRandall Stewart return (0);
106644249214SRandall Stewart }
106744249214SRandall Stewart while (control) {
1068f2ea2a2dSMichael Tuexen SCTPDBG(SCTP_DEBUG_XXX, "Looking at control: %p e(%d) ssn: %u top_fsn: %u inc_fsn: %u -uo\n",
106949656eefSMichael Tuexen control, control->end_added, control->mid, control->top_fsn, control->fsn_included);
107044249214SRandall Stewart nctl = TAILQ_NEXT(control, next_instrm);
107144249214SRandall Stewart if (control->end_added) {
107244249214SRandall Stewart /* We just put the last bit on */
107344249214SRandall Stewart if (control->on_strm_q) {
107498d5fd97SMichael Tuexen #ifdef INVARIANTS
107544249214SRandall Stewart if (control->on_strm_q != SCTP_ON_UNORDERED) {
107644249214SRandall Stewart panic("Huh control: %p on_q: %d -- not unordered?",
107744249214SRandall Stewart control, control->on_strm_q);
107844249214SRandall Stewart }
107998d5fd97SMichael Tuexen #endif
108026f0250aSMichael Tuexen SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
108144249214SRandall Stewart TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
1082132c0738SMichael Tuexen if (asoc->size_on_all_streams >= control->length) {
1083132c0738SMichael Tuexen asoc->size_on_all_streams -= control->length;
1084132c0738SMichael Tuexen } else {
1085132c0738SMichael Tuexen #ifdef INVARIANTS
1086132c0738SMichael Tuexen panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
1087132c0738SMichael Tuexen #else
1088132c0738SMichael Tuexen asoc->size_on_all_streams = 0;
1089132c0738SMichael Tuexen #endif
1090132c0738SMichael Tuexen }
1091132c0738SMichael Tuexen sctp_ucount_decr(asoc->cnt_on_all_streams);
109244249214SRandall Stewart control->on_strm_q = 0;
109344249214SRandall Stewart }
109444249214SRandall Stewart if (control->on_read_q == 0) {
109544249214SRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb,
109644249214SRandall Stewart control,
109744249214SRandall Stewart &stcb->sctp_socket->so_rcv, control->end_added,
1098d1ea5fa9SMichael Tuexen inp_read_lock_held, SCTP_SO_NOT_LOCKED);
109944249214SRandall Stewart }
1100f8829a4aSRandall Stewart } else {
110144249214SRandall Stewart /* Can we do a PD-API for this un-ordered guy? */
110244249214SRandall Stewart if ((control->length >= pd_point) && (strm->pd_api_started == 0)) {
110344249214SRandall Stewart strm->pd_api_started = 1;
110444249214SRandall Stewart control->pdapi_started = 1;
110544249214SRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb,
110644249214SRandall Stewart control,
110744249214SRandall Stewart &stcb->sctp_socket->so_rcv, control->end_added,
1108d1ea5fa9SMichael Tuexen inp_read_lock_held, SCTP_SO_NOT_LOCKED);
110944249214SRandall Stewart
111044249214SRandall Stewart break;
1111139bc87fSRandall Stewart }
1112f8829a4aSRandall Stewart }
111344249214SRandall Stewart control = nctl;
111444249214SRandall Stewart }
111544249214SRandall Stewart done_un:
111644249214SRandall Stewart control = TAILQ_FIRST(&strm->inqueue);
111744249214SRandall Stewart if (strm->pd_api_started) {
111844249214SRandall Stewart /* Can't add more */
111944249214SRandall Stewart return (0);
112044249214SRandall Stewart }
112144249214SRandall Stewart if (control == NULL) {
112244249214SRandall Stewart return (ret);
112344249214SRandall Stewart }
112449656eefSMichael Tuexen if (SCTP_MID_EQ(asoc->idata_supported, strm->last_mid_delivered, control->mid)) {
112544249214SRandall Stewart /*
112644249214SRandall Stewart * Ok the guy at the top was being partially delivered
112744249214SRandall Stewart * completed, so we remove it. Note the pd_api flag was
112844249214SRandall Stewart * taken off when the chunk was merged on in
112944249214SRandall Stewart * sctp_queue_data_for_reasm below.
113044249214SRandall Stewart */
113144249214SRandall Stewart nctl = TAILQ_NEXT(control, next_instrm);
113244249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX,
1133f2ea2a2dSMichael Tuexen "Looking at control: %p e(%d) ssn: %u top_fsn: %u inc_fsn: %u (lastdel: %u)- o\n",
113449656eefSMichael Tuexen control, control->end_added, control->mid,
113544249214SRandall Stewart control->top_fsn, control->fsn_included,
113649656eefSMichael Tuexen strm->last_mid_delivered);
113744249214SRandall Stewart if (control->end_added) {
113844249214SRandall Stewart if (control->on_strm_q) {
113998d5fd97SMichael Tuexen #ifdef INVARIANTS
114044249214SRandall Stewart if (control->on_strm_q != SCTP_ON_ORDERED) {
114144249214SRandall Stewart panic("Huh control: %p on_q: %d -- not ordered?",
114244249214SRandall Stewart control, control->on_strm_q);
114344249214SRandall Stewart }
114498d5fd97SMichael Tuexen #endif
114526f0250aSMichael Tuexen SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
114644249214SRandall Stewart TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
114728cd0699SMichael Tuexen if (asoc->size_on_all_streams >= control->length) {
114828cd0699SMichael Tuexen asoc->size_on_all_streams -= control->length;
114928cd0699SMichael Tuexen } else {
115028cd0699SMichael Tuexen #ifdef INVARIANTS
115128cd0699SMichael Tuexen panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
115228cd0699SMichael Tuexen #else
115328cd0699SMichael Tuexen asoc->size_on_all_streams = 0;
115428cd0699SMichael Tuexen #endif
115528cd0699SMichael Tuexen }
115628cd0699SMichael Tuexen sctp_ucount_decr(asoc->cnt_on_all_streams);
115744249214SRandall Stewart control->on_strm_q = 0;
115844249214SRandall Stewart }
1159c09a1534SMichael Tuexen if (strm->pd_api_started && control->pdapi_started) {
1160c09a1534SMichael Tuexen control->pdapi_started = 0;
1161c09a1534SMichael Tuexen strm->pd_api_started = 0;
1162c09a1534SMichael Tuexen }
116344249214SRandall Stewart if (control->on_read_q == 0) {
116444249214SRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb,
116544249214SRandall Stewart control,
116644249214SRandall Stewart &stcb->sctp_socket->so_rcv, control->end_added,
1167d1ea5fa9SMichael Tuexen inp_read_lock_held, SCTP_SO_NOT_LOCKED);
116844249214SRandall Stewart }
116944249214SRandall Stewart control = nctl;
117044249214SRandall Stewart }
117144249214SRandall Stewart }
117244249214SRandall Stewart if (strm->pd_api_started) {
1173b7b84c0eSMichael Tuexen /*
1174b7b84c0eSMichael Tuexen * Can't add more must have gotten an un-ordered above being
1175b7b84c0eSMichael Tuexen * partially delivered.
1176b7b84c0eSMichael Tuexen */
117744249214SRandall Stewart return (0);
117844249214SRandall Stewart }
117944249214SRandall Stewart deliver_more:
118049656eefSMichael Tuexen next_to_del = strm->last_mid_delivered + 1;
118144249214SRandall Stewart if (control) {
118244249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX,
1183f2ea2a2dSMichael Tuexen "Looking at control: %p e(%d) ssn: %u top_fsn: %u inc_fsn: %u (nxtdel: %u)- o\n",
118449656eefSMichael Tuexen control, control->end_added, control->mid, control->top_fsn, control->fsn_included,
118544249214SRandall Stewart next_to_del);
118644249214SRandall Stewart nctl = TAILQ_NEXT(control, next_instrm);
118749656eefSMichael Tuexen if (SCTP_MID_EQ(asoc->idata_supported, control->mid, next_to_del) &&
118844249214SRandall Stewart (control->first_frag_seen)) {
1189c09a1534SMichael Tuexen int done;
1190c09a1534SMichael Tuexen
119144249214SRandall Stewart /* Ok we can deliver it onto the stream. */
119244249214SRandall Stewart if (control->end_added) {
119344249214SRandall Stewart /* We are done with it afterwards */
119444249214SRandall Stewart if (control->on_strm_q) {
119598d5fd97SMichael Tuexen #ifdef INVARIANTS
119644249214SRandall Stewart if (control->on_strm_q != SCTP_ON_ORDERED) {
119744249214SRandall Stewart panic("Huh control: %p on_q: %d -- not ordered?",
119844249214SRandall Stewart control, control->on_strm_q);
119944249214SRandall Stewart }
120098d5fd97SMichael Tuexen #endif
120126f0250aSMichael Tuexen SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
120244249214SRandall Stewart TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
120328cd0699SMichael Tuexen if (asoc->size_on_all_streams >= control->length) {
120428cd0699SMichael Tuexen asoc->size_on_all_streams -= control->length;
120528cd0699SMichael Tuexen } else {
120628cd0699SMichael Tuexen #ifdef INVARIANTS
120728cd0699SMichael Tuexen panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
120828cd0699SMichael Tuexen #else
120928cd0699SMichael Tuexen asoc->size_on_all_streams = 0;
121028cd0699SMichael Tuexen #endif
121128cd0699SMichael Tuexen }
121228cd0699SMichael Tuexen sctp_ucount_decr(asoc->cnt_on_all_streams);
121344249214SRandall Stewart control->on_strm_q = 0;
121444249214SRandall Stewart }
121544249214SRandall Stewart ret++;
121644249214SRandall Stewart }
121744249214SRandall Stewart if (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
1218b7b84c0eSMichael Tuexen /*
1219b7b84c0eSMichael Tuexen * A singleton now slipping through - mark
1220b7b84c0eSMichael Tuexen * it non-revokable too
1221b7b84c0eSMichael Tuexen */
122244249214SRandall Stewart sctp_mark_non_revokable(asoc, control->sinfo_tsn);
122344249214SRandall Stewart } else if (control->end_added == 0) {
1224b7b84c0eSMichael Tuexen /*
1225b7b84c0eSMichael Tuexen * Check if we can defer adding until its
1226b7b84c0eSMichael Tuexen * all there
1227b7b84c0eSMichael Tuexen */
122844249214SRandall Stewart if ((control->length < pd_point) || (strm->pd_api_started)) {
1229b7b84c0eSMichael Tuexen /*
1230b7b84c0eSMichael Tuexen * Don't need it or cannot add more
1231b7b84c0eSMichael Tuexen * (one being delivered that way)
1232b7b84c0eSMichael Tuexen */
123344249214SRandall Stewart goto out;
123444249214SRandall Stewart }
123544249214SRandall Stewart }
1236c09a1534SMichael Tuexen done = (control->end_added) && (control->last_frag_seen);
123744249214SRandall Stewart if (control->on_read_q == 0) {
1238253a63b8SMichael Tuexen if (!done) {
1239253a63b8SMichael Tuexen if (asoc->size_on_all_streams >= control->length) {
1240253a63b8SMichael Tuexen asoc->size_on_all_streams -= control->length;
1241253a63b8SMichael Tuexen } else {
1242253a63b8SMichael Tuexen #ifdef INVARIANTS
1243253a63b8SMichael Tuexen panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
1244253a63b8SMichael Tuexen #else
1245253a63b8SMichael Tuexen asoc->size_on_all_streams = 0;
1246253a63b8SMichael Tuexen #endif
1247253a63b8SMichael Tuexen }
1248253a63b8SMichael Tuexen strm->pd_api_started = 1;
1249253a63b8SMichael Tuexen control->pdapi_started = 1;
1250253a63b8SMichael Tuexen }
125144249214SRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb,
125244249214SRandall Stewart control,
125344249214SRandall Stewart &stcb->sctp_socket->so_rcv, control->end_added,
1254d1ea5fa9SMichael Tuexen inp_read_lock_held, SCTP_SO_NOT_LOCKED);
125544249214SRandall Stewart }
125649656eefSMichael Tuexen strm->last_mid_delivered = next_to_del;
1257c09a1534SMichael Tuexen if (done) {
125844249214SRandall Stewart control = nctl;
125944249214SRandall Stewart goto deliver_more;
126044249214SRandall Stewart }
126144249214SRandall Stewart }
126244249214SRandall Stewart }
126344249214SRandall Stewart out:
126444249214SRandall Stewart return (ret);
126544249214SRandall Stewart }
126644249214SRandall Stewart
126728cd0699SMichael Tuexen uint32_t
sctp_add_chk_to_control(struct sctp_queued_to_read * control,struct sctp_stream_in * strm,struct sctp_tcb * stcb,struct sctp_association * asoc,struct sctp_tmit_chunk * chk,int hold_rlock)126844249214SRandall Stewart sctp_add_chk_to_control(struct sctp_queued_to_read *control,
126944249214SRandall Stewart struct sctp_stream_in *strm,
127044249214SRandall Stewart struct sctp_tcb *stcb, struct sctp_association *asoc,
1271b0471b4bSMichael Tuexen struct sctp_tmit_chunk *chk, int hold_rlock)
1272b0471b4bSMichael Tuexen {
127344249214SRandall Stewart /*
127444249214SRandall Stewart * Given a control and a chunk, merge the data from the chk onto the
127544249214SRandall Stewart * control and free up the chunk resources.
127644249214SRandall Stewart */
127728cd0699SMichael Tuexen uint32_t added = 0;
1278847fa61fSMichael Tuexen bool i_locked = false;
127944249214SRandall Stewart
1280847fa61fSMichael Tuexen if (control->on_read_q) {
1281847fa61fSMichael Tuexen if (hold_rlock == 0) {
1282847fa61fSMichael Tuexen /* Its being pd-api'd so we must do some locks. */
128344249214SRandall Stewart SCTP_INP_READ_LOCK(stcb->sctp_ep);
1284847fa61fSMichael Tuexen i_locked = true;
1285847fa61fSMichael Tuexen }
1286847fa61fSMichael Tuexen if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ) {
1287847fa61fSMichael Tuexen goto out;
1288847fa61fSMichael Tuexen }
128944249214SRandall Stewart }
129044249214SRandall Stewart if (control->data == NULL) {
129144249214SRandall Stewart control->data = chk->data;
129244249214SRandall Stewart sctp_setup_tail_pointer(control);
129344249214SRandall Stewart } else {
129428cd0699SMichael Tuexen sctp_add_to_tail_pointer(control, chk->data, &added);
129544249214SRandall Stewart }
129649656eefSMichael Tuexen control->fsn_included = chk->rec.data.fsn;
129744249214SRandall Stewart asoc->size_on_reasm_queue -= chk->send_size;
129844249214SRandall Stewart sctp_ucount_decr(asoc->cnt_on_reasm_queue);
129949656eefSMichael Tuexen sctp_mark_non_revokable(asoc, chk->rec.data.tsn);
130044249214SRandall Stewart chk->data = NULL;
130144249214SRandall Stewart if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
130244249214SRandall Stewart control->first_frag_seen = 1;
13038b9c95f4SMichael Tuexen control->sinfo_tsn = chk->rec.data.tsn;
13048b9c95f4SMichael Tuexen control->sinfo_ppid = chk->rec.data.ppid;
130544249214SRandall Stewart }
130644249214SRandall Stewart if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
130744249214SRandall Stewart /* Its complete */
130844249214SRandall Stewart if ((control->on_strm_q) && (control->on_read_q)) {
130944249214SRandall Stewart if (control->pdapi_started) {
131044249214SRandall Stewart control->pdapi_started = 0;
131144249214SRandall Stewart strm->pd_api_started = 0;
131244249214SRandall Stewart }
131344249214SRandall Stewart if (control->on_strm_q == SCTP_ON_UNORDERED) {
131444249214SRandall Stewart /* Unordered */
131544249214SRandall Stewart TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
131644249214SRandall Stewart control->on_strm_q = 0;
131744249214SRandall Stewart } else if (control->on_strm_q == SCTP_ON_ORDERED) {
131844249214SRandall Stewart /* Ordered */
131944249214SRandall Stewart TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
1320253a63b8SMichael Tuexen /*
1321253a63b8SMichael Tuexen * Don't need to decrement
1322253a63b8SMichael Tuexen * size_on_all_streams, since control is on
1323253a63b8SMichael Tuexen * the read queue.
1324253a63b8SMichael Tuexen */
132528cd0699SMichael Tuexen sctp_ucount_decr(asoc->cnt_on_all_streams);
132644249214SRandall Stewart control->on_strm_q = 0;
132798d5fd97SMichael Tuexen #ifdef INVARIANTS
132844249214SRandall Stewart } else if (control->on_strm_q) {
132944249214SRandall Stewart panic("Unknown state on ctrl: %p on_strm_q: %d", control,
133044249214SRandall Stewart control->on_strm_q);
133198d5fd97SMichael Tuexen #endif
133244249214SRandall Stewart }
133344249214SRandall Stewart }
133444249214SRandall Stewart control->end_added = 1;
133544249214SRandall Stewart control->last_frag_seen = 1;
133644249214SRandall Stewart }
1337847fa61fSMichael Tuexen out:
133844249214SRandall Stewart if (i_locked) {
133944249214SRandall Stewart SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
134044249214SRandall Stewart }
134144249214SRandall Stewart sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
134228cd0699SMichael Tuexen return (added);
1343f8829a4aSRandall Stewart }
1344f8829a4aSRandall Stewart
1345f8829a4aSRandall Stewart /*
1346f8829a4aSRandall Stewart * Dump onto the re-assembly queue, in its proper place. After dumping on the
13472fb174d1SGordon Bergling * queue, see if anything can be delivered. If so pull it off (or as much as
1348f8829a4aSRandall Stewart * we can. If we run out of space then we must dump what we can and set the
1349f8829a4aSRandall Stewart * appropriate flag to say we queued what we could.
1350f8829a4aSRandall Stewart */
1351f8829a4aSRandall Stewart static void
sctp_queue_data_for_reasm(struct sctp_tcb * stcb,struct sctp_association * asoc,struct sctp_queued_to_read * control,struct sctp_tmit_chunk * chk,int created_control,int * abort_flag,uint32_t tsn)1352f8829a4aSRandall Stewart sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
135344249214SRandall Stewart struct sctp_queued_to_read *control,
135444249214SRandall Stewart struct sctp_tmit_chunk *chk,
135544249214SRandall Stewart int created_control,
135644249214SRandall Stewart int *abort_flag, uint32_t tsn)
1357f8829a4aSRandall Stewart {
135844249214SRandall Stewart uint32_t next_fsn;
135944249214SRandall Stewart struct sctp_tmit_chunk *at, *nat;
13603d6fe5d8SMichael Tuexen struct sctp_stream_in *strm;
1361c09a1534SMichael Tuexen int do_wakeup, unordered;
136228cd0699SMichael Tuexen uint32_t lenadded;
1363f8829a4aSRandall Stewart
13643d6fe5d8SMichael Tuexen strm = &asoc->strmin[control->sinfo_stream];
1365f8829a4aSRandall Stewart /*
136644249214SRandall Stewart * For old un-ordered data chunks.
1367f8829a4aSRandall Stewart */
136844249214SRandall Stewart if ((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED) {
136944249214SRandall Stewart unordered = 1;
1370f8829a4aSRandall Stewart } else {
137144249214SRandall Stewart unordered = 0;
137244249214SRandall Stewart }
137344249214SRandall Stewart /* Must be added to the stream-in queue */
137444249214SRandall Stewart if (created_control) {
1375132c0738SMichael Tuexen if ((unordered == 0) || (asoc->idata_supported)) {
137628cd0699SMichael Tuexen sctp_ucount_incr(asoc->cnt_on_all_streams);
137728cd0699SMichael Tuexen }
137844249214SRandall Stewart if (sctp_place_control_in_stream(strm, asoc, control)) {
137944249214SRandall Stewart /* Duplicate SSN? */
1380b1deed45SMichael Tuexen sctp_abort_in_reasm(stcb, control, chk,
138144249214SRandall Stewart abort_flag,
138244249214SRandall Stewart SCTP_FROM_SCTP_INDATA + SCTP_LOC_6);
138353999485SMichael Tuexen sctp_clean_up_control(stcb, control);
138444249214SRandall Stewart return;
138544249214SRandall Stewart }
138644249214SRandall Stewart if ((tsn == (asoc->cumulative_tsn + 1) && (asoc->idata_supported == 0))) {
1387f8829a4aSRandall Stewart /*
138844249214SRandall Stewart * Ok we created this control and now lets validate
138944249214SRandall Stewart * that its legal i.e. there is a B bit set, if not
139044249214SRandall Stewart * and we have up to the cum-ack then its invalid.
139144249214SRandall Stewart */
139244249214SRandall Stewart if ((chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) == 0) {
1393b1deed45SMichael Tuexen sctp_abort_in_reasm(stcb, control, chk,
139444249214SRandall Stewart abort_flag,
139544249214SRandall Stewart SCTP_FROM_SCTP_INDATA + SCTP_LOC_7);
139644249214SRandall Stewart return;
139744249214SRandall Stewart }
139844249214SRandall Stewart }
139944249214SRandall Stewart }
1400a39ddef0SMichael Tuexen if ((asoc->idata_supported == 0) && (unordered == 1)) {
1401d1ea5fa9SMichael Tuexen sctp_inject_old_unordered_data(stcb, asoc, control, chk, abort_flag);
140244249214SRandall Stewart return;
140344249214SRandall Stewart }
140444249214SRandall Stewart /*
140544249214SRandall Stewart * Ok we must queue the chunk into the reasembly portion: o if its
140644249214SRandall Stewart * the first it goes to the control mbuf. o if its not first but the
140744249214SRandall Stewart * next in sequence it goes to the control, and each succeeding one
140844249214SRandall Stewart * in order also goes. o if its not in order we place it on the list
140944249214SRandall Stewart * in its place.
141044249214SRandall Stewart */
141144249214SRandall Stewart if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
141244249214SRandall Stewart /* Its the very first one. */
141344249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX,
1414f2ea2a2dSMichael Tuexen "chunk is a first fsn: %u becomes fsn_included\n",
141549656eefSMichael Tuexen chk->rec.data.fsn);
141644249214SRandall Stewart if (control->first_frag_seen) {
141744249214SRandall Stewart /*
141844249214SRandall Stewart * Error on senders part, they either sent us two
141944249214SRandall Stewart * data chunks with FIRST, or they sent two
142044249214SRandall Stewart * un-ordered chunks that were fragmented at the
142144249214SRandall Stewart * same time in the same stream.
142244249214SRandall Stewart */
1423b1deed45SMichael Tuexen sctp_abort_in_reasm(stcb, control, chk,
142444249214SRandall Stewart abort_flag,
142544249214SRandall Stewart SCTP_FROM_SCTP_INDATA + SCTP_LOC_8);
142644249214SRandall Stewart return;
142744249214SRandall Stewart }
142844249214SRandall Stewart control->first_frag_seen = 1;
14298b9c95f4SMichael Tuexen control->sinfo_ppid = chk->rec.data.ppid;
14308b9c95f4SMichael Tuexen control->sinfo_tsn = chk->rec.data.tsn;
143149656eefSMichael Tuexen control->fsn_included = chk->rec.data.fsn;
143244249214SRandall Stewart control->data = chk->data;
143349656eefSMichael Tuexen sctp_mark_non_revokable(asoc, chk->rec.data.tsn);
143444249214SRandall Stewart chk->data = NULL;
143544249214SRandall Stewart sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
143644249214SRandall Stewart sctp_setup_tail_pointer(control);
143728cd0699SMichael Tuexen asoc->size_on_all_streams += control->length;
143844249214SRandall Stewart } else {
143944249214SRandall Stewart /* Place the chunk in our list */
144044249214SRandall Stewart int inserted = 0;
144144249214SRandall Stewart
144244249214SRandall Stewart if (control->last_frag_seen == 0) {
144344249214SRandall Stewart /* Still willing to raise highest FSN seen */
144449656eefSMichael Tuexen if (SCTP_TSN_GT(chk->rec.data.fsn, control->top_fsn)) {
144544249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX,
1446f2ea2a2dSMichael Tuexen "We have a new top_fsn: %u\n",
144749656eefSMichael Tuexen chk->rec.data.fsn);
144849656eefSMichael Tuexen control->top_fsn = chk->rec.data.fsn;
144944249214SRandall Stewart }
145044249214SRandall Stewart if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
145144249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX,
1452f2ea2a2dSMichael Tuexen "The last fsn is now in place fsn: %u\n",
145349656eefSMichael Tuexen chk->rec.data.fsn);
145444249214SRandall Stewart control->last_frag_seen = 1;
1455ec24a1b6SMichael Tuexen if (SCTP_TSN_GT(control->top_fsn, chk->rec.data.fsn)) {
1456ec24a1b6SMichael Tuexen SCTPDBG(SCTP_DEBUG_XXX,
1457ec24a1b6SMichael Tuexen "New fsn: %u is not at top_fsn: %u -- abort\n",
1458ec24a1b6SMichael Tuexen chk->rec.data.fsn,
1459ec24a1b6SMichael Tuexen control->top_fsn);
1460ec24a1b6SMichael Tuexen sctp_abort_in_reasm(stcb, control, chk,
1461ec24a1b6SMichael Tuexen abort_flag,
1462ec24a1b6SMichael Tuexen SCTP_FROM_SCTP_INDATA + SCTP_LOC_9);
1463ec24a1b6SMichael Tuexen return;
1464ec24a1b6SMichael Tuexen }
146544249214SRandall Stewart }
146644249214SRandall Stewart if (asoc->idata_supported || control->first_frag_seen) {
146744249214SRandall Stewart /*
146844249214SRandall Stewart * For IDATA we always check since we know
146944249214SRandall Stewart * that the first fragment is 0. For old
147044249214SRandall Stewart * DATA we have to receive the first before
1471cd0a4ff6SPedro F. Giffuni * we know the first FSN (which is the TSN).
147244249214SRandall Stewart */
147349656eefSMichael Tuexen if (SCTP_TSN_GE(control->fsn_included, chk->rec.data.fsn)) {
1474b7b84c0eSMichael Tuexen /*
1475b7b84c0eSMichael Tuexen * We have already delivered up to
1476b7b84c0eSMichael Tuexen * this so its a dup
1477b7b84c0eSMichael Tuexen */
1478b1deed45SMichael Tuexen sctp_abort_in_reasm(stcb, control, chk,
147944249214SRandall Stewart abort_flag,
1480ec24a1b6SMichael Tuexen SCTP_FROM_SCTP_INDATA + SCTP_LOC_10);
148144249214SRandall Stewart return;
148244249214SRandall Stewart }
148344249214SRandall Stewart }
148444249214SRandall Stewart } else {
148544249214SRandall Stewart if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
148644249214SRandall Stewart /* Second last? huh? */
148744249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX,
1488f2ea2a2dSMichael Tuexen "Duplicate last fsn: %u (top: %u) -- abort\n",
148949656eefSMichael Tuexen chk->rec.data.fsn, control->top_fsn);
1490b1deed45SMichael Tuexen sctp_abort_in_reasm(stcb, control,
149144249214SRandall Stewart chk, abort_flag,
1492ec24a1b6SMichael Tuexen SCTP_FROM_SCTP_INDATA + SCTP_LOC_11);
149344249214SRandall Stewart return;
149444249214SRandall Stewart }
149544249214SRandall Stewart if (asoc->idata_supported || control->first_frag_seen) {
149644249214SRandall Stewart /*
149744249214SRandall Stewart * For IDATA we always check since we know
149844249214SRandall Stewart * that the first fragment is 0. For old
149944249214SRandall Stewart * DATA we have to receive the first before
1500cd0a4ff6SPedro F. Giffuni * we know the first FSN (which is the TSN).
150144249214SRandall Stewart */
150244249214SRandall Stewart
150349656eefSMichael Tuexen if (SCTP_TSN_GE(control->fsn_included, chk->rec.data.fsn)) {
1504b7b84c0eSMichael Tuexen /*
1505b7b84c0eSMichael Tuexen * We have already delivered up to
1506b7b84c0eSMichael Tuexen * this so its a dup
1507b7b84c0eSMichael Tuexen */
150844249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX,
1509f2ea2a2dSMichael Tuexen "New fsn: %u is already seen in included_fsn: %u -- abort\n",
151049656eefSMichael Tuexen chk->rec.data.fsn, control->fsn_included);
1511b1deed45SMichael Tuexen sctp_abort_in_reasm(stcb, control, chk,
151244249214SRandall Stewart abort_flag,
1513ec24a1b6SMichael Tuexen SCTP_FROM_SCTP_INDATA + SCTP_LOC_12);
151444249214SRandall Stewart return;
151544249214SRandall Stewart }
151644249214SRandall Stewart }
1517b7b84c0eSMichael Tuexen /*
1518b7b84c0eSMichael Tuexen * validate not beyond top FSN if we have seen last
1519b7b84c0eSMichael Tuexen * one
1520b7b84c0eSMichael Tuexen */
152149656eefSMichael Tuexen if (SCTP_TSN_GT(chk->rec.data.fsn, control->top_fsn)) {
152244249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX,
1523f2ea2a2dSMichael Tuexen "New fsn: %u is beyond or at top_fsn: %u -- abort\n",
152449656eefSMichael Tuexen chk->rec.data.fsn,
152544249214SRandall Stewart control->top_fsn);
1526b1deed45SMichael Tuexen sctp_abort_in_reasm(stcb, control, chk,
152744249214SRandall Stewart abort_flag,
1528ec24a1b6SMichael Tuexen SCTP_FROM_SCTP_INDATA + SCTP_LOC_13);
152944249214SRandall Stewart return;
153044249214SRandall Stewart }
153144249214SRandall Stewart }
153244249214SRandall Stewart /*
153344249214SRandall Stewart * If we reach here, we need to place the new chunk in the
153444249214SRandall Stewart * reassembly for this control.
153544249214SRandall Stewart */
153644249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX,
1537f2ea2a2dSMichael Tuexen "chunk is a not first fsn: %u needs to be inserted\n",
153849656eefSMichael Tuexen chk->rec.data.fsn);
153944249214SRandall Stewart TAILQ_FOREACH(at, &control->reasm, sctp_next) {
154049656eefSMichael Tuexen if (SCTP_TSN_GT(at->rec.data.fsn, chk->rec.data.fsn)) {
154191e04f9eSMichael Tuexen if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
154291e04f9eSMichael Tuexen /* Last not at the end? huh? */
154391e04f9eSMichael Tuexen SCTPDBG(SCTP_DEBUG_XXX,
154491e04f9eSMichael Tuexen "Last fragment not last in list: -- abort\n");
154591e04f9eSMichael Tuexen sctp_abort_in_reasm(stcb, control,
154691e04f9eSMichael Tuexen chk, abort_flag,
154791e04f9eSMichael Tuexen SCTP_FROM_SCTP_INDATA + SCTP_LOC_14);
154891e04f9eSMichael Tuexen return;
154991e04f9eSMichael Tuexen }
155044249214SRandall Stewart /*
155144249214SRandall Stewart * This one in queue is bigger than the new
155244249214SRandall Stewart * one, insert the new one before at.
155344249214SRandall Stewart */
155444249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX,
1555f2ea2a2dSMichael Tuexen "Insert it before fsn: %u\n",
155649656eefSMichael Tuexen at->rec.data.fsn);
1557f8829a4aSRandall Stewart asoc->size_on_reasm_queue += chk->send_size;
1558f8829a4aSRandall Stewart sctp_ucount_incr(asoc->cnt_on_reasm_queue);
155944249214SRandall Stewart TAILQ_INSERT_BEFORE(at, chk, sctp_next);
156044249214SRandall Stewart inserted = 1;
156144249214SRandall Stewart break;
156249656eefSMichael Tuexen } else if (at->rec.data.fsn == chk->rec.data.fsn) {
1563b7b84c0eSMichael Tuexen /*
1564b7b84c0eSMichael Tuexen * Gak, He sent me a duplicate str seq
1565b7b84c0eSMichael Tuexen * number
1566b7b84c0eSMichael Tuexen */
156744249214SRandall Stewart /*
156844249214SRandall Stewart * foo bar, I guess I will just free this
156944249214SRandall Stewart * new guy, should we abort too? FIX ME
157044249214SRandall Stewart * MAYBE? Or it COULD be that the SSN's have
157144249214SRandall Stewart * wrapped. Maybe I should compare to TSN
157244249214SRandall Stewart * somehow... sigh for now just blow away
157344249214SRandall Stewart * the chunk!
157444249214SRandall Stewart */
157544249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX,
1576f2ea2a2dSMichael Tuexen "Duplicate to fsn: %u -- abort\n",
157749656eefSMichael Tuexen at->rec.data.fsn);
1578b1deed45SMichael Tuexen sctp_abort_in_reasm(stcb, control,
157944249214SRandall Stewart chk, abort_flag,
158091e04f9eSMichael Tuexen SCTP_FROM_SCTP_INDATA + SCTP_LOC_15);
158144249214SRandall Stewart return;
158244249214SRandall Stewart }
158344249214SRandall Stewart }
158444249214SRandall Stewart if (inserted == 0) {
158544249214SRandall Stewart /* Goes on the end */
1586f2ea2a2dSMichael Tuexen SCTPDBG(SCTP_DEBUG_XXX, "Inserting at tail of list fsn: %u\n",
158749656eefSMichael Tuexen chk->rec.data.fsn);
158844249214SRandall Stewart asoc->size_on_reasm_queue += chk->send_size;
158944249214SRandall Stewart sctp_ucount_incr(asoc->cnt_on_reasm_queue);
159044249214SRandall Stewart TAILQ_INSERT_TAIL(&control->reasm, chk, sctp_next);
159144249214SRandall Stewart }
159244249214SRandall Stewart }
159344249214SRandall Stewart /*
159444249214SRandall Stewart * Ok lets see if we can suck any up into the control structure that
159544249214SRandall Stewart * are in seq if it makes sense.
159644249214SRandall Stewart */
1597c09a1534SMichael Tuexen do_wakeup = 0;
159844249214SRandall Stewart /*
159944249214SRandall Stewart * If the first fragment has not been seen there is no sense in
160044249214SRandall Stewart * looking.
160144249214SRandall Stewart */
160244249214SRandall Stewart if (control->first_frag_seen) {
160344249214SRandall Stewart next_fsn = control->fsn_included + 1;
160444249214SRandall Stewart TAILQ_FOREACH_SAFE(at, &control->reasm, sctp_next, nat) {
160549656eefSMichael Tuexen if (at->rec.data.fsn == next_fsn) {
160644249214SRandall Stewart /* We can add this one now to the control */
160744249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX,
1608f2ea2a2dSMichael Tuexen "Adding more to control: %p at: %p fsn: %u next_fsn: %u included: %u\n",
160944249214SRandall Stewart control, at,
161049656eefSMichael Tuexen at->rec.data.fsn,
161144249214SRandall Stewart next_fsn, control->fsn_included);
161244249214SRandall Stewart TAILQ_REMOVE(&control->reasm, at, sctp_next);
161328cd0699SMichael Tuexen lenadded = sctp_add_chk_to_control(control, strm, stcb, asoc, at, SCTP_READ_LOCK_NOT_HELD);
1614c09a1534SMichael Tuexen if (control->on_read_q) {
1615c09a1534SMichael Tuexen do_wakeup = 1;
161672e23abaSMichael Tuexen } else {
161772e23abaSMichael Tuexen /*
161872e23abaSMichael Tuexen * We only add to the
161972e23abaSMichael Tuexen * size-on-all-streams if its not on
162072e23abaSMichael Tuexen * the read q. The read q flag will
162172e23abaSMichael Tuexen * cause a sballoc so its accounted
162272e23abaSMichael Tuexen * for there.
162372e23abaSMichael Tuexen */
162472e23abaSMichael Tuexen asoc->size_on_all_streams += lenadded;
1625c09a1534SMichael Tuexen }
162644249214SRandall Stewart next_fsn++;
162744249214SRandall Stewart if (control->end_added && control->pdapi_started) {
162844249214SRandall Stewart if (strm->pd_api_started) {
162944249214SRandall Stewart strm->pd_api_started = 0;
163044249214SRandall Stewart control->pdapi_started = 0;
163144249214SRandall Stewart }
163244249214SRandall Stewart if (control->on_read_q == 0) {
163344249214SRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb,
163444249214SRandall Stewart control,
163544249214SRandall Stewart &stcb->sctp_socket->so_rcv, control->end_added,
163644249214SRandall Stewart SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
163744249214SRandall Stewart }
163844249214SRandall Stewart break;
163944249214SRandall Stewart }
164044249214SRandall Stewart } else {
1641f8829a4aSRandall Stewart break;
1642f8829a4aSRandall Stewart }
1643f8829a4aSRandall Stewart }
1644f8829a4aSRandall Stewart }
1645c09a1534SMichael Tuexen if (do_wakeup) {
164644249214SRandall Stewart /* Need to wakeup the reader */
1647b1deed45SMichael Tuexen sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
1648f8829a4aSRandall Stewart }
1649f8829a4aSRandall Stewart }
1650f8829a4aSRandall Stewart
165144249214SRandall Stewart static struct sctp_queued_to_read *
sctp_find_reasm_entry(struct sctp_stream_in * strm,uint32_t mid,int ordered,int idata_supported)165249656eefSMichael Tuexen sctp_find_reasm_entry(struct sctp_stream_in *strm, uint32_t mid, int ordered, int idata_supported)
1653f8829a4aSRandall Stewart {
1654c09a1534SMichael Tuexen struct sctp_queued_to_read *control;
1655f8829a4aSRandall Stewart
165644249214SRandall Stewart if (ordered) {
1657c09a1534SMichael Tuexen TAILQ_FOREACH(control, &strm->inqueue, next_instrm) {
165849656eefSMichael Tuexen if (SCTP_MID_EQ(idata_supported, control->mid, mid)) {
165944249214SRandall Stewart break;
166044249214SRandall Stewart }
166144249214SRandall Stewart }
1662f8829a4aSRandall Stewart } else {
166349656eefSMichael Tuexen if (idata_supported) {
1664c09a1534SMichael Tuexen TAILQ_FOREACH(control, &strm->uno_inqueue, next_instrm) {
166549656eefSMichael Tuexen if (SCTP_MID_EQ(idata_supported, control->mid, mid)) {
166644249214SRandall Stewart break;
1667f8829a4aSRandall Stewart }
1668f8829a4aSRandall Stewart }
166949656eefSMichael Tuexen } else {
167049656eefSMichael Tuexen control = TAILQ_FIRST(&strm->uno_inqueue);
167149656eefSMichael Tuexen }
1672f8829a4aSRandall Stewart }
1673c09a1534SMichael Tuexen return (control);
1674f8829a4aSRandall Stewart }
167544249214SRandall Stewart
1676f8829a4aSRandall Stewart static int
sctp_process_a_data_chunk(struct sctp_tcb * stcb,struct sctp_association * asoc,struct mbuf ** m,int offset,int chk_length,struct sctp_nets * net,uint32_t * high_tsn,int * abort_flag,int * break_flag,int last_chunk,uint8_t chk_type)1677f8829a4aSRandall Stewart sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
167844249214SRandall Stewart struct mbuf **m, int offset, int chk_length,
1679f8829a4aSRandall Stewart struct sctp_nets *net, uint32_t *high_tsn, int *abort_flag,
16808b9c95f4SMichael Tuexen int *break_flag, int last_chunk, uint8_t chk_type)
1681f8829a4aSRandall Stewart {
168295844fceSMichael Tuexen struct sctp_tmit_chunk *chk = NULL; /* make gcc happy */
16836ddc8438SMichael Tuexen struct sctp_stream_in *strm;
168449656eefSMichael Tuexen uint32_t tsn, fsn, gap, mid;
1685f8829a4aSRandall Stewart struct mbuf *dmbuf;
16867215cc1bSMichael Tuexen int the_len;
1687139bc87fSRandall Stewart int need_reasm_check = 0;
168849656eefSMichael Tuexen uint16_t sid;
1689ff1ffd74SMichael Tuexen struct mbuf *op_err;
1690ff1ffd74SMichael Tuexen char msg[SCTP_DIAG_INFO_LEN];
169128cd0699SMichael Tuexen struct sctp_queued_to_read *control, *ncontrol;
169249656eefSMichael Tuexen uint32_t ppid;
16938b9c95f4SMichael Tuexen uint8_t chk_flags;
169417205eccSRandall Stewart struct sctp_stream_reset_list *liste;
169544249214SRandall Stewart int ordered;
169644249214SRandall Stewart size_t clen;
169744249214SRandall Stewart int created_control = 0;
1698f8829a4aSRandall Stewart
16998b9c95f4SMichael Tuexen if (chk_type == SCTP_IDATA) {
17008b9c95f4SMichael Tuexen struct sctp_idata_chunk *chunk, chunk_buf;
17018b9c95f4SMichael Tuexen
17028b9c95f4SMichael Tuexen chunk = (struct sctp_idata_chunk *)sctp_m_getptr(*m, offset,
170344249214SRandall Stewart sizeof(struct sctp_idata_chunk), (uint8_t *)&chunk_buf);
17048b9c95f4SMichael Tuexen chk_flags = chunk->ch.chunk_flags;
170544249214SRandall Stewart clen = sizeof(struct sctp_idata_chunk);
17068b9c95f4SMichael Tuexen tsn = ntohl(chunk->dp.tsn);
17078b9c95f4SMichael Tuexen sid = ntohs(chunk->dp.sid);
17088b9c95f4SMichael Tuexen mid = ntohl(chunk->dp.mid);
17098b9c95f4SMichael Tuexen if (chk_flags & SCTP_DATA_FIRST_FRAG) {
171044249214SRandall Stewart fsn = 0;
17118b9c95f4SMichael Tuexen ppid = chunk->dp.ppid_fsn.ppid;
171244249214SRandall Stewart } else {
17138b9c95f4SMichael Tuexen fsn = ntohl(chunk->dp.ppid_fsn.fsn);
17148b9c95f4SMichael Tuexen ppid = 0xffffffff; /* Use as an invalid value. */
171544249214SRandall Stewart }
17168b9c95f4SMichael Tuexen } else {
17178b9c95f4SMichael Tuexen struct sctp_data_chunk *chunk, chunk_buf;
17188b9c95f4SMichael Tuexen
17198b9c95f4SMichael Tuexen chunk = (struct sctp_data_chunk *)sctp_m_getptr(*m, offset,
17208b9c95f4SMichael Tuexen sizeof(struct sctp_data_chunk), (uint8_t *)&chunk_buf);
17218b9c95f4SMichael Tuexen chk_flags = chunk->ch.chunk_flags;
17228b9c95f4SMichael Tuexen clen = sizeof(struct sctp_data_chunk);
17238b9c95f4SMichael Tuexen tsn = ntohl(chunk->dp.tsn);
17248b9c95f4SMichael Tuexen sid = ntohs(chunk->dp.sid);
17258b9c95f4SMichael Tuexen mid = (uint32_t)(ntohs(chunk->dp.ssn));
17268b9c95f4SMichael Tuexen fsn = tsn;
17278b9c95f4SMichael Tuexen ppid = chunk->dp.ppid;
17288b9c95f4SMichael Tuexen }
172944249214SRandall Stewart if ((size_t)chk_length == clen) {
173044249214SRandall Stewart /*
173144249214SRandall Stewart * Need to send an abort since we had a empty data chunk.
173244249214SRandall Stewart */
17338b9c95f4SMichael Tuexen op_err = sctp_generate_no_user_data_cause(tsn);
173491e04f9eSMichael Tuexen stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_16;
1735105b68b4SMichael Tuexen sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED);
173644249214SRandall Stewart *abort_flag = 1;
173744249214SRandall Stewart return (0);
173844249214SRandall Stewart }
17398b9c95f4SMichael Tuexen if ((chk_flags & SCTP_DATA_SACK_IMMEDIATELY) == SCTP_DATA_SACK_IMMEDIATELY) {
1740b3f1ea41SRandall Stewart asoc->send_sack = 1;
1741b3f1ea41SRandall Stewart }
17428b9c95f4SMichael Tuexen ordered = ((chk_flags & SCTP_DATA_UNORDERED) == 0);
1743b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
1744c4739e2fSRandall Stewart sctp_log_map(tsn, asoc->cumulative_tsn, asoc->highest_tsn_inside_map, SCTP_MAP_TSN_ENTERS);
174580fefe0aSRandall Stewart }
1746ad81507eSRandall Stewart if (stcb == NULL) {
1747ad81507eSRandall Stewart return (0);
1748ad81507eSRandall Stewart }
17498b9c95f4SMichael Tuexen SCTP_LTRACE_CHK(stcb->sctp_ep, stcb, chk_type, tsn);
175020b07a4dSMichael Tuexen if (SCTP_TSN_GE(asoc->cumulative_tsn, tsn)) {
1751f8829a4aSRandall Stewart /* It is a duplicate */
1752f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_recvdupdata);
1753f8829a4aSRandall Stewart if (asoc->numduptsns < SCTP_MAX_DUP_TSNS) {
1754f8829a4aSRandall Stewart /* Record a dup for the next outbound sack */
1755f8829a4aSRandall Stewart asoc->dup_tsns[asoc->numduptsns] = tsn;
1756f8829a4aSRandall Stewart asoc->numduptsns++;
1757f8829a4aSRandall Stewart }
1758b201f536SRandall Stewart asoc->send_sack = 1;
1759f8829a4aSRandall Stewart return (0);
1760f8829a4aSRandall Stewart }
1761f8829a4aSRandall Stewart /* Calculate the number of TSN's between the base and this TSN */
1762d50c1d79SRandall Stewart SCTP_CALC_TSN_TO_GAP(gap, tsn, asoc->mapping_array_base_tsn);
1763f8829a4aSRandall Stewart if (gap >= (SCTP_MAPPING_ARRAY << 3)) {
1764f8829a4aSRandall Stewart /* Can't hold the bit in the mapping at max array, toss it */
1765f8829a4aSRandall Stewart return (0);
1766f8829a4aSRandall Stewart }
1767f8829a4aSRandall Stewart if (gap >= (uint32_t)(asoc->mapping_array_size << 3)) {
1768207304d4SRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb);
17690696e120SRandall Stewart if (sctp_expand_mapping_array(asoc, gap)) {
1770f8829a4aSRandall Stewart /* Can't expand, drop it */
1771f8829a4aSRandall Stewart return (0);
1772f8829a4aSRandall Stewart }
1773f8829a4aSRandall Stewart }
177420b07a4dSMichael Tuexen if (SCTP_TSN_GT(tsn, *high_tsn)) {
1775f8829a4aSRandall Stewart *high_tsn = tsn;
1776f8829a4aSRandall Stewart }
1777f8829a4aSRandall Stewart /* See if we have received this one already */
177877acdc25SRandall Stewart if (SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap) ||
177977acdc25SRandall Stewart SCTP_IS_TSN_PRESENT(asoc->nr_mapping_array, gap)) {
1780f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_recvdupdata);
1781f8829a4aSRandall Stewart if (asoc->numduptsns < SCTP_MAX_DUP_TSNS) {
1782f8829a4aSRandall Stewart /* Record a dup for the next outbound sack */
1783f8829a4aSRandall Stewart asoc->dup_tsns[asoc->numduptsns] = tsn;
1784f8829a4aSRandall Stewart asoc->numduptsns++;
1785f8829a4aSRandall Stewart }
178642551e99SRandall Stewart asoc->send_sack = 1;
1787f8829a4aSRandall Stewart return (0);
1788f8829a4aSRandall Stewart }
1789f8829a4aSRandall Stewart /*
1790f8829a4aSRandall Stewart * Check to see about the GONE flag, duplicates would cause a sack
1791f8829a4aSRandall Stewart * to be sent up above
1792f8829a4aSRandall Stewart */
1793ad81507eSRandall Stewart if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
1794f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
1795ff1ffd74SMichael Tuexen (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET))) {
1796f8829a4aSRandall Stewart /*
1797f8829a4aSRandall Stewart * wait a minute, this guy is gone, there is no longer a
1798f8829a4aSRandall Stewart * receiver. Send peer an ABORT!
1799f8829a4aSRandall Stewart */
1800ff1ffd74SMichael Tuexen op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, "");
1801105b68b4SMichael Tuexen sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED);
1802f8829a4aSRandall Stewart *abort_flag = 1;
1803f8829a4aSRandall Stewart return (0);
1804f8829a4aSRandall Stewart }
1805f8829a4aSRandall Stewart /*
1806f8829a4aSRandall Stewart * Now before going further we see if there is room. If NOT then we
1807f8829a4aSRandall Stewart * MAY let one through only IF this TSN is the one we are waiting
1808f8829a4aSRandall Stewart * for on a partial delivery API.
1809f8829a4aSRandall Stewart */
1810f8829a4aSRandall Stewart
181144249214SRandall Stewart /* Is the stream valid? */
181249656eefSMichael Tuexen if (sid >= asoc->streamincnt) {
181386eda749SMichael Tuexen struct sctp_error_invalid_stream *cause;
1814f8829a4aSRandall Stewart
181586eda749SMichael Tuexen op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_error_invalid_stream),
1816eb1b1807SGleb Smirnoff 0, M_NOWAIT, 1, MT_DATA);
181786eda749SMichael Tuexen if (op_err != NULL) {
1818f8829a4aSRandall Stewart /* add some space up front so prepend will work well */
181986eda749SMichael Tuexen SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr));
182086eda749SMichael Tuexen cause = mtod(op_err, struct sctp_error_invalid_stream *);
1821f8829a4aSRandall Stewart /*
1822f8829a4aSRandall Stewart * Error causes are just param's and this one has
1823f8829a4aSRandall Stewart * two back to back phdr, one with the error type
1824f8829a4aSRandall Stewart * and size, the other with the streamid and a rsvd
1825f8829a4aSRandall Stewart */
182686eda749SMichael Tuexen SCTP_BUF_LEN(op_err) = sizeof(struct sctp_error_invalid_stream);
182786eda749SMichael Tuexen cause->cause.code = htons(SCTP_CAUSE_INVALID_STREAM);
182886eda749SMichael Tuexen cause->cause.length = htons(sizeof(struct sctp_error_invalid_stream));
18298b9c95f4SMichael Tuexen cause->stream_id = htons(sid);
183086eda749SMichael Tuexen cause->reserved = htons(0);
183186eda749SMichael Tuexen sctp_queue_op_err(stcb, op_err);
1832f8829a4aSRandall Stewart }
1833f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_badsid);
1834207304d4SRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb);
1835830d754dSRandall Stewart SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
183620b07a4dSMichael Tuexen if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
1837830d754dSRandall Stewart asoc->highest_tsn_inside_nr_map = tsn;
1838d06c82f1SRandall Stewart }
1839d06c82f1SRandall Stewart if (tsn == (asoc->cumulative_tsn + 1)) {
1840d06c82f1SRandall Stewart /* Update cum-ack */
1841d06c82f1SRandall Stewart asoc->cumulative_tsn = tsn;
1842d06c82f1SRandall Stewart }
1843f8829a4aSRandall Stewart return (0);
1844f8829a4aSRandall Stewart }
1845f8829a4aSRandall Stewart /*
184644249214SRandall Stewart * If its a fragmented message, lets see if we can find the control
184744249214SRandall Stewart * on the reassembly queues.
1848f8829a4aSRandall Stewart */
18498b9c95f4SMichael Tuexen if ((chk_type == SCTP_IDATA) &&
18508b9c95f4SMichael Tuexen ((chk_flags & SCTP_DATA_FIRST_FRAG) == 0) &&
1851be46a7c5SMichael Tuexen (fsn == 0)) {
185244249214SRandall Stewart /*
185344249214SRandall Stewart * The first *must* be fsn 0, and other (middle/end) pieces
1854be46a7c5SMichael Tuexen * can *not* be fsn 0. XXX: This can happen in case of a
1855be46a7c5SMichael Tuexen * wrap around. Ignore is for now.
185644249214SRandall Stewart */
1857999f86d6SMichael Tuexen SCTP_SNPRINTF(msg, sizeof(msg), "FSN zero for MID=%8.8x, but flags=%2.2x", mid, chk_flags);
185844249214SRandall Stewart goto err_out;
185944249214SRandall Stewart }
18603d6fe5d8SMichael Tuexen control = sctp_find_reasm_entry(&asoc->strmin[sid], mid, ordered, asoc->idata_supported);
186144249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags:0x%x look for control on queues %p\n",
18628b9c95f4SMichael Tuexen chk_flags, control);
18638b9c95f4SMichael Tuexen if ((chk_flags & SCTP_DATA_NOT_FRAG) != SCTP_DATA_NOT_FRAG) {
1864be46a7c5SMichael Tuexen /* See if we can find the re-assembly entity */
1865be46a7c5SMichael Tuexen if (control != NULL) {
186644249214SRandall Stewart /* We found something, does it belong? */
186749656eefSMichael Tuexen if (ordered && (mid != control->mid)) {
1868999f86d6SMichael Tuexen SCTP_SNPRINTF(msg, sizeof(msg), "Reassembly problem (MID=%8.8x)", mid);
186944249214SRandall Stewart err_out:
187044249214SRandall Stewart op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
187191e04f9eSMichael Tuexen stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_17;
1872105b68b4SMichael Tuexen sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED);
187344249214SRandall Stewart *abort_flag = 1;
187444249214SRandall Stewart return (0);
187544249214SRandall Stewart }
187644249214SRandall Stewart if (ordered && ((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED)) {
1877b7b84c0eSMichael Tuexen /*
1878b7b84c0eSMichael Tuexen * We can't have a switched order with an
1879b7b84c0eSMichael Tuexen * unordered chunk
1880b7b84c0eSMichael Tuexen */
1881999f86d6SMichael Tuexen SCTP_SNPRINTF(msg, sizeof(msg),
1882999f86d6SMichael Tuexen "All fragments of a user message must be ordered or unordered (TSN=%8.8x)",
1883821bae7cSMichael Tuexen tsn);
188444249214SRandall Stewart goto err_out;
188544249214SRandall Stewart }
188644249214SRandall Stewart if (!ordered && (((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED) == 0)) {
1887b7b84c0eSMichael Tuexen /*
1888b7b84c0eSMichael Tuexen * We can't have a switched unordered with a
1889b7b84c0eSMichael Tuexen * ordered chunk
1890b7b84c0eSMichael Tuexen */
1891999f86d6SMichael Tuexen SCTP_SNPRINTF(msg, sizeof(msg),
1892999f86d6SMichael Tuexen "All fragments of a user message must be ordered or unordered (TSN=%8.8x)",
1893821bae7cSMichael Tuexen tsn);
189444249214SRandall Stewart goto err_out;
189544249214SRandall Stewart }
189644249214SRandall Stewart }
189744249214SRandall Stewart } else {
189844249214SRandall Stewart /*
189944249214SRandall Stewart * Its a complete segment. Lets validate we don't have a
190044249214SRandall Stewart * re-assembly going on with the same Stream/Seq (for
190144249214SRandall Stewart * ordered) or in the same Stream for unordered.
190244249214SRandall Stewart */
1903be46a7c5SMichael Tuexen if (control != NULL) {
190449656eefSMichael Tuexen if (ordered || asoc->idata_supported) {
190549656eefSMichael Tuexen SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags: 0x%x dup detected on MID: %u\n",
19068b9c95f4SMichael Tuexen chk_flags, mid);
1907999f86d6SMichael Tuexen SCTP_SNPRINTF(msg, sizeof(msg), "Duplicate MID=%8.8x detected.", mid);
190844249214SRandall Stewart goto err_out;
1909be46a7c5SMichael Tuexen } else {
1910*101a0f09SMichael Tuexen if ((control->first_frag_seen) &&
1911*101a0f09SMichael Tuexen (tsn == control->fsn_included + 1) &&
1912be46a7c5SMichael Tuexen (control->end_added == 0)) {
1913999f86d6SMichael Tuexen SCTP_SNPRINTF(msg, sizeof(msg),
1914999f86d6SMichael Tuexen "Illegal message sequence, missing end for MID: %8.8x",
1915999f86d6SMichael Tuexen control->fsn_included);
1916be46a7c5SMichael Tuexen goto err_out;
1917be46a7c5SMichael Tuexen } else {
1918be46a7c5SMichael Tuexen control = NULL;
1919be46a7c5SMichael Tuexen }
1920be46a7c5SMichael Tuexen }
192144249214SRandall Stewart }
192244249214SRandall Stewart }
192344249214SRandall Stewart /* now do the tests */
192444249214SRandall Stewart if (((asoc->cnt_on_all_streams +
192544249214SRandall Stewart asoc->cnt_on_reasm_queue +
192644249214SRandall Stewart asoc->cnt_msg_on_sb) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue)) ||
192744249214SRandall Stewart (((int)asoc->my_rwnd) <= 0)) {
192844249214SRandall Stewart /*
192944249214SRandall Stewart * When we have NO room in the rwnd we check to make sure
193044249214SRandall Stewart * the reader is doing its job...
193144249214SRandall Stewart */
1932edc5b6eaSMichael Tuexen if (SCTP_SBAVAIL(&stcb->sctp_socket->so_rcv) > 0) {
193344249214SRandall Stewart /* some to read, wake-up */
193444249214SRandall Stewart sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
193544249214SRandall Stewart }
193644249214SRandall Stewart /* now is it in the mapping array of what we have accepted? */
19378b9c95f4SMichael Tuexen if (chk_type == SCTP_DATA) {
193844249214SRandall Stewart if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_map) &&
193944249214SRandall Stewart SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
194044249214SRandall Stewart /* Nope not in the valid range dump it */
194144249214SRandall Stewart dump_packet:
194244249214SRandall Stewart sctp_set_rwnd(stcb, asoc);
194344249214SRandall Stewart if ((asoc->cnt_on_all_streams +
194444249214SRandall Stewart asoc->cnt_on_reasm_queue +
194544249214SRandall Stewart asoc->cnt_msg_on_sb) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue)) {
194644249214SRandall Stewart SCTP_STAT_INCR(sctps_datadropchklmt);
194744249214SRandall Stewart } else {
194844249214SRandall Stewart SCTP_STAT_INCR(sctps_datadroprwnd);
194944249214SRandall Stewart }
195044249214SRandall Stewart *break_flag = 1;
195144249214SRandall Stewart return (0);
195244249214SRandall Stewart }
195344249214SRandall Stewart } else {
195444249214SRandall Stewart if (control == NULL) {
195544249214SRandall Stewart goto dump_packet;
195644249214SRandall Stewart }
195744249214SRandall Stewart if (SCTP_TSN_GT(fsn, control->top_fsn)) {
195844249214SRandall Stewart goto dump_packet;
195944249214SRandall Stewart }
196044249214SRandall Stewart }
196144249214SRandall Stewart }
1962f42a358aSRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS
196318e198d3SRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb);
196418e198d3SRandall Stewart if (asoc->tsn_in_at >= SCTP_TSN_LOG_SIZE) {
196518e198d3SRandall Stewart asoc->tsn_in_at = 0;
196618e198d3SRandall Stewart asoc->tsn_in_wrapped = 1;
196718e198d3SRandall Stewart }
1968f42a358aSRandall Stewart asoc->in_tsnlog[asoc->tsn_in_at].tsn = tsn;
196949656eefSMichael Tuexen asoc->in_tsnlog[asoc->tsn_in_at].strm = sid;
197049656eefSMichael Tuexen asoc->in_tsnlog[asoc->tsn_in_at].seq = mid;
1971f1f73e57SRandall Stewart asoc->in_tsnlog[asoc->tsn_in_at].sz = chk_length;
1972f1f73e57SRandall Stewart asoc->in_tsnlog[asoc->tsn_in_at].flgs = chunk_flags;
197318e198d3SRandall Stewart asoc->in_tsnlog[asoc->tsn_in_at].stcb = (void *)stcb;
197418e198d3SRandall Stewart asoc->in_tsnlog[asoc->tsn_in_at].in_pos = asoc->tsn_in_at;
197518e198d3SRandall Stewart asoc->in_tsnlog[asoc->tsn_in_at].in_out = 1;
1976f42a358aSRandall Stewart asoc->tsn_in_at++;
1977f42a358aSRandall Stewart #endif
197844249214SRandall Stewart /*
197944249214SRandall Stewart * Before we continue lets validate that we are not being fooled by
198044249214SRandall Stewart * an evil attacker. We can only have Nk chunks based on our TSN
198144249214SRandall Stewart * spread allowed by the mapping array N * 8 bits, so there is no
198244249214SRandall Stewart * way our stream sequence numbers could have wrapped. We of course
198344249214SRandall Stewart * only validate the FIRST fragment so the bit must be set.
198444249214SRandall Stewart */
19858b9c95f4SMichael Tuexen if ((chk_flags & SCTP_DATA_FIRST_FRAG) &&
1986d61a0ae0SRandall Stewart (TAILQ_EMPTY(&asoc->resetHead)) &&
19878b9c95f4SMichael Tuexen (chk_flags & SCTP_DATA_UNORDERED) == 0 &&
198849656eefSMichael Tuexen SCTP_MID_GE(asoc->idata_supported, asoc->strmin[sid].last_mid_delivered, mid)) {
1989f8829a4aSRandall Stewart /* The incoming sseq is behind where we last delivered? */
1990f2ea2a2dSMichael Tuexen SCTPDBG(SCTP_DEBUG_INDATA1, "EVIL/Broken-Dup S-SEQ: %u delivered: %u from peer, Abort!\n",
199149656eefSMichael Tuexen mid, asoc->strmin[sid].last_mid_delivered);
1992f8829a4aSRandall Stewart
199349656eefSMichael Tuexen if (asoc->idata_supported) {
1994999f86d6SMichael Tuexen SCTP_SNPRINTF(msg, sizeof(msg), "Delivered MID=%8.8x, got TSN=%8.8x, SID=%4.4x, MID=%8.8x",
199549656eefSMichael Tuexen asoc->strmin[sid].last_mid_delivered,
199649656eefSMichael Tuexen tsn,
199749656eefSMichael Tuexen sid,
1998821bae7cSMichael Tuexen mid);
199949656eefSMichael Tuexen } else {
2000999f86d6SMichael Tuexen SCTP_SNPRINTF(msg, sizeof(msg), "Delivered SSN=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
200149656eefSMichael Tuexen (uint16_t)asoc->strmin[sid].last_mid_delivered,
200249656eefSMichael Tuexen tsn,
200349656eefSMichael Tuexen sid,
2004821bae7cSMichael Tuexen (uint16_t)mid);
200549656eefSMichael Tuexen }
2006ff1ffd74SMichael Tuexen op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
200791e04f9eSMichael Tuexen stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_18;
2008105b68b4SMichael Tuexen sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED);
2009f8829a4aSRandall Stewart *abort_flag = 1;
2010f8829a4aSRandall Stewart return (0);
2011f8829a4aSRandall Stewart }
20128b9c95f4SMichael Tuexen if (chk_type == SCTP_IDATA) {
201344249214SRandall Stewart the_len = (chk_length - sizeof(struct sctp_idata_chunk));
201444249214SRandall Stewart } else {
2015f8829a4aSRandall Stewart the_len = (chk_length - sizeof(struct sctp_data_chunk));
201644249214SRandall Stewart }
2017f8829a4aSRandall Stewart if (last_chunk == 0) {
20188b9c95f4SMichael Tuexen if (chk_type == SCTP_IDATA) {
201944249214SRandall Stewart dmbuf = SCTP_M_COPYM(*m,
202044249214SRandall Stewart (offset + sizeof(struct sctp_idata_chunk)),
202144249214SRandall Stewart the_len, M_NOWAIT);
202244249214SRandall Stewart } else {
202344b7479bSRandall Stewart dmbuf = SCTP_M_COPYM(*m,
2024f8829a4aSRandall Stewart (offset + sizeof(struct sctp_data_chunk)),
2025eb1b1807SGleb Smirnoff the_len, M_NOWAIT);
202644249214SRandall Stewart }
2027f8829a4aSRandall Stewart #ifdef SCTP_MBUF_LOGGING
2028b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
20294be807c4SMichael Tuexen sctp_log_mbc(dmbuf, SCTP_MBUF_ICOPY);
2030f8829a4aSRandall Stewart }
2031f8829a4aSRandall Stewart #endif
2032f8829a4aSRandall Stewart } else {
2033f8829a4aSRandall Stewart /* We can steal the last chunk */
2034139bc87fSRandall Stewart int l_len;
2035139bc87fSRandall Stewart
2036f8829a4aSRandall Stewart dmbuf = *m;
2037f8829a4aSRandall Stewart /* lop off the top part */
20388b9c95f4SMichael Tuexen if (chk_type == SCTP_IDATA) {
203944249214SRandall Stewart m_adj(dmbuf, (offset + sizeof(struct sctp_idata_chunk)));
204044249214SRandall Stewart } else {
2041f8829a4aSRandall Stewart m_adj(dmbuf, (offset + sizeof(struct sctp_data_chunk)));
204244249214SRandall Stewart }
2043139bc87fSRandall Stewart if (SCTP_BUF_NEXT(dmbuf) == NULL) {
2044139bc87fSRandall Stewart l_len = SCTP_BUF_LEN(dmbuf);
2045139bc87fSRandall Stewart } else {
2046139bc87fSRandall Stewart /*
2047139bc87fSRandall Stewart * need to count up the size hopefully does not hit
2048139bc87fSRandall Stewart * this to often :-0
2049139bc87fSRandall Stewart */
2050139bc87fSRandall Stewart struct mbuf *lat;
2051139bc87fSRandall Stewart
2052139bc87fSRandall Stewart l_len = 0;
205360990c0cSMichael Tuexen for (lat = dmbuf; lat; lat = SCTP_BUF_NEXT(lat)) {
2054139bc87fSRandall Stewart l_len += SCTP_BUF_LEN(lat);
2055139bc87fSRandall Stewart }
2056139bc87fSRandall Stewart }
2057139bc87fSRandall Stewart if (l_len > the_len) {
2058f8829a4aSRandall Stewart /* Trim the end round bytes off too */
2059139bc87fSRandall Stewart m_adj(dmbuf, -(l_len - the_len));
2060f8829a4aSRandall Stewart }
2061f8829a4aSRandall Stewart }
2062f8829a4aSRandall Stewart if (dmbuf == NULL) {
2063f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_nomem);
2064f8829a4aSRandall Stewart return (0);
2065f8829a4aSRandall Stewart }
206644249214SRandall Stewart /*
20678b9c95f4SMichael Tuexen * Now no matter what, we need a control, get one if we don't have
206844249214SRandall Stewart * one (we may have gotten it above when we found the message was
206944249214SRandall Stewart * fragmented
207044249214SRandall Stewart */
207144249214SRandall Stewart if (control == NULL) {
207244249214SRandall Stewart sctp_alloc_a_readq(stcb, control);
207344249214SRandall Stewart sctp_build_readq_entry_mac(control, stcb, asoc->context, net, tsn,
207449656eefSMichael Tuexen ppid,
207549656eefSMichael Tuexen sid,
20768b9c95f4SMichael Tuexen chk_flags,
207749656eefSMichael Tuexen NULL, fsn, mid);
207844249214SRandall Stewart if (control == NULL) {
207944249214SRandall Stewart SCTP_STAT_INCR(sctps_nomem);
208044249214SRandall Stewart return (0);
208144249214SRandall Stewart }
20828b9c95f4SMichael Tuexen if ((chk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
20831f76872cSMichael Tuexen struct mbuf *mm;
208428cd0699SMichael Tuexen
208544249214SRandall Stewart control->data = dmbuf;
208663fb39baSMichael Tuexen control->tail_mbuf = NULL;
20871f76872cSMichael Tuexen for (mm = control->data; mm; mm = mm->m_next) {
20881f76872cSMichael Tuexen control->length += SCTP_BUF_LEN(mm);
208963fb39baSMichael Tuexen if (SCTP_BUF_NEXT(mm) == NULL) {
209063fb39baSMichael Tuexen control->tail_mbuf = mm;
209128cd0699SMichael Tuexen }
209263fb39baSMichael Tuexen }
20938b9c95f4SMichael Tuexen control->end_added = 1;
20948b9c95f4SMichael Tuexen control->last_frag_seen = 1;
20958b9c95f4SMichael Tuexen control->first_frag_seen = 1;
20968b9c95f4SMichael Tuexen control->fsn_included = fsn;
20978b9c95f4SMichael Tuexen control->top_fsn = fsn;
209844249214SRandall Stewart }
209944249214SRandall Stewart created_control = 1;
210044249214SRandall Stewart }
210149656eefSMichael Tuexen SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags: 0x%x ordered: %d MID: %u control: %p\n",
21028b9c95f4SMichael Tuexen chk_flags, ordered, mid, control);
21038b9c95f4SMichael Tuexen if ((chk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG &&
2104f8829a4aSRandall Stewart TAILQ_EMPTY(&asoc->resetHead) &&
2105f42a358aSRandall Stewart ((ordered == 0) ||
210649656eefSMichael Tuexen (SCTP_MID_EQ(asoc->idata_supported, asoc->strmin[sid].last_mid_delivered + 1, mid) &&
210749656eefSMichael Tuexen TAILQ_EMPTY(&asoc->strmin[sid].inqueue)))) {
2108f8829a4aSRandall Stewart /* Candidate for express delivery */
2109f8829a4aSRandall Stewart /*
2110f8829a4aSRandall Stewart * Its not fragmented, No PD-API is up, Nothing in the
2111f8829a4aSRandall Stewart * delivery queue, Its un-ordered OR ordered and the next to
2112f8829a4aSRandall Stewart * deliver AND nothing else is stuck on the stream queue,
2113f8829a4aSRandall Stewart * And there is room for it in the socket buffer. Lets just
2114f8829a4aSRandall Stewart * stuff it up the buffer....
2115f8829a4aSRandall Stewart */
21161ea735c8SMichael Tuexen SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
211720b07a4dSMichael Tuexen if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
21181ea735c8SMichael Tuexen asoc->highest_tsn_inside_nr_map = tsn;
21191ea735c8SMichael Tuexen }
212049656eefSMichael Tuexen SCTPDBG(SCTP_DEBUG_XXX, "Injecting control: %p to be read (MID: %u)\n",
212149656eefSMichael Tuexen control, mid);
212244249214SRandall Stewart
2123cfde3ff7SRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb,
2124cfde3ff7SRandall Stewart control, &stcb->sctp_socket->so_rcv,
2125cfde3ff7SRandall Stewart 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
2126830d754dSRandall Stewart
21278b9c95f4SMichael Tuexen if ((chk_flags & SCTP_DATA_UNORDERED) == 0) {
2128f8829a4aSRandall Stewart /* for ordered, bump what we delivered */
21293d6fe5d8SMichael Tuexen asoc->strmin[sid].last_mid_delivered++;
2130f8829a4aSRandall Stewart }
2131f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_recvexpress);
2132b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
213349656eefSMichael Tuexen sctp_log_strm_del_alt(stcb, tsn, mid, sid,
2134f8829a4aSRandall Stewart SCTP_STR_LOG_FROM_EXPRS_DEL);
213580fefe0aSRandall Stewart }
2136f8829a4aSRandall Stewart control = NULL;
2137f8829a4aSRandall Stewart goto finish_express_del;
2138f8829a4aSRandall Stewart }
21390053ed28SMichael Tuexen
214044249214SRandall Stewart /* Now will we need a chunk too? */
21418b9c95f4SMichael Tuexen if ((chk_flags & SCTP_DATA_NOT_FRAG) != SCTP_DATA_NOT_FRAG) {
2142f8829a4aSRandall Stewart sctp_alloc_a_chunk(stcb, chk);
2143f8829a4aSRandall Stewart if (chk == NULL) {
2144f8829a4aSRandall Stewart /* No memory so we drop the chunk */
2145f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_nomem);
2146f8829a4aSRandall Stewart if (last_chunk == 0) {
2147f8829a4aSRandall Stewart /* we copied it, free the copy */
2148f8829a4aSRandall Stewart sctp_m_freem(dmbuf);
2149f8829a4aSRandall Stewart }
2150f8829a4aSRandall Stewart return (0);
2151f8829a4aSRandall Stewart }
215249656eefSMichael Tuexen chk->rec.data.tsn = tsn;
2153f8829a4aSRandall Stewart chk->no_fr_allowed = 0;
215449656eefSMichael Tuexen chk->rec.data.fsn = fsn;
215549656eefSMichael Tuexen chk->rec.data.mid = mid;
215649656eefSMichael Tuexen chk->rec.data.sid = sid;
215749656eefSMichael Tuexen chk->rec.data.ppid = ppid;
2158f8829a4aSRandall Stewart chk->rec.data.context = stcb->asoc.context;
2159f8829a4aSRandall Stewart chk->rec.data.doing_fast_retransmit = 0;
21608b9c95f4SMichael Tuexen chk->rec.data.rcv_flags = chk_flags;
2161f8829a4aSRandall Stewart chk->asoc = asoc;
2162f8829a4aSRandall Stewart chk->send_size = the_len;
2163f8829a4aSRandall Stewart chk->whoTo = net;
216449656eefSMichael Tuexen SCTPDBG(SCTP_DEBUG_XXX, "Building ck: %p for control: %p to be read (MID: %u)\n",
216544249214SRandall Stewart chk,
216649656eefSMichael Tuexen control, mid);
2167f8829a4aSRandall Stewart atomic_add_int(&net->ref_count, 1);
2168f8829a4aSRandall Stewart chk->data = dmbuf;
216944249214SRandall Stewart }
217044249214SRandall Stewart /* Set the appropriate TSN mark */
217144249214SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_do_drain) == 0) {
217244249214SRandall Stewart SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
217344249214SRandall Stewart if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
217444249214SRandall Stewart asoc->highest_tsn_inside_nr_map = tsn;
217544249214SRandall Stewart }
2176f8829a4aSRandall Stewart } else {
217744249214SRandall Stewart SCTP_SET_TSN_PRESENT(asoc->mapping_array, gap);
217844249214SRandall Stewart if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_map)) {
217944249214SRandall Stewart asoc->highest_tsn_inside_map = tsn;
2180f8829a4aSRandall Stewart }
2181f8829a4aSRandall Stewart }
218244249214SRandall Stewart /* Now is it complete (i.e. not fragmented)? */
21838b9c95f4SMichael Tuexen if ((chk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
2184f8829a4aSRandall Stewart /*
218544249214SRandall Stewart * Special check for when streams are resetting. We could be
218644249214SRandall Stewart * more smart about this and check the actual stream to see
218744249214SRandall Stewart * if it is not being reset.. that way we would not create a
218844249214SRandall Stewart * HOLB when amongst streams being reset and those not being
218944249214SRandall Stewart * reset.
2190f8829a4aSRandall Stewart *
2191f8829a4aSRandall Stewart */
2192f8829a4aSRandall Stewart if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) &&
219320b07a4dSMichael Tuexen SCTP_TSN_GT(tsn, liste->tsn)) {
2194f8829a4aSRandall Stewart /*
219544249214SRandall Stewart * yep its past where we need to reset... go ahead
219644249214SRandall Stewart * and queue it.
2197f8829a4aSRandall Stewart */
2198f8829a4aSRandall Stewart if (TAILQ_EMPTY(&asoc->pending_reply_queue)) {
2199f8829a4aSRandall Stewart /* first one on */
2200f8829a4aSRandall Stewart TAILQ_INSERT_TAIL(&asoc->pending_reply_queue, control, next);
2201f8829a4aSRandall Stewart } else {
220228cd0699SMichael Tuexen struct sctp_queued_to_read *lcontrol, *nlcontrol;
2203f8829a4aSRandall Stewart unsigned char inserted = 0;
2204f8829a4aSRandall Stewart
220528cd0699SMichael Tuexen TAILQ_FOREACH_SAFE(lcontrol, &asoc->pending_reply_queue, next, nlcontrol) {
220628cd0699SMichael Tuexen if (SCTP_TSN_GT(control->sinfo_tsn, lcontrol->sinfo_tsn)) {
22074a9ef3f8SMichael Tuexen continue;
2208f8829a4aSRandall Stewart } else {
2209f8829a4aSRandall Stewart /* found it */
221028cd0699SMichael Tuexen TAILQ_INSERT_BEFORE(lcontrol, control, next);
2211f8829a4aSRandall Stewart inserted = 1;
2212f8829a4aSRandall Stewart break;
2213f8829a4aSRandall Stewart }
2214f8829a4aSRandall Stewart }
2215f8829a4aSRandall Stewart if (inserted == 0) {
2216f8829a4aSRandall Stewart /*
221744249214SRandall Stewart * must be put at end, use prevP
221844249214SRandall Stewart * (all setup from loop) to setup
221944249214SRandall Stewart * nextP.
2220f8829a4aSRandall Stewart */
2221f8829a4aSRandall Stewart TAILQ_INSERT_TAIL(&asoc->pending_reply_queue, control, next);
2222f8829a4aSRandall Stewart }
2223f8829a4aSRandall Stewart }
222444249214SRandall Stewart goto finish_express_del;
222544249214SRandall Stewart }
22268b9c95f4SMichael Tuexen if (chk_flags & SCTP_DATA_UNORDERED) {
222744249214SRandall Stewart /* queue directly into socket buffer */
222849656eefSMichael Tuexen SCTPDBG(SCTP_DEBUG_XXX, "Unordered data to be read control: %p MID: %u\n",
222949656eefSMichael Tuexen control, mid);
223044249214SRandall Stewart sctp_mark_non_revokable(asoc, control->sinfo_tsn);
223144249214SRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb,
223244249214SRandall Stewart control,
223344249214SRandall Stewart &stcb->sctp_socket->so_rcv, 1,
223444249214SRandall Stewart SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
223544249214SRandall Stewart
2236f8829a4aSRandall Stewart } else {
223749656eefSMichael Tuexen SCTPDBG(SCTP_DEBUG_XXX, "Queue control: %p for reordering MID: %u\n", control,
223849656eefSMichael Tuexen mid);
22393d6fe5d8SMichael Tuexen sctp_queue_data_to_stream(stcb, asoc, control, abort_flag, &need_reasm_check);
2240f8829a4aSRandall Stewart if (*abort_flag) {
22418be0fd55SMichael Tuexen if (last_chunk) {
22428be0fd55SMichael Tuexen *m = NULL;
22438be0fd55SMichael Tuexen }
2244f8829a4aSRandall Stewart return (0);
2245f8829a4aSRandall Stewart }
2246f8829a4aSRandall Stewart }
224744249214SRandall Stewart goto finish_express_del;
2248f8829a4aSRandall Stewart }
224944249214SRandall Stewart /* If we reach here its a reassembly */
225044249214SRandall Stewart need_reasm_check = 1;
225144249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX,
225249656eefSMichael Tuexen "Queue data to stream for reasm control: %p MID: %u\n",
225349656eefSMichael Tuexen control, mid);
22543d6fe5d8SMichael Tuexen sctp_queue_data_for_reasm(stcb, asoc, control, chk, created_control, abort_flag, tsn);
2255f8829a4aSRandall Stewart if (*abort_flag) {
2256a5d547adSRandall Stewart /*
225744249214SRandall Stewart * the assoc is now gone and chk was put onto the reasm
225844249214SRandall Stewart * queue, which has all been freed.
2259a5d547adSRandall Stewart */
22608be0fd55SMichael Tuexen if (last_chunk) {
2261a5d547adSRandall Stewart *m = NULL;
22628be0fd55SMichael Tuexen }
2263f8829a4aSRandall Stewart return (0);
2264f8829a4aSRandall Stewart }
2265f8829a4aSRandall Stewart finish_express_del:
226644249214SRandall Stewart /* Here we tidy up things */
2267307b49efSMichael Tuexen if (tsn == (asoc->cumulative_tsn + 1)) {
2268307b49efSMichael Tuexen /* Update cum-ack */
2269307b49efSMichael Tuexen asoc->cumulative_tsn = tsn;
2270307b49efSMichael Tuexen }
2271f8829a4aSRandall Stewart if (last_chunk) {
2272f8829a4aSRandall Stewart *m = NULL;
2273f8829a4aSRandall Stewart }
2274f42a358aSRandall Stewart if (ordered) {
2275f8829a4aSRandall Stewart SCTP_STAT_INCR_COUNTER64(sctps_inorderchunks);
2276f8829a4aSRandall Stewart } else {
2277f8829a4aSRandall Stewart SCTP_STAT_INCR_COUNTER64(sctps_inunorderchunks);
2278f8829a4aSRandall Stewart }
2279f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_recvdata);
2280f8829a4aSRandall Stewart /* Set it present please */
2281b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
228249656eefSMichael Tuexen sctp_log_strm_del_alt(stcb, tsn, mid, sid, SCTP_STR_LOG_FROM_MARK_TSN);
228380fefe0aSRandall Stewart }
2284b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
2285f8829a4aSRandall Stewart sctp_log_map(asoc->mapping_array_base_tsn, asoc->cumulative_tsn,
2286f8829a4aSRandall Stewart asoc->highest_tsn_inside_map, SCTP_MAP_PREPARE_SLIDE);
228780fefe0aSRandall Stewart }
22883d6fe5d8SMichael Tuexen if (need_reasm_check) {
22893d6fe5d8SMichael Tuexen (void)sctp_deliver_reasm_check(stcb, asoc, &asoc->strmin[sid], SCTP_READ_LOCK_NOT_HELD);
22903d6fe5d8SMichael Tuexen need_reasm_check = 0;
22913d6fe5d8SMichael Tuexen }
229217205eccSRandall Stewart /* check the special flag for stream resets */
229317205eccSRandall Stewart if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) &&
229420b07a4dSMichael Tuexen SCTP_TSN_GE(asoc->cumulative_tsn, liste->tsn)) {
229517205eccSRandall Stewart /*
229617205eccSRandall Stewart * we have finished working through the backlogged TSN's now
229717205eccSRandall Stewart * time to reset streams. 1: call reset function. 2: free
229817205eccSRandall Stewart * pending_reply space 3: distribute any chunks in
229917205eccSRandall Stewart * pending_reply_queue.
230017205eccSRandall Stewart */
2301a169d6ecSMichael Tuexen sctp_reset_in_stream(stcb, liste->number_entries, liste->list_of_streams);
230217205eccSRandall Stewart TAILQ_REMOVE(&asoc->resetHead, liste, next_resp);
23037cca1775SRandall Stewart sctp_send_deferred_reset_response(stcb, liste, SCTP_STREAM_RESET_RESULT_PERFORMED);
2304207304d4SRandall Stewart SCTP_FREE(liste, SCTP_M_STRESET);
23053c503c28SRandall Stewart /* sa_ignore FREED_MEMORY */
230617205eccSRandall Stewart liste = TAILQ_FIRST(&asoc->resetHead);
23074a9ef3f8SMichael Tuexen if (TAILQ_EMPTY(&asoc->resetHead)) {
230817205eccSRandall Stewart /* All can be removed */
230928cd0699SMichael Tuexen TAILQ_FOREACH_SAFE(control, &asoc->pending_reply_queue, next, ncontrol) {
231028cd0699SMichael Tuexen TAILQ_REMOVE(&asoc->pending_reply_queue, control, next);
23116ddc8438SMichael Tuexen strm = &asoc->strmin[control->sinfo_stream];
231228cd0699SMichael Tuexen sctp_queue_data_to_stream(stcb, asoc, control, abort_flag, &need_reasm_check);
231317205eccSRandall Stewart if (*abort_flag) {
231417205eccSRandall Stewart return (0);
231517205eccSRandall Stewart }
23163d6fe5d8SMichael Tuexen if (need_reasm_check) {
23176ddc8438SMichael Tuexen (void)sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_NOT_HELD);
23183d6fe5d8SMichael Tuexen need_reasm_check = 0;
23193d6fe5d8SMichael Tuexen }
232017205eccSRandall Stewart }
23214a9ef3f8SMichael Tuexen } else {
232228cd0699SMichael Tuexen TAILQ_FOREACH_SAFE(control, &asoc->pending_reply_queue, next, ncontrol) {
232328cd0699SMichael Tuexen if (SCTP_TSN_GT(control->sinfo_tsn, liste->tsn)) {
23244a9ef3f8SMichael Tuexen break;
23254a9ef3f8SMichael Tuexen }
232617205eccSRandall Stewart /*
232728cd0699SMichael Tuexen * if control->sinfo_tsn is <= liste->tsn we
232828cd0699SMichael Tuexen * can process it which is the NOT of
232928cd0699SMichael Tuexen * control->sinfo_tsn > liste->tsn
233017205eccSRandall Stewart */
233128cd0699SMichael Tuexen TAILQ_REMOVE(&asoc->pending_reply_queue, control, next);
23326ddc8438SMichael Tuexen strm = &asoc->strmin[control->sinfo_stream];
233328cd0699SMichael Tuexen sctp_queue_data_to_stream(stcb, asoc, control, abort_flag, &need_reasm_check);
233417205eccSRandall Stewart if (*abort_flag) {
233517205eccSRandall Stewart return (0);
233617205eccSRandall Stewart }
23373d6fe5d8SMichael Tuexen if (need_reasm_check) {
23386ddc8438SMichael Tuexen (void)sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_NOT_HELD);
233917205eccSRandall Stewart need_reasm_check = 0;
234017205eccSRandall Stewart }
23413d6fe5d8SMichael Tuexen }
23423d6fe5d8SMichael Tuexen }
2343139bc87fSRandall Stewart }
2344f8829a4aSRandall Stewart return (1);
2345f8829a4aSRandall Stewart }
2346f8829a4aSRandall Stewart
2347ed654363SMichael Tuexen static const int8_t sctp_map_lookup_tab[256] = {
2348b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3,
2349b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 4,
2350b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3,
2351b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 5,
2352b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3,
2353b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 4,
2354b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3,
2355b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 6,
2356b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3,
2357b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 4,
2358b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3,
2359b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 5,
2360b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3,
2361b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 4,
2362b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3,
2363b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 7,
2364b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3,
2365b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 4,
2366b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3,
2367b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 5,
2368b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3,
2369b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 4,
2370b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3,
2371b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 6,
2372b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3,
2373b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 4,
2374b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3,
2375b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 5,
2376b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3,
2377b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 4,
2378b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3,
2379b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 8
2380f8829a4aSRandall Stewart };
2381f8829a4aSRandall Stewart
2382f8829a4aSRandall Stewart void
sctp_slide_mapping_arrays(struct sctp_tcb * stcb)2383b5c16493SMichael Tuexen sctp_slide_mapping_arrays(struct sctp_tcb *stcb)
2384f8829a4aSRandall Stewart {
2385f8829a4aSRandall Stewart /*
2386f8829a4aSRandall Stewart * Now we also need to check the mapping array in a couple of ways.
2387f8829a4aSRandall Stewart * 1) Did we move the cum-ack point?
238866bd30bdSRandall Stewart *
23895b495f17SMichael Tuexen * When you first glance at this you might think that all entries
23905b495f17SMichael Tuexen * that make up the position of the cum-ack would be in the
23915b495f17SMichael Tuexen * nr-mapping array only.. i.e. things up to the cum-ack are always
239266bd30bdSRandall Stewart * deliverable. Thats true with one exception, when its a fragmented
239366bd30bdSRandall Stewart * message we may not deliver the data until some threshold (or all
239466bd30bdSRandall Stewart * of it) is in place. So we must OR the nr_mapping_array and
239566bd30bdSRandall Stewart * mapping_array to get a true picture of the cum-ack.
2396f8829a4aSRandall Stewart */
2397f8829a4aSRandall Stewart struct sctp_association *asoc;
2398b3f1ea41SRandall Stewart int at;
239966bd30bdSRandall Stewart uint8_t val;
2400f8829a4aSRandall Stewart int slide_from, slide_end, lgap, distance;
240177acdc25SRandall Stewart uint32_t old_cumack, old_base, old_highest, highest_tsn;
2402f8829a4aSRandall Stewart
2403f8829a4aSRandall Stewart asoc = &stcb->asoc;
2404f8829a4aSRandall Stewart
2405f8829a4aSRandall Stewart old_cumack = asoc->cumulative_tsn;
2406f8829a4aSRandall Stewart old_base = asoc->mapping_array_base_tsn;
2407f8829a4aSRandall Stewart old_highest = asoc->highest_tsn_inside_map;
2408f8829a4aSRandall Stewart /*
2409f8829a4aSRandall Stewart * We could probably improve this a small bit by calculating the
2410f8829a4aSRandall Stewart * offset of the current cum-ack as the starting point.
2411f8829a4aSRandall Stewart */
2412f8829a4aSRandall Stewart at = 0;
2413b5c16493SMichael Tuexen for (slide_from = 0; slide_from < stcb->asoc.mapping_array_size; slide_from++) {
241466bd30bdSRandall Stewart val = asoc->nr_mapping_array[slide_from] | asoc->mapping_array[slide_from];
241566bd30bdSRandall Stewart if (val == 0xff) {
2416f8829a4aSRandall Stewart at += 8;
2417f8829a4aSRandall Stewart } else {
2418f8829a4aSRandall Stewart /* there is a 0 bit */
241966bd30bdSRandall Stewart at += sctp_map_lookup_tab[val];
2420f8829a4aSRandall Stewart break;
2421f8829a4aSRandall Stewart }
2422f8829a4aSRandall Stewart }
2423b5c16493SMichael Tuexen asoc->cumulative_tsn = asoc->mapping_array_base_tsn + (at - 1);
2424f8829a4aSRandall Stewart
242520b07a4dSMichael Tuexen if (SCTP_TSN_GT(asoc->cumulative_tsn, asoc->highest_tsn_inside_map) &&
242620b07a4dSMichael Tuexen SCTP_TSN_GT(asoc->cumulative_tsn, asoc->highest_tsn_inside_nr_map)) {
2427a5d547adSRandall Stewart #ifdef INVARIANTS
2428ceaad40aSRandall Stewart panic("huh, cumack 0x%x greater than high-tsn 0x%x in map",
2429ceaad40aSRandall Stewart asoc->cumulative_tsn, asoc->highest_tsn_inside_map);
2430f8829a4aSRandall Stewart #else
2431ceaad40aSRandall Stewart SCTP_PRINTF("huh, cumack 0x%x greater than high-tsn 0x%x in map - should panic?\n",
2432ceaad40aSRandall Stewart asoc->cumulative_tsn, asoc->highest_tsn_inside_map);
24330e13104dSRandall Stewart sctp_print_mapping_array(asoc);
2434b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
2435b3f1ea41SRandall Stewart sctp_log_map(0, 6, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT);
2436b3f1ea41SRandall Stewart }
2437f8829a4aSRandall Stewart asoc->highest_tsn_inside_map = asoc->cumulative_tsn;
2438830d754dSRandall Stewart asoc->highest_tsn_inside_nr_map = asoc->cumulative_tsn;
2439f8829a4aSRandall Stewart #endif
2440f8829a4aSRandall Stewart }
244120b07a4dSMichael Tuexen if (SCTP_TSN_GT(asoc->highest_tsn_inside_nr_map, asoc->highest_tsn_inside_map)) {
244277acdc25SRandall Stewart highest_tsn = asoc->highest_tsn_inside_nr_map;
244377acdc25SRandall Stewart } else {
244477acdc25SRandall Stewart highest_tsn = asoc->highest_tsn_inside_map;
244577acdc25SRandall Stewart }
244677acdc25SRandall Stewart if ((asoc->cumulative_tsn == highest_tsn) && (at >= 8)) {
2447f8829a4aSRandall Stewart /* The complete array was completed by a single FR */
244877acdc25SRandall Stewart /* highest becomes the cum-ack */
244937f144ebSMichael Tuexen int clr;
245037f144ebSMichael Tuexen #ifdef INVARIANTS
245137f144ebSMichael Tuexen unsigned int i;
245237f144ebSMichael Tuexen #endif
2453f8829a4aSRandall Stewart
2454f8829a4aSRandall Stewart /* clear the array */
2455b5c16493SMichael Tuexen clr = ((at + 7) >> 3);
2456c4739e2fSRandall Stewart if (clr > asoc->mapping_array_size) {
2457f8829a4aSRandall Stewart clr = asoc->mapping_array_size;
2458f8829a4aSRandall Stewart }
2459f8829a4aSRandall Stewart memset(asoc->mapping_array, 0, clr);
2460830d754dSRandall Stewart memset(asoc->nr_mapping_array, 0, clr);
246137f144ebSMichael Tuexen #ifdef INVARIANTS
2462b5c16493SMichael Tuexen for (i = 0; i < asoc->mapping_array_size; i++) {
2463b5c16493SMichael Tuexen if ((asoc->mapping_array[i]) || (asoc->nr_mapping_array[i])) {
2464cd3fd531SMichael Tuexen SCTP_PRINTF("Error Mapping array's not clean at clear\n");
2465b5c16493SMichael Tuexen sctp_print_mapping_array(asoc);
2466b5c16493SMichael Tuexen }
2467b5c16493SMichael Tuexen }
246837f144ebSMichael Tuexen #endif
246977acdc25SRandall Stewart asoc->mapping_array_base_tsn = asoc->cumulative_tsn + 1;
247077acdc25SRandall Stewart asoc->highest_tsn_inside_nr_map = asoc->highest_tsn_inside_map = asoc->cumulative_tsn;
2471f8829a4aSRandall Stewart } else if (at >= 8) {
2472f8829a4aSRandall Stewart /* we can slide the mapping array down */
2473b3f1ea41SRandall Stewart /* slide_from holds where we hit the first NON 0xff byte */
2474b3f1ea41SRandall Stewart
2475f8829a4aSRandall Stewart /*
2476f8829a4aSRandall Stewart * now calculate the ceiling of the move using our highest
2477f8829a4aSRandall Stewart * TSN value
2478f8829a4aSRandall Stewart */
247977acdc25SRandall Stewart SCTP_CALC_TSN_TO_GAP(lgap, highest_tsn, asoc->mapping_array_base_tsn);
248077acdc25SRandall Stewart slide_end = (lgap >> 3);
2481f8829a4aSRandall Stewart if (slide_end < slide_from) {
248277acdc25SRandall Stewart sctp_print_mapping_array(asoc);
2483d55b0b1bSRandall Stewart #ifdef INVARIANTS
2484f8829a4aSRandall Stewart panic("impossible slide");
2485d55b0b1bSRandall Stewart #else
2486cd3fd531SMichael Tuexen SCTP_PRINTF("impossible slide lgap: %x slide_end: %x slide_from: %x? at: %d\n",
248777acdc25SRandall Stewart lgap, slide_end, slide_from, at);
2488d55b0b1bSRandall Stewart return;
2489d55b0b1bSRandall Stewart #endif
2490f8829a4aSRandall Stewart }
2491b3f1ea41SRandall Stewart if (slide_end > asoc->mapping_array_size) {
2492b3f1ea41SRandall Stewart #ifdef INVARIANTS
2493b3f1ea41SRandall Stewart panic("would overrun buffer");
2494b3f1ea41SRandall Stewart #else
2495cd3fd531SMichael Tuexen SCTP_PRINTF("Gak, would have overrun map end: %d slide_end: %d\n",
2496b3f1ea41SRandall Stewart asoc->mapping_array_size, slide_end);
2497b3f1ea41SRandall Stewart slide_end = asoc->mapping_array_size;
2498b3f1ea41SRandall Stewart #endif
2499b3f1ea41SRandall Stewart }
2500f8829a4aSRandall Stewart distance = (slide_end - slide_from) + 1;
2501b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
2502f8829a4aSRandall Stewart sctp_log_map(old_base, old_cumack, old_highest,
2503f8829a4aSRandall Stewart SCTP_MAP_PREPARE_SLIDE);
2504f8829a4aSRandall Stewart sctp_log_map((uint32_t)slide_from, (uint32_t)slide_end,
2505f8829a4aSRandall Stewart (uint32_t)lgap, SCTP_MAP_SLIDE_FROM);
250680fefe0aSRandall Stewart }
2507f8829a4aSRandall Stewart if (distance + slide_from > asoc->mapping_array_size ||
2508f8829a4aSRandall Stewart distance < 0) {
2509f8829a4aSRandall Stewart /*
2510f8829a4aSRandall Stewart * Here we do NOT slide forward the array so that
2511f8829a4aSRandall Stewart * hopefully when more data comes in to fill it up
2512f8829a4aSRandall Stewart * we will be able to slide it forward. Really I
2513f8829a4aSRandall Stewart * don't think this should happen :-0
2514f8829a4aSRandall Stewart */
2515b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
2516f8829a4aSRandall Stewart sctp_log_map((uint32_t)distance, (uint32_t)slide_from,
2517f8829a4aSRandall Stewart (uint32_t)asoc->mapping_array_size,
2518f8829a4aSRandall Stewart SCTP_MAP_SLIDE_NONE);
251980fefe0aSRandall Stewart }
2520f8829a4aSRandall Stewart } else {
2521f8829a4aSRandall Stewart int ii;
2522f8829a4aSRandall Stewart
2523f8829a4aSRandall Stewart for (ii = 0; ii < distance; ii++) {
252437f144ebSMichael Tuexen asoc->mapping_array[ii] = asoc->mapping_array[slide_from + ii];
252537f144ebSMichael Tuexen asoc->nr_mapping_array[ii] = asoc->nr_mapping_array[slide_from + ii];
2526f8829a4aSRandall Stewart }
2527aed5947cSMichael Tuexen for (ii = distance; ii < asoc->mapping_array_size; ii++) {
2528f8829a4aSRandall Stewart asoc->mapping_array[ii] = 0;
252977acdc25SRandall Stewart asoc->nr_mapping_array[ii] = 0;
2530f8829a4aSRandall Stewart }
2531ee94f0a2SMichael Tuexen if (asoc->highest_tsn_inside_map + 1 == asoc->mapping_array_base_tsn) {
2532ee94f0a2SMichael Tuexen asoc->highest_tsn_inside_map += (slide_from << 3);
2533ee94f0a2SMichael Tuexen }
2534ee94f0a2SMichael Tuexen if (asoc->highest_tsn_inside_nr_map + 1 == asoc->mapping_array_base_tsn) {
2535ee94f0a2SMichael Tuexen asoc->highest_tsn_inside_nr_map += (slide_from << 3);
2536ee94f0a2SMichael Tuexen }
2537f8829a4aSRandall Stewart asoc->mapping_array_base_tsn += (slide_from << 3);
2538b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
2539f8829a4aSRandall Stewart sctp_log_map(asoc->mapping_array_base_tsn,
2540f8829a4aSRandall Stewart asoc->cumulative_tsn, asoc->highest_tsn_inside_map,
2541f8829a4aSRandall Stewart SCTP_MAP_SLIDE_RESULT);
254280fefe0aSRandall Stewart }
2543830d754dSRandall Stewart }
2544830d754dSRandall Stewart }
2545b5c16493SMichael Tuexen }
2546b5c16493SMichael Tuexen
2547b5c16493SMichael Tuexen void
sctp_sack_check(struct sctp_tcb * stcb,int was_a_gap)25487215cc1bSMichael Tuexen sctp_sack_check(struct sctp_tcb *stcb, int was_a_gap)
2549b5c16493SMichael Tuexen {
2550b5c16493SMichael Tuexen struct sctp_association *asoc;
2551b5c16493SMichael Tuexen uint32_t highest_tsn;
2552ebecdad8SMichael Tuexen int is_a_gap;
2553b5c16493SMichael Tuexen
2554ebecdad8SMichael Tuexen sctp_slide_mapping_arrays(stcb);
2555b5c16493SMichael Tuexen asoc = &stcb->asoc;
255620b07a4dSMichael Tuexen if (SCTP_TSN_GT(asoc->highest_tsn_inside_nr_map, asoc->highest_tsn_inside_map)) {
2557b5c16493SMichael Tuexen highest_tsn = asoc->highest_tsn_inside_nr_map;
2558b5c16493SMichael Tuexen } else {
2559b5c16493SMichael Tuexen highest_tsn = asoc->highest_tsn_inside_map;
2560b5c16493SMichael Tuexen }
2561ebecdad8SMichael Tuexen /* Is there a gap now? */
2562ebecdad8SMichael Tuexen is_a_gap = SCTP_TSN_GT(highest_tsn, stcb->asoc.cumulative_tsn);
2563b5c16493SMichael Tuexen
2564830d754dSRandall Stewart /*
2565f8829a4aSRandall Stewart * Now we need to see if we need to queue a sack or just start the
2566f8829a4aSRandall Stewart * timer (if allowed).
2567f8829a4aSRandall Stewart */
2568839d21d6SMichael Tuexen if (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_SENT) {
2569f8829a4aSRandall Stewart /*
2570b5c16493SMichael Tuexen * Ok special case, in SHUTDOWN-SENT case. here we maker
2571b5c16493SMichael Tuexen * sure SACK timer is off and instead send a SHUTDOWN and a
2572b5c16493SMichael Tuexen * SACK
2573f8829a4aSRandall Stewart */
2574139bc87fSRandall Stewart if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) {
2575f8829a4aSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
2576b7d130beSMichael Tuexen stcb->sctp_ep, stcb, NULL,
257791e04f9eSMichael Tuexen SCTP_FROM_SCTP_INDATA + SCTP_LOC_19);
2578f8829a4aSRandall Stewart }
2579ca85e948SMichael Tuexen sctp_send_shutdown(stcb,
2580ca85e948SMichael Tuexen ((stcb->asoc.alternate) ? stcb->asoc.alternate : stcb->asoc.primary_destination));
2581ebecdad8SMichael Tuexen if (is_a_gap) {
2582689e6a5fSMichael Tuexen sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
2583ebecdad8SMichael Tuexen }
2584f8829a4aSRandall Stewart } else {
2585f8829a4aSRandall Stewart /*
2586b5c16493SMichael Tuexen * CMT DAC algorithm: increase number of packets received
2587b5c16493SMichael Tuexen * since last ack
2588f8829a4aSRandall Stewart */
2589f8829a4aSRandall Stewart stcb->asoc.cmt_dac_pkts_rcvd++;
2590f8829a4aSRandall Stewart
259142551e99SRandall Stewart if ((stcb->asoc.send_sack == 1) || /* We need to send a
259242551e99SRandall Stewart * SACK */
2593f8829a4aSRandall Stewart ((was_a_gap) && (is_a_gap == 0)) || /* was a gap, but no
2594f8829a4aSRandall Stewart * longer is one */
2595f8829a4aSRandall Stewart (stcb->asoc.numduptsns) || /* we have dup's */
2596f8829a4aSRandall Stewart (is_a_gap) || /* is still a gap */
259742551e99SRandall Stewart (stcb->asoc.delayed_ack == 0) || /* Delayed sack disabled */
2598b6db274dSMichael Tuexen (stcb->asoc.data_pkts_seen >= stcb->asoc.sack_freq)) { /* hit limit of pkts */
25997c99d56fSMichael Tuexen if ((stcb->asoc.sctp_cmt_on_off > 0) &&
2600b3f1ea41SRandall Stewart (SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) &&
260142551e99SRandall Stewart (stcb->asoc.send_sack == 0) &&
2602f8829a4aSRandall Stewart (stcb->asoc.numduptsns == 0) &&
2603f8829a4aSRandall Stewart (stcb->asoc.delayed_ack) &&
2604139bc87fSRandall Stewart (!SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer))) {
2605f8829a4aSRandall Stewart /*
2606b5c16493SMichael Tuexen * CMT DAC algorithm: With CMT, delay acks
2607b6db274dSMichael Tuexen * even in the face of reordering.
2608b6db274dSMichael Tuexen * Therefore, if acks that do not have to be
2609b6db274dSMichael Tuexen * sent because of the above reasons, will
2610b6db274dSMichael Tuexen * be delayed. That is, acks that would have
2611b6db274dSMichael Tuexen * been sent due to gap reports will be
2612b6db274dSMichael Tuexen * delayed with DAC. Start the delayed ack
2613b6db274dSMichael Tuexen * timer.
2614f8829a4aSRandall Stewart */
2615f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_RECV,
2616f8829a4aSRandall Stewart stcb->sctp_ep, stcb, NULL);
2617f8829a4aSRandall Stewart } else {
2618f8829a4aSRandall Stewart /*
2619b5c16493SMichael Tuexen * Ok we must build a SACK since the timer
2620b5c16493SMichael Tuexen * is pending, we got our first packet OR
2621b5c16493SMichael Tuexen * there are gaps or duplicates.
2622f8829a4aSRandall Stewart */
26235555400aSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL,
262491e04f9eSMichael Tuexen SCTP_FROM_SCTP_INDATA + SCTP_LOC_20);
2625689e6a5fSMichael Tuexen sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
2626f8829a4aSRandall Stewart }
2627f8829a4aSRandall Stewart } else {
262842551e99SRandall Stewart if (!SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) {
2629f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_RECV,
2630f8829a4aSRandall Stewart stcb->sctp_ep, stcb, NULL);
2631f8829a4aSRandall Stewart }
2632f8829a4aSRandall Stewart }
2633f8829a4aSRandall Stewart }
2634f8829a4aSRandall Stewart }
2635f8829a4aSRandall Stewart
2636f8829a4aSRandall Stewart int
sctp_process_data(struct mbuf ** mm,int iphlen,int * offset,int length,struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net,uint32_t * high_tsn)2637f8829a4aSRandall Stewart sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
2638e7e71dd7SMichael Tuexen struct sctp_inpcb *inp, struct sctp_tcb *stcb,
2639e7e71dd7SMichael Tuexen struct sctp_nets *net, uint32_t *high_tsn)
2640f8829a4aSRandall Stewart {
264144249214SRandall Stewart struct sctp_chunkhdr *ch, chunk_buf;
2642f8829a4aSRandall Stewart struct sctp_association *asoc;
2643f8829a4aSRandall Stewart int num_chunks = 0; /* number of control chunks processed */
2644f8829a4aSRandall Stewart int stop_proc = 0;
2645af03054cSMichael Tuexen int break_flag, last_chunk;
26468f777478SMichael Tuexen int abort_flag = 0, was_a_gap;
2647f8829a4aSRandall Stewart struct mbuf *m;
26488f777478SMichael Tuexen uint32_t highest_tsn;
2649af03054cSMichael Tuexen uint16_t chk_length;
2650f8829a4aSRandall Stewart
2651f8829a4aSRandall Stewart /* set the rwnd */
2652f8829a4aSRandall Stewart sctp_set_rwnd(stcb, &stcb->asoc);
2653f8829a4aSRandall Stewart
2654f8829a4aSRandall Stewart m = *mm;
2655f8829a4aSRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb);
2656f8829a4aSRandall Stewart asoc = &stcb->asoc;
265720b07a4dSMichael Tuexen if (SCTP_TSN_GT(asoc->highest_tsn_inside_nr_map, asoc->highest_tsn_inside_map)) {
26588f777478SMichael Tuexen highest_tsn = asoc->highest_tsn_inside_nr_map;
26598f777478SMichael Tuexen } else {
26608f777478SMichael Tuexen highest_tsn = asoc->highest_tsn_inside_map;
2661f8829a4aSRandall Stewart }
266220b07a4dSMichael Tuexen was_a_gap = SCTP_TSN_GT(highest_tsn, stcb->asoc.cumulative_tsn);
2663f8829a4aSRandall Stewart /*
2664f8829a4aSRandall Stewart * setup where we got the last DATA packet from for any SACK that
2665f8829a4aSRandall Stewart * may need to go out. Don't bump the net. This is done ONLY when a
2666f8829a4aSRandall Stewart * chunk is assigned.
2667f8829a4aSRandall Stewart */
2668f8829a4aSRandall Stewart asoc->last_data_chunk_from = net;
2669f8829a4aSRandall Stewart
2670d06c82f1SRandall Stewart /*-
2671f8829a4aSRandall Stewart * Now before we proceed we must figure out if this is a wasted
2672f8829a4aSRandall Stewart * cluster... i.e. it is a small packet sent in and yet the driver
2673f8829a4aSRandall Stewart * underneath allocated a full cluster for it. If so we must copy it
2674f8829a4aSRandall Stewart * to a smaller mbuf and free up the cluster mbuf. This will help
26752cf33471SMichael Tuexen * with cluster starvation.
2676f8829a4aSRandall Stewart */
267744b7479bSRandall Stewart if (SCTP_BUF_LEN(m) < (long)MLEN && SCTP_BUF_NEXT(m) == NULL) {
2678f8829a4aSRandall Stewart /* we only handle mbufs that are singletons.. not chains */
2679eb1b1807SGleb Smirnoff m = sctp_get_mbuf_for_msg(SCTP_BUF_LEN(m), 0, M_NOWAIT, 1, MT_DATA);
2680f8829a4aSRandall Stewart if (m) {
2681f8829a4aSRandall Stewart /* ok lets see if we can copy the data up */
2682f8829a4aSRandall Stewart caddr_t *from, *to;
2683f8829a4aSRandall Stewart
2684f8829a4aSRandall Stewart /* get the pointers and copy */
2685f8829a4aSRandall Stewart to = mtod(m, caddr_t *);
2686f8829a4aSRandall Stewart from = mtod((*mm), caddr_t *);
2687139bc87fSRandall Stewart memcpy(to, from, SCTP_BUF_LEN((*mm)));
2688f8829a4aSRandall Stewart /* copy the length and free up the old */
2689139bc87fSRandall Stewart SCTP_BUF_LEN(m) = SCTP_BUF_LEN((*mm));
2690f8829a4aSRandall Stewart sctp_m_freem(*mm);
2691cd0a4ff6SPedro F. Giffuni /* success, back copy */
2692f8829a4aSRandall Stewart *mm = m;
2693f8829a4aSRandall Stewart } else {
2694f8829a4aSRandall Stewart /* We are in trouble in the mbuf world .. yikes */
2695f8829a4aSRandall Stewart m = *mm;
2696f8829a4aSRandall Stewart }
2697f8829a4aSRandall Stewart }
2698f8829a4aSRandall Stewart /* get pointer to the first chunk header */
269944249214SRandall Stewart ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
27007f75695aSMichael Tuexen sizeof(struct sctp_chunkhdr),
27017f75695aSMichael Tuexen (uint8_t *)&chunk_buf);
2702f8829a4aSRandall Stewart if (ch == NULL) {
2703f8829a4aSRandall Stewart return (1);
2704f8829a4aSRandall Stewart }
2705f8829a4aSRandall Stewart /*
2706f8829a4aSRandall Stewart * process all DATA chunks...
2707f8829a4aSRandall Stewart */
2708f8829a4aSRandall Stewart *high_tsn = asoc->cumulative_tsn;
2709f8829a4aSRandall Stewart break_flag = 0;
271042551e99SRandall Stewart asoc->data_pkts_seen++;
2711f8829a4aSRandall Stewart while (stop_proc == 0) {
2712f8829a4aSRandall Stewart /* validate chunk length */
271344249214SRandall Stewart chk_length = ntohs(ch->chunk_length);
2714f8829a4aSRandall Stewart if (length - *offset < chk_length) {
2715f8829a4aSRandall Stewart /* all done, mutulated chunk */
2716f8829a4aSRandall Stewart stop_proc = 1;
271760990c0cSMichael Tuexen continue;
2718f8829a4aSRandall Stewart }
271944249214SRandall Stewart if ((asoc->idata_supported == 1) &&
272044249214SRandall Stewart (ch->chunk_type == SCTP_DATA)) {
272144249214SRandall Stewart struct mbuf *op_err;
272244249214SRandall Stewart char msg[SCTP_DIAG_INFO_LEN];
272344249214SRandall Stewart
2724ef9095c7SMichael Tuexen SCTP_SNPRINTF(msg, sizeof(msg), "%s", "DATA chunk received when I-DATA was negotiated");
272544249214SRandall Stewart op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
272691e04f9eSMichael Tuexen stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_21;
2727105b68b4SMichael Tuexen sctp_abort_an_association(inp, stcb, op_err, false, SCTP_SO_NOT_LOCKED);
272844249214SRandall Stewart return (2);
272944249214SRandall Stewart }
273044249214SRandall Stewart if ((asoc->idata_supported == 0) &&
273144249214SRandall Stewart (ch->chunk_type == SCTP_IDATA)) {
273244249214SRandall Stewart struct mbuf *op_err;
273344249214SRandall Stewart char msg[SCTP_DIAG_INFO_LEN];
273444249214SRandall Stewart
2735ef9095c7SMichael Tuexen SCTP_SNPRINTF(msg, sizeof(msg), "%s", "I-DATA chunk received when DATA was negotiated");
273644249214SRandall Stewart op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
273791e04f9eSMichael Tuexen stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_22;
2738105b68b4SMichael Tuexen sctp_abort_an_association(inp, stcb, op_err, false, SCTP_SO_NOT_LOCKED);
273944249214SRandall Stewart return (2);
274044249214SRandall Stewart }
274144249214SRandall Stewart if ((ch->chunk_type == SCTP_DATA) ||
274244249214SRandall Stewart (ch->chunk_type == SCTP_IDATA)) {
2743af03054cSMichael Tuexen uint16_t clen;
274444249214SRandall Stewart
274544249214SRandall Stewart if (ch->chunk_type == SCTP_DATA) {
274644249214SRandall Stewart clen = sizeof(struct sctp_data_chunk);
274744249214SRandall Stewart } else {
274844249214SRandall Stewart clen = sizeof(struct sctp_idata_chunk);
274944249214SRandall Stewart }
2750f8ee69bfSMichael Tuexen if (chk_length < clen) {
2751f8829a4aSRandall Stewart /*
2752f8829a4aSRandall Stewart * Need to send an abort since we had a
2753f8829a4aSRandall Stewart * invalid data chunk.
2754f8829a4aSRandall Stewart */
2755f8829a4aSRandall Stewart struct mbuf *op_err;
2756ff1ffd74SMichael Tuexen char msg[SCTP_DIAG_INFO_LEN];
2757f8829a4aSRandall Stewart
2758999f86d6SMichael Tuexen SCTP_SNPRINTF(msg, sizeof(msg), "%s chunk of length %u",
27597f75695aSMichael Tuexen ch->chunk_type == SCTP_DATA ? "DATA" : "I-DATA",
2760821bae7cSMichael Tuexen chk_length);
2761ff1ffd74SMichael Tuexen op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
276291e04f9eSMichael Tuexen stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_23;
2763105b68b4SMichael Tuexen sctp_abort_an_association(inp, stcb, op_err, false, SCTP_SO_NOT_LOCKED);
276432451da4SMichael Tuexen return (2);
276532451da4SMichael Tuexen }
2766f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
2767f8829a4aSRandall Stewart sctp_audit_log(0xB1, 0);
2768f8829a4aSRandall Stewart #endif
2769f8829a4aSRandall Stewart if (SCTP_SIZE32(chk_length) == (length - *offset)) {
2770f8829a4aSRandall Stewart last_chunk = 1;
2771f8829a4aSRandall Stewart } else {
2772f8829a4aSRandall Stewart last_chunk = 0;
2773f8829a4aSRandall Stewart }
277444249214SRandall Stewart if (sctp_process_a_data_chunk(stcb, asoc, mm, *offset,
2775f8829a4aSRandall Stewart chk_length, net, high_tsn, &abort_flag, &break_flag,
277644249214SRandall Stewart last_chunk, ch->chunk_type)) {
2777f8829a4aSRandall Stewart num_chunks++;
2778f8829a4aSRandall Stewart }
2779f8829a4aSRandall Stewart if (abort_flag)
2780f8829a4aSRandall Stewart return (2);
2781f8829a4aSRandall Stewart
2782f8829a4aSRandall Stewart if (break_flag) {
2783f8829a4aSRandall Stewart /*
2784f8829a4aSRandall Stewart * Set because of out of rwnd space and no
2785f8829a4aSRandall Stewart * drop rep space left.
2786f8829a4aSRandall Stewart */
2787f8829a4aSRandall Stewart stop_proc = 1;
278860990c0cSMichael Tuexen continue;
2789f8829a4aSRandall Stewart }
2790f8829a4aSRandall Stewart } else {
2791f8829a4aSRandall Stewart /* not a data chunk in the data region */
279244249214SRandall Stewart switch (ch->chunk_type) {
2793f8829a4aSRandall Stewart case SCTP_INITIATION:
2794f8829a4aSRandall Stewart case SCTP_INITIATION_ACK:
2795f8829a4aSRandall Stewart case SCTP_SELECTIVE_ACK:
279660990c0cSMichael Tuexen case SCTP_NR_SELECTIVE_ACK:
2797f8829a4aSRandall Stewart case SCTP_HEARTBEAT_REQUEST:
2798f8829a4aSRandall Stewart case SCTP_HEARTBEAT_ACK:
2799f8829a4aSRandall Stewart case SCTP_ABORT_ASSOCIATION:
2800f8829a4aSRandall Stewart case SCTP_SHUTDOWN:
2801f8829a4aSRandall Stewart case SCTP_SHUTDOWN_ACK:
2802f8829a4aSRandall Stewart case SCTP_OPERATION_ERROR:
2803f8829a4aSRandall Stewart case SCTP_COOKIE_ECHO:
2804f8829a4aSRandall Stewart case SCTP_COOKIE_ACK:
2805f8829a4aSRandall Stewart case SCTP_ECN_ECHO:
2806f8829a4aSRandall Stewart case SCTP_ECN_CWR:
2807f8829a4aSRandall Stewart case SCTP_SHUTDOWN_COMPLETE:
2808f8829a4aSRandall Stewart case SCTP_AUTHENTICATION:
2809f8829a4aSRandall Stewart case SCTP_ASCONF_ACK:
2810f8829a4aSRandall Stewart case SCTP_PACKET_DROPPED:
2811f8829a4aSRandall Stewart case SCTP_STREAM_RESET:
2812f8829a4aSRandall Stewart case SCTP_FORWARD_CUM_TSN:
2813f8829a4aSRandall Stewart case SCTP_ASCONF:
2814fd60718dSMichael Tuexen {
2815f8829a4aSRandall Stewart /*
2816fd60718dSMichael Tuexen * Now, what do we do with KNOWN
2817fd60718dSMichael Tuexen * chunks that are NOT in the right
2818fd60718dSMichael Tuexen * place?
2819f8829a4aSRandall Stewart *
2820fd60718dSMichael Tuexen * For now, I do nothing but ignore
2821fd60718dSMichael Tuexen * them. We may later want to add
2822fd60718dSMichael Tuexen * sysctl stuff to switch out and do
2823fd60718dSMichael Tuexen * either an ABORT() or possibly
2824fd60718dSMichael Tuexen * process them.
2825f8829a4aSRandall Stewart */
2826f8829a4aSRandall Stewart struct mbuf *op_err;
2827267dbe63SMichael Tuexen char msg[SCTP_DIAG_INFO_LEN];
2828f8829a4aSRandall Stewart
2829999f86d6SMichael Tuexen SCTP_SNPRINTF(msg, sizeof(msg), "DATA chunk followed by chunk of type %2.2x",
2830821bae7cSMichael Tuexen ch->chunk_type);
2831267dbe63SMichael Tuexen op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
2832105b68b4SMichael Tuexen sctp_abort_an_association(inp, stcb, op_err, false, SCTP_SO_NOT_LOCKED);
2833f8829a4aSRandall Stewart return (2);
2834f8829a4aSRandall Stewart }
2835f8829a4aSRandall Stewart default:
28367f75695aSMichael Tuexen /*
28377f75695aSMichael Tuexen * Unknown chunk type: use bit rules after
28387f75695aSMichael Tuexen * checking length
28397f75695aSMichael Tuexen */
28407f75695aSMichael Tuexen if (chk_length < sizeof(struct sctp_chunkhdr)) {
28417f75695aSMichael Tuexen /*
28427f75695aSMichael Tuexen * Need to send an abort since we
28437f75695aSMichael Tuexen * had a invalid chunk.
28447f75695aSMichael Tuexen */
28457f75695aSMichael Tuexen struct mbuf *op_err;
28467f75695aSMichael Tuexen char msg[SCTP_DIAG_INFO_LEN];
28477f75695aSMichael Tuexen
2848999f86d6SMichael Tuexen SCTP_SNPRINTF(msg, sizeof(msg), "Chunk of length %u", chk_length);
28497f75695aSMichael Tuexen op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
285091e04f9eSMichael Tuexen stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_24;
2851105b68b4SMichael Tuexen sctp_abort_an_association(inp, stcb, op_err, false, SCTP_SO_NOT_LOCKED);
28527f75695aSMichael Tuexen return (2);
28537f75695aSMichael Tuexen }
285444249214SRandall Stewart if (ch->chunk_type & 0x40) {
2855f8829a4aSRandall Stewart /* Add a error report to the queue */
285686eda749SMichael Tuexen struct mbuf *op_err;
285786eda749SMichael Tuexen struct sctp_gen_error_cause *cause;
2858f8829a4aSRandall Stewart
285986eda749SMichael Tuexen op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_gen_error_cause),
286086eda749SMichael Tuexen 0, M_NOWAIT, 1, MT_DATA);
286186eda749SMichael Tuexen if (op_err != NULL) {
286286eda749SMichael Tuexen cause = mtod(op_err, struct sctp_gen_error_cause *);
286386eda749SMichael Tuexen cause->code = htons(SCTP_CAUSE_UNRECOG_CHUNK);
28649a8e3088SMichael Tuexen cause->length = htons((uint16_t)(chk_length + sizeof(struct sctp_gen_error_cause)));
286586eda749SMichael Tuexen SCTP_BUF_LEN(op_err) = sizeof(struct sctp_gen_error_cause);
286686eda749SMichael Tuexen SCTP_BUF_NEXT(op_err) = SCTP_M_COPYM(m, *offset, chk_length, M_NOWAIT);
286786eda749SMichael Tuexen if (SCTP_BUF_NEXT(op_err) != NULL) {
286886eda749SMichael Tuexen sctp_queue_op_err(stcb, op_err);
2869f8829a4aSRandall Stewart } else {
287086eda749SMichael Tuexen sctp_m_freem(op_err);
2871f8829a4aSRandall Stewart }
2872f8829a4aSRandall Stewart }
2873f8829a4aSRandall Stewart }
287444249214SRandall Stewart if ((ch->chunk_type & 0x80) == 0) {
2875f8829a4aSRandall Stewart /* discard the rest of this packet */
2876f8829a4aSRandall Stewart stop_proc = 1;
2877f8829a4aSRandall Stewart } /* else skip this bad chunk and
2878b7b84c0eSMichael Tuexen * continue... */
2879b7b84c0eSMichael Tuexen break;
288060990c0cSMichael Tuexen } /* switch of chunk type */
2881f8829a4aSRandall Stewart }
2882f8829a4aSRandall Stewart *offset += SCTP_SIZE32(chk_length);
2883f8829a4aSRandall Stewart if ((*offset >= length) || stop_proc) {
2884f8829a4aSRandall Stewart /* no more data left in the mbuf chain */
2885f8829a4aSRandall Stewart stop_proc = 1;
2886f8829a4aSRandall Stewart continue;
2887f8829a4aSRandall Stewart }
288844249214SRandall Stewart ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
28897f75695aSMichael Tuexen sizeof(struct sctp_chunkhdr),
28907f75695aSMichael Tuexen (uint8_t *)&chunk_buf);
2891f8829a4aSRandall Stewart if (ch == NULL) {
2892f8829a4aSRandall Stewart *offset = length;
2893f8829a4aSRandall Stewart stop_proc = 1;
289460990c0cSMichael Tuexen continue;
2895f8829a4aSRandall Stewart }
289660990c0cSMichael Tuexen }
2897f8829a4aSRandall Stewart if (break_flag) {
2898f8829a4aSRandall Stewart /*
2899f8829a4aSRandall Stewart * we need to report rwnd overrun drops.
2900f8829a4aSRandall Stewart */
290120cc2188SMichael Tuexen sctp_send_packet_dropped(stcb, net, *mm, length, iphlen, 0);
2902f8829a4aSRandall Stewart }
2903f8829a4aSRandall Stewart if (num_chunks) {
2904f8829a4aSRandall Stewart /*
2905ceaad40aSRandall Stewart * Did we get data, if so update the time for auto-close and
2906f8829a4aSRandall Stewart * give peer credit for being alive.
2907f8829a4aSRandall Stewart */
2908f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_recvpktwithdata);
2909b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
2910c4739e2fSRandall Stewart sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
2911c4739e2fSRandall Stewart stcb->asoc.overall_error_count,
2912c4739e2fSRandall Stewart 0,
2913c4739e2fSRandall Stewart SCTP_FROM_SCTP_INDATA,
2914c4739e2fSRandall Stewart __LINE__);
2915c4739e2fSRandall Stewart }
2916f8829a4aSRandall Stewart stcb->asoc.overall_error_count = 0;
29176e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_last_rcvd);
2918f8829a4aSRandall Stewart }
2919f8829a4aSRandall Stewart /* now service all of the reassm queue if needed */
2920839d21d6SMichael Tuexen if (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_SENT) {
292142551e99SRandall Stewart /* Assure that we ack right away */
292242551e99SRandall Stewart stcb->asoc.send_sack = 1;
2923f8829a4aSRandall Stewart }
2924f8829a4aSRandall Stewart /* Start a sack timer or QUEUE a SACK for sending */
29257215cc1bSMichael Tuexen sctp_sack_check(stcb, was_a_gap);
2926f8829a4aSRandall Stewart return (0);
2927f8829a4aSRandall Stewart }
2928f8829a4aSRandall Stewart
29290fa753b3SRandall Stewart static int
sctp_process_segment_range(struct sctp_tcb * stcb,struct sctp_tmit_chunk ** p_tp1,uint32_t last_tsn,uint16_t frag_strt,uint16_t frag_end,int nr_sacking,int * num_frs,uint32_t * biggest_newly_acked_tsn,uint32_t * this_sack_lowest_newack,int * rto_ok)29300fa753b3SRandall Stewart sctp_process_segment_range(struct sctp_tcb *stcb, struct sctp_tmit_chunk **p_tp1, uint32_t last_tsn,
29310fa753b3SRandall Stewart uint16_t frag_strt, uint16_t frag_end, int nr_sacking,
29320fa753b3SRandall Stewart int *num_frs,
29330fa753b3SRandall Stewart uint32_t *biggest_newly_acked_tsn,
29340fa753b3SRandall Stewart uint32_t *this_sack_lowest_newack,
29357215cc1bSMichael Tuexen int *rto_ok)
29360fa753b3SRandall Stewart {
29370fa753b3SRandall Stewart struct sctp_tmit_chunk *tp1;
29380fa753b3SRandall Stewart unsigned int theTSN;
2939b5c16493SMichael Tuexen int j, wake_him = 0, circled = 0;
29400fa753b3SRandall Stewart
29410fa753b3SRandall Stewart /* Recover the tp1 we last saw */
29420fa753b3SRandall Stewart tp1 = *p_tp1;
29430fa753b3SRandall Stewart if (tp1 == NULL) {
29440fa753b3SRandall Stewart tp1 = TAILQ_FIRST(&stcb->asoc.sent_queue);
29450fa753b3SRandall Stewart }
29460fa753b3SRandall Stewart for (j = frag_strt; j <= frag_end; j++) {
29470fa753b3SRandall Stewart theTSN = j + last_tsn;
29480fa753b3SRandall Stewart while (tp1) {
29490fa753b3SRandall Stewart if (tp1->rec.data.doing_fast_retransmit)
29500fa753b3SRandall Stewart (*num_frs) += 1;
29510fa753b3SRandall Stewart
29520fa753b3SRandall Stewart /*-
29530fa753b3SRandall Stewart * CMT: CUCv2 algorithm. For each TSN being
29540fa753b3SRandall Stewart * processed from the sent queue, track the
29550fa753b3SRandall Stewart * next expected pseudo-cumack, or
29560fa753b3SRandall Stewart * rtx_pseudo_cumack, if required. Separate
29570fa753b3SRandall Stewart * cumack trackers for first transmissions,
29580fa753b3SRandall Stewart * and retransmissions.
29590fa753b3SRandall Stewart */
29608427b3fdSMichael Tuexen if ((tp1->sent < SCTP_DATAGRAM_RESEND) &&
29618427b3fdSMichael Tuexen (tp1->whoTo->find_pseudo_cumack == 1) &&
29620fa753b3SRandall Stewart (tp1->snd_count == 1)) {
296349656eefSMichael Tuexen tp1->whoTo->pseudo_cumack = tp1->rec.data.tsn;
29640fa753b3SRandall Stewart tp1->whoTo->find_pseudo_cumack = 0;
29650fa753b3SRandall Stewart }
29668427b3fdSMichael Tuexen if ((tp1->sent < SCTP_DATAGRAM_RESEND) &&
29678427b3fdSMichael Tuexen (tp1->whoTo->find_rtx_pseudo_cumack == 1) &&
29680fa753b3SRandall Stewart (tp1->snd_count > 1)) {
296949656eefSMichael Tuexen tp1->whoTo->rtx_pseudo_cumack = tp1->rec.data.tsn;
29700fa753b3SRandall Stewart tp1->whoTo->find_rtx_pseudo_cumack = 0;
29710fa753b3SRandall Stewart }
297249656eefSMichael Tuexen if (tp1->rec.data.tsn == theTSN) {
29730fa753b3SRandall Stewart if (tp1->sent != SCTP_DATAGRAM_UNSENT) {
29740fa753b3SRandall Stewart /*-
29750fa753b3SRandall Stewart * must be held until
29760fa753b3SRandall Stewart * cum-ack passes
29770fa753b3SRandall Stewart */
29780fa753b3SRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND) {
29790fa753b3SRandall Stewart /*-
29800fa753b3SRandall Stewart * If it is less than RESEND, it is
29810fa753b3SRandall Stewart * now no-longer in flight.
29820fa753b3SRandall Stewart * Higher values may already be set
29830fa753b3SRandall Stewart * via previous Gap Ack Blocks...
29840fa753b3SRandall Stewart * i.e. ACKED or RESEND.
29850fa753b3SRandall Stewart */
298649656eefSMichael Tuexen if (SCTP_TSN_GT(tp1->rec.data.tsn,
298720b07a4dSMichael Tuexen *biggest_newly_acked_tsn)) {
298849656eefSMichael Tuexen *biggest_newly_acked_tsn = tp1->rec.data.tsn;
29890fa753b3SRandall Stewart }
29900fa753b3SRandall Stewart /*-
29910fa753b3SRandall Stewart * CMT: SFR algo (and HTNA) - set
29920fa753b3SRandall Stewart * saw_newack to 1 for dest being
29930fa753b3SRandall Stewart * newly acked. update
29940fa753b3SRandall Stewart * this_sack_highest_newack if
29950fa753b3SRandall Stewart * appropriate.
29960fa753b3SRandall Stewart */
29970fa753b3SRandall Stewart if (tp1->rec.data.chunk_was_revoked == 0)
29980fa753b3SRandall Stewart tp1->whoTo->saw_newack = 1;
29990fa753b3SRandall Stewart
300049656eefSMichael Tuexen if (SCTP_TSN_GT(tp1->rec.data.tsn,
300120b07a4dSMichael Tuexen tp1->whoTo->this_sack_highest_newack)) {
30020fa753b3SRandall Stewart tp1->whoTo->this_sack_highest_newack =
300349656eefSMichael Tuexen tp1->rec.data.tsn;
30040fa753b3SRandall Stewart }
30050fa753b3SRandall Stewart /*-
30060fa753b3SRandall Stewart * CMT DAC algo: also update
30070fa753b3SRandall Stewart * this_sack_lowest_newack
30080fa753b3SRandall Stewart */
30090fa753b3SRandall Stewart if (*this_sack_lowest_newack == 0) {
30100fa753b3SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
30110fa753b3SRandall Stewart sctp_log_sack(*this_sack_lowest_newack,
30120fa753b3SRandall Stewart last_tsn,
301349656eefSMichael Tuexen tp1->rec.data.tsn,
30140fa753b3SRandall Stewart 0,
30150fa753b3SRandall Stewart 0,
30160fa753b3SRandall Stewart SCTP_LOG_TSN_ACKED);
30170fa753b3SRandall Stewart }
301849656eefSMichael Tuexen *this_sack_lowest_newack = tp1->rec.data.tsn;
30190fa753b3SRandall Stewart }
30200fa753b3SRandall Stewart /*-
30210fa753b3SRandall Stewart * CMT: CUCv2 algorithm. If (rtx-)pseudo-cumack for corresp
30220fa753b3SRandall Stewart * dest is being acked, then we have a new (rtx-)pseudo-cumack. Set
30230fa753b3SRandall Stewart * new_(rtx_)pseudo_cumack to TRUE so that the cwnd for this dest can be
30240fa753b3SRandall Stewart * updated. Also trigger search for the next expected (rtx-)pseudo-cumack.
30250fa753b3SRandall Stewart * Separate pseudo_cumack trackers for first transmissions and
30260fa753b3SRandall Stewart * retransmissions.
30270fa753b3SRandall Stewart */
302849656eefSMichael Tuexen if (tp1->rec.data.tsn == tp1->whoTo->pseudo_cumack) {
30290fa753b3SRandall Stewart if (tp1->rec.data.chunk_was_revoked == 0) {
30300fa753b3SRandall Stewart tp1->whoTo->new_pseudo_cumack = 1;
30310fa753b3SRandall Stewart }
30320fa753b3SRandall Stewart tp1->whoTo->find_pseudo_cumack = 1;
30330fa753b3SRandall Stewart }
30340fa753b3SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
303549656eefSMichael Tuexen sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.tsn, SCTP_CWND_LOG_FROM_SACK);
30360fa753b3SRandall Stewart }
303749656eefSMichael Tuexen if (tp1->rec.data.tsn == tp1->whoTo->rtx_pseudo_cumack) {
30380fa753b3SRandall Stewart if (tp1->rec.data.chunk_was_revoked == 0) {
30390fa753b3SRandall Stewart tp1->whoTo->new_pseudo_cumack = 1;
30400fa753b3SRandall Stewart }
30410fa753b3SRandall Stewart tp1->whoTo->find_rtx_pseudo_cumack = 1;
30420fa753b3SRandall Stewart }
30430fa753b3SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
30440fa753b3SRandall Stewart sctp_log_sack(*biggest_newly_acked_tsn,
30450fa753b3SRandall Stewart last_tsn,
304649656eefSMichael Tuexen tp1->rec.data.tsn,
30470fa753b3SRandall Stewart frag_strt,
30480fa753b3SRandall Stewart frag_end,
30490fa753b3SRandall Stewart SCTP_LOG_TSN_ACKED);
30500fa753b3SRandall Stewart }
30510fa753b3SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
30520fa753b3SRandall Stewart sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_GAP,
30530fa753b3SRandall Stewart tp1->whoTo->flight_size,
30540fa753b3SRandall Stewart tp1->book_size,
30559a8e3088SMichael Tuexen (uint32_t)(uintptr_t)tp1->whoTo,
305649656eefSMichael Tuexen tp1->rec.data.tsn);
30570fa753b3SRandall Stewart }
30580fa753b3SRandall Stewart sctp_flight_size_decrease(tp1);
3059299108c5SRandall Stewart if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) {
3060299108c5SRandall Stewart (*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) (tp1->whoTo,
3061299108c5SRandall Stewart tp1);
3062299108c5SRandall Stewart }
30630fa753b3SRandall Stewart sctp_total_flight_decrease(stcb, tp1);
30640fa753b3SRandall Stewart
30650fa753b3SRandall Stewart tp1->whoTo->net_ack += tp1->send_size;
30660fa753b3SRandall Stewart if (tp1->snd_count < 2) {
30670fa753b3SRandall Stewart /*-
3068ab9ed8a1SDevin Teske * True non-retransmitted chunk
30690fa753b3SRandall Stewart */
30700fa753b3SRandall Stewart tp1->whoTo->net_ack2 += tp1->send_size;
30710fa753b3SRandall Stewart
30720fa753b3SRandall Stewart /*-
30730fa753b3SRandall Stewart * update RTO too ?
30740fa753b3SRandall Stewart */
30750fa753b3SRandall Stewart if (tp1->do_rtt) {
307644f2a327SMichael Tuexen if (*rto_ok &&
30770fa753b3SRandall Stewart sctp_calculate_rto(stcb,
30780fa753b3SRandall Stewart &stcb->asoc,
30790fa753b3SRandall Stewart tp1->whoTo,
30800fa753b3SRandall Stewart &tp1->sent_rcv_time,
308144f2a327SMichael Tuexen SCTP_RTT_FROM_DATA)) {
3082f79aab18SRandall Stewart *rto_ok = 0;
3083f79aab18SRandall Stewart }
3084f79aab18SRandall Stewart if (tp1->whoTo->rto_needed == 0) {
3085f79aab18SRandall Stewart tp1->whoTo->rto_needed = 1;
3086f79aab18SRandall Stewart }
30870fa753b3SRandall Stewart tp1->do_rtt = 0;
30880fa753b3SRandall Stewart }
30890fa753b3SRandall Stewart }
30900fa753b3SRandall Stewart }
30910fa753b3SRandall Stewart if (tp1->sent <= SCTP_DATAGRAM_RESEND) {
309249656eefSMichael Tuexen if (SCTP_TSN_GT(tp1->rec.data.tsn,
309320b07a4dSMichael Tuexen stcb->asoc.this_sack_highest_gap)) {
30940fa753b3SRandall Stewart stcb->asoc.this_sack_highest_gap =
309549656eefSMichael Tuexen tp1->rec.data.tsn;
30960fa753b3SRandall Stewart }
30970fa753b3SRandall Stewart if (tp1->sent == SCTP_DATAGRAM_RESEND) {
30980fa753b3SRandall Stewart sctp_ucount_decr(stcb->asoc.sent_queue_retran_cnt);
30990fa753b3SRandall Stewart #ifdef SCTP_AUDITING_ENABLED
31000fa753b3SRandall Stewart sctp_audit_log(0xB2,
31010fa753b3SRandall Stewart (stcb->asoc.sent_queue_retran_cnt & 0x000000ff));
31020fa753b3SRandall Stewart #endif
31030fa753b3SRandall Stewart }
31040fa753b3SRandall Stewart }
31050fa753b3SRandall Stewart /*-
31060fa753b3SRandall Stewart * All chunks NOT UNSENT fall through here and are marked
31070fa753b3SRandall Stewart * (leave PR-SCTP ones that are to skip alone though)
31080fa753b3SRandall Stewart */
31092a498584SMichael Tuexen if ((tp1->sent != SCTP_FORWARD_TSN_SKIP) &&
3110325c8c46SMichael Tuexen (tp1->sent != SCTP_DATAGRAM_NR_ACKED)) {
31110fa753b3SRandall Stewart tp1->sent = SCTP_DATAGRAM_MARKED;
31122a498584SMichael Tuexen }
31130fa753b3SRandall Stewart if (tp1->rec.data.chunk_was_revoked) {
31140fa753b3SRandall Stewart /* deflate the cwnd */
31150fa753b3SRandall Stewart tp1->whoTo->cwnd -= tp1->book_size;
31160fa753b3SRandall Stewart tp1->rec.data.chunk_was_revoked = 0;
31170fa753b3SRandall Stewart }
31180fa753b3SRandall Stewart /* NR Sack code here */
3119325c8c46SMichael Tuexen if (nr_sacking &&
3120325c8c46SMichael Tuexen (tp1->sent != SCTP_DATAGRAM_NR_ACKED)) {
312149656eefSMichael Tuexen if (stcb->asoc.strmout[tp1->rec.data.sid].chunks_on_queues > 0) {
312249656eefSMichael Tuexen stcb->asoc.strmout[tp1->rec.data.sid].chunks_on_queues--;
3123325c8c46SMichael Tuexen #ifdef INVARIANTS
3124325c8c46SMichael Tuexen } else {
312549656eefSMichael Tuexen panic("No chunks on the queues for sid %u.", tp1->rec.data.sid);
3126325c8c46SMichael Tuexen #endif
3127325c8c46SMichael Tuexen }
312849656eefSMichael Tuexen if ((stcb->asoc.strmout[tp1->rec.data.sid].chunks_on_queues == 0) &&
312949656eefSMichael Tuexen (stcb->asoc.strmout[tp1->rec.data.sid].state == SCTP_STREAM_RESET_PENDING) &&
313049656eefSMichael Tuexen TAILQ_EMPTY(&stcb->asoc.strmout[tp1->rec.data.sid].outqueue)) {
3131d96bef9cSMichael Tuexen stcb->asoc.trigger_reset = 1;
3132d96bef9cSMichael Tuexen }
3133325c8c46SMichael Tuexen tp1->sent = SCTP_DATAGRAM_NR_ACKED;
31340fa753b3SRandall Stewart if (tp1->data) {
3135b7b84c0eSMichael Tuexen /*
3136b7b84c0eSMichael Tuexen * sa_ignore
3137b7b84c0eSMichael Tuexen * NO_NULL_CHK
3138b7b84c0eSMichael Tuexen */
31390fa753b3SRandall Stewart sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1);
31400fa753b3SRandall Stewart sctp_m_freem(tp1->data);
31410fa753b3SRandall Stewart tp1->data = NULL;
3142b5c16493SMichael Tuexen }
31430fa753b3SRandall Stewart wake_him++;
31440fa753b3SRandall Stewart }
31450fa753b3SRandall Stewart }
31460fa753b3SRandall Stewart break;
3147b7b84c0eSMichael Tuexen } /* if (tp1->tsn == theTSN) */
3148b7b84c0eSMichael Tuexen if (SCTP_TSN_GT(tp1->rec.data.tsn, theTSN)) {
31490fa753b3SRandall Stewart break;
315020b07a4dSMichael Tuexen }
31510fa753b3SRandall Stewart tp1 = TAILQ_NEXT(tp1, sctp_next);
3152b5c16493SMichael Tuexen if ((tp1 == NULL) && (circled == 0)) {
3153b5c16493SMichael Tuexen circled++;
31540fa753b3SRandall Stewart tp1 = TAILQ_FIRST(&stcb->asoc.sent_queue);
31550fa753b3SRandall Stewart }
3156b5c16493SMichael Tuexen } /* end while (tp1) */
3157b5c16493SMichael Tuexen if (tp1 == NULL) {
3158b5c16493SMichael Tuexen circled = 0;
3159b5c16493SMichael Tuexen tp1 = TAILQ_FIRST(&stcb->asoc.sent_queue);
3160b5c16493SMichael Tuexen }
3161b5c16493SMichael Tuexen /* In case the fragments were not in order we must reset */
31620fa753b3SRandall Stewart } /* end for (j = fragStart */
31630fa753b3SRandall Stewart *p_tp1 = tp1;
31640fa753b3SRandall Stewart return (wake_him); /* Return value only used for nr-sack */
31650fa753b3SRandall Stewart }
31660fa753b3SRandall Stewart
3167cd554309SMichael Tuexen static int
sctp_handle_segments(struct mbuf * m,int * offset,struct sctp_tcb * stcb,struct sctp_association * asoc,uint32_t last_tsn,uint32_t * biggest_tsn_acked,uint32_t * biggest_newly_acked_tsn,uint32_t * this_sack_lowest_newack,int num_seg,int num_nr_seg,int * rto_ok)3168458303daSRandall Stewart sctp_handle_segments(struct mbuf *m, int *offset, struct sctp_tcb *stcb, struct sctp_association *asoc,
3169cd554309SMichael Tuexen uint32_t last_tsn, uint32_t *biggest_tsn_acked,
3170139bc87fSRandall Stewart uint32_t *biggest_newly_acked_tsn, uint32_t *this_sack_lowest_newack,
31717215cc1bSMichael Tuexen int num_seg, int num_nr_seg, int *rto_ok)
3172f8829a4aSRandall Stewart {
3173458303daSRandall Stewart struct sctp_gap_ack_block *frag, block;
3174f8829a4aSRandall Stewart struct sctp_tmit_chunk *tp1;
31750fa753b3SRandall Stewart int i;
3176f8829a4aSRandall Stewart int num_frs = 0;
3177cd554309SMichael Tuexen int chunk_freed;
3178cd554309SMichael Tuexen int non_revocable;
3179d9c5cfeaSMichael Tuexen uint16_t frag_strt, frag_end, prev_frag_end;
3180f8829a4aSRandall Stewart
3181d9c5cfeaSMichael Tuexen tp1 = TAILQ_FIRST(&asoc->sent_queue);
3182d9c5cfeaSMichael Tuexen prev_frag_end = 0;
3183cd554309SMichael Tuexen chunk_freed = 0;
3184f8829a4aSRandall Stewart
3185cd554309SMichael Tuexen for (i = 0; i < (num_seg + num_nr_seg); i++) {
3186d9c5cfeaSMichael Tuexen if (i == num_seg) {
3187d9c5cfeaSMichael Tuexen prev_frag_end = 0;
3188d9c5cfeaSMichael Tuexen tp1 = TAILQ_FIRST(&asoc->sent_queue);
3189d9c5cfeaSMichael Tuexen }
3190458303daSRandall Stewart frag = (struct sctp_gap_ack_block *)sctp_m_getptr(m, *offset,
3191458303daSRandall Stewart sizeof(struct sctp_gap_ack_block), (uint8_t *)&block);
3192458303daSRandall Stewart *offset += sizeof(block);
3193458303daSRandall Stewart if (frag == NULL) {
3194cd554309SMichael Tuexen return (chunk_freed);
3195458303daSRandall Stewart }
3196f8829a4aSRandall Stewart frag_strt = ntohs(frag->start);
3197f8829a4aSRandall Stewart frag_end = ntohs(frag->end);
3198d9c5cfeaSMichael Tuexen
3199f8829a4aSRandall Stewart if (frag_strt > frag_end) {
3200d9c5cfeaSMichael Tuexen /* This gap report is malformed, skip it. */
3201f8829a4aSRandall Stewart continue;
3202f8829a4aSRandall Stewart }
3203d9c5cfeaSMichael Tuexen if (frag_strt <= prev_frag_end) {
3204d9c5cfeaSMichael Tuexen /* This gap report is not in order, so restart. */
3205f8829a4aSRandall Stewart tp1 = TAILQ_FIRST(&asoc->sent_queue);
3206f8829a4aSRandall Stewart }
320720b07a4dSMichael Tuexen if (SCTP_TSN_GT((last_tsn + frag_end), *biggest_tsn_acked)) {
3208d9c5cfeaSMichael Tuexen *biggest_tsn_acked = last_tsn + frag_end;
3209f8829a4aSRandall Stewart }
3210cd554309SMichael Tuexen if (i < num_seg) {
3211cd554309SMichael Tuexen non_revocable = 0;
3212cd554309SMichael Tuexen } else {
3213cd554309SMichael Tuexen non_revocable = 1;
3214cd554309SMichael Tuexen }
3215cd554309SMichael Tuexen if (sctp_process_segment_range(stcb, &tp1, last_tsn, frag_strt, frag_end,
3216cd554309SMichael Tuexen non_revocable, &num_frs, biggest_newly_acked_tsn,
32177215cc1bSMichael Tuexen this_sack_lowest_newack, rto_ok)) {
3218cd554309SMichael Tuexen chunk_freed = 1;
3219458303daSRandall Stewart }
3220d9c5cfeaSMichael Tuexen prev_frag_end = frag_end;
3221f8829a4aSRandall Stewart }
3222b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
322380fefe0aSRandall Stewart if (num_frs)
322480fefe0aSRandall Stewart sctp_log_fr(*biggest_tsn_acked,
322580fefe0aSRandall Stewart *biggest_newly_acked_tsn,
322680fefe0aSRandall Stewart last_tsn, SCTP_FR_LOG_BIGGEST_TSNS);
322780fefe0aSRandall Stewart }
3228cd554309SMichael Tuexen return (chunk_freed);
3229f8829a4aSRandall Stewart }
3230f8829a4aSRandall Stewart
3231f8829a4aSRandall Stewart static void
sctp_check_for_revoked(struct sctp_tcb * stcb,struct sctp_association * asoc,uint32_t cumack,uint32_t biggest_tsn_acked)3232c105859eSRandall Stewart sctp_check_for_revoked(struct sctp_tcb *stcb,
3233c105859eSRandall Stewart struct sctp_association *asoc, uint32_t cumack,
323463eda93dSMichael Tuexen uint32_t biggest_tsn_acked)
3235f8829a4aSRandall Stewart {
3236f8829a4aSRandall Stewart struct sctp_tmit_chunk *tp1;
3237f8829a4aSRandall Stewart
32384a9ef3f8SMichael Tuexen TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
323949656eefSMichael Tuexen if (SCTP_TSN_GT(tp1->rec.data.tsn, cumack)) {
3240f8829a4aSRandall Stewart /*
3241f8829a4aSRandall Stewart * ok this guy is either ACK or MARKED. If it is
3242f8829a4aSRandall Stewart * ACKED it has been previously acked but not this
3243f8829a4aSRandall Stewart * time i.e. revoked. If it is MARKED it was ACK'ed
3244f8829a4aSRandall Stewart * again.
3245f8829a4aSRandall Stewart */
324649656eefSMichael Tuexen if (SCTP_TSN_GT(tp1->rec.data.tsn, biggest_tsn_acked)) {
3247d06c82f1SRandall Stewart break;
324820b07a4dSMichael Tuexen }
3249f8829a4aSRandall Stewart if (tp1->sent == SCTP_DATAGRAM_ACKED) {
3250f8829a4aSRandall Stewart /* it has been revoked */
3251f8829a4aSRandall Stewart tp1->sent = SCTP_DATAGRAM_SENT;
3252f8829a4aSRandall Stewart tp1->rec.data.chunk_was_revoked = 1;
3253a5d547adSRandall Stewart /*
325442551e99SRandall Stewart * We must add this stuff back in to assure
325542551e99SRandall Stewart * timers and such get started.
3256a5d547adSRandall Stewart */
3257b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
3258c105859eSRandall Stewart sctp_misc_ints(SCTP_FLIGHT_LOG_UP_REVOKE,
3259c105859eSRandall Stewart tp1->whoTo->flight_size,
3260c105859eSRandall Stewart tp1->book_size,
32619a8e3088SMichael Tuexen (uint32_t)(uintptr_t)tp1->whoTo,
326249656eefSMichael Tuexen tp1->rec.data.tsn);
326380fefe0aSRandall Stewart }
3264c105859eSRandall Stewart sctp_flight_size_increase(tp1);
3265c105859eSRandall Stewart sctp_total_flight_increase(stcb, tp1);
326642551e99SRandall Stewart /*
326742551e99SRandall Stewart * We inflate the cwnd to compensate for our
326842551e99SRandall Stewart * artificial inflation of the flight_size.
326942551e99SRandall Stewart */
327042551e99SRandall Stewart tp1->whoTo->cwnd += tp1->book_size;
3271b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
3272f8829a4aSRandall Stewart sctp_log_sack(asoc->last_acked_seq,
3273f8829a4aSRandall Stewart cumack,
327449656eefSMichael Tuexen tp1->rec.data.tsn,
3275f8829a4aSRandall Stewart 0,
3276f8829a4aSRandall Stewart 0,
3277f8829a4aSRandall Stewart SCTP_LOG_TSN_REVOKED);
327880fefe0aSRandall Stewart }
3279f8829a4aSRandall Stewart } else if (tp1->sent == SCTP_DATAGRAM_MARKED) {
3280f8829a4aSRandall Stewart /* it has been re-acked in this SACK */
3281f8829a4aSRandall Stewart tp1->sent = SCTP_DATAGRAM_ACKED;
3282f8829a4aSRandall Stewart }
3283f8829a4aSRandall Stewart }
3284f8829a4aSRandall Stewart if (tp1->sent == SCTP_DATAGRAM_UNSENT)
3285f8829a4aSRandall Stewart break;
3286f8829a4aSRandall Stewart }
3287f8829a4aSRandall Stewart }
3288f8829a4aSRandall Stewart
3289f8829a4aSRandall Stewart static void
sctp_strike_gap_ack_chunks(struct sctp_tcb * stcb,struct sctp_association * asoc,uint32_t biggest_tsn_acked,uint32_t biggest_tsn_newly_acked,uint32_t this_sack_lowest_newack,int accum_moved)3290f8829a4aSRandall Stewart sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
329163eda93dSMichael Tuexen uint32_t biggest_tsn_acked, uint32_t biggest_tsn_newly_acked, uint32_t this_sack_lowest_newack, int accum_moved)
3292f8829a4aSRandall Stewart {
3293f8829a4aSRandall Stewart struct sctp_tmit_chunk *tp1;
3294f8829a4aSRandall Stewart int strike_flag = 0;
3295f8829a4aSRandall Stewart struct timeval now;
3296f8829a4aSRandall Stewart uint32_t sending_seq;
3297f8829a4aSRandall Stewart struct sctp_nets *net;
3298f8829a4aSRandall Stewart int num_dests_sacked = 0;
3299f8829a4aSRandall Stewart
3300f8829a4aSRandall Stewart /*
3301f8829a4aSRandall Stewart * select the sending_seq, this is either the next thing ready to be
3302f8829a4aSRandall Stewart * sent but not transmitted, OR, the next seq we assign.
3303f8829a4aSRandall Stewart */
3304f8829a4aSRandall Stewart tp1 = TAILQ_FIRST(&stcb->asoc.send_queue);
3305f8829a4aSRandall Stewart if (tp1 == NULL) {
3306f8829a4aSRandall Stewart sending_seq = asoc->sending_seq;
3307f8829a4aSRandall Stewart } else {
330849656eefSMichael Tuexen sending_seq = tp1->rec.data.tsn;
3309f8829a4aSRandall Stewart }
3310f8829a4aSRandall Stewart
3311f8829a4aSRandall Stewart /* CMT DAC algo: finding out if SACK is a mixed SACK */
33127c99d56fSMichael Tuexen if ((asoc->sctp_cmt_on_off > 0) &&
331320083c2eSMichael Tuexen SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) {
3314f8829a4aSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
3315f8829a4aSRandall Stewart if (net->saw_newack)
3316f8829a4aSRandall Stewart num_dests_sacked++;
3317f8829a4aSRandall Stewart }
3318f8829a4aSRandall Stewart }
3319dd973b0eSMichael Tuexen if (stcb->asoc.prsctp_supported) {
33206e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&now);
3321f8829a4aSRandall Stewart }
33224a9ef3f8SMichael Tuexen TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
3323f8829a4aSRandall Stewart strike_flag = 0;
3324f8829a4aSRandall Stewart if (tp1->no_fr_allowed) {
3325f8829a4aSRandall Stewart /* this one had a timeout or something */
3326f8829a4aSRandall Stewart continue;
3327f8829a4aSRandall Stewart }
3328b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
3329f8829a4aSRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND)
3330f8829a4aSRandall Stewart sctp_log_fr(biggest_tsn_newly_acked,
333149656eefSMichael Tuexen tp1->rec.data.tsn,
3332f8829a4aSRandall Stewart tp1->sent,
3333f8829a4aSRandall Stewart SCTP_FR_LOG_CHECK_STRIKE);
333480fefe0aSRandall Stewart }
333549656eefSMichael Tuexen if (SCTP_TSN_GT(tp1->rec.data.tsn, biggest_tsn_acked) ||
3336f8829a4aSRandall Stewart tp1->sent == SCTP_DATAGRAM_UNSENT) {
3337f8829a4aSRandall Stewart /* done */
3338f8829a4aSRandall Stewart break;
3339f8829a4aSRandall Stewart }
3340dd973b0eSMichael Tuexen if (stcb->asoc.prsctp_supported) {
3341f8829a4aSRandall Stewart if ((PR_SCTP_TTL_ENABLED(tp1->flags)) && tp1->sent < SCTP_DATAGRAM_ACKED) {
3342f8829a4aSRandall Stewart /* Is it expired? */
334399ddc825SMichael Tuexen if (timevalcmp(&now, &tp1->rec.data.timetodrop, >)) {
3344f8829a4aSRandall Stewart /* Yes so drop it */
3345f8829a4aSRandall Stewart if (tp1->data != NULL) {
33461edc9dbaSMichael Tuexen (void)sctp_release_pr_sctp_chunk(stcb, tp1, 1,
33470c0982b8SRandall Stewart SCTP_SO_NOT_LOCKED);
3348f8829a4aSRandall Stewart }
3349f8829a4aSRandall Stewart continue;
3350f8829a4aSRandall Stewart }
3351f8829a4aSRandall Stewart }
3352f8829a4aSRandall Stewart }
3353e9a3a1b1SMichael Tuexen if (SCTP_TSN_GT(tp1->rec.data.tsn, asoc->this_sack_highest_gap) &&
3354e9a3a1b1SMichael Tuexen !(accum_moved && asoc->fast_retran_loss_recovery)) {
3355f8829a4aSRandall Stewart /* we are beyond the tsn in the sack */
3356f8829a4aSRandall Stewart break;
3357f8829a4aSRandall Stewart }
3358f8829a4aSRandall Stewart if (tp1->sent >= SCTP_DATAGRAM_RESEND) {
3359f8829a4aSRandall Stewart /* either a RESEND, ACKED, or MARKED */
3360f8829a4aSRandall Stewart /* skip */
336144fbe462SRandall Stewart if (tp1->sent == SCTP_FORWARD_TSN_SKIP) {
336244fbe462SRandall Stewart /* Continue strikin FWD-TSN chunks */
336344fbe462SRandall Stewart tp1->rec.data.fwd_tsn_cnt++;
336444fbe462SRandall Stewart }
3365f8829a4aSRandall Stewart continue;
3366f8829a4aSRandall Stewart }
3367f8829a4aSRandall Stewart /*
3368f8829a4aSRandall Stewart * CMT : SFR algo (covers part of DAC and HTNA as well)
3369f8829a4aSRandall Stewart */
3370ad81507eSRandall Stewart if (tp1->whoTo && tp1->whoTo->saw_newack == 0) {
3371f8829a4aSRandall Stewart /*
3372e7e65008SMichael Tuexen * No new acks were received for data sent to this
3373f8829a4aSRandall Stewart * dest. Therefore, according to the SFR algo for
3374f8829a4aSRandall Stewart * CMT, no data sent to this dest can be marked for
3375c105859eSRandall Stewart * FR using this SACK.
3376f8829a4aSRandall Stewart */
3377f8829a4aSRandall Stewart continue;
3378e9a3a1b1SMichael Tuexen } else if (tp1->whoTo &&
3379e9a3a1b1SMichael Tuexen SCTP_TSN_GT(tp1->rec.data.tsn,
3380e9a3a1b1SMichael Tuexen tp1->whoTo->this_sack_highest_newack) &&
3381e9a3a1b1SMichael Tuexen !(accum_moved && asoc->fast_retran_loss_recovery)) {
3382f8829a4aSRandall Stewart /*
3383e7e65008SMichael Tuexen * CMT: New acks were received for data sent to this
3384e7e65008SMichael Tuexen * dest. But no new acks were seen for data sent
3385e7e65008SMichael Tuexen * after tp1. Therefore, according to the SFR algo
3386e7e65008SMichael Tuexen * for CMT, tp1 cannot be marked for FR using this
3387e7e65008SMichael Tuexen * SACK. This step covers part of the DAC algo and
3388e7e65008SMichael Tuexen * the HTNA algo as well.
3389f8829a4aSRandall Stewart */
3390f8829a4aSRandall Stewart continue;
3391f8829a4aSRandall Stewart }
3392f8829a4aSRandall Stewart /*
3393f8829a4aSRandall Stewart * Here we check to see if we were have already done a FR
3394f8829a4aSRandall Stewart * and if so we see if the biggest TSN we saw in the sack is
3395f8829a4aSRandall Stewart * smaller than the recovery point. If so we don't strike
3396f8829a4aSRandall Stewart * the tsn... otherwise we CAN strike the TSN.
3397f8829a4aSRandall Stewart */
3398f8829a4aSRandall Stewart /*
339942551e99SRandall Stewart * @@@ JRI: Check for CMT if (accum_moved &&
340042551e99SRandall Stewart * asoc->fast_retran_loss_recovery && (sctp_cmt_on_off ==
340142551e99SRandall Stewart * 0)) {
3402f8829a4aSRandall Stewart */
340342551e99SRandall Stewart if (accum_moved && asoc->fast_retran_loss_recovery) {
3404f8829a4aSRandall Stewart /*
3405f8829a4aSRandall Stewart * Strike the TSN if in fast-recovery and cum-ack
3406f8829a4aSRandall Stewart * moved.
3407f8829a4aSRandall Stewart */
3408b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
3409f8829a4aSRandall Stewart sctp_log_fr(biggest_tsn_newly_acked,
341049656eefSMichael Tuexen tp1->rec.data.tsn,
3411f8829a4aSRandall Stewart tp1->sent,
3412f8829a4aSRandall Stewart SCTP_FR_LOG_STRIKE_CHUNK);
341380fefe0aSRandall Stewart }
34145e54f665SRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND) {
3415f8829a4aSRandall Stewart tp1->sent++;
34165e54f665SRandall Stewart }
34177c99d56fSMichael Tuexen if ((asoc->sctp_cmt_on_off > 0) &&
341820083c2eSMichael Tuexen SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) {
3419f8829a4aSRandall Stewart /*
3420f8829a4aSRandall Stewart * CMT DAC algorithm: If SACK flag is set to
3421f8829a4aSRandall Stewart * 0, then lowest_newack test will not pass
3422f8829a4aSRandall Stewart * because it would have been set to the
3423f8829a4aSRandall Stewart * cumack earlier. If not already to be
3424f8829a4aSRandall Stewart * rtx'd, If not a mixed sack and if tp1 is
3425f8829a4aSRandall Stewart * not between two sacked TSNs, then mark by
3426c105859eSRandall Stewart * one more. NOTE that we are marking by one
3427c105859eSRandall Stewart * additional time since the SACK DAC flag
3428c105859eSRandall Stewart * indicates that two packets have been
3429c105859eSRandall Stewart * received after this missing TSN.
34305e54f665SRandall Stewart */
34315e54f665SRandall Stewart if ((tp1->sent < SCTP_DATAGRAM_RESEND) && (num_dests_sacked == 1) &&
343249656eefSMichael Tuexen SCTP_TSN_GT(this_sack_lowest_newack, tp1->rec.data.tsn)) {
3433b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
3434f8829a4aSRandall Stewart sctp_log_fr(16 + num_dests_sacked,
343549656eefSMichael Tuexen tp1->rec.data.tsn,
3436f8829a4aSRandall Stewart tp1->sent,
3437f8829a4aSRandall Stewart SCTP_FR_LOG_STRIKE_CHUNK);
343880fefe0aSRandall Stewart }
3439f8829a4aSRandall Stewart tp1->sent++;
3440f8829a4aSRandall Stewart }
3441f8829a4aSRandall Stewart }
344220083c2eSMichael Tuexen } else if ((tp1->rec.data.doing_fast_retransmit) &&
344320083c2eSMichael Tuexen (asoc->sctp_cmt_on_off == 0)) {
3444f8829a4aSRandall Stewart /*
3445f8829a4aSRandall Stewart * For those that have done a FR we must take
3446f8829a4aSRandall Stewart * special consideration if we strike. I.e the
3447f8829a4aSRandall Stewart * biggest_newly_acked must be higher than the
3448f8829a4aSRandall Stewart * sending_seq at the time we did the FR.
3449f8829a4aSRandall Stewart */
34505e54f665SRandall Stewart if (
3451f8829a4aSRandall Stewart #ifdef SCTP_FR_TO_ALTERNATE
3452f8829a4aSRandall Stewart /*
3453f8829a4aSRandall Stewart * If FR's go to new networks, then we must only do
3454f8829a4aSRandall Stewart * this for singly homed asoc's. However if the FR's
3455f8829a4aSRandall Stewart * go to the same network (Armando's work) then its
3456f8829a4aSRandall Stewart * ok to FR multiple times.
3457f8829a4aSRandall Stewart */
34585e54f665SRandall Stewart (asoc->numnets < 2)
3459f8829a4aSRandall Stewart #else
34605e54f665SRandall Stewart (1)
3461f8829a4aSRandall Stewart #endif
34625e54f665SRandall Stewart ) {
346320b07a4dSMichael Tuexen if (SCTP_TSN_GE(biggest_tsn_newly_acked,
3464f8829a4aSRandall Stewart tp1->rec.data.fast_retran_tsn)) {
3465f8829a4aSRandall Stewart /*
3466f8829a4aSRandall Stewart * Strike the TSN, since this ack is
3467f8829a4aSRandall Stewart * beyond where things were when we
3468f8829a4aSRandall Stewart * did a FR.
3469f8829a4aSRandall Stewart */
3470b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
3471f8829a4aSRandall Stewart sctp_log_fr(biggest_tsn_newly_acked,
347249656eefSMichael Tuexen tp1->rec.data.tsn,
3473f8829a4aSRandall Stewart tp1->sent,
3474f8829a4aSRandall Stewart SCTP_FR_LOG_STRIKE_CHUNK);
347580fefe0aSRandall Stewart }
34765e54f665SRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND) {
3477f8829a4aSRandall Stewart tp1->sent++;
34785e54f665SRandall Stewart }
3479f8829a4aSRandall Stewart strike_flag = 1;
34807c99d56fSMichael Tuexen if ((asoc->sctp_cmt_on_off > 0) &&
348120083c2eSMichael Tuexen SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) {
3482f8829a4aSRandall Stewart /*
3483f8829a4aSRandall Stewart * CMT DAC algorithm: If
3484f8829a4aSRandall Stewart * SACK flag is set to 0,
3485f8829a4aSRandall Stewart * then lowest_newack test
3486f8829a4aSRandall Stewart * will not pass because it
3487f8829a4aSRandall Stewart * would have been set to
3488f8829a4aSRandall Stewart * the cumack earlier. If
3489f8829a4aSRandall Stewart * not already to be rtx'd,
3490f8829a4aSRandall Stewart * If not a mixed sack and
3491f8829a4aSRandall Stewart * if tp1 is not between two
3492f8829a4aSRandall Stewart * sacked TSNs, then mark by
3493c105859eSRandall Stewart * one more. NOTE that we
3494c105859eSRandall Stewart * are marking by one
3495c105859eSRandall Stewart * additional time since the
3496c105859eSRandall Stewart * SACK DAC flag indicates
3497c105859eSRandall Stewart * that two packets have
3498c105859eSRandall Stewart * been received after this
3499c105859eSRandall Stewart * missing TSN.
3500f8829a4aSRandall Stewart */
35015e54f665SRandall Stewart if ((tp1->sent < SCTP_DATAGRAM_RESEND) &&
35025e54f665SRandall Stewart (num_dests_sacked == 1) &&
350320b07a4dSMichael Tuexen SCTP_TSN_GT(this_sack_lowest_newack,
350449656eefSMichael Tuexen tp1->rec.data.tsn)) {
3505b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
3506f8829a4aSRandall Stewart sctp_log_fr(32 + num_dests_sacked,
350749656eefSMichael Tuexen tp1->rec.data.tsn,
3508f8829a4aSRandall Stewart tp1->sent,
3509f8829a4aSRandall Stewart SCTP_FR_LOG_STRIKE_CHUNK);
351080fefe0aSRandall Stewart }
35115e54f665SRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND) {
3512f8829a4aSRandall Stewart tp1->sent++;
35135e54f665SRandall Stewart }
3514f8829a4aSRandall Stewart }
3515f8829a4aSRandall Stewart }
3516f8829a4aSRandall Stewart }
3517f8829a4aSRandall Stewart }
3518f8829a4aSRandall Stewart /*
351942551e99SRandall Stewart * JRI: TODO: remove code for HTNA algo. CMT's SFR
352042551e99SRandall Stewart * algo covers HTNA.
3521f8829a4aSRandall Stewart */
352249656eefSMichael Tuexen } else if (SCTP_TSN_GT(tp1->rec.data.tsn,
352320b07a4dSMichael Tuexen biggest_tsn_newly_acked)) {
3524f8829a4aSRandall Stewart /*
3525f8829a4aSRandall Stewart * We don't strike these: This is the HTNA
3526f8829a4aSRandall Stewart * algorithm i.e. we don't strike If our TSN is
3527f8829a4aSRandall Stewart * larger than the Highest TSN Newly Acked.
3528f8829a4aSRandall Stewart */
3529f8829a4aSRandall Stewart ;
3530f8829a4aSRandall Stewart } else {
3531f8829a4aSRandall Stewart /* Strike the TSN */
3532b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
3533f8829a4aSRandall Stewart sctp_log_fr(biggest_tsn_newly_acked,
353449656eefSMichael Tuexen tp1->rec.data.tsn,
3535f8829a4aSRandall Stewart tp1->sent,
3536f8829a4aSRandall Stewart SCTP_FR_LOG_STRIKE_CHUNK);
353780fefe0aSRandall Stewart }
35385e54f665SRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND) {
3539f8829a4aSRandall Stewart tp1->sent++;
35405e54f665SRandall Stewart }
35417c99d56fSMichael Tuexen if ((asoc->sctp_cmt_on_off > 0) &&
354220083c2eSMichael Tuexen SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) {
3543f8829a4aSRandall Stewart /*
3544f8829a4aSRandall Stewart * CMT DAC algorithm: If SACK flag is set to
3545f8829a4aSRandall Stewart * 0, then lowest_newack test will not pass
3546f8829a4aSRandall Stewart * because it would have been set to the
3547f8829a4aSRandall Stewart * cumack earlier. If not already to be
3548f8829a4aSRandall Stewart * rtx'd, If not a mixed sack and if tp1 is
3549f8829a4aSRandall Stewart * not between two sacked TSNs, then mark by
3550c105859eSRandall Stewart * one more. NOTE that we are marking by one
3551c105859eSRandall Stewart * additional time since the SACK DAC flag
3552c105859eSRandall Stewart * indicates that two packets have been
3553c105859eSRandall Stewart * received after this missing TSN.
3554f8829a4aSRandall Stewart */
35555e54f665SRandall Stewart if ((tp1->sent < SCTP_DATAGRAM_RESEND) && (num_dests_sacked == 1) &&
355649656eefSMichael Tuexen SCTP_TSN_GT(this_sack_lowest_newack, tp1->rec.data.tsn)) {
3557b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
3558f8829a4aSRandall Stewart sctp_log_fr(48 + num_dests_sacked,
355949656eefSMichael Tuexen tp1->rec.data.tsn,
3560f8829a4aSRandall Stewart tp1->sent,
3561f8829a4aSRandall Stewart SCTP_FR_LOG_STRIKE_CHUNK);
356280fefe0aSRandall Stewart }
3563f8829a4aSRandall Stewart tp1->sent++;
3564f8829a4aSRandall Stewart }
3565f8829a4aSRandall Stewart }
3566f8829a4aSRandall Stewart }
3567f8829a4aSRandall Stewart if (tp1->sent == SCTP_DATAGRAM_RESEND) {
3568f8829a4aSRandall Stewart struct sctp_nets *alt;
3569f8829a4aSRandall Stewart
3570544e35bdSRandall Stewart /* fix counts and things */
3571544e35bdSRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
3572544e35bdSRandall Stewart sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_RSND,
3573544e35bdSRandall Stewart (tp1->whoTo ? (tp1->whoTo->flight_size) : 0),
3574544e35bdSRandall Stewart tp1->book_size,
35759a8e3088SMichael Tuexen (uint32_t)(uintptr_t)tp1->whoTo,
357649656eefSMichael Tuexen tp1->rec.data.tsn);
3577544e35bdSRandall Stewart }
3578544e35bdSRandall Stewart if (tp1->whoTo) {
3579544e35bdSRandall Stewart tp1->whoTo->net_ack++;
3580544e35bdSRandall Stewart sctp_flight_size_decrease(tp1);
3581299108c5SRandall Stewart if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) {
3582299108c5SRandall Stewart (*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) (tp1->whoTo,
3583299108c5SRandall Stewart tp1);
3584299108c5SRandall Stewart }
3585544e35bdSRandall Stewart }
35860053ed28SMichael Tuexen
3587544e35bdSRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) {
3588544e35bdSRandall Stewart sctp_log_rwnd(SCTP_INCREASE_PEER_RWND,
3589544e35bdSRandall Stewart asoc->peers_rwnd, tp1->send_size, SCTP_BASE_SYSCTL(sctp_peer_chunk_oh));
3590544e35bdSRandall Stewart }
3591544e35bdSRandall Stewart /* add back to the rwnd */
3592544e35bdSRandall Stewart asoc->peers_rwnd += (tp1->send_size + SCTP_BASE_SYSCTL(sctp_peer_chunk_oh));
3593544e35bdSRandall Stewart
3594544e35bdSRandall Stewart /* remove from the total flight */
3595544e35bdSRandall Stewart sctp_total_flight_decrease(stcb, tp1);
3596544e35bdSRandall Stewart
3597dd973b0eSMichael Tuexen if ((stcb->asoc.prsctp_supported) &&
3598475d0674SMichael Tuexen (PR_SCTP_RTX_ENABLED(tp1->flags))) {
3599b7b84c0eSMichael Tuexen /*
3600b7b84c0eSMichael Tuexen * Has it been retransmitted tv_sec times? -
3601b7b84c0eSMichael Tuexen * we store the retran count there.
3602b7b84c0eSMichael Tuexen */
3603475d0674SMichael Tuexen if (tp1->snd_count > tp1->rec.data.timetodrop.tv_sec) {
3604475d0674SMichael Tuexen /* Yes, so drop it */
3605475d0674SMichael Tuexen if (tp1->data != NULL) {
36061edc9dbaSMichael Tuexen (void)sctp_release_pr_sctp_chunk(stcb, tp1, 1,
3607475d0674SMichael Tuexen SCTP_SO_NOT_LOCKED);
3608475d0674SMichael Tuexen }
3609475d0674SMichael Tuexen /* Make sure to flag we had a FR */
361067e8b08bSMichael Tuexen if (tp1->whoTo != NULL) {
3611475d0674SMichael Tuexen tp1->whoTo->net_ack++;
361267e8b08bSMichael Tuexen }
3613475d0674SMichael Tuexen continue;
3614475d0674SMichael Tuexen }
3615475d0674SMichael Tuexen }
3616b7b84c0eSMichael Tuexen /*
3617b7b84c0eSMichael Tuexen * SCTP_PRINTF("OK, we are now ready to FR this
3618b7b84c0eSMichael Tuexen * guy\n");
3619b7b84c0eSMichael Tuexen */
3620b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
362149656eefSMichael Tuexen sctp_log_fr(tp1->rec.data.tsn, tp1->snd_count,
3622f8829a4aSRandall Stewart 0, SCTP_FR_MARKED);
362380fefe0aSRandall Stewart }
3624f8829a4aSRandall Stewart if (strike_flag) {
3625f8829a4aSRandall Stewart /* This is a subsequent FR */
3626f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_sendmultfastretrans);
3627f8829a4aSRandall Stewart }
36285e54f665SRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
36297c99d56fSMichael Tuexen if (asoc->sctp_cmt_on_off > 0) {
3630f8829a4aSRandall Stewart /*
3631f8829a4aSRandall Stewart * CMT: Using RTX_SSTHRESH policy for CMT.
3632f8829a4aSRandall Stewart * If CMT is being used, then pick dest with
3633f8829a4aSRandall Stewart * largest ssthresh for any retransmission.
3634f8829a4aSRandall Stewart */
3635f8829a4aSRandall Stewart tp1->no_fr_allowed = 1;
3636f8829a4aSRandall Stewart alt = tp1->whoTo;
36373c503c28SRandall Stewart /* sa_ignore NO_NULL_CHK */
363820083c2eSMichael Tuexen if (asoc->sctp_cmt_pf > 0) {
3639b7b84c0eSMichael Tuexen /*
3640b7b84c0eSMichael Tuexen * JRS 5/18/07 - If CMT PF is on,
3641b54d3a6cSRandall Stewart * use the PF version of
3642b7b84c0eSMichael Tuexen * find_alt_net()
3643b7b84c0eSMichael Tuexen */
3644b54d3a6cSRandall Stewart alt = sctp_find_alternate_net(stcb, alt, 2);
3645b54d3a6cSRandall Stewart } else {
3646b7b84c0eSMichael Tuexen /*
3647b7b84c0eSMichael Tuexen * JRS 5/18/07 - If only CMT is on,
3648b54d3a6cSRandall Stewart * use the CMT version of
3649b7b84c0eSMichael Tuexen * find_alt_net()
3650b7b84c0eSMichael Tuexen */
365152be287eSRandall Stewart /* sa_ignore NO_NULL_CHK */
3652f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, alt, 1);
3653b54d3a6cSRandall Stewart }
3654ad81507eSRandall Stewart if (alt == NULL) {
3655ad81507eSRandall Stewart alt = tp1->whoTo;
3656ad81507eSRandall Stewart }
3657f8829a4aSRandall Stewart /*
3658f8829a4aSRandall Stewart * CUCv2: If a different dest is picked for
3659f8829a4aSRandall Stewart * the retransmission, then new
3660f8829a4aSRandall Stewart * (rtx-)pseudo_cumack needs to be tracked
3661f8829a4aSRandall Stewart * for orig dest. Let CUCv2 track new (rtx-)
3662f8829a4aSRandall Stewart * pseudo-cumack always.
3663f8829a4aSRandall Stewart */
3664ad81507eSRandall Stewart if (tp1->whoTo) {
3665f8829a4aSRandall Stewart tp1->whoTo->find_pseudo_cumack = 1;
3666f8829a4aSRandall Stewart tp1->whoTo->find_rtx_pseudo_cumack = 1;
3667ad81507eSRandall Stewart }
3668f8829a4aSRandall Stewart } else { /* CMT is OFF */
3669f8829a4aSRandall Stewart #ifdef SCTP_FR_TO_ALTERNATE
3670f8829a4aSRandall Stewart /* Can we find an alternate? */
3671f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, tp1->whoTo, 0);
3672f8829a4aSRandall Stewart #else
3673f8829a4aSRandall Stewart /*
3674f8829a4aSRandall Stewart * default behavior is to NOT retransmit
3675f8829a4aSRandall Stewart * FR's to an alternate. Armando Caro's
3676f8829a4aSRandall Stewart * paper details why.
3677f8829a4aSRandall Stewart */
3678f8829a4aSRandall Stewart alt = tp1->whoTo;
3679f8829a4aSRandall Stewart #endif
3680f8829a4aSRandall Stewart }
3681f8829a4aSRandall Stewart
3682f8829a4aSRandall Stewart tp1->rec.data.doing_fast_retransmit = 1;
3683f8829a4aSRandall Stewart /* mark the sending seq for possible subsequent FR's */
3684f8829a4aSRandall Stewart /*
3685cd3fd531SMichael Tuexen * SCTP_PRINTF("Marking TSN for FR new value %x\n",
368649656eefSMichael Tuexen * (uint32_t)tpi->rec.data.tsn);
3687f8829a4aSRandall Stewart */
3688f8829a4aSRandall Stewart if (TAILQ_EMPTY(&asoc->send_queue)) {
3689f8829a4aSRandall Stewart /*
3690f8829a4aSRandall Stewart * If the queue of send is empty then its
3691f8829a4aSRandall Stewart * the next sequence number that will be
3692f8829a4aSRandall Stewart * assigned so we subtract one from this to
3693f8829a4aSRandall Stewart * get the one we last sent.
3694f8829a4aSRandall Stewart */
3695f8829a4aSRandall Stewart tp1->rec.data.fast_retran_tsn = sending_seq;
3696f8829a4aSRandall Stewart } else {
3697f8829a4aSRandall Stewart /*
3698f8829a4aSRandall Stewart * If there are chunks on the send queue
3699f8829a4aSRandall Stewart * (unsent data that has made it from the
3700f8829a4aSRandall Stewart * stream queues but not out the door, we
3701f8829a4aSRandall Stewart * take the first one (which will have the
3702f8829a4aSRandall Stewart * lowest TSN) and subtract one to get the
3703f8829a4aSRandall Stewart * one we last sent.
3704f8829a4aSRandall Stewart */
3705f8829a4aSRandall Stewart struct sctp_tmit_chunk *ttt;
3706f8829a4aSRandall Stewart
3707f8829a4aSRandall Stewart ttt = TAILQ_FIRST(&asoc->send_queue);
3708f8829a4aSRandall Stewart tp1->rec.data.fast_retran_tsn =
370949656eefSMichael Tuexen ttt->rec.data.tsn;
3710f8829a4aSRandall Stewart }
3711f8829a4aSRandall Stewart
3712f8829a4aSRandall Stewart if (tp1->do_rtt) {
3713f8829a4aSRandall Stewart /*
3714f8829a4aSRandall Stewart * this guy had a RTO calculation pending on
3715f8829a4aSRandall Stewart * it, cancel it
3716f8829a4aSRandall Stewart */
371760990c0cSMichael Tuexen if ((tp1->whoTo != NULL) &&
371860990c0cSMichael Tuexen (tp1->whoTo->rto_needed == 0)) {
3719f79aab18SRandall Stewart tp1->whoTo->rto_needed = 1;
3720f79aab18SRandall Stewart }
3721f8829a4aSRandall Stewart tp1->do_rtt = 0;
3722f8829a4aSRandall Stewart }
3723f8829a4aSRandall Stewart if (alt != tp1->whoTo) {
3724f8829a4aSRandall Stewart /* yes, there is an alternate. */
3725f8829a4aSRandall Stewart sctp_free_remote_addr(tp1->whoTo);
37263c503c28SRandall Stewart /* sa_ignore FREED_MEMORY */
3727f8829a4aSRandall Stewart tp1->whoTo = alt;
3728f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1);
3729f8829a4aSRandall Stewart }
3730f8829a4aSRandall Stewart }
37314a9ef3f8SMichael Tuexen }
3732f8829a4aSRandall Stewart }
3733f8829a4aSRandall Stewart
3734f8829a4aSRandall Stewart struct sctp_tmit_chunk *
sctp_try_advance_peer_ack_point(struct sctp_tcb * stcb,struct sctp_association * asoc)3735f8829a4aSRandall Stewart sctp_try_advance_peer_ack_point(struct sctp_tcb *stcb,
3736f8829a4aSRandall Stewart struct sctp_association *asoc)
3737f8829a4aSRandall Stewart {
3738f8829a4aSRandall Stewart struct sctp_tmit_chunk *tp1, *tp2, *a_adv = NULL;
3739f8829a4aSRandall Stewart struct timeval now;
3740f8829a4aSRandall Stewart int now_filled = 0;
3741f8829a4aSRandall Stewart
3742dd973b0eSMichael Tuexen if (asoc->prsctp_supported == 0) {
3743f8829a4aSRandall Stewart return (NULL);
3744f8829a4aSRandall Stewart }
37454a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(tp1, &asoc->sent_queue, sctp_next, tp2) {
3746f8829a4aSRandall Stewart if (tp1->sent != SCTP_FORWARD_TSN_SKIP &&
374798f2956cSMichael Tuexen tp1->sent != SCTP_DATAGRAM_RESEND &&
3748325c8c46SMichael Tuexen tp1->sent != SCTP_DATAGRAM_NR_ACKED) {
3749f8829a4aSRandall Stewart /* no chance to advance, out of here */
3750f8829a4aSRandall Stewart break;
3751f8829a4aSRandall Stewart }
37520c0982b8SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
37532a498584SMichael Tuexen if ((tp1->sent == SCTP_FORWARD_TSN_SKIP) ||
3754325c8c46SMichael Tuexen (tp1->sent == SCTP_DATAGRAM_NR_ACKED)) {
37550c0982b8SRandall Stewart sctp_misc_ints(SCTP_FWD_TSN_CHECK,
37560c0982b8SRandall Stewart asoc->advanced_peer_ack_point,
375749656eefSMichael Tuexen tp1->rec.data.tsn, 0, 0);
37580c0982b8SRandall Stewart }
37590c0982b8SRandall Stewart }
3760f8829a4aSRandall Stewart if (!PR_SCTP_ENABLED(tp1->flags)) {
3761f8829a4aSRandall Stewart /*
3762f8829a4aSRandall Stewart * We can't fwd-tsn past any that are reliable aka
3763f8829a4aSRandall Stewart * retransmitted until the asoc fails.
3764f8829a4aSRandall Stewart */
3765f8829a4aSRandall Stewart break;
3766f8829a4aSRandall Stewart }
3767f8829a4aSRandall Stewart if (!now_filled) {
37686e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&now);
3769f8829a4aSRandall Stewart now_filled = 1;
3770f8829a4aSRandall Stewart }
3771f8829a4aSRandall Stewart /*
3772f8829a4aSRandall Stewart * now we got a chunk which is marked for another
3773f8829a4aSRandall Stewart * retransmission to a PR-stream but has run out its chances
3774f8829a4aSRandall Stewart * already maybe OR has been marked to skip now. Can we skip
3775f8829a4aSRandall Stewart * it if its a resend?
3776f8829a4aSRandall Stewart */
3777f8829a4aSRandall Stewart if (tp1->sent == SCTP_DATAGRAM_RESEND &&
3778f8829a4aSRandall Stewart (PR_SCTP_TTL_ENABLED(tp1->flags))) {
3779f8829a4aSRandall Stewart /*
3780f8829a4aSRandall Stewart * Now is this one marked for resend and its time is
3781f8829a4aSRandall Stewart * now up?
3782f8829a4aSRandall Stewart */
3783f8829a4aSRandall Stewart if (timevalcmp(&now, &tp1->rec.data.timetodrop, >)) {
3784f8829a4aSRandall Stewart /* Yes so drop it */
3785f8829a4aSRandall Stewart if (tp1->data) {
3786ad81507eSRandall Stewart (void)sctp_release_pr_sctp_chunk(stcb, tp1,
37871edc9dbaSMichael Tuexen 1, SCTP_SO_NOT_LOCKED);
3788f8829a4aSRandall Stewart }
3789f8829a4aSRandall Stewart } else {
3790f8829a4aSRandall Stewart /*
3791f8829a4aSRandall Stewart * No, we are done when hit one for resend
3792f8829a4aSRandall Stewart * whos time as not expired.
3793f8829a4aSRandall Stewart */
3794f8829a4aSRandall Stewart break;
3795f8829a4aSRandall Stewart }
3796f8829a4aSRandall Stewart }
3797f8829a4aSRandall Stewart /*
3798f8829a4aSRandall Stewart * Ok now if this chunk is marked to drop it we can clean up
3799f8829a4aSRandall Stewart * the chunk, advance our peer ack point and we can check
3800f8829a4aSRandall Stewart * the next chunk.
3801f8829a4aSRandall Stewart */
380298f2956cSMichael Tuexen if ((tp1->sent == SCTP_FORWARD_TSN_SKIP) ||
3803325c8c46SMichael Tuexen (tp1->sent == SCTP_DATAGRAM_NR_ACKED)) {
3804f8829a4aSRandall Stewart /* advance PeerAckPoint goes forward */
380549656eefSMichael Tuexen if (SCTP_TSN_GT(tp1->rec.data.tsn, asoc->advanced_peer_ack_point)) {
380649656eefSMichael Tuexen asoc->advanced_peer_ack_point = tp1->rec.data.tsn;
3807f8829a4aSRandall Stewart a_adv = tp1;
380849656eefSMichael Tuexen } else if (tp1->rec.data.tsn == asoc->advanced_peer_ack_point) {
38090c0982b8SRandall Stewart /* No update but we do save the chk */
38100c0982b8SRandall Stewart a_adv = tp1;
38110c0982b8SRandall Stewart }
3812f8829a4aSRandall Stewart } else {
3813f8829a4aSRandall Stewart /*
3814f8829a4aSRandall Stewart * If it is still in RESEND we can advance no
3815f8829a4aSRandall Stewart * further
3816f8829a4aSRandall Stewart */
3817f8829a4aSRandall Stewart break;
3818f8829a4aSRandall Stewart }
3819f8829a4aSRandall Stewart }
3820f8829a4aSRandall Stewart return (a_adv);
3821f8829a4aSRandall Stewart }
3822f8829a4aSRandall Stewart
38230c0982b8SRandall Stewart static int
sctp_fs_audit(struct sctp_association * asoc)3824c105859eSRandall Stewart sctp_fs_audit(struct sctp_association *asoc)
3825bff64a4dSRandall Stewart {
3826bff64a4dSRandall Stewart struct sctp_tmit_chunk *chk;
3827979bc32cSMichael Tuexen int inflight = 0, resend = 0, inbetween = 0, acked = 0, above = 0;
3828548f47a8SMichael Tuexen int ret;
3829548f47a8SMichael Tuexen #ifndef INVARIANTS
3830548f47a8SMichael Tuexen int entry_flight, entry_cnt;
3831548f47a8SMichael Tuexen #endif
3832548f47a8SMichael Tuexen
3833548f47a8SMichael Tuexen ret = 0;
3834548f47a8SMichael Tuexen #ifndef INVARIANTS
38350c0982b8SRandall Stewart entry_flight = asoc->total_flight;
38360c0982b8SRandall Stewart entry_cnt = asoc->total_flight_count;
3837548f47a8SMichael Tuexen #endif
38380c0982b8SRandall Stewart if (asoc->pr_sctp_cnt >= asoc->sent_queue_cnt)
38390c0982b8SRandall Stewart return (0);
3840bff64a4dSRandall Stewart
3841bff64a4dSRandall Stewart TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) {
3842bff64a4dSRandall Stewart if (chk->sent < SCTP_DATAGRAM_RESEND) {
3843cd3fd531SMichael Tuexen SCTP_PRINTF("Chk TSN: %u size: %d inflight cnt: %d\n",
384449656eefSMichael Tuexen chk->rec.data.tsn,
38450c0982b8SRandall Stewart chk->send_size,
3846cd3fd531SMichael Tuexen chk->snd_count);
3847bff64a4dSRandall Stewart inflight++;
3848bff64a4dSRandall Stewart } else if (chk->sent == SCTP_DATAGRAM_RESEND) {
3849bff64a4dSRandall Stewart resend++;
3850bff64a4dSRandall Stewart } else if (chk->sent < SCTP_DATAGRAM_ACKED) {
3851bff64a4dSRandall Stewart inbetween++;
3852bff64a4dSRandall Stewart } else if (chk->sent > SCTP_DATAGRAM_ACKED) {
3853bff64a4dSRandall Stewart above++;
3854bff64a4dSRandall Stewart } else {
3855bff64a4dSRandall Stewart acked++;
3856bff64a4dSRandall Stewart }
3857bff64a4dSRandall Stewart }
3858f1f73e57SRandall Stewart
3859c105859eSRandall Stewart if ((inflight > 0) || (inbetween > 0)) {
3860f1f73e57SRandall Stewart #ifdef INVARIANTS
3861979bc32cSMichael Tuexen panic("Flight size-express incorrect F: %d I: %d R: %d Ab: %d ACK: %d",
3862979bc32cSMichael Tuexen inflight, inbetween, resend, above, acked);
3863f1f73e57SRandall Stewart #else
3864cd3fd531SMichael Tuexen SCTP_PRINTF("asoc->total_flight: %d cnt: %d\n",
38650c0982b8SRandall Stewart entry_flight, entry_cnt);
38660c0982b8SRandall Stewart SCTP_PRINTF("Flight size-express incorrect F: %d I: %d R: %d Ab: %d ACK: %d\n",
38670c0982b8SRandall Stewart inflight, inbetween, resend, above, acked);
38680c0982b8SRandall Stewart ret = 1;
3869f1f73e57SRandall Stewart #endif
3870bff64a4dSRandall Stewart }
38710c0982b8SRandall Stewart return (ret);
3872c105859eSRandall Stewart }
3873c105859eSRandall Stewart
3874c105859eSRandall Stewart static void
sctp_window_probe_recovery(struct sctp_tcb * stcb,struct sctp_association * asoc,struct sctp_tmit_chunk * tp1)3875c105859eSRandall Stewart sctp_window_probe_recovery(struct sctp_tcb *stcb,
3876c105859eSRandall Stewart struct sctp_association *asoc,
3877c105859eSRandall Stewart struct sctp_tmit_chunk *tp1)
3878c105859eSRandall Stewart {
3879dfb11ef8SRandall Stewart tp1->window_probe = 0;
38805171328bSRandall Stewart if ((tp1->sent >= SCTP_DATAGRAM_ACKED) || (tp1->data == NULL)) {
3881dfb11ef8SRandall Stewart /* TSN's skipped we do NOT move back. */
3882dfb11ef8SRandall Stewart sctp_misc_ints(SCTP_FLIGHT_LOG_DWN_WP_FWD,
38838427b3fdSMichael Tuexen tp1->whoTo ? tp1->whoTo->flight_size : 0,
3884dfb11ef8SRandall Stewart tp1->book_size,
38859a8e3088SMichael Tuexen (uint32_t)(uintptr_t)tp1->whoTo,
388649656eefSMichael Tuexen tp1->rec.data.tsn);
3887dfb11ef8SRandall Stewart return;
3888dfb11ef8SRandall Stewart }
38895171328bSRandall Stewart /* First setup this by shrinking flight */
3890299108c5SRandall Stewart if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) {
3891299108c5SRandall Stewart (*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) (tp1->whoTo,
3892299108c5SRandall Stewart tp1);
3893299108c5SRandall Stewart }
38945171328bSRandall Stewart sctp_flight_size_decrease(tp1);
38955171328bSRandall Stewart sctp_total_flight_decrease(stcb, tp1);
38965171328bSRandall Stewart /* Now mark for resend */
38975171328bSRandall Stewart tp1->sent = SCTP_DATAGRAM_RESEND;
3898791437b5SRandall Stewart sctp_ucount_incr(asoc->sent_queue_retran_cnt);
3899791437b5SRandall Stewart
3900b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
3901c105859eSRandall Stewart sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_WP,
3902c105859eSRandall Stewart tp1->whoTo->flight_size,
3903c105859eSRandall Stewart tp1->book_size,
39049a8e3088SMichael Tuexen (uint32_t)(uintptr_t)tp1->whoTo,
390549656eefSMichael Tuexen tp1->rec.data.tsn);
390680fefe0aSRandall Stewart }
3907c105859eSRandall Stewart }
3908c105859eSRandall Stewart
3909f8829a4aSRandall Stewart void
sctp_express_handle_sack(struct sctp_tcb * stcb,uint32_t cumack,uint32_t rwnd,int * abort_now,int ecne_seen)3910f8829a4aSRandall Stewart sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
3911899288aeSRandall Stewart uint32_t rwnd, int *abort_now, int ecne_seen)
3912f8829a4aSRandall Stewart {
3913f8829a4aSRandall Stewart struct sctp_nets *net;
3914f8829a4aSRandall Stewart struct sctp_association *asoc;
3915f8829a4aSRandall Stewart struct sctp_tmit_chunk *tp1, *tp2;
39165e54f665SRandall Stewart uint32_t old_rwnd;
39175e54f665SRandall Stewart int win_probe_recovery = 0;
3918c105859eSRandall Stewart int win_probe_recovered = 0;
3919d06c82f1SRandall Stewart int j, done_once = 0;
3920f79aab18SRandall Stewart int rto_ok = 1;
3921fd60718dSMichael Tuexen uint32_t send_s;
3922f8829a4aSRandall Stewart
3923b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_SACK_ARRIVALS_ENABLE) {
3924d06c82f1SRandall Stewart sctp_misc_ints(SCTP_SACK_LOG_EXPRESS, cumack,
3925d06c82f1SRandall Stewart rwnd, stcb->asoc.last_acked_seq, stcb->asoc.peers_rwnd);
392680fefe0aSRandall Stewart }
3927f8829a4aSRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb);
392818e198d3SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS
392918e198d3SRandall Stewart stcb->asoc.cumack_log[stcb->asoc.cumack_log_at] = cumack;
393018e198d3SRandall Stewart stcb->asoc.cumack_log_at++;
393118e198d3SRandall Stewart if (stcb->asoc.cumack_log_at > SCTP_TSN_LOG_SIZE) {
393218e198d3SRandall Stewart stcb->asoc.cumack_log_at = 0;
393318e198d3SRandall Stewart }
393418e198d3SRandall Stewart #endif
3935f8829a4aSRandall Stewart asoc = &stcb->asoc;
3936d06c82f1SRandall Stewart old_rwnd = asoc->peers_rwnd;
393720b07a4dSMichael Tuexen if (SCTP_TSN_GT(asoc->last_acked_seq, cumack)) {
39385e54f665SRandall Stewart /* old ack */
39395e54f665SRandall Stewart return;
3940d06c82f1SRandall Stewart } else if (asoc->last_acked_seq == cumack) {
3941d06c82f1SRandall Stewart /* Window update sack */
3942d06c82f1SRandall Stewart asoc->peers_rwnd = sctp_sbspace_sub(rwnd,
394344fbe462SRandall Stewart (uint32_t)(asoc->total_flight + (asoc->total_flight_count * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh))));
3944d06c82f1SRandall Stewart if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) {
3945d06c82f1SRandall Stewart /* SWS sender side engages */
3946d06c82f1SRandall Stewart asoc->peers_rwnd = 0;
3947d06c82f1SRandall Stewart }
3948d06c82f1SRandall Stewart if (asoc->peers_rwnd > old_rwnd) {
3949d06c82f1SRandall Stewart goto again;
3950d06c82f1SRandall Stewart }
3951d06c82f1SRandall Stewart return;
39525e54f665SRandall Stewart }
39530053ed28SMichael Tuexen
3954f8829a4aSRandall Stewart /* First setup for CC stuff */
3955f8829a4aSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
3956a21779f0SRandall Stewart if (SCTP_TSN_GT(cumack, net->cwr_window_tsn)) {
3957a21779f0SRandall Stewart /* Drag along the window_tsn for cwr's */
3958a21779f0SRandall Stewart net->cwr_window_tsn = cumack;
3959a21779f0SRandall Stewart }
3960f8829a4aSRandall Stewart net->prev_cwnd = net->cwnd;
3961f8829a4aSRandall Stewart net->net_ack = 0;
3962f8829a4aSRandall Stewart net->net_ack2 = 0;
3963132dea7dSRandall Stewart
3964132dea7dSRandall Stewart /*
3965132dea7dSRandall Stewart * CMT: Reset CUC and Fast recovery algo variables before
3966132dea7dSRandall Stewart * SACK processing
3967132dea7dSRandall Stewart */
3968132dea7dSRandall Stewart net->new_pseudo_cumack = 0;
3969132dea7dSRandall Stewart net->will_exit_fast_recovery = 0;
3970299108c5SRandall Stewart if (stcb->asoc.cc_functions.sctp_cwnd_prepare_net_for_sack) {
3971299108c5SRandall Stewart (*stcb->asoc.cc_functions.sctp_cwnd_prepare_net_for_sack) (stcb, net);
3972299108c5SRandall Stewart }
3973f8829a4aSRandall Stewart }
3974c105859eSRandall Stewart if (!TAILQ_EMPTY(&asoc->sent_queue)) {
3975c105859eSRandall Stewart tp1 = TAILQ_LAST(&asoc->sent_queue,
3976c105859eSRandall Stewart sctpchunk_listhead);
397749656eefSMichael Tuexen send_s = tp1->rec.data.tsn + 1;
3978139bc87fSRandall Stewart } else {
3979c105859eSRandall Stewart send_s = asoc->sending_seq;
3980139bc87fSRandall Stewart }
398120b07a4dSMichael Tuexen if (SCTP_TSN_GE(cumack, send_s)) {
3982ff1ffd74SMichael Tuexen struct mbuf *op_err;
3983ff1ffd74SMichael Tuexen char msg[SCTP_DIAG_INFO_LEN];
3984139bc87fSRandall Stewart
3985139bc87fSRandall Stewart *abort_now = 1;
3986139bc87fSRandall Stewart /* XXX */
3987999f86d6SMichael Tuexen SCTP_SNPRINTF(msg, sizeof(msg),
3988999f86d6SMichael Tuexen "Cum ack %8.8x greater or equal than TSN %8.8x",
3989821bae7cSMichael Tuexen cumack, send_s);
3990ff1ffd74SMichael Tuexen op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
399191e04f9eSMichael Tuexen stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_25;
3992105b68b4SMichael Tuexen sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED);
3993139bc87fSRandall Stewart return;
3994139bc87fSRandall Stewart }
3995f8829a4aSRandall Stewart asoc->this_sack_highest_gap = cumack;
3996b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
3997c4739e2fSRandall Stewart sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
3998c4739e2fSRandall Stewart stcb->asoc.overall_error_count,
3999c4739e2fSRandall Stewart 0,
4000c4739e2fSRandall Stewart SCTP_FROM_SCTP_INDATA,
4001c4739e2fSRandall Stewart __LINE__);
4002c4739e2fSRandall Stewart }
4003f8829a4aSRandall Stewart stcb->asoc.overall_error_count = 0;
400420b07a4dSMichael Tuexen if (SCTP_TSN_GT(cumack, asoc->last_acked_seq)) {
4005f8829a4aSRandall Stewart /* process the new consecutive TSN first */
40064a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(tp1, &asoc->sent_queue, sctp_next, tp2) {
400749656eefSMichael Tuexen if (SCTP_TSN_GE(cumack, tp1->rec.data.tsn)) {
400818e198d3SRandall Stewart if (tp1->sent == SCTP_DATAGRAM_UNSENT) {
4009cd3fd531SMichael Tuexen SCTP_PRINTF("Warning, an unsent is now acked?\n");
401018e198d3SRandall Stewart }
4011f8829a4aSRandall Stewart if (tp1->sent < SCTP_DATAGRAM_ACKED) {
4012f8829a4aSRandall Stewart /*
401318e198d3SRandall Stewart * If it is less than ACKED, it is
401418e198d3SRandall Stewart * now no-longer in flight. Higher
401518e198d3SRandall Stewart * values may occur during marking
4016f8829a4aSRandall Stewart */
4017c105859eSRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND) {
4018b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
4019c105859eSRandall Stewart sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_CA,
4020a5d547adSRandall Stewart tp1->whoTo->flight_size,
4021a5d547adSRandall Stewart tp1->book_size,
40229a8e3088SMichael Tuexen (uint32_t)(uintptr_t)tp1->whoTo,
402349656eefSMichael Tuexen tp1->rec.data.tsn);
402480fefe0aSRandall Stewart }
4025c105859eSRandall Stewart sctp_flight_size_decrease(tp1);
4026299108c5SRandall Stewart if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) {
4027299108c5SRandall Stewart (*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) (tp1->whoTo,
4028299108c5SRandall Stewart tp1);
4029299108c5SRandall Stewart }
403004ee05e8SRandall Stewart /* sa_ignore NO_NULL_CHK */
4031c105859eSRandall Stewart sctp_total_flight_decrease(stcb, tp1);
4032f8829a4aSRandall Stewart }
4033f8829a4aSRandall Stewart tp1->whoTo->net_ack += tp1->send_size;
4034f8829a4aSRandall Stewart if (tp1->snd_count < 2) {
4035f8829a4aSRandall Stewart /*
4036ab9ed8a1SDevin Teske * True non-retransmitted
4037f8829a4aSRandall Stewart * chunk
4038f8829a4aSRandall Stewart */
4039f8829a4aSRandall Stewart tp1->whoTo->net_ack2 +=
4040f8829a4aSRandall Stewart tp1->send_size;
4041f8829a4aSRandall Stewart
4042f8829a4aSRandall Stewart /* update RTO too? */
404362c1ff9cSRandall Stewart if (tp1->do_rtt) {
404444f2a327SMichael Tuexen if (rto_ok &&
4045f8829a4aSRandall Stewart sctp_calculate_rto(stcb,
404644f2a327SMichael Tuexen &stcb->asoc,
404744f2a327SMichael Tuexen tp1->whoTo,
404818e198d3SRandall Stewart &tp1->sent_rcv_time,
404944f2a327SMichael Tuexen SCTP_RTT_FROM_DATA)) {
4050f79aab18SRandall Stewart rto_ok = 0;
4051f79aab18SRandall Stewart }
4052f79aab18SRandall Stewart if (tp1->whoTo->rto_needed == 0) {
4053f79aab18SRandall Stewart tp1->whoTo->rto_needed = 1;
4054f79aab18SRandall Stewart }
4055f8829a4aSRandall Stewart tp1->do_rtt = 0;
4056f8829a4aSRandall Stewart }
4057f8829a4aSRandall Stewart }
4058132dea7dSRandall Stewart /*
405918e198d3SRandall Stewart * CMT: CUCv2 algorithm. From the
406018e198d3SRandall Stewart * cumack'd TSNs, for each TSN being
406118e198d3SRandall Stewart * acked for the first time, set the
406218e198d3SRandall Stewart * following variables for the
406318e198d3SRandall Stewart * corresp destination.
406418e198d3SRandall Stewart * new_pseudo_cumack will trigger a
406518e198d3SRandall Stewart * cwnd update.
406618e198d3SRandall Stewart * find_(rtx_)pseudo_cumack will
406718e198d3SRandall Stewart * trigger search for the next
406818e198d3SRandall Stewart * expected (rtx-)pseudo-cumack.
4069132dea7dSRandall Stewart */
4070132dea7dSRandall Stewart tp1->whoTo->new_pseudo_cumack = 1;
4071132dea7dSRandall Stewart tp1->whoTo->find_pseudo_cumack = 1;
4072132dea7dSRandall Stewart tp1->whoTo->find_rtx_pseudo_cumack = 1;
4073b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
407404ee05e8SRandall Stewart /* sa_ignore NO_NULL_CHK */
407549656eefSMichael Tuexen sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.tsn, SCTP_CWND_LOG_FROM_SACK);
407680fefe0aSRandall Stewart }
4077f8829a4aSRandall Stewart }
4078f8829a4aSRandall Stewart if (tp1->sent == SCTP_DATAGRAM_RESEND) {
4079f8829a4aSRandall Stewart sctp_ucount_decr(asoc->sent_queue_retran_cnt);
4080f8829a4aSRandall Stewart }
408142551e99SRandall Stewart if (tp1->rec.data.chunk_was_revoked) {
408242551e99SRandall Stewart /* deflate the cwnd */
408342551e99SRandall Stewart tp1->whoTo->cwnd -= tp1->book_size;
408442551e99SRandall Stewart tp1->rec.data.chunk_was_revoked = 0;
408542551e99SRandall Stewart }
4086325c8c46SMichael Tuexen if (tp1->sent != SCTP_DATAGRAM_NR_ACKED) {
408749656eefSMichael Tuexen if (asoc->strmout[tp1->rec.data.sid].chunks_on_queues > 0) {
408849656eefSMichael Tuexen asoc->strmout[tp1->rec.data.sid].chunks_on_queues--;
4089a7ad6026SMichael Tuexen #ifdef INVARIANTS
4090a7ad6026SMichael Tuexen } else {
409149656eefSMichael Tuexen panic("No chunks on the queues for sid %u.", tp1->rec.data.sid);
4092a7ad6026SMichael Tuexen #endif
4093a7ad6026SMichael Tuexen }
4094a7ad6026SMichael Tuexen }
409549656eefSMichael Tuexen if ((asoc->strmout[tp1->rec.data.sid].chunks_on_queues == 0) &&
409649656eefSMichael Tuexen (asoc->strmout[tp1->rec.data.sid].state == SCTP_STREAM_RESET_PENDING) &&
409749656eefSMichael Tuexen TAILQ_EMPTY(&asoc->strmout[tp1->rec.data.sid].outqueue)) {
4098d96bef9cSMichael Tuexen asoc->trigger_reset = 1;
4099d96bef9cSMichael Tuexen }
4100f8829a4aSRandall Stewart TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next);
4101f8829a4aSRandall Stewart if (tp1->data) {
410204ee05e8SRandall Stewart /* sa_ignore NO_NULL_CHK */
4103f8829a4aSRandall Stewart sctp_free_bufspace(stcb, asoc, tp1, 1);
4104f8829a4aSRandall Stewart sctp_m_freem(tp1->data);
41054a9ef3f8SMichael Tuexen tp1->data = NULL;
4106f8829a4aSRandall Stewart }
4107b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
4108f8829a4aSRandall Stewart sctp_log_sack(asoc->last_acked_seq,
4109f8829a4aSRandall Stewart cumack,
411049656eefSMichael Tuexen tp1->rec.data.tsn,
4111f8829a4aSRandall Stewart 0,
4112f8829a4aSRandall Stewart 0,
4113f8829a4aSRandall Stewart SCTP_LOG_FREE_SENT);
411480fefe0aSRandall Stewart }
4115f8829a4aSRandall Stewart asoc->sent_queue_cnt--;
4116689e6a5fSMichael Tuexen sctp_free_a_chunk(stcb, tp1, SCTP_SO_NOT_LOCKED);
411718e198d3SRandall Stewart } else {
411818e198d3SRandall Stewart break;
4119f8829a4aSRandall Stewart }
41205e54f665SRandall Stewart }
412118e198d3SRandall Stewart }
412204ee05e8SRandall Stewart /* sa_ignore NO_NULL_CHK */
4123f8829a4aSRandall Stewart if (stcb->sctp_socket) {
4124f8829a4aSRandall Stewart SOCKBUF_LOCK(&stcb->sctp_socket->so_snd);
4125b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_WAKE_LOGGING_ENABLE) {
412604ee05e8SRandall Stewart /* sa_ignore NO_NULL_CHK */
41277215cc1bSMichael Tuexen sctp_wakeup_log(stcb, 1, SCTP_WAKESND_FROM_SACK);
412880fefe0aSRandall Stewart }
4129f8829a4aSRandall Stewart sctp_sowwakeup_locked(stcb->sctp_ep, stcb->sctp_socket);
4130f8829a4aSRandall Stewart } else {
4131b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_WAKE_LOGGING_ENABLE) {
41327215cc1bSMichael Tuexen sctp_wakeup_log(stcb, 1, SCTP_NOWAKE_FROM_SACK);
413380fefe0aSRandall Stewart }
4134f8829a4aSRandall Stewart }
4135f8829a4aSRandall Stewart
4136b54d3a6cSRandall Stewart /* JRS - Use the congestion control given in the CC module */
4137ca85e948SMichael Tuexen if ((asoc->last_acked_seq != cumack) && (ecne_seen == 0)) {
4138ca85e948SMichael Tuexen TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4139ca85e948SMichael Tuexen if (net->net_ack2 > 0) {
4140ca85e948SMichael Tuexen /*
4141ca85e948SMichael Tuexen * Karn's rule applies to clearing error
4142ca85e948SMichael Tuexen * count, this is optional.
4143ca85e948SMichael Tuexen */
4144ca85e948SMichael Tuexen net->error_count = 0;
41459b2a35b3SMichael Tuexen if ((net->dest_state & SCTP_ADDR_REACHABLE) == 0) {
4146ca85e948SMichael Tuexen /* addr came good */
4147ca85e948SMichael Tuexen net->dest_state |= SCTP_ADDR_REACHABLE;
4148ca85e948SMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
41494b1f78e1SMichael Tuexen 0, (void *)net, SCTP_SO_NOT_LOCKED);
4150ca85e948SMichael Tuexen }
4151ca85e948SMichael Tuexen if (net == stcb->asoc.primary_destination) {
4152ca85e948SMichael Tuexen if (stcb->asoc.alternate) {
4153b7b84c0eSMichael Tuexen /*
4154b7b84c0eSMichael Tuexen * release the alternate,
4155b7b84c0eSMichael Tuexen * primary is good
4156b7b84c0eSMichael Tuexen */
4157ca85e948SMichael Tuexen sctp_free_remote_addr(stcb->asoc.alternate);
4158ca85e948SMichael Tuexen stcb->asoc.alternate = NULL;
4159ca85e948SMichael Tuexen }
4160ca85e948SMichael Tuexen }
4161ca85e948SMichael Tuexen if (net->dest_state & SCTP_ADDR_PF) {
4162ca85e948SMichael Tuexen net->dest_state &= ~SCTP_ADDR_PF;
4163b7d130beSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
4164b7d130beSMichael Tuexen stcb->sctp_ep, stcb, net,
416591e04f9eSMichael Tuexen SCTP_FROM_SCTP_INDATA + SCTP_LOC_26);
4166ca85e948SMichael Tuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
4167ca85e948SMichael Tuexen asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net);
4168ca85e948SMichael Tuexen /* Done with this net */
4169ca85e948SMichael Tuexen net->net_ack = 0;
4170ca85e948SMichael Tuexen }
4171ca85e948SMichael Tuexen /* restore any doubled timers */
4172ca85e948SMichael Tuexen net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
4173ca85e948SMichael Tuexen if (net->RTO < stcb->asoc.minrto) {
4174ca85e948SMichael Tuexen net->RTO = stcb->asoc.minrto;
4175ca85e948SMichael Tuexen }
4176ca85e948SMichael Tuexen if (net->RTO > stcb->asoc.maxrto) {
4177ca85e948SMichael Tuexen net->RTO = stcb->asoc.maxrto;
4178ca85e948SMichael Tuexen }
4179ca85e948SMichael Tuexen }
4180ca85e948SMichael Tuexen }
4181b54d3a6cSRandall Stewart asoc->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, 1, 0, 0);
4182ca85e948SMichael Tuexen }
4183f8829a4aSRandall Stewart asoc->last_acked_seq = cumack;
41845e54f665SRandall Stewart
4185f8829a4aSRandall Stewart if (TAILQ_EMPTY(&asoc->sent_queue)) {
4186f8829a4aSRandall Stewart /* nothing left in-flight */
4187f8829a4aSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4188f8829a4aSRandall Stewart net->flight_size = 0;
4189f8829a4aSRandall Stewart net->partial_bytes_acked = 0;
4190f8829a4aSRandall Stewart }
4191f8829a4aSRandall Stewart asoc->total_flight = 0;
4192f8829a4aSRandall Stewart asoc->total_flight_count = 0;
4193f8829a4aSRandall Stewart }
41940053ed28SMichael Tuexen
4195f8829a4aSRandall Stewart /* RWND update */
4196f8829a4aSRandall Stewart asoc->peers_rwnd = sctp_sbspace_sub(rwnd,
419744fbe462SRandall Stewart (uint32_t)(asoc->total_flight + (asoc->total_flight_count * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh))));
4198f8829a4aSRandall Stewart if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) {
4199f8829a4aSRandall Stewart /* SWS sender side engages */
4200f8829a4aSRandall Stewart asoc->peers_rwnd = 0;
4201f8829a4aSRandall Stewart }
42025e54f665SRandall Stewart if (asoc->peers_rwnd > old_rwnd) {
42035e54f665SRandall Stewart win_probe_recovery = 1;
42045e54f665SRandall Stewart }
4205f8829a4aSRandall Stewart /* Now assure a timer where data is queued at */
4206a5d547adSRandall Stewart again:
4207a5d547adSRandall Stewart j = 0;
4208f8829a4aSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
42095e54f665SRandall Stewart if (win_probe_recovery && (net->window_probe)) {
4210c105859eSRandall Stewart win_probe_recovered = 1;
42115e54f665SRandall Stewart /*
42125e54f665SRandall Stewart * Find first chunk that was used with window probe
42135e54f665SRandall Stewart * and clear the sent
42145e54f665SRandall Stewart */
42153c503c28SRandall Stewart /* sa_ignore FREED_MEMORY */
42165e54f665SRandall Stewart TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
42175e54f665SRandall Stewart if (tp1->window_probe) {
4218cd554309SMichael Tuexen /* move back to data send queue */
42197215cc1bSMichael Tuexen sctp_window_probe_recovery(stcb, asoc, tp1);
42205e54f665SRandall Stewart break;
42215e54f665SRandall Stewart }
42225e54f665SRandall Stewart }
42235e54f665SRandall Stewart }
42245171328bSRandall Stewart if (net->flight_size) {
4225a5d547adSRandall Stewart j++;
422672e23abaSMichael Tuexen sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net);
42275171328bSRandall Stewart if (net->window_probe) {
42285171328bSRandall Stewart net->window_probe = 0;
42295171328bSRandall Stewart }
4230f8829a4aSRandall Stewart } else {
42315171328bSRandall Stewart if (net->window_probe) {
4232b7b84c0eSMichael Tuexen /*
4233b7b84c0eSMichael Tuexen * In window probes we must assure a timer
4234b7b84c0eSMichael Tuexen * is still running there
4235b7b84c0eSMichael Tuexen */
42365171328bSRandall Stewart net->window_probe = 0;
42375171328bSRandall Stewart if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
423872e23abaSMichael Tuexen sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net);
42395171328bSRandall Stewart }
42405171328bSRandall Stewart } else if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
4241f8829a4aSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
4242a5d547adSRandall Stewart stcb, net,
424391e04f9eSMichael Tuexen SCTP_FROM_SCTP_INDATA + SCTP_LOC_27);
4244f8829a4aSRandall Stewart }
4245f8829a4aSRandall Stewart }
4246f8829a4aSRandall Stewart }
4247bff64a4dSRandall Stewart if ((j == 0) &&
4248bff64a4dSRandall Stewart (!TAILQ_EMPTY(&asoc->sent_queue)) &&
4249bff64a4dSRandall Stewart (asoc->sent_queue_retran_cnt == 0) &&
4250c105859eSRandall Stewart (win_probe_recovered == 0) &&
4251bff64a4dSRandall Stewart (done_once == 0)) {
42520c0982b8SRandall Stewart /*
42530c0982b8SRandall Stewart * huh, this should not happen unless all packets are
42540c0982b8SRandall Stewart * PR-SCTP and marked to skip of course.
42550c0982b8SRandall Stewart */
42560c0982b8SRandall Stewart if (sctp_fs_audit(asoc)) {
4257a5d547adSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4258a5d547adSRandall Stewart net->flight_size = 0;
4259a5d547adSRandall Stewart }
4260a5d547adSRandall Stewart asoc->total_flight = 0;
4261a5d547adSRandall Stewart asoc->total_flight_count = 0;
4262a5d547adSRandall Stewart asoc->sent_queue_retran_cnt = 0;
4263a5d547adSRandall Stewart TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
4264a5d547adSRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND) {
4265c105859eSRandall Stewart sctp_flight_size_increase(tp1);
4266c105859eSRandall Stewart sctp_total_flight_increase(stcb, tp1);
4267a5d547adSRandall Stewart } else if (tp1->sent == SCTP_DATAGRAM_RESEND) {
4268791437b5SRandall Stewart sctp_ucount_incr(asoc->sent_queue_retran_cnt);
4269a5d547adSRandall Stewart }
4270a5d547adSRandall Stewart }
42710c0982b8SRandall Stewart }
4272bff64a4dSRandall Stewart done_once = 1;
4273a5d547adSRandall Stewart goto again;
4274a5d547adSRandall Stewart }
4275f8829a4aSRandall Stewart /**********************************/
4276f8829a4aSRandall Stewart /* Now what about shutdown issues */
4277f8829a4aSRandall Stewart /**********************************/
4278f8829a4aSRandall Stewart if (TAILQ_EMPTY(&asoc->send_queue) && TAILQ_EMPTY(&asoc->sent_queue)) {
4279f8829a4aSRandall Stewart /* nothing left on sendqueue.. consider done */
4280f8829a4aSRandall Stewart /* clean up */
4281f8829a4aSRandall Stewart if ((asoc->stream_queue_cnt == 1) &&
4282f8829a4aSRandall Stewart ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) ||
4283839d21d6SMichael Tuexen (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) &&
4284d1ea5fa9SMichael Tuexen ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc))) {
4285839d21d6SMichael Tuexen SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT);
42862afb3e84SRandall Stewart }
4287bbc9dfbcSMichael Tuexen if (((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) ||
4288839d21d6SMichael Tuexen (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) &&
4289bbc9dfbcSMichael Tuexen (asoc->stream_queue_cnt == 1) &&
4290bbc9dfbcSMichael Tuexen (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
4291ff1ffd74SMichael Tuexen struct mbuf *op_err;
4292f8829a4aSRandall Stewart
4293f8829a4aSRandall Stewart *abort_now = 1;
4294f8829a4aSRandall Stewart /* XXX */
4295ff1ffd74SMichael Tuexen op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
429691e04f9eSMichael Tuexen stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_28;
4297105b68b4SMichael Tuexen sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED);
4298fe4a59b3SMichael Tuexen return;
4299bbc9dfbcSMichael Tuexen }
4300bbc9dfbcSMichael Tuexen if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) &&
4301bbc9dfbcSMichael Tuexen (asoc->stream_queue_cnt == 0)) {
4302ca85e948SMichael Tuexen struct sctp_nets *netp;
4303ca85e948SMichael Tuexen
4304839d21d6SMichael Tuexen if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
4305839d21d6SMichael Tuexen (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
4306f8829a4aSRandall Stewart SCTP_STAT_DECR_GAUGE32(sctps_currestab);
4307f42a358aSRandall Stewart }
4308839d21d6SMichael Tuexen SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT);
4309f8829a4aSRandall Stewart sctp_stop_timers_for_shutdown(stcb);
4310ca85e948SMichael Tuexen if (asoc->alternate) {
4311ca85e948SMichael Tuexen netp = asoc->alternate;
4312ca85e948SMichael Tuexen } else {
4313ca85e948SMichael Tuexen netp = asoc->primary_destination;
4314ca85e948SMichael Tuexen }
4315ca85e948SMichael Tuexen sctp_send_shutdown(stcb, netp);
4316f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
4317ca85e948SMichael Tuexen stcb->sctp_ep, stcb, netp);
4318f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
43196fb7b4fbSMichael Tuexen stcb->sctp_ep, stcb, NULL);
4320839d21d6SMichael Tuexen } else if ((SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED) &&
4321f8829a4aSRandall Stewart (asoc->stream_queue_cnt == 0)) {
4322ca85e948SMichael Tuexen struct sctp_nets *netp;
4323ca85e948SMichael Tuexen
4324f8829a4aSRandall Stewart SCTP_STAT_DECR_GAUGE32(sctps_currestab);
4325839d21d6SMichael Tuexen SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_ACK_SENT);
432612af6654SMichael Tuexen sctp_stop_timers_for_shutdown(stcb);
4327c39cfa1fSMichael Tuexen if (asoc->alternate) {
4328c39cfa1fSMichael Tuexen netp = asoc->alternate;
4329c39cfa1fSMichael Tuexen } else {
4330c39cfa1fSMichael Tuexen netp = asoc->primary_destination;
4331c39cfa1fSMichael Tuexen }
4332c39cfa1fSMichael Tuexen sctp_send_shutdown_ack(stcb, netp);
4333f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK,
4334ca85e948SMichael Tuexen stcb->sctp_ep, stcb, netp);
4335f8829a4aSRandall Stewart }
4336f8829a4aSRandall Stewart }
4337dfb11ef8SRandall Stewart /*********************************************/
4338dfb11ef8SRandall Stewart /* Here we perform PR-SCTP procedures */
4339dfb11ef8SRandall Stewart /* (section 4.2) */
4340dfb11ef8SRandall Stewart /*********************************************/
4341dfb11ef8SRandall Stewart /* C1. update advancedPeerAckPoint */
434220b07a4dSMichael Tuexen if (SCTP_TSN_GT(cumack, asoc->advanced_peer_ack_point)) {
4343dfb11ef8SRandall Stewart asoc->advanced_peer_ack_point = cumack;
4344dfb11ef8SRandall Stewart }
4345830d754dSRandall Stewart /* PR-Sctp issues need to be addressed too */
4346dd973b0eSMichael Tuexen if ((asoc->prsctp_supported) && (asoc->pr_sctp_cnt > 0)) {
4347830d754dSRandall Stewart struct sctp_tmit_chunk *lchk;
4348830d754dSRandall Stewart uint32_t old_adv_peer_ack_point;
4349830d754dSRandall Stewart
4350830d754dSRandall Stewart old_adv_peer_ack_point = asoc->advanced_peer_ack_point;
4351830d754dSRandall Stewart lchk = sctp_try_advance_peer_ack_point(stcb, asoc);
4352830d754dSRandall Stewart /* C3. See if we need to send a Fwd-TSN */
435320b07a4dSMichael Tuexen if (SCTP_TSN_GT(asoc->advanced_peer_ack_point, cumack)) {
4354830d754dSRandall Stewart /*
4355493d8e5aSRandall Stewart * ISSUE with ECN, see FWD-TSN processing.
4356830d754dSRandall Stewart */
435720b07a4dSMichael Tuexen if (SCTP_TSN_GT(asoc->advanced_peer_ack_point, old_adv_peer_ack_point)) {
4358830d754dSRandall Stewart send_forward_tsn(stcb, asoc);
43590c0982b8SRandall Stewart } else if (lchk) {
43600c0982b8SRandall Stewart /* try to FR fwd-tsn's that get lost too */
436144fbe462SRandall Stewart if (lchk->rec.data.fwd_tsn_cnt >= 3) {
43620c0982b8SRandall Stewart send_forward_tsn(stcb, asoc);
43630c0982b8SRandall Stewart }
4364830d754dSRandall Stewart }
4365830d754dSRandall Stewart }
4366efd5e692SMichael Tuexen for (; lchk != NULL; lchk = TAILQ_NEXT(lchk, sctp_next)) {
4367efd5e692SMichael Tuexen if (lchk->whoTo != NULL) {
4368efd5e692SMichael Tuexen break;
4369efd5e692SMichael Tuexen }
4370efd5e692SMichael Tuexen }
4371efd5e692SMichael Tuexen if (lchk != NULL) {
4372830d754dSRandall Stewart /* Assure a timer is up */
4373830d754dSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SEND,
4374830d754dSRandall Stewart stcb->sctp_ep, stcb, lchk->whoTo);
4375830d754dSRandall Stewart }
4376830d754dSRandall Stewart }
4377b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_RWND_LOGGING_ENABLE) {
4378f8829a4aSRandall Stewart sctp_misc_ints(SCTP_SACK_RWND_UPDATE,
4379f8829a4aSRandall Stewart rwnd,
4380f8829a4aSRandall Stewart stcb->asoc.peers_rwnd,
4381f8829a4aSRandall Stewart stcb->asoc.total_flight,
4382f8829a4aSRandall Stewart stcb->asoc.total_output_queue_size);
438380fefe0aSRandall Stewart }
4384f8829a4aSRandall Stewart }
4385f8829a4aSRandall Stewart
4386f8829a4aSRandall Stewart void
sctp_handle_sack(struct mbuf * m,int offset_seg,int offset_dup,struct sctp_tcb * stcb,uint16_t num_seg,uint16_t num_nr_seg,uint16_t num_dup,int * abort_now,uint8_t flags,uint32_t cum_ack,uint32_t rwnd,int ecne_seen)4387cd554309SMichael Tuexen sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
43887215cc1bSMichael Tuexen struct sctp_tcb *stcb,
4389cd554309SMichael Tuexen uint16_t num_seg, uint16_t num_nr_seg, uint16_t num_dup,
4390cd554309SMichael Tuexen int *abort_now, uint8_t flags,
4391899288aeSRandall Stewart uint32_t cum_ack, uint32_t rwnd, int ecne_seen)
4392f8829a4aSRandall Stewart {
4393f8829a4aSRandall Stewart struct sctp_association *asoc;
4394f8829a4aSRandall Stewart struct sctp_tmit_chunk *tp1, *tp2;
4395cd554309SMichael Tuexen uint32_t last_tsn, biggest_tsn_acked, biggest_tsn_newly_acked, this_sack_lowest_newack;
4396f8829a4aSRandall Stewart uint16_t wake_him = 0;
4397c105859eSRandall Stewart uint32_t send_s = 0;
4398f8829a4aSRandall Stewart long j;
4399f8829a4aSRandall Stewart int accum_moved = 0;
4400f8829a4aSRandall Stewart int will_exit_fast_recovery = 0;
44015e54f665SRandall Stewart uint32_t a_rwnd, old_rwnd;
44025e54f665SRandall Stewart int win_probe_recovery = 0;
4403c105859eSRandall Stewart int win_probe_recovered = 0;
4404f8829a4aSRandall Stewart struct sctp_nets *net = NULL;
4405bff64a4dSRandall Stewart int done_once;
4406f79aab18SRandall Stewart int rto_ok = 1;
4407f8829a4aSRandall Stewart uint8_t reneged_all = 0;
4408f8829a4aSRandall Stewart uint8_t cmt_dac_flag;
4409f8829a4aSRandall Stewart
4410f8829a4aSRandall Stewart /*
4411f8829a4aSRandall Stewart * we take any chance we can to service our queues since we cannot
4412f8829a4aSRandall Stewart * get awoken when the socket is read from :<
4413f8829a4aSRandall Stewart */
4414f8829a4aSRandall Stewart /*
4415f8829a4aSRandall Stewart * Now perform the actual SACK handling: 1) Verify that it is not an
4416f8829a4aSRandall Stewart * old sack, if so discard. 2) If there is nothing left in the send
4417f8829a4aSRandall Stewart * queue (cum-ack is equal to last acked) then you have a duplicate
4418f8829a4aSRandall Stewart * too, update any rwnd change and verify no timers are running.
4419e7e65008SMichael Tuexen * then return. 3) Process any new consecutive data i.e. cum-ack
4420f8829a4aSRandall Stewart * moved process these first and note that it moved. 4) Process any
4421f8829a4aSRandall Stewart * sack blocks. 5) Drop any acked from the queue. 6) Check for any
4422f8829a4aSRandall Stewart * revoked blocks and mark. 7) Update the cwnd. 8) Nothing left,
4423f8829a4aSRandall Stewart * sync up flightsizes and things, stop all timers and also check
4424f8829a4aSRandall Stewart * for shutdown_pending state. If so then go ahead and send off the
4425f8829a4aSRandall Stewart * shutdown. If in shutdown recv, send off the shutdown-ack and
4426f8829a4aSRandall Stewart * start that timer, Ret. 9) Strike any non-acked things and do FR
4427f8829a4aSRandall Stewart * procedure if needed being sure to set the FR flag. 10) Do pr-sctp
4428f8829a4aSRandall Stewart * procedures. 11) Apply any FR penalties. 12) Assure we will SACK
4429f8829a4aSRandall Stewart * if in shutdown_recv state.
4430f8829a4aSRandall Stewart */
4431f8829a4aSRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb);
4432f8829a4aSRandall Stewart /* CMT DAC algo */
4433f8829a4aSRandall Stewart this_sack_lowest_newack = 0;
4434f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_slowpath_sack);
4435cd554309SMichael Tuexen last_tsn = cum_ack;
4436cd554309SMichael Tuexen cmt_dac_flag = flags & SCTP_SACK_CMT_DAC;
443718e198d3SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS
443818e198d3SRandall Stewart stcb->asoc.cumack_log[stcb->asoc.cumack_log_at] = cum_ack;
443918e198d3SRandall Stewart stcb->asoc.cumack_log_at++;
444018e198d3SRandall Stewart if (stcb->asoc.cumack_log_at > SCTP_TSN_LOG_SIZE) {
444118e198d3SRandall Stewart stcb->asoc.cumack_log_at = 0;
444218e198d3SRandall Stewart }
444318e198d3SRandall Stewart #endif
4444d06c82f1SRandall Stewart a_rwnd = rwnd;
4445f8829a4aSRandall Stewart
4446cd554309SMichael Tuexen if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_SACK_ARRIVALS_ENABLE) {
4447cd554309SMichael Tuexen sctp_misc_ints(SCTP_SACK_LOG_NORMAL, cum_ack,
4448cd554309SMichael Tuexen rwnd, stcb->asoc.last_acked_seq, stcb->asoc.peers_rwnd);
4449cd554309SMichael Tuexen }
44500053ed28SMichael Tuexen
44515e54f665SRandall Stewart old_rwnd = stcb->asoc.peers_rwnd;
4452b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
4453c4739e2fSRandall Stewart sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
4454c4739e2fSRandall Stewart stcb->asoc.overall_error_count,
4455c4739e2fSRandall Stewart 0,
4456c4739e2fSRandall Stewart SCTP_FROM_SCTP_INDATA,
4457c4739e2fSRandall Stewart __LINE__);
4458c4739e2fSRandall Stewart }
4459f8829a4aSRandall Stewart stcb->asoc.overall_error_count = 0;
4460f8829a4aSRandall Stewart asoc = &stcb->asoc;
4461b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
4462f8829a4aSRandall Stewart sctp_log_sack(asoc->last_acked_seq,
4463f8829a4aSRandall Stewart cum_ack,
4464f8829a4aSRandall Stewart 0,
4465f8829a4aSRandall Stewart num_seg,
4466f8829a4aSRandall Stewart num_dup,
4467f8829a4aSRandall Stewart SCTP_LOG_NEW_SACK);
446880fefe0aSRandall Stewart }
4469ca85e948SMichael Tuexen if ((num_dup) && (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE)) {
4470cd554309SMichael Tuexen uint16_t i;
4471458303daSRandall Stewart uint32_t *dupdata, dblock;
4472f8829a4aSRandall Stewart
4473cd554309SMichael Tuexen for (i = 0; i < num_dup; i++) {
4474cd554309SMichael Tuexen dupdata = (uint32_t *)sctp_m_getptr(m, offset_dup + i * sizeof(uint32_t),
4475458303daSRandall Stewart sizeof(uint32_t), (uint8_t *)&dblock);
4476cd554309SMichael Tuexen if (dupdata == NULL) {
4477458303daSRandall Stewart break;
4478458303daSRandall Stewart }
4479cd554309SMichael Tuexen sctp_log_fr(*dupdata, 0, 0, SCTP_FR_DUPED);
4480f8829a4aSRandall Stewart }
4481f8829a4aSRandall Stewart }
4482c105859eSRandall Stewart /* reality check */
4483c105859eSRandall Stewart if (!TAILQ_EMPTY(&asoc->sent_queue)) {
4484c105859eSRandall Stewart tp1 = TAILQ_LAST(&asoc->sent_queue,
4485c105859eSRandall Stewart sctpchunk_listhead);
448649656eefSMichael Tuexen send_s = tp1->rec.data.tsn + 1;
4487c105859eSRandall Stewart } else {
4488b5c16493SMichael Tuexen tp1 = NULL;
4489c105859eSRandall Stewart send_s = asoc->sending_seq;
4490c105859eSRandall Stewart }
449120b07a4dSMichael Tuexen if (SCTP_TSN_GE(cum_ack, send_s)) {
4492ff1ffd74SMichael Tuexen struct mbuf *op_err;
4493ff1ffd74SMichael Tuexen char msg[SCTP_DIAG_INFO_LEN];
4494c105859eSRandall Stewart
4495f8829a4aSRandall Stewart /*
4496fd60718dSMichael Tuexen * no way, we have not even sent this TSN out yet. Peer is
4497fd60718dSMichael Tuexen * hopelessly messed up with us.
4498f8829a4aSRandall Stewart */
4499cd3fd531SMichael Tuexen SCTP_PRINTF("NEW cum_ack:%x send_s:%x is smaller or equal\n",
4500b5c16493SMichael Tuexen cum_ack, send_s);
4501b5c16493SMichael Tuexen if (tp1) {
4502cd3fd531SMichael Tuexen SCTP_PRINTF("Got send_s from tsn:%x + 1 of tp1: %p\n",
450349656eefSMichael Tuexen tp1->rec.data.tsn, (void *)tp1);
4504b5c16493SMichael Tuexen }
4505f8829a4aSRandall Stewart hopeless_peer:
4506f8829a4aSRandall Stewart *abort_now = 1;
4507f8829a4aSRandall Stewart /* XXX */
4508999f86d6SMichael Tuexen SCTP_SNPRINTF(msg, sizeof(msg),
4509999f86d6SMichael Tuexen "Cum ack %8.8x greater or equal than TSN %8.8x",
4510821bae7cSMichael Tuexen cum_ack, send_s);
4511ff1ffd74SMichael Tuexen op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
451291e04f9eSMichael Tuexen stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_29;
4513105b68b4SMichael Tuexen sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED);
4514f8829a4aSRandall Stewart return;
4515f8829a4aSRandall Stewart }
4516f8829a4aSRandall Stewart /**********************/
4517f8829a4aSRandall Stewart /* 1) check the range */
4518f8829a4aSRandall Stewart /**********************/
451920b07a4dSMichael Tuexen if (SCTP_TSN_GT(asoc->last_acked_seq, last_tsn)) {
4520f8829a4aSRandall Stewart /* acking something behind */
4521f8829a4aSRandall Stewart return;
4522f8829a4aSRandall Stewart }
45230053ed28SMichael Tuexen
4524f8829a4aSRandall Stewart /* update the Rwnd of the peer */
4525f8829a4aSRandall Stewart if (TAILQ_EMPTY(&asoc->sent_queue) &&
4526f8829a4aSRandall Stewart TAILQ_EMPTY(&asoc->send_queue) &&
4527cd554309SMichael Tuexen (asoc->stream_queue_cnt == 0)) {
4528f8829a4aSRandall Stewart /* nothing left on send/sent and strmq */
4529b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) {
4530f8829a4aSRandall Stewart sctp_log_rwnd_set(SCTP_SET_PEER_RWND_VIA_SACK,
4531f8829a4aSRandall Stewart asoc->peers_rwnd, 0, 0, a_rwnd);
453280fefe0aSRandall Stewart }
4533f8829a4aSRandall Stewart asoc->peers_rwnd = a_rwnd;
4534f8829a4aSRandall Stewart if (asoc->sent_queue_retran_cnt) {
4535f8829a4aSRandall Stewart asoc->sent_queue_retran_cnt = 0;
4536f8829a4aSRandall Stewart }
4537f8829a4aSRandall Stewart if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) {
4538f8829a4aSRandall Stewart /* SWS sender side engages */
4539f8829a4aSRandall Stewart asoc->peers_rwnd = 0;
4540f8829a4aSRandall Stewart }
4541f8829a4aSRandall Stewart /* stop any timers */
4542f8829a4aSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4543f8829a4aSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
454491e04f9eSMichael Tuexen stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_30);
4545f8829a4aSRandall Stewart net->partial_bytes_acked = 0;
4546f8829a4aSRandall Stewart net->flight_size = 0;
4547f8829a4aSRandall Stewart }
4548f8829a4aSRandall Stewart asoc->total_flight = 0;
4549f8829a4aSRandall Stewart asoc->total_flight_count = 0;
4550f8829a4aSRandall Stewart return;
4551f8829a4aSRandall Stewart }
4552f8829a4aSRandall Stewart /*
4553f8829a4aSRandall Stewart * We init netAckSz and netAckSz2 to 0. These are used to track 2
4554f8829a4aSRandall Stewart * things. The total byte count acked is tracked in netAckSz AND
4555f8829a4aSRandall Stewart * netAck2 is used to track the total bytes acked that are un-
4556e7e65008SMichael Tuexen * ambiguous and were never retransmitted. We track these on a per
4557f8829a4aSRandall Stewart * destination address basis.
4558f8829a4aSRandall Stewart */
4559f8829a4aSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4560a21779f0SRandall Stewart if (SCTP_TSN_GT(cum_ack, net->cwr_window_tsn)) {
4561a21779f0SRandall Stewart /* Drag along the window_tsn for cwr's */
4562a21779f0SRandall Stewart net->cwr_window_tsn = cum_ack;
4563a21779f0SRandall Stewart }
4564f8829a4aSRandall Stewart net->prev_cwnd = net->cwnd;
4565f8829a4aSRandall Stewart net->net_ack = 0;
4566f8829a4aSRandall Stewart net->net_ack2 = 0;
4567f8829a4aSRandall Stewart
4568f8829a4aSRandall Stewart /*
456942551e99SRandall Stewart * CMT: Reset CUC and Fast recovery algo variables before
457042551e99SRandall Stewart * SACK processing
4571f8829a4aSRandall Stewart */
4572f8829a4aSRandall Stewart net->new_pseudo_cumack = 0;
4573f8829a4aSRandall Stewart net->will_exit_fast_recovery = 0;
4574299108c5SRandall Stewart if (stcb->asoc.cc_functions.sctp_cwnd_prepare_net_for_sack) {
4575299108c5SRandall Stewart (*stcb->asoc.cc_functions.sctp_cwnd_prepare_net_for_sack) (stcb, net);
4576299108c5SRandall Stewart }
45770053ed28SMichael Tuexen
4578e9a3a1b1SMichael Tuexen /*
4579e9a3a1b1SMichael Tuexen * CMT: SFR algo (and HTNA) - this_sack_highest_newack has
4580e9a3a1b1SMichael Tuexen * to be greater than the cumack. Also reset saw_newack to 0
4581e9a3a1b1SMichael Tuexen * for all dests.
4582e9a3a1b1SMichael Tuexen */
4583e9a3a1b1SMichael Tuexen net->saw_newack = 0;
4584e9a3a1b1SMichael Tuexen net->this_sack_highest_newack = last_tsn;
4585f8829a4aSRandall Stewart }
4586f8829a4aSRandall Stewart /* process the new consecutive TSN first */
45874a9ef3f8SMichael Tuexen TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
458849656eefSMichael Tuexen if (SCTP_TSN_GE(last_tsn, tp1->rec.data.tsn)) {
4589f8829a4aSRandall Stewart if (tp1->sent != SCTP_DATAGRAM_UNSENT) {
4590f8829a4aSRandall Stewart accum_moved = 1;
4591f8829a4aSRandall Stewart if (tp1->sent < SCTP_DATAGRAM_ACKED) {
4592f8829a4aSRandall Stewart /*
4593f8829a4aSRandall Stewart * If it is less than ACKED, it is
4594f8829a4aSRandall Stewart * now no-longer in flight. Higher
4595f8829a4aSRandall Stewart * values may occur during marking
4596f8829a4aSRandall Stewart */
4597f8829a4aSRandall Stewart if ((tp1->whoTo->dest_state &
4598f8829a4aSRandall Stewart SCTP_ADDR_UNCONFIRMED) &&
4599f8829a4aSRandall Stewart (tp1->snd_count < 2)) {
4600f8829a4aSRandall Stewart /*
4601f8829a4aSRandall Stewart * If there was no retran
4602f8829a4aSRandall Stewart * and the address is
4603f8829a4aSRandall Stewart * un-confirmed and we sent
4604f8829a4aSRandall Stewart * there and are now
4605f8829a4aSRandall Stewart * sacked.. its confirmed,
4606f8829a4aSRandall Stewart * mark it so.
4607f8829a4aSRandall Stewart */
4608f8829a4aSRandall Stewart tp1->whoTo->dest_state &=
4609f8829a4aSRandall Stewart ~SCTP_ADDR_UNCONFIRMED;
4610f8829a4aSRandall Stewart }
4611c105859eSRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND) {
4612b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
4613c105859eSRandall Stewart sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_CA,
4614a5d547adSRandall Stewart tp1->whoTo->flight_size,
4615a5d547adSRandall Stewart tp1->book_size,
46169a8e3088SMichael Tuexen (uint32_t)(uintptr_t)tp1->whoTo,
461749656eefSMichael Tuexen tp1->rec.data.tsn);
461880fefe0aSRandall Stewart }
4619c105859eSRandall Stewart sctp_flight_size_decrease(tp1);
4620c105859eSRandall Stewart sctp_total_flight_decrease(stcb, tp1);
4621299108c5SRandall Stewart if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) {
4622299108c5SRandall Stewart (*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) (tp1->whoTo,
4623299108c5SRandall Stewart tp1);
4624299108c5SRandall Stewart }
4625f8829a4aSRandall Stewart }
4626f8829a4aSRandall Stewart tp1->whoTo->net_ack += tp1->send_size;
4627f8829a4aSRandall Stewart
4628f8829a4aSRandall Stewart /* CMT SFR and DAC algos */
462949656eefSMichael Tuexen this_sack_lowest_newack = tp1->rec.data.tsn;
4630f8829a4aSRandall Stewart tp1->whoTo->saw_newack = 1;
4631f8829a4aSRandall Stewart
4632f8829a4aSRandall Stewart if (tp1->snd_count < 2) {
4633f8829a4aSRandall Stewart /*
4634ab9ed8a1SDevin Teske * True non-retransmitted
4635f8829a4aSRandall Stewart * chunk
4636f8829a4aSRandall Stewart */
4637f8829a4aSRandall Stewart tp1->whoTo->net_ack2 +=
4638f8829a4aSRandall Stewart tp1->send_size;
4639f8829a4aSRandall Stewart
4640f8829a4aSRandall Stewart /* update RTO too? */
4641f8829a4aSRandall Stewart if (tp1->do_rtt) {
464244f2a327SMichael Tuexen if (rto_ok &&
4643f8829a4aSRandall Stewart sctp_calculate_rto(stcb,
464444f2a327SMichael Tuexen &stcb->asoc,
464544f2a327SMichael Tuexen tp1->whoTo,
464618e198d3SRandall Stewart &tp1->sent_rcv_time,
464744f2a327SMichael Tuexen SCTP_RTT_FROM_DATA)) {
4648f79aab18SRandall Stewart rto_ok = 0;
4649f79aab18SRandall Stewart }
4650f79aab18SRandall Stewart if (tp1->whoTo->rto_needed == 0) {
4651f79aab18SRandall Stewart tp1->whoTo->rto_needed = 1;
4652f79aab18SRandall Stewart }
4653f8829a4aSRandall Stewart tp1->do_rtt = 0;
4654f8829a4aSRandall Stewart }
4655f8829a4aSRandall Stewart }
4656f8829a4aSRandall Stewart /*
4657f8829a4aSRandall Stewart * CMT: CUCv2 algorithm. From the
4658f8829a4aSRandall Stewart * cumack'd TSNs, for each TSN being
4659f8829a4aSRandall Stewart * acked for the first time, set the
4660f8829a4aSRandall Stewart * following variables for the
4661f8829a4aSRandall Stewart * corresp destination.
4662f8829a4aSRandall Stewart * new_pseudo_cumack will trigger a
4663f8829a4aSRandall Stewart * cwnd update.
4664f8829a4aSRandall Stewart * find_(rtx_)pseudo_cumack will
4665f8829a4aSRandall Stewart * trigger search for the next
4666f8829a4aSRandall Stewart * expected (rtx-)pseudo-cumack.
4667f8829a4aSRandall Stewart */
4668f8829a4aSRandall Stewart tp1->whoTo->new_pseudo_cumack = 1;
4669f8829a4aSRandall Stewart tp1->whoTo->find_pseudo_cumack = 1;
4670f8829a4aSRandall Stewart tp1->whoTo->find_rtx_pseudo_cumack = 1;
4671b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
4672f8829a4aSRandall Stewart sctp_log_sack(asoc->last_acked_seq,
4673f8829a4aSRandall Stewart cum_ack,
467449656eefSMichael Tuexen tp1->rec.data.tsn,
4675f8829a4aSRandall Stewart 0,
4676f8829a4aSRandall Stewart 0,
4677f8829a4aSRandall Stewart SCTP_LOG_TSN_ACKED);
467880fefe0aSRandall Stewart }
4679b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
468049656eefSMichael Tuexen sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.tsn, SCTP_CWND_LOG_FROM_SACK);
468180fefe0aSRandall Stewart }
4682f8829a4aSRandall Stewart }
4683f8829a4aSRandall Stewart if (tp1->sent == SCTP_DATAGRAM_RESEND) {
4684f8829a4aSRandall Stewart sctp_ucount_decr(asoc->sent_queue_retran_cnt);
4685f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
4686f8829a4aSRandall Stewart sctp_audit_log(0xB3,
4687f8829a4aSRandall Stewart (asoc->sent_queue_retran_cnt & 0x000000ff));
4688f8829a4aSRandall Stewart #endif
4689f8829a4aSRandall Stewart }
469042551e99SRandall Stewart if (tp1->rec.data.chunk_was_revoked) {
469142551e99SRandall Stewart /* deflate the cwnd */
469242551e99SRandall Stewart tp1->whoTo->cwnd -= tp1->book_size;
469342551e99SRandall Stewart tp1->rec.data.chunk_was_revoked = 0;
469442551e99SRandall Stewart }
4695325c8c46SMichael Tuexen if (tp1->sent != SCTP_DATAGRAM_NR_ACKED) {
4696f8829a4aSRandall Stewart tp1->sent = SCTP_DATAGRAM_ACKED;
4697f8829a4aSRandall Stewart }
4698325c8c46SMichael Tuexen }
4699f8829a4aSRandall Stewart } else {
4700f8829a4aSRandall Stewart break;
4701f8829a4aSRandall Stewart }
4702f8829a4aSRandall Stewart }
4703f8829a4aSRandall Stewart biggest_tsn_newly_acked = biggest_tsn_acked = last_tsn;
4704f8829a4aSRandall Stewart /* always set this up to cum-ack */
4705f8829a4aSRandall Stewart asoc->this_sack_highest_gap = last_tsn;
4706f8829a4aSRandall Stewart
4707cd554309SMichael Tuexen if ((num_seg > 0) || (num_nr_seg > 0)) {
4708f8829a4aSRandall Stewart /*
4709f8829a4aSRandall Stewart * thisSackHighestGap will increase while handling NEW
4710f8829a4aSRandall Stewart * segments this_sack_highest_newack will increase while
4711f8829a4aSRandall Stewart * handling NEWLY ACKED chunks. this_sack_lowest_newack is
4712f8829a4aSRandall Stewart * used for CMT DAC algo. saw_newack will also change.
4713f8829a4aSRandall Stewart */
4714cd554309SMichael Tuexen if (sctp_handle_segments(m, &offset_seg, stcb, asoc, last_tsn, &biggest_tsn_acked,
4715cd554309SMichael Tuexen &biggest_tsn_newly_acked, &this_sack_lowest_newack,
47167215cc1bSMichael Tuexen num_seg, num_nr_seg, &rto_ok)) {
4717cd554309SMichael Tuexen wake_him++;
4718cd554309SMichael Tuexen }
4719f8829a4aSRandall Stewart /*
4720fd60718dSMichael Tuexen * validate the biggest_tsn_acked in the gap acks if strict
4721fd60718dSMichael Tuexen * adherence is wanted.
4722f8829a4aSRandall Stewart */
472320b07a4dSMichael Tuexen if (SCTP_TSN_GE(biggest_tsn_acked, send_s)) {
4724f8829a4aSRandall Stewart /*
4725fd60718dSMichael Tuexen * peer is either confused or we are under attack.
4726fd60718dSMichael Tuexen * We must abort.
4727f8829a4aSRandall Stewart */
4728cd3fd531SMichael Tuexen SCTP_PRINTF("Hopeless peer! biggest_tsn_acked:%x largest seq:%x\n",
4729cd3fd531SMichael Tuexen biggest_tsn_acked, send_s);
4730f8829a4aSRandall Stewart goto hopeless_peer;
4731f8829a4aSRandall Stewart }
4732f8829a4aSRandall Stewart }
4733f8829a4aSRandall Stewart /*******************************************/
4734f8829a4aSRandall Stewart /* cancel ALL T3-send timer if accum moved */
4735f8829a4aSRandall Stewart /*******************************************/
47367c99d56fSMichael Tuexen if (asoc->sctp_cmt_on_off > 0) {
4737f8829a4aSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4738f8829a4aSRandall Stewart if (net->new_pseudo_cumack)
4739f8829a4aSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
4740a5d547adSRandall Stewart stcb, net,
474191e04f9eSMichael Tuexen SCTP_FROM_SCTP_INDATA + SCTP_LOC_31);
4742f8829a4aSRandall Stewart }
4743f8829a4aSRandall Stewart } else {
4744f8829a4aSRandall Stewart if (accum_moved) {
4745f8829a4aSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4746f8829a4aSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
474791e04f9eSMichael Tuexen stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32);
4748f8829a4aSRandall Stewart }
4749f8829a4aSRandall Stewart }
4750f8829a4aSRandall Stewart }
4751f8829a4aSRandall Stewart /********************************************/
4752d9c5cfeaSMichael Tuexen /* drop the acked chunks from the sentqueue */
4753f8829a4aSRandall Stewart /********************************************/
4754f8829a4aSRandall Stewart asoc->last_acked_seq = cum_ack;
4755f8829a4aSRandall Stewart
47567c99d56fSMichael Tuexen TAILQ_FOREACH_SAFE(tp1, &asoc->sent_queue, sctp_next, tp2) {
475749656eefSMichael Tuexen if (SCTP_TSN_GT(tp1->rec.data.tsn, cum_ack)) {
4758f8829a4aSRandall Stewart break;
4759f8829a4aSRandall Stewart }
4760325c8c46SMichael Tuexen if (tp1->sent != SCTP_DATAGRAM_NR_ACKED) {
476149656eefSMichael Tuexen if (asoc->strmout[tp1->rec.data.sid].chunks_on_queues > 0) {
476249656eefSMichael Tuexen asoc->strmout[tp1->rec.data.sid].chunks_on_queues--;
4763a7ad6026SMichael Tuexen #ifdef INVARIANTS
4764a7ad6026SMichael Tuexen } else {
476549656eefSMichael Tuexen panic("No chunks on the queues for sid %u.", tp1->rec.data.sid);
4766a7ad6026SMichael Tuexen #endif
4767a7ad6026SMichael Tuexen }
4768f8829a4aSRandall Stewart }
476949656eefSMichael Tuexen if ((asoc->strmout[tp1->rec.data.sid].chunks_on_queues == 0) &&
477049656eefSMichael Tuexen (asoc->strmout[tp1->rec.data.sid].state == SCTP_STREAM_RESET_PENDING) &&
477149656eefSMichael Tuexen TAILQ_EMPTY(&asoc->strmout[tp1->rec.data.sid].outqueue)) {
4772d96bef9cSMichael Tuexen asoc->trigger_reset = 1;
4773d96bef9cSMichael Tuexen }
4774f8829a4aSRandall Stewart TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next);
47750ddb4299SMichael Tuexen if (PR_SCTP_ENABLED(tp1->flags)) {
4776f8829a4aSRandall Stewart if (asoc->pr_sctp_cnt != 0)
4777f8829a4aSRandall Stewart asoc->pr_sctp_cnt--;
4778f8829a4aSRandall Stewart }
47797c99d56fSMichael Tuexen asoc->sent_queue_cnt--;
4780f8829a4aSRandall Stewart if (tp1->data) {
478104ee05e8SRandall Stewart /* sa_ignore NO_NULL_CHK */
4782f8829a4aSRandall Stewart sctp_free_bufspace(stcb, asoc, tp1, 1);
4783f8829a4aSRandall Stewart sctp_m_freem(tp1->data);
47847c99d56fSMichael Tuexen tp1->data = NULL;
4785dd973b0eSMichael Tuexen if (asoc->prsctp_supported && PR_SCTP_BUF_ENABLED(tp1->flags)) {
4786f8829a4aSRandall Stewart asoc->sent_queue_cnt_removeable--;
4787f8829a4aSRandall Stewart }
4788f8829a4aSRandall Stewart }
4789b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
4790f8829a4aSRandall Stewart sctp_log_sack(asoc->last_acked_seq,
4791f8829a4aSRandall Stewart cum_ack,
479249656eefSMichael Tuexen tp1->rec.data.tsn,
4793f8829a4aSRandall Stewart 0,
4794f8829a4aSRandall Stewart 0,
4795f8829a4aSRandall Stewart SCTP_LOG_FREE_SENT);
479680fefe0aSRandall Stewart }
4797689e6a5fSMichael Tuexen sctp_free_a_chunk(stcb, tp1, SCTP_SO_NOT_LOCKED);
4798f8829a4aSRandall Stewart wake_him++;
47997c99d56fSMichael Tuexen }
48007c99d56fSMichael Tuexen if (TAILQ_EMPTY(&asoc->sent_queue) && (asoc->total_flight > 0)) {
48017c99d56fSMichael Tuexen #ifdef INVARIANTS
4802cd0a4ff6SPedro F. Giffuni panic("Warning flight size is positive and should be 0");
48037c99d56fSMichael Tuexen #else
48047c99d56fSMichael Tuexen SCTP_PRINTF("Warning flight size incorrect should be 0 is %d\n",
48057c99d56fSMichael Tuexen asoc->total_flight);
48067c99d56fSMichael Tuexen #endif
48077c99d56fSMichael Tuexen asoc->total_flight = 0;
48087c99d56fSMichael Tuexen }
48090053ed28SMichael Tuexen
481004ee05e8SRandall Stewart /* sa_ignore NO_NULL_CHK */
4811f8829a4aSRandall Stewart if ((wake_him) && (stcb->sctp_socket)) {
4812f8829a4aSRandall Stewart SOCKBUF_LOCK(&stcb->sctp_socket->so_snd);
4813b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_WAKE_LOGGING_ENABLE) {
48147215cc1bSMichael Tuexen sctp_wakeup_log(stcb, wake_him, SCTP_WAKESND_FROM_SACK);
481580fefe0aSRandall Stewart }
4816f8829a4aSRandall Stewart sctp_sowwakeup_locked(stcb->sctp_ep, stcb->sctp_socket);
4817f8829a4aSRandall Stewart } else {
4818b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_WAKE_LOGGING_ENABLE) {
48197215cc1bSMichael Tuexen sctp_wakeup_log(stcb, wake_him, SCTP_NOWAKE_FROM_SACK);
482080fefe0aSRandall Stewart }
4821f8829a4aSRandall Stewart }
4822f8829a4aSRandall Stewart
482342551e99SRandall Stewart if (asoc->fast_retran_loss_recovery && accum_moved) {
482420b07a4dSMichael Tuexen if (SCTP_TSN_GE(asoc->last_acked_seq, asoc->fast_recovery_tsn)) {
4825f8829a4aSRandall Stewart /* Setup so we will exit RFC2582 fast recovery */
4826f8829a4aSRandall Stewart will_exit_fast_recovery = 1;
4827f8829a4aSRandall Stewart }
4828f8829a4aSRandall Stewart }
4829f8829a4aSRandall Stewart /*
4830f8829a4aSRandall Stewart * Check for revoked fragments:
4831f8829a4aSRandall Stewart *
4832f8829a4aSRandall Stewart * if Previous sack - Had no frags then we can't have any revoked if
4833f8829a4aSRandall Stewart * Previous sack - Had frag's then - If we now have frags aka
4834f8829a4aSRandall Stewart * num_seg > 0 call sctp_check_for_revoked() to tell if peer revoked
4835f8829a4aSRandall Stewart * some of them. else - The peer revoked all ACKED fragments, since
4836f8829a4aSRandall Stewart * we had some before and now we have NONE.
4837f8829a4aSRandall Stewart */
4838f8829a4aSRandall Stewart
4839d9c5cfeaSMichael Tuexen if (num_seg) {
4840c105859eSRandall Stewart sctp_check_for_revoked(stcb, asoc, cum_ack, biggest_tsn_acked);
4841d9c5cfeaSMichael Tuexen asoc->saw_sack_with_frags = 1;
4842d9c5cfeaSMichael Tuexen } else if (asoc->saw_sack_with_frags) {
4843f8829a4aSRandall Stewart int cnt_revoked = 0;
4844f8829a4aSRandall Stewart
4845f8829a4aSRandall Stewart /* Peer revoked all dg's marked or acked */
4846f8829a4aSRandall Stewart TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
4847b5c16493SMichael Tuexen if (tp1->sent == SCTP_DATAGRAM_ACKED) {
4848f8829a4aSRandall Stewart tp1->sent = SCTP_DATAGRAM_SENT;
4849b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
4850c105859eSRandall Stewart sctp_misc_ints(SCTP_FLIGHT_LOG_UP_REVOKE,
4851c105859eSRandall Stewart tp1->whoTo->flight_size,
4852c105859eSRandall Stewart tp1->book_size,
48539a8e3088SMichael Tuexen (uint32_t)(uintptr_t)tp1->whoTo,
485449656eefSMichael Tuexen tp1->rec.data.tsn);
485580fefe0aSRandall Stewart }
4856c105859eSRandall Stewart sctp_flight_size_increase(tp1);
4857c105859eSRandall Stewart sctp_total_flight_increase(stcb, tp1);
4858a5d547adSRandall Stewart tp1->rec.data.chunk_was_revoked = 1;
485942551e99SRandall Stewart /*
486042551e99SRandall Stewart * To ensure that this increase in
48614a9ef3f8SMichael Tuexen * flightsize, which is artificial, does not
48624a9ef3f8SMichael Tuexen * throttle the sender, we also increase the
48634a9ef3f8SMichael Tuexen * cwnd artificially.
486442551e99SRandall Stewart */
486542551e99SRandall Stewart tp1->whoTo->cwnd += tp1->book_size;
4866f8829a4aSRandall Stewart cnt_revoked++;
4867f8829a4aSRandall Stewart }
4868f8829a4aSRandall Stewart }
4869f8829a4aSRandall Stewart if (cnt_revoked) {
4870f8829a4aSRandall Stewart reneged_all = 1;
4871f8829a4aSRandall Stewart }
4872f8829a4aSRandall Stewart asoc->saw_sack_with_frags = 0;
4873f8829a4aSRandall Stewart }
4874d9c5cfeaSMichael Tuexen if (num_nr_seg > 0)
4875d9c5cfeaSMichael Tuexen asoc->saw_sack_with_nr_frags = 1;
4876f8829a4aSRandall Stewart else
4877d9c5cfeaSMichael Tuexen asoc->saw_sack_with_nr_frags = 0;
4878f8829a4aSRandall Stewart
4879b54d3a6cSRandall Stewart /* JRS - Use the congestion control given in the CC module */
4880ca85e948SMichael Tuexen if (ecne_seen == 0) {
4881ca85e948SMichael Tuexen TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4882ca85e948SMichael Tuexen if (net->net_ack2 > 0) {
4883ca85e948SMichael Tuexen /*
4884ca85e948SMichael Tuexen * Karn's rule applies to clearing error
4885ca85e948SMichael Tuexen * count, this is optional.
4886ca85e948SMichael Tuexen */
4887ca85e948SMichael Tuexen net->error_count = 0;
48889b2a35b3SMichael Tuexen if ((net->dest_state & SCTP_ADDR_REACHABLE) == 0) {
4889ca85e948SMichael Tuexen /* addr came good */
4890ca85e948SMichael Tuexen net->dest_state |= SCTP_ADDR_REACHABLE;
4891ca85e948SMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
48924b1f78e1SMichael Tuexen 0, (void *)net, SCTP_SO_NOT_LOCKED);
4893ca85e948SMichael Tuexen }
48940053ed28SMichael Tuexen
4895ca85e948SMichael Tuexen if (net == stcb->asoc.primary_destination) {
4896ca85e948SMichael Tuexen if (stcb->asoc.alternate) {
4897b7b84c0eSMichael Tuexen /*
4898b7b84c0eSMichael Tuexen * release the alternate,
4899b7b84c0eSMichael Tuexen * primary is good
4900b7b84c0eSMichael Tuexen */
4901ca85e948SMichael Tuexen sctp_free_remote_addr(stcb->asoc.alternate);
4902ca85e948SMichael Tuexen stcb->asoc.alternate = NULL;
4903ca85e948SMichael Tuexen }
4904ca85e948SMichael Tuexen }
49050053ed28SMichael Tuexen
4906ca85e948SMichael Tuexen if (net->dest_state & SCTP_ADDR_PF) {
4907ca85e948SMichael Tuexen net->dest_state &= ~SCTP_ADDR_PF;
4908b7d130beSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
4909b7d130beSMichael Tuexen stcb->sctp_ep, stcb, net,
491091e04f9eSMichael Tuexen SCTP_FROM_SCTP_INDATA + SCTP_LOC_33);
4911ca85e948SMichael Tuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
4912ca85e948SMichael Tuexen asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net);
4913ca85e948SMichael Tuexen /* Done with this net */
4914ca85e948SMichael Tuexen net->net_ack = 0;
4915ca85e948SMichael Tuexen }
4916ca85e948SMichael Tuexen /* restore any doubled timers */
4917ca85e948SMichael Tuexen net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
4918ca85e948SMichael Tuexen if (net->RTO < stcb->asoc.minrto) {
4919ca85e948SMichael Tuexen net->RTO = stcb->asoc.minrto;
4920ca85e948SMichael Tuexen }
4921ca85e948SMichael Tuexen if (net->RTO > stcb->asoc.maxrto) {
4922ca85e948SMichael Tuexen net->RTO = stcb->asoc.maxrto;
4923ca85e948SMichael Tuexen }
4924ca85e948SMichael Tuexen }
4925ca85e948SMichael Tuexen }
4926b54d3a6cSRandall Stewart asoc->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, accum_moved, reneged_all, will_exit_fast_recovery);
4927ca85e948SMichael Tuexen }
49280053ed28SMichael Tuexen
4929f8829a4aSRandall Stewart if (TAILQ_EMPTY(&asoc->sent_queue)) {
4930f8829a4aSRandall Stewart /* nothing left in-flight */
4931f8829a4aSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4932f8829a4aSRandall Stewart /* stop all timers */
4933f8829a4aSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
4934b7d130beSMichael Tuexen stcb, net,
493591e04f9eSMichael Tuexen SCTP_FROM_SCTP_INDATA + SCTP_LOC_34);
4936f8829a4aSRandall Stewart net->flight_size = 0;
4937f8829a4aSRandall Stewart net->partial_bytes_acked = 0;
4938f8829a4aSRandall Stewart }
4939f8829a4aSRandall Stewart asoc->total_flight = 0;
4940f8829a4aSRandall Stewart asoc->total_flight_count = 0;
4941f8829a4aSRandall Stewart }
49420053ed28SMichael Tuexen
4943f8829a4aSRandall Stewart /**********************************/
4944f8829a4aSRandall Stewart /* Now what about shutdown issues */
4945f8829a4aSRandall Stewart /**********************************/
4946f8829a4aSRandall Stewart if (TAILQ_EMPTY(&asoc->send_queue) && TAILQ_EMPTY(&asoc->sent_queue)) {
4947f8829a4aSRandall Stewart /* nothing left on sendqueue.. consider done */
4948b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) {
4949f8829a4aSRandall Stewart sctp_log_rwnd_set(SCTP_SET_PEER_RWND_VIA_SACK,
4950f8829a4aSRandall Stewart asoc->peers_rwnd, 0, 0, a_rwnd);
495180fefe0aSRandall Stewart }
4952f8829a4aSRandall Stewart asoc->peers_rwnd = a_rwnd;
4953f8829a4aSRandall Stewart if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) {
4954f8829a4aSRandall Stewart /* SWS sender side engages */
4955f8829a4aSRandall Stewart asoc->peers_rwnd = 0;
4956f8829a4aSRandall Stewart }
4957f8829a4aSRandall Stewart /* clean up */
4958f8829a4aSRandall Stewart if ((asoc->stream_queue_cnt == 1) &&
4959f8829a4aSRandall Stewart ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) ||
4960839d21d6SMichael Tuexen (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) &&
4961d1ea5fa9SMichael Tuexen ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc))) {
4962839d21d6SMichael Tuexen SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT);
4963f8829a4aSRandall Stewart }
4964bbc9dfbcSMichael Tuexen if (((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) ||
4965839d21d6SMichael Tuexen (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) &&
4966bbc9dfbcSMichael Tuexen (asoc->stream_queue_cnt == 1) &&
4967bbc9dfbcSMichael Tuexen (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
4968ff1ffd74SMichael Tuexen struct mbuf *op_err;
4969f8829a4aSRandall Stewart
4970f8829a4aSRandall Stewart *abort_now = 1;
4971f8829a4aSRandall Stewart /* XXX */
4972ff1ffd74SMichael Tuexen op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
497391e04f9eSMichael Tuexen stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_35;
4974105b68b4SMichael Tuexen sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED);
4975f8829a4aSRandall Stewart return;
4976bbc9dfbcSMichael Tuexen }
4977bbc9dfbcSMichael Tuexen if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) &&
4978bbc9dfbcSMichael Tuexen (asoc->stream_queue_cnt == 0)) {
4979ca85e948SMichael Tuexen struct sctp_nets *netp;
4980ca85e948SMichael Tuexen
4981839d21d6SMichael Tuexen if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
4982839d21d6SMichael Tuexen (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
4983f8829a4aSRandall Stewart SCTP_STAT_DECR_GAUGE32(sctps_currestab);
4984f42a358aSRandall Stewart }
4985839d21d6SMichael Tuexen SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT);
4986f8829a4aSRandall Stewart sctp_stop_timers_for_shutdown(stcb);
4987c39cfa1fSMichael Tuexen if (asoc->alternate) {
4988c39cfa1fSMichael Tuexen netp = asoc->alternate;
4989c39cfa1fSMichael Tuexen } else {
4990c39cfa1fSMichael Tuexen netp = asoc->primary_destination;
4991c39cfa1fSMichael Tuexen }
4992ca85e948SMichael Tuexen sctp_send_shutdown(stcb, netp);
4993f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
4994ca85e948SMichael Tuexen stcb->sctp_ep, stcb, netp);
4995f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
49966fb7b4fbSMichael Tuexen stcb->sctp_ep, stcb, NULL);
4997f8829a4aSRandall Stewart return;
4998839d21d6SMichael Tuexen } else if ((SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED) &&
4999f8829a4aSRandall Stewart (asoc->stream_queue_cnt == 0)) {
5000ca85e948SMichael Tuexen struct sctp_nets *netp;
5001ca85e948SMichael Tuexen
5002f8829a4aSRandall Stewart SCTP_STAT_DECR_GAUGE32(sctps_currestab);
5003839d21d6SMichael Tuexen SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_ACK_SENT);
500412af6654SMichael Tuexen sctp_stop_timers_for_shutdown(stcb);
5005c39cfa1fSMichael Tuexen if (asoc->alternate) {
5006c39cfa1fSMichael Tuexen netp = asoc->alternate;
5007c39cfa1fSMichael Tuexen } else {
5008c39cfa1fSMichael Tuexen netp = asoc->primary_destination;
5009c39cfa1fSMichael Tuexen }
5010c39cfa1fSMichael Tuexen sctp_send_shutdown_ack(stcb, netp);
5011f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK,
5012ca85e948SMichael Tuexen stcb->sctp_ep, stcb, netp);
5013f8829a4aSRandall Stewart return;
5014f8829a4aSRandall Stewart }
5015f8829a4aSRandall Stewart }
5016f8829a4aSRandall Stewart /*
5017f8829a4aSRandall Stewart * Now here we are going to recycle net_ack for a different use...
5018f8829a4aSRandall Stewart * HEADS UP.
5019f8829a4aSRandall Stewart */
5020f8829a4aSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
5021f8829a4aSRandall Stewart net->net_ack = 0;
5022f8829a4aSRandall Stewart }
5023f8829a4aSRandall Stewart
5024f8829a4aSRandall Stewart /*
5025f8829a4aSRandall Stewart * CMT DAC algorithm: If SACK DAC flag was 0, then no extra marking
5026f8829a4aSRandall Stewart * to be done. Setting this_sack_lowest_newack to the cum_ack will
5027f8829a4aSRandall Stewart * automatically ensure that.
5028f8829a4aSRandall Stewart */
50297c99d56fSMichael Tuexen if ((asoc->sctp_cmt_on_off > 0) &&
503020083c2eSMichael Tuexen SCTP_BASE_SYSCTL(sctp_cmt_use_dac) &&
503120083c2eSMichael Tuexen (cmt_dac_flag == 0)) {
5032f8829a4aSRandall Stewart this_sack_lowest_newack = cum_ack;
5033f8829a4aSRandall Stewart }
5034cd554309SMichael Tuexen if ((num_seg > 0) || (num_nr_seg > 0)) {
5035f8829a4aSRandall Stewart sctp_strike_gap_ack_chunks(stcb, asoc, biggest_tsn_acked,
5036f8829a4aSRandall Stewart biggest_tsn_newly_acked, this_sack_lowest_newack, accum_moved);
5037f8829a4aSRandall Stewart }
5038b54d3a6cSRandall Stewart /* JRS - Use the congestion control given in the CC module */
5039b54d3a6cSRandall Stewart asoc->cc_functions.sctp_cwnd_update_after_fr(stcb, asoc);
5040f8829a4aSRandall Stewart
5041f8829a4aSRandall Stewart /* Now are we exiting loss recovery ? */
5042f8829a4aSRandall Stewart if (will_exit_fast_recovery) {
5043f8829a4aSRandall Stewart /* Ok, we must exit fast recovery */
5044f8829a4aSRandall Stewart asoc->fast_retran_loss_recovery = 0;
5045f8829a4aSRandall Stewart }
5046f8829a4aSRandall Stewart if ((asoc->sat_t3_loss_recovery) &&
504720b07a4dSMichael Tuexen SCTP_TSN_GE(asoc->last_acked_seq, asoc->sat_t3_recovery_tsn)) {
5048f8829a4aSRandall Stewart /* end satellite t3 loss recovery */
5049f8829a4aSRandall Stewart asoc->sat_t3_loss_recovery = 0;
5050f8829a4aSRandall Stewart }
505142551e99SRandall Stewart /*
505242551e99SRandall Stewart * CMT Fast recovery
505342551e99SRandall Stewart */
5054f8829a4aSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
5055f8829a4aSRandall Stewart if (net->will_exit_fast_recovery) {
5056f8829a4aSRandall Stewart /* Ok, we must exit fast recovery */
5057f8829a4aSRandall Stewart net->fast_retran_loss_recovery = 0;
5058f8829a4aSRandall Stewart }
5059f8829a4aSRandall Stewart }
5060f8829a4aSRandall Stewart
5061f8829a4aSRandall Stewart /* Adjust and set the new rwnd value */
5062b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) {
5063f8829a4aSRandall Stewart sctp_log_rwnd_set(SCTP_SET_PEER_RWND_VIA_SACK,
506444fbe462SRandall Stewart asoc->peers_rwnd, asoc->total_flight, (asoc->total_flight_count * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)), a_rwnd);
506580fefe0aSRandall Stewart }
5066f8829a4aSRandall Stewart asoc->peers_rwnd = sctp_sbspace_sub(a_rwnd,
506744fbe462SRandall Stewart (uint32_t)(asoc->total_flight + (asoc->total_flight_count * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh))));
5068f8829a4aSRandall Stewart if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) {
5069f8829a4aSRandall Stewart /* SWS sender side engages */
5070f8829a4aSRandall Stewart asoc->peers_rwnd = 0;
5071f8829a4aSRandall Stewart }
50725e54f665SRandall Stewart if (asoc->peers_rwnd > old_rwnd) {
50735e54f665SRandall Stewart win_probe_recovery = 1;
50745e54f665SRandall Stewart }
50750053ed28SMichael Tuexen
5076f8829a4aSRandall Stewart /*
5077f8829a4aSRandall Stewart * Now we must setup so we have a timer up for anyone with
5078f8829a4aSRandall Stewart * outstanding data.
5079f8829a4aSRandall Stewart */
5080bff64a4dSRandall Stewart done_once = 0;
5081a5d547adSRandall Stewart again:
5082a5d547adSRandall Stewart j = 0;
5083f8829a4aSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
50845e54f665SRandall Stewart if (win_probe_recovery && (net->window_probe)) {
5085c105859eSRandall Stewart win_probe_recovered = 1;
50865e54f665SRandall Stewart /*-
50875e54f665SRandall Stewart * Find first chunk that was used with
50885e54f665SRandall Stewart * window probe and clear the event. Put
50895e54f665SRandall Stewart * it back into the send queue as if has
50905e54f665SRandall Stewart * not been sent.
50915e54f665SRandall Stewart */
50925e54f665SRandall Stewart TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
50935e54f665SRandall Stewart if (tp1->window_probe) {
50947215cc1bSMichael Tuexen sctp_window_probe_recovery(stcb, asoc, tp1);
50955e54f665SRandall Stewart break;
50965e54f665SRandall Stewart }
50975e54f665SRandall Stewart }
50985e54f665SRandall Stewart }
5099f8829a4aSRandall Stewart if (net->flight_size) {
5100a5d547adSRandall Stewart j++;
5101cd554309SMichael Tuexen if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
5102f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SEND,
5103f8829a4aSRandall Stewart stcb->sctp_ep, stcb, net);
5104cd554309SMichael Tuexen }
51055171328bSRandall Stewart if (net->window_probe) {
5106cd554309SMichael Tuexen net->window_probe = 0;
51075171328bSRandall Stewart }
5108c105859eSRandall Stewart } else {
51095171328bSRandall Stewart if (net->window_probe) {
5110b7b84c0eSMichael Tuexen /*
5111b7b84c0eSMichael Tuexen * In window probes we must assure a timer
5112b7b84c0eSMichael Tuexen * is still running there
5113b7b84c0eSMichael Tuexen */
51145171328bSRandall Stewart if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
51155171328bSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SEND,
51165171328bSRandall Stewart stcb->sctp_ep, stcb, net);
51175171328bSRandall Stewart }
51185171328bSRandall Stewart } else if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
5119c105859eSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
5120c105859eSRandall Stewart stcb, net,
512191e04f9eSMichael Tuexen SCTP_FROM_SCTP_INDATA + SCTP_LOC_36);
5122c105859eSRandall Stewart }
5123f8829a4aSRandall Stewart }
5124f8829a4aSRandall Stewart }
5125bff64a4dSRandall Stewart if ((j == 0) &&
5126bff64a4dSRandall Stewart (!TAILQ_EMPTY(&asoc->sent_queue)) &&
5127bff64a4dSRandall Stewart (asoc->sent_queue_retran_cnt == 0) &&
5128c105859eSRandall Stewart (win_probe_recovered == 0) &&
5129bff64a4dSRandall Stewart (done_once == 0)) {
51300c0982b8SRandall Stewart /*
51310c0982b8SRandall Stewart * huh, this should not happen unless all packets are
51320c0982b8SRandall Stewart * PR-SCTP and marked to skip of course.
51330c0982b8SRandall Stewart */
51340c0982b8SRandall Stewart if (sctp_fs_audit(asoc)) {
5135a5d547adSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
5136a5d547adSRandall Stewart net->flight_size = 0;
5137a5d547adSRandall Stewart }
5138a5d547adSRandall Stewart asoc->total_flight = 0;
5139a5d547adSRandall Stewart asoc->total_flight_count = 0;
5140a5d547adSRandall Stewart asoc->sent_queue_retran_cnt = 0;
5141a5d547adSRandall Stewart TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
5142a5d547adSRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND) {
5143c105859eSRandall Stewart sctp_flight_size_increase(tp1);
5144c105859eSRandall Stewart sctp_total_flight_increase(stcb, tp1);
5145a5d547adSRandall Stewart } else if (tp1->sent == SCTP_DATAGRAM_RESEND) {
5146791437b5SRandall Stewart sctp_ucount_incr(asoc->sent_queue_retran_cnt);
5147a5d547adSRandall Stewart }
5148a5d547adSRandall Stewart }
51490c0982b8SRandall Stewart }
5150bff64a4dSRandall Stewart done_once = 1;
5151a5d547adSRandall Stewart goto again;
5152a5d547adSRandall Stewart }
5153cd554309SMichael Tuexen /*********************************************/
5154cd554309SMichael Tuexen /* Here we perform PR-SCTP procedures */
5155cd554309SMichael Tuexen /* (section 4.2) */
5156cd554309SMichael Tuexen /*********************************************/
5157cd554309SMichael Tuexen /* C1. update advancedPeerAckPoint */
515820b07a4dSMichael Tuexen if (SCTP_TSN_GT(cum_ack, asoc->advanced_peer_ack_point)) {
5159dfb11ef8SRandall Stewart asoc->advanced_peer_ack_point = cum_ack;
5160dfb11ef8SRandall Stewart }
5161830d754dSRandall Stewart /* C2. try to further move advancedPeerAckPoint ahead */
5162dd973b0eSMichael Tuexen if ((asoc->prsctp_supported) && (asoc->pr_sctp_cnt > 0)) {
5163830d754dSRandall Stewart struct sctp_tmit_chunk *lchk;
5164830d754dSRandall Stewart uint32_t old_adv_peer_ack_point;
5165830d754dSRandall Stewart
5166830d754dSRandall Stewart old_adv_peer_ack_point = asoc->advanced_peer_ack_point;
5167830d754dSRandall Stewart lchk = sctp_try_advance_peer_ack_point(stcb, asoc);
5168830d754dSRandall Stewart /* C3. See if we need to send a Fwd-TSN */
516920b07a4dSMichael Tuexen if (SCTP_TSN_GT(asoc->advanced_peer_ack_point, cum_ack)) {
5170830d754dSRandall Stewart /*
5171493d8e5aSRandall Stewart * ISSUE with ECN, see FWD-TSN processing.
5172830d754dSRandall Stewart */
51730c0982b8SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
51740c0982b8SRandall Stewart sctp_misc_ints(SCTP_FWD_TSN_CHECK,
51750c0982b8SRandall Stewart 0xee, cum_ack, asoc->advanced_peer_ack_point,
51760c0982b8SRandall Stewart old_adv_peer_ack_point);
51770c0982b8SRandall Stewart }
517820b07a4dSMichael Tuexen if (SCTP_TSN_GT(asoc->advanced_peer_ack_point, old_adv_peer_ack_point)) {
5179830d754dSRandall Stewart send_forward_tsn(stcb, asoc);
51800c0982b8SRandall Stewart } else if (lchk) {
51810c0982b8SRandall Stewart /* try to FR fwd-tsn's that get lost too */
518244fbe462SRandall Stewart if (lchk->rec.data.fwd_tsn_cnt >= 3) {
51830c0982b8SRandall Stewart send_forward_tsn(stcb, asoc);
51840c0982b8SRandall Stewart }
5185830d754dSRandall Stewart }
5186830d754dSRandall Stewart }
5187efd5e692SMichael Tuexen for (; lchk != NULL; lchk = TAILQ_NEXT(lchk, sctp_next)) {
5188efd5e692SMichael Tuexen if (lchk->whoTo != NULL) {
5189efd5e692SMichael Tuexen break;
5190efd5e692SMichael Tuexen }
5191efd5e692SMichael Tuexen }
5192efd5e692SMichael Tuexen if (lchk != NULL) {
5193830d754dSRandall Stewart /* Assure a timer is up */
5194830d754dSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SEND,
5195830d754dSRandall Stewart stcb->sctp_ep, stcb, lchk->whoTo);
5196830d754dSRandall Stewart }
5197830d754dSRandall Stewart }
5198b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_RWND_LOGGING_ENABLE) {
5199f8829a4aSRandall Stewart sctp_misc_ints(SCTP_SACK_RWND_UPDATE,
5200f8829a4aSRandall Stewart a_rwnd,
5201f8829a4aSRandall Stewart stcb->asoc.peers_rwnd,
5202f8829a4aSRandall Stewart stcb->asoc.total_flight,
5203f8829a4aSRandall Stewart stcb->asoc.total_output_queue_size);
520480fefe0aSRandall Stewart }
5205f8829a4aSRandall Stewart }
5206f8829a4aSRandall Stewart
5207f8829a4aSRandall Stewart void
sctp_update_acked(struct sctp_tcb * stcb,struct sctp_shutdown_chunk * cp,int * abort_flag)52087215cc1bSMichael Tuexen sctp_update_acked(struct sctp_tcb *stcb, struct sctp_shutdown_chunk *cp, int *abort_flag)
5209f8829a4aSRandall Stewart {
5210f8829a4aSRandall Stewart /* Copy cum-ack */
5211f8829a4aSRandall Stewart uint32_t cum_ack, a_rwnd;
5212f8829a4aSRandall Stewart
5213f8829a4aSRandall Stewart cum_ack = ntohl(cp->cumulative_tsn_ack);
5214f8829a4aSRandall Stewart /* Arrange so a_rwnd does NOT change */
5215f8829a4aSRandall Stewart a_rwnd = stcb->asoc.peers_rwnd + stcb->asoc.total_flight;
5216f8829a4aSRandall Stewart
5217f8829a4aSRandall Stewart /* Now call the express sack handling */
5218899288aeSRandall Stewart sctp_express_handle_sack(stcb, cum_ack, a_rwnd, abort_flag, 0);
5219f8829a4aSRandall Stewart }
5220f8829a4aSRandall Stewart
5221f8829a4aSRandall Stewart static void
sctp_kick_prsctp_reorder_queue(struct sctp_tcb * stcb,struct sctp_stream_in * strmin)5222f8829a4aSRandall Stewart sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb,
5223f8829a4aSRandall Stewart struct sctp_stream_in *strmin)
5224f8829a4aSRandall Stewart {
522528cd0699SMichael Tuexen struct sctp_queued_to_read *control, *ncontrol;
5226f8829a4aSRandall Stewart struct sctp_association *asoc;
522749656eefSMichael Tuexen uint32_t mid;
522849656eefSMichael Tuexen int need_reasm_check = 0;
5229f8829a4aSRandall Stewart
52300d15140dSMichael Tuexen KASSERT(stcb != NULL, ("stcb == NULL"));
52310d15140dSMichael Tuexen SCTP_TCB_LOCK_ASSERT(stcb);
52320d15140dSMichael Tuexen SCTP_INP_READ_LOCK_ASSERT(stcb->sctp_ep);
52330d15140dSMichael Tuexen
5234f8829a4aSRandall Stewart asoc = &stcb->asoc;
523549656eefSMichael Tuexen mid = strmin->last_mid_delivered;
5236f8829a4aSRandall Stewart /*
5237f8829a4aSRandall Stewart * First deliver anything prior to and including the stream no that
523844249214SRandall Stewart * came in.
5239f8829a4aSRandall Stewart */
524028cd0699SMichael Tuexen TAILQ_FOREACH_SAFE(control, &strmin->inqueue, next_instrm, ncontrol) {
524128cd0699SMichael Tuexen if (SCTP_MID_GE(asoc->idata_supported, mid, control->mid)) {
5242f8829a4aSRandall Stewart /* this is deliverable now */
524328cd0699SMichael Tuexen if (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
524428cd0699SMichael Tuexen if (control->on_strm_q) {
524528cd0699SMichael Tuexen if (control->on_strm_q == SCTP_ON_ORDERED) {
524628cd0699SMichael Tuexen TAILQ_REMOVE(&strmin->inqueue, control, next_instrm);
524728cd0699SMichael Tuexen } else if (control->on_strm_q == SCTP_ON_UNORDERED) {
524828cd0699SMichael Tuexen TAILQ_REMOVE(&strmin->uno_inqueue, control, next_instrm);
524998d5fd97SMichael Tuexen #ifdef INVARIANTS
525044249214SRandall Stewart } else {
525144249214SRandall Stewart panic("strmin: %p ctl: %p unknown %d",
525228cd0699SMichael Tuexen strmin, control, control->on_strm_q);
525398d5fd97SMichael Tuexen #endif
525444249214SRandall Stewart }
525528cd0699SMichael Tuexen control->on_strm_q = 0;
525644249214SRandall Stewart }
5257f8829a4aSRandall Stewart /* subtract pending on streams */
525828cd0699SMichael Tuexen if (asoc->size_on_all_streams >= control->length) {
525928cd0699SMichael Tuexen asoc->size_on_all_streams -= control->length;
526028cd0699SMichael Tuexen } else {
526128cd0699SMichael Tuexen #ifdef INVARIANTS
526228cd0699SMichael Tuexen panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
526328cd0699SMichael Tuexen #else
526428cd0699SMichael Tuexen asoc->size_on_all_streams = 0;
526528cd0699SMichael Tuexen #endif
526628cd0699SMichael Tuexen }
5267f8829a4aSRandall Stewart sctp_ucount_decr(asoc->cnt_on_all_streams);
5268f8829a4aSRandall Stewart /* deliver it to at least the delivery-q */
5269f8829a4aSRandall Stewart if (stcb->sctp_socket) {
527028cd0699SMichael Tuexen sctp_mark_non_revokable(asoc, control->sinfo_tsn);
52710d15140dSMichael Tuexen sctp_add_to_readq(stcb->sctp_ep, stcb, control,
52720d15140dSMichael Tuexen &stcb->sctp_socket->so_rcv, 1,
52730d15140dSMichael Tuexen SCTP_READ_LOCK_HELD, SCTP_SO_NOT_LOCKED);
527444249214SRandall Stewart }
527544249214SRandall Stewart } else {
527644249214SRandall Stewart /* Its a fragmented message */
527728cd0699SMichael Tuexen if (control->first_frag_seen) {
5278b7b84c0eSMichael Tuexen /*
5279b7b84c0eSMichael Tuexen * Make it so this is next to
5280b7b84c0eSMichael Tuexen * deliver, we restore later
5281b7b84c0eSMichael Tuexen */
528228cd0699SMichael Tuexen strmin->last_mid_delivered = control->mid - 1;
528344249214SRandall Stewart need_reasm_check = 1;
528444249214SRandall Stewart break;
528544249214SRandall Stewart }
5286f8829a4aSRandall Stewart }
5287f8829a4aSRandall Stewart } else {
5288f8829a4aSRandall Stewart /* no more delivery now. */
5289f8829a4aSRandall Stewart break;
5290f8829a4aSRandall Stewart }
5291f8829a4aSRandall Stewart }
529244249214SRandall Stewart if (need_reasm_check) {
529344249214SRandall Stewart int ret;
529444249214SRandall Stewart
5295d1ea5fa9SMichael Tuexen ret = sctp_deliver_reasm_check(stcb, &stcb->asoc, strmin, SCTP_READ_LOCK_HELD);
529649656eefSMichael Tuexen if (SCTP_MID_GT(asoc->idata_supported, mid, strmin->last_mid_delivered)) {
529744249214SRandall Stewart /* Restore the next to deliver unless we are ahead */
529849656eefSMichael Tuexen strmin->last_mid_delivered = mid;
529944249214SRandall Stewart }
530044249214SRandall Stewart if (ret == 0) {
530144249214SRandall Stewart /* Left the front Partial one on */
530244249214SRandall Stewart return;
530344249214SRandall Stewart }
530444249214SRandall Stewart need_reasm_check = 0;
530544249214SRandall Stewart }
5306f8829a4aSRandall Stewart /*
5307f8829a4aSRandall Stewart * now we must deliver things in queue the normal way if any are
5308f8829a4aSRandall Stewart * now ready.
5309f8829a4aSRandall Stewart */
531049656eefSMichael Tuexen mid = strmin->last_mid_delivered + 1;
531128cd0699SMichael Tuexen TAILQ_FOREACH_SAFE(control, &strmin->inqueue, next_instrm, ncontrol) {
531228cd0699SMichael Tuexen if (SCTP_MID_EQ(asoc->idata_supported, mid, control->mid)) {
531328cd0699SMichael Tuexen if (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
5314f8829a4aSRandall Stewart /* this is deliverable now */
531528cd0699SMichael Tuexen if (control->on_strm_q) {
531628cd0699SMichael Tuexen if (control->on_strm_q == SCTP_ON_ORDERED) {
531728cd0699SMichael Tuexen TAILQ_REMOVE(&strmin->inqueue, control, next_instrm);
531828cd0699SMichael Tuexen } else if (control->on_strm_q == SCTP_ON_UNORDERED) {
531928cd0699SMichael Tuexen TAILQ_REMOVE(&strmin->uno_inqueue, control, next_instrm);
532098d5fd97SMichael Tuexen #ifdef INVARIANTS
532144249214SRandall Stewart } else {
532244249214SRandall Stewart panic("strmin: %p ctl: %p unknown %d",
532328cd0699SMichael Tuexen strmin, control, control->on_strm_q);
532498d5fd97SMichael Tuexen #endif
532544249214SRandall Stewart }
532628cd0699SMichael Tuexen control->on_strm_q = 0;
532744249214SRandall Stewart }
5328f8829a4aSRandall Stewart /* subtract pending on streams */
532928cd0699SMichael Tuexen if (asoc->size_on_all_streams >= control->length) {
533028cd0699SMichael Tuexen asoc->size_on_all_streams -= control->length;
533128cd0699SMichael Tuexen } else {
533228cd0699SMichael Tuexen #ifdef INVARIANTS
533328cd0699SMichael Tuexen panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
533428cd0699SMichael Tuexen #else
533528cd0699SMichael Tuexen asoc->size_on_all_streams = 0;
533628cd0699SMichael Tuexen #endif
533728cd0699SMichael Tuexen }
5338f8829a4aSRandall Stewart sctp_ucount_decr(asoc->cnt_on_all_streams);
5339f8829a4aSRandall Stewart /* deliver it to at least the delivery-q */
534028cd0699SMichael Tuexen strmin->last_mid_delivered = control->mid;
5341f8829a4aSRandall Stewart if (stcb->sctp_socket) {
534228cd0699SMichael Tuexen sctp_mark_non_revokable(asoc, control->sinfo_tsn);
53430d15140dSMichael Tuexen sctp_add_to_readq(stcb->sctp_ep, stcb, control,
534444249214SRandall Stewart &stcb->sctp_socket->so_rcv, 1,
534544249214SRandall Stewart SCTP_READ_LOCK_HELD, SCTP_SO_NOT_LOCKED);
5346f8829a4aSRandall Stewart }
534749656eefSMichael Tuexen mid = strmin->last_mid_delivered + 1;
5348f8829a4aSRandall Stewart } else {
534944249214SRandall Stewart /* Its a fragmented message */
535028cd0699SMichael Tuexen if (control->first_frag_seen) {
5351b7b84c0eSMichael Tuexen /*
5352b7b84c0eSMichael Tuexen * Make it so this is next to
5353b7b84c0eSMichael Tuexen * deliver
5354b7b84c0eSMichael Tuexen */
535528cd0699SMichael Tuexen strmin->last_mid_delivered = control->mid - 1;
535644249214SRandall Stewart need_reasm_check = 1;
5357f8829a4aSRandall Stewart break;
5358f8829a4aSRandall Stewart }
5359f8829a4aSRandall Stewart }
536044249214SRandall Stewart } else {
536144249214SRandall Stewart break;
536244249214SRandall Stewart }
536344249214SRandall Stewart }
536444249214SRandall Stewart if (need_reasm_check) {
5365d1ea5fa9SMichael Tuexen (void)sctp_deliver_reasm_check(stcb, &stcb->asoc, strmin, SCTP_READ_LOCK_HELD);
536644249214SRandall Stewart }
5367f8829a4aSRandall Stewart }
5368f8829a4aSRandall Stewart
53698933fa13SRandall Stewart static void
sctp_flush_reassm_for_str_seq(struct sctp_tcb * stcb,struct sctp_association * asoc,struct sctp_stream_in * strm,struct sctp_queued_to_read * control,int ordered,uint32_t cumtsn)53708933fa13SRandall Stewart sctp_flush_reassm_for_str_seq(struct sctp_tcb *stcb,
5371b6734d8fSMichael Tuexen struct sctp_association *asoc, struct sctp_stream_in *strm,
5372b6734d8fSMichael Tuexen struct sctp_queued_to_read *control, int ordered, uint32_t cumtsn)
53738933fa13SRandall Stewart {
53744a9ef3f8SMichael Tuexen struct sctp_tmit_chunk *chk, *nchk;
53758933fa13SRandall Stewart
53768933fa13SRandall Stewart /*
537744249214SRandall Stewart * For now large messages held on the stream reasm that are complete
53784a9ef3f8SMichael Tuexen * will be tossed too. We could in theory do more work to spin
53794a9ef3f8SMichael Tuexen * through and stop after dumping one msg aka seeing the start of a
53804a9ef3f8SMichael Tuexen * new msg at the head, and call the delivery function... to see if
53814a9ef3f8SMichael Tuexen * it can be delivered... But for now we just dump everything on the
53824a9ef3f8SMichael Tuexen * queue.
53838933fa13SRandall Stewart */
53840d15140dSMichael Tuexen
53850d15140dSMichael Tuexen KASSERT(stcb != NULL, ("stcb == NULL"));
53860d15140dSMichael Tuexen SCTP_TCB_LOCK_ASSERT(stcb);
53870d15140dSMichael Tuexen SCTP_INP_READ_LOCK_ASSERT(stcb->sctp_ep);
53880d15140dSMichael Tuexen
53898f269b82SMichael Tuexen if (!asoc->idata_supported && !ordered &&
53908f269b82SMichael Tuexen control->first_frag_seen &&
53918f269b82SMichael Tuexen SCTP_TSN_GT(control->fsn_included, cumtsn)) {
53925cb91655SMichael Tuexen return;
53935cb91655SMichael Tuexen }
539444249214SRandall Stewart TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) {
539544249214SRandall Stewart /* Purge hanging chunks */
53961d1b4bceSMichael Tuexen if (!asoc->idata_supported && !ordered) {
539749656eefSMichael Tuexen if (SCTP_TSN_GT(chk->rec.data.tsn, cumtsn)) {
5398d1ea5fa9SMichael Tuexen break;
5399d1ea5fa9SMichael Tuexen }
5400d1ea5fa9SMichael Tuexen }
540144249214SRandall Stewart TAILQ_REMOVE(&control->reasm, chk, sctp_next);
540228cd0699SMichael Tuexen if (asoc->size_on_reasm_queue >= chk->send_size) {
54038933fa13SRandall Stewart asoc->size_on_reasm_queue -= chk->send_size;
540428cd0699SMichael Tuexen } else {
540528cd0699SMichael Tuexen #ifdef INVARIANTS
540628cd0699SMichael Tuexen panic("size_on_reasm_queue = %u smaller than chunk length %u", asoc->size_on_reasm_queue, chk->send_size);
540728cd0699SMichael Tuexen #else
540828cd0699SMichael Tuexen asoc->size_on_reasm_queue = 0;
540928cd0699SMichael Tuexen #endif
541028cd0699SMichael Tuexen }
54118933fa13SRandall Stewart sctp_ucount_decr(asoc->cnt_on_reasm_queue);
54128933fa13SRandall Stewart if (chk->data) {
54138933fa13SRandall Stewart sctp_m_freem(chk->data);
54148933fa13SRandall Stewart chk->data = NULL;
54158933fa13SRandall Stewart }
5416689e6a5fSMichael Tuexen sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
54178933fa13SRandall Stewart }
5418d1ea5fa9SMichael Tuexen if (!TAILQ_EMPTY(&control->reasm)) {
5419*101a0f09SMichael Tuexen KASSERT(!asoc->idata_supported,
5420*101a0f09SMichael Tuexen ("Reassembly queue not empty for I-DATA"));
5421*101a0f09SMichael Tuexen KASSERT(!ordered,
5422*101a0f09SMichael Tuexen ("Reassembly queue not empty for ordered data"));
5423d1ea5fa9SMichael Tuexen if (control->data) {
5424d1ea5fa9SMichael Tuexen sctp_m_freem(control->data);
5425d1ea5fa9SMichael Tuexen control->data = NULL;
5426d1ea5fa9SMichael Tuexen }
5427*101a0f09SMichael Tuexen control->fsn_included = 0xffffffff;
5428*101a0f09SMichael Tuexen control->first_frag_seen = 0;
5429*101a0f09SMichael Tuexen control->last_frag_seen = 0;
5430*101a0f09SMichael Tuexen if (control->on_read_q) {
5431*101a0f09SMichael Tuexen /*
5432*101a0f09SMichael Tuexen * We have to purge it from there, hopefully this
5433*101a0f09SMichael Tuexen * will work :-)
5434*101a0f09SMichael Tuexen */
5435*101a0f09SMichael Tuexen TAILQ_REMOVE(&stcb->sctp_ep->read_queue, control, next);
5436*101a0f09SMichael Tuexen control->on_read_q = 0;
5437*101a0f09SMichael Tuexen }
5438d1ea5fa9SMichael Tuexen chk = TAILQ_FIRST(&control->reasm);
5439d1ea5fa9SMichael Tuexen if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
5440d1ea5fa9SMichael Tuexen TAILQ_REMOVE(&control->reasm, chk, sctp_next);
5441d1ea5fa9SMichael Tuexen sctp_add_chk_to_control(control, strm, stcb, asoc,
5442d1ea5fa9SMichael Tuexen chk, SCTP_READ_LOCK_HELD);
5443d1ea5fa9SMichael Tuexen }
5444d1ea5fa9SMichael Tuexen sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_HELD);
5445d1ea5fa9SMichael Tuexen return;
5446d1ea5fa9SMichael Tuexen }
5447d1ea5fa9SMichael Tuexen if (control->on_strm_q == SCTP_ON_ORDERED) {
544844249214SRandall Stewart TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
544928cd0699SMichael Tuexen if (asoc->size_on_all_streams >= control->length) {
545028cd0699SMichael Tuexen asoc->size_on_all_streams -= control->length;
545128cd0699SMichael Tuexen } else {
545228cd0699SMichael Tuexen #ifdef INVARIANTS
545328cd0699SMichael Tuexen panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
545428cd0699SMichael Tuexen #else
545528cd0699SMichael Tuexen asoc->size_on_all_streams = 0;
545628cd0699SMichael Tuexen #endif
545728cd0699SMichael Tuexen }
545828cd0699SMichael Tuexen sctp_ucount_decr(asoc->cnt_on_all_streams);
5459d1ea5fa9SMichael Tuexen control->on_strm_q = 0;
5460d1ea5fa9SMichael Tuexen } else if (control->on_strm_q == SCTP_ON_UNORDERED) {
5461d1ea5fa9SMichael Tuexen TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
5462d1ea5fa9SMichael Tuexen control->on_strm_q = 0;
5463d1ea5fa9SMichael Tuexen #ifdef INVARIANTS
5464d1ea5fa9SMichael Tuexen } else if (control->on_strm_q) {
5465d1ea5fa9SMichael Tuexen panic("strm: %p ctl: %p unknown %d",
5466d1ea5fa9SMichael Tuexen strm, control, control->on_strm_q);
5467d1ea5fa9SMichael Tuexen #endif
5468d1ea5fa9SMichael Tuexen }
5469d1ea5fa9SMichael Tuexen control->on_strm_q = 0;
547044249214SRandall Stewart if (control->on_read_q == 0) {
547144249214SRandall Stewart sctp_free_remote_addr(control->whoFrom);
547244249214SRandall Stewart if (control->data) {
547344249214SRandall Stewart sctp_m_freem(control->data);
547444249214SRandall Stewart control->data = NULL;
547544249214SRandall Stewart }
547644249214SRandall Stewart sctp_free_a_readq(stcb, control);
54778933fa13SRandall Stewart }
54788933fa13SRandall Stewart }
54798933fa13SRandall Stewart
5480f8829a4aSRandall Stewart void
sctp_handle_forward_tsn(struct sctp_tcb * stcb,struct sctp_forward_tsn_chunk * fwd,int * abort_flag,struct mbuf * m,int offset)5481f8829a4aSRandall Stewart sctp_handle_forward_tsn(struct sctp_tcb *stcb,
5482b5c16493SMichael Tuexen struct sctp_forward_tsn_chunk *fwd,
5483b5c16493SMichael Tuexen int *abort_flag, struct mbuf *m, int offset)
5484f8829a4aSRandall Stewart {
5485f8829a4aSRandall Stewart /* The pr-sctp fwd tsn */
5486f8829a4aSRandall Stewart /*
5487f8829a4aSRandall Stewart * here we will perform all the data receiver side steps for
5488f8829a4aSRandall Stewart * processing FwdTSN, as required in by pr-sctp draft:
5489f8829a4aSRandall Stewart *
5490f8829a4aSRandall Stewart * Assume we get FwdTSN(x):
5491f8829a4aSRandall Stewart *
54925b495f17SMichael Tuexen * 1) update local cumTSN to x 2) try to further advance cumTSN to x
54935b495f17SMichael Tuexen * + others we have 3) examine and update re-ordering queue on
5494f8829a4aSRandall Stewart * pr-in-streams 4) clean up re-assembly queue 5) Send a sack to
5495f8829a4aSRandall Stewart * report where we are.
5496f8829a4aSRandall Stewart */
5497f8829a4aSRandall Stewart struct sctp_association *asoc;
54987898f408SRandall Stewart uint32_t new_cum_tsn, gap;
54997215cc1bSMichael Tuexen unsigned int i, fwd_sz, m_size;
5500f8829a4aSRandall Stewart struct sctp_stream_in *strm;
5501749a7fb5SMichael Tuexen struct sctp_queued_to_read *control, *ncontrol;
5502f8829a4aSRandall Stewart
5503f8829a4aSRandall Stewart asoc = &stcb->asoc;
5504f8829a4aSRandall Stewart if ((fwd_sz = ntohs(fwd->ch.chunk_length)) < sizeof(struct sctp_forward_tsn_chunk)) {
5505ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_INDATA1,
5506ad81507eSRandall Stewart "Bad size too small/big fwd-tsn\n");
5507f8829a4aSRandall Stewart return;
5508f8829a4aSRandall Stewart }
5509f8829a4aSRandall Stewart m_size = (stcb->asoc.mapping_array_size << 3);
5510f8829a4aSRandall Stewart /*************************************************************/
5511f8829a4aSRandall Stewart /* 1. Here we update local cumTSN and shift the bitmap array */
5512f8829a4aSRandall Stewart /*************************************************************/
5513f8829a4aSRandall Stewart new_cum_tsn = ntohl(fwd->new_cumulative_tsn);
5514f8829a4aSRandall Stewart
551520b07a4dSMichael Tuexen if (SCTP_TSN_GE(asoc->cumulative_tsn, new_cum_tsn)) {
5516f8829a4aSRandall Stewart /* Already got there ... */
5517f8829a4aSRandall Stewart return;
5518f8829a4aSRandall Stewart }
5519f8829a4aSRandall Stewart /*
5520f8829a4aSRandall Stewart * now we know the new TSN is more advanced, let's find the actual
5521f8829a4aSRandall Stewart * gap
5522f8829a4aSRandall Stewart */
5523b5c16493SMichael Tuexen SCTP_CALC_TSN_TO_GAP(gap, new_cum_tsn, asoc->mapping_array_base_tsn);
552477acdc25SRandall Stewart asoc->cumulative_tsn = new_cum_tsn;
55252afb3e84SRandall Stewart if (gap >= m_size) {
5526f8829a4aSRandall Stewart if ((long)gap > sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv)) {
5527ff1ffd74SMichael Tuexen struct mbuf *op_err;
5528ff1ffd74SMichael Tuexen char msg[SCTP_DIAG_INFO_LEN];
552917205eccSRandall Stewart
5530f8829a4aSRandall Stewart /*
5531f8829a4aSRandall Stewart * out of range (of single byte chunks in the rwnd I
553217205eccSRandall Stewart * give out). This must be an attacker.
5533f8829a4aSRandall Stewart */
553417205eccSRandall Stewart *abort_flag = 1;
5535999f86d6SMichael Tuexen SCTP_SNPRINTF(msg, sizeof(msg),
5536ff1ffd74SMichael Tuexen "New cum ack %8.8x too high, highest TSN %8.8x",
5537821bae7cSMichael Tuexen new_cum_tsn, asoc->highest_tsn_inside_map);
5538ff1ffd74SMichael Tuexen op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
553991e04f9eSMichael Tuexen stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_37;
5540105b68b4SMichael Tuexen sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED);
5541f8829a4aSRandall Stewart return;
5542f8829a4aSRandall Stewart }
5543207304d4SRandall Stewart SCTP_STAT_INCR(sctps_fwdtsn_map_over);
554477acdc25SRandall Stewart
55452afb3e84SRandall Stewart memset(stcb->asoc.mapping_array, 0, stcb->asoc.mapping_array_size);
55462afb3e84SRandall Stewart asoc->mapping_array_base_tsn = new_cum_tsn + 1;
554777acdc25SRandall Stewart asoc->highest_tsn_inside_map = new_cum_tsn;
554877acdc25SRandall Stewart
5549b5c16493SMichael Tuexen memset(stcb->asoc.nr_mapping_array, 0, stcb->asoc.mapping_array_size);
5550830d754dSRandall Stewart asoc->highest_tsn_inside_nr_map = new_cum_tsn;
555177acdc25SRandall Stewart
5552b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
5553f8829a4aSRandall Stewart sctp_log_map(0, 3, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT);
555480fefe0aSRandall Stewart }
55552afb3e84SRandall Stewart } else {
55562afb3e84SRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb);
55572afb3e84SRandall Stewart for (i = 0; i <= gap; i++) {
55587898f408SRandall Stewart if (!SCTP_IS_TSN_PRESENT(asoc->mapping_array, i) &&
55597898f408SRandall Stewart !SCTP_IS_TSN_PRESENT(asoc->nr_mapping_array, i)) {
55608933fa13SRandall Stewart SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, i);
556120b07a4dSMichael Tuexen if (SCTP_TSN_GT(asoc->mapping_array_base_tsn + i, asoc->highest_tsn_inside_nr_map)) {
55627898f408SRandall Stewart asoc->highest_tsn_inside_nr_map = asoc->mapping_array_base_tsn + i;
5563b5c16493SMichael Tuexen }
5564b5c16493SMichael Tuexen }
5565b5c16493SMichael Tuexen }
5566f8829a4aSRandall Stewart }
5567f8829a4aSRandall Stewart /*************************************************************/
5568f8829a4aSRandall Stewart /* 2. Clear up re-assembly queue */
5569f8829a4aSRandall Stewart /*************************************************************/
5570f8829a4aSRandall Stewart
557144249214SRandall Stewart /* This is now done as part of clearing up the stream/seq */
5572d1ea5fa9SMichael Tuexen if (asoc->idata_supported == 0) {
5573d1ea5fa9SMichael Tuexen uint16_t sid;
557444249214SRandall Stewart
5575d1ea5fa9SMichael Tuexen /* Flush all the un-ordered data based on cum-tsn */
5576d1ea5fa9SMichael Tuexen SCTP_INP_READ_LOCK(stcb->sctp_ep);
5577d1ea5fa9SMichael Tuexen for (sid = 0; sid < asoc->streamincnt; sid++) {
5578b6734d8fSMichael Tuexen strm = &asoc->strmin[sid];
5579b6734d8fSMichael Tuexen if (!TAILQ_EMPTY(&strm->uno_inqueue)) {
5580b6734d8fSMichael Tuexen sctp_flush_reassm_for_str_seq(stcb, asoc, strm, TAILQ_FIRST(&strm->uno_inqueue), 0, new_cum_tsn);
5581b6734d8fSMichael Tuexen }
5582d1ea5fa9SMichael Tuexen }
5583d1ea5fa9SMichael Tuexen SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
5584d1ea5fa9SMichael Tuexen }
55858933fa13SRandall Stewart /*******************************************************/
55868933fa13SRandall Stewart /* 3. Update the PR-stream re-ordering queues and fix */
55878933fa13SRandall Stewart /* delivery issues as needed. */
55888933fa13SRandall Stewart /*******************************************************/
5589f8829a4aSRandall Stewart fwd_sz -= sizeof(*fwd);
5590671d309cSRandall Stewart if (m && fwd_sz) {
5591f8829a4aSRandall Stewart /* New method. */
5592d61a0ae0SRandall Stewart unsigned int num_str;
5593b6734d8fSMichael Tuexen uint32_t mid;
559449656eefSMichael Tuexen uint16_t sid;
55958e1b295fSMichael Tuexen uint16_t ordered, flags;
5596671d309cSRandall Stewart struct sctp_strseq *stseq, strseqbuf;
559744249214SRandall Stewart struct sctp_strseq_mid *stseq_m, strseqbuf_m;
5598671d309cSRandall Stewart
5599671d309cSRandall Stewart offset += sizeof(*fwd);
5600f8829a4aSRandall Stewart
56018933fa13SRandall Stewart SCTP_INP_READ_LOCK(stcb->sctp_ep);
560244249214SRandall Stewart if (asoc->idata_supported) {
560344249214SRandall Stewart num_str = fwd_sz / sizeof(struct sctp_strseq_mid);
560444249214SRandall Stewart } else {
5605f8829a4aSRandall Stewart num_str = fwd_sz / sizeof(struct sctp_strseq);
560644249214SRandall Stewart }
5607f8829a4aSRandall Stewart for (i = 0; i < num_str; i++) {
560844249214SRandall Stewart if (asoc->idata_supported) {
560944249214SRandall Stewart stseq_m = (struct sctp_strseq_mid *)sctp_m_getptr(m, offset,
561044249214SRandall Stewart sizeof(struct sctp_strseq_mid),
561144249214SRandall Stewart (uint8_t *)&strseqbuf_m);
561244249214SRandall Stewart offset += sizeof(struct sctp_strseq_mid);
561344249214SRandall Stewart if (stseq_m == NULL) {
561444249214SRandall Stewart break;
561544249214SRandall Stewart }
561649656eefSMichael Tuexen sid = ntohs(stseq_m->sid);
561749656eefSMichael Tuexen mid = ntohl(stseq_m->mid);
56188e1b295fSMichael Tuexen flags = ntohs(stseq_m->flags);
56198e1b295fSMichael Tuexen if (flags & PR_SCTP_UNORDERED_FLAG) {
56208e1b295fSMichael Tuexen ordered = 0;
56218e1b295fSMichael Tuexen } else {
56228e1b295fSMichael Tuexen ordered = 1;
56238e1b295fSMichael Tuexen }
562444249214SRandall Stewart } else {
5625671d309cSRandall Stewart stseq = (struct sctp_strseq *)sctp_m_getptr(m, offset,
5626671d309cSRandall Stewart sizeof(struct sctp_strseq),
5627671d309cSRandall Stewart (uint8_t *)&strseqbuf);
5628671d309cSRandall Stewart offset += sizeof(struct sctp_strseq);
56292afb3e84SRandall Stewart if (stseq == NULL) {
5630671d309cSRandall Stewart break;
56312afb3e84SRandall Stewart }
563249656eefSMichael Tuexen sid = ntohs(stseq->sid);
563349656eefSMichael Tuexen mid = (uint32_t)ntohs(stseq->ssn);
56348e1b295fSMichael Tuexen ordered = 1;
563544249214SRandall Stewart }
5636f8829a4aSRandall Stewart /* Convert */
56378933fa13SRandall Stewart
5638f8829a4aSRandall Stewart /* now process */
56398933fa13SRandall Stewart
56408933fa13SRandall Stewart /*
56418933fa13SRandall Stewart * Ok we now look for the stream/seq on the read
56428933fa13SRandall Stewart * queue where its not all delivered. If we find it
56438933fa13SRandall Stewart * we transmute the read entry into a PDI_ABORTED.
56448933fa13SRandall Stewart */
564549656eefSMichael Tuexen if (sid >= asoc->streamincnt) {
56462afb3e84SRandall Stewart /* screwed up streams, stop! */
56472afb3e84SRandall Stewart break;
5648f8829a4aSRandall Stewart }
564949656eefSMichael Tuexen if ((asoc->str_of_pdapi == sid) &&
565049656eefSMichael Tuexen (asoc->ssn_of_pdapi == mid)) {
56518933fa13SRandall Stewart /*
56528933fa13SRandall Stewart * If this is the one we were partially
56538933fa13SRandall Stewart * delivering now then we no longer are.
56548933fa13SRandall Stewart * Note this will change with the reassembly
56558933fa13SRandall Stewart * re-write.
56568933fa13SRandall Stewart */
56578933fa13SRandall Stewart asoc->fragmented_delivery_inprogress = 0;
56588933fa13SRandall Stewart }
565949656eefSMichael Tuexen strm = &asoc->strmin[sid];
5660b6734d8fSMichael Tuexen if (ordered) {
5661e597bae4SMichael Tuexen TAILQ_FOREACH_SAFE(control, &strm->inqueue, next_instrm, ncontrol) {
5662b6734d8fSMichael Tuexen if (SCTP_MID_GE(asoc->idata_supported, mid, control->mid)) {
5663b6734d8fSMichael Tuexen sctp_flush_reassm_for_str_seq(stcb, asoc, strm, control, ordered, new_cum_tsn);
5664b6734d8fSMichael Tuexen }
5665b6734d8fSMichael Tuexen }
5666b6734d8fSMichael Tuexen } else {
5667b6734d8fSMichael Tuexen if (asoc->idata_supported) {
5668e597bae4SMichael Tuexen TAILQ_FOREACH_SAFE(control, &strm->uno_inqueue, next_instrm, ncontrol) {
5669b6734d8fSMichael Tuexen if (SCTP_MID_GE(asoc->idata_supported, mid, control->mid)) {
5670b6734d8fSMichael Tuexen sctp_flush_reassm_for_str_seq(stcb, asoc, strm, control, ordered, new_cum_tsn);
5671b6734d8fSMichael Tuexen }
5672b6734d8fSMichael Tuexen }
5673b6734d8fSMichael Tuexen } else {
5674b6734d8fSMichael Tuexen if (!TAILQ_EMPTY(&strm->uno_inqueue)) {
5675b6734d8fSMichael Tuexen sctp_flush_reassm_for_str_seq(stcb, asoc, strm, TAILQ_FIRST(&strm->uno_inqueue), ordered, new_cum_tsn);
5676b6734d8fSMichael Tuexen }
5677b6734d8fSMichael Tuexen }
5678d1ea5fa9SMichael Tuexen }
567928cd0699SMichael Tuexen TAILQ_FOREACH(control, &stcb->sctp_ep->read_queue, next) {
568028cd0699SMichael Tuexen if ((control->sinfo_stream == sid) &&
568128cd0699SMichael Tuexen (SCTP_MID_EQ(asoc->idata_supported, control->mid, mid))) {
568228cd0699SMichael Tuexen control->pdapi_aborted = 1;
568328cd0699SMichael Tuexen control->end_added = 1;
568428cd0699SMichael Tuexen if (control->on_strm_q == SCTP_ON_ORDERED) {
568528cd0699SMichael Tuexen TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
568628cd0699SMichael Tuexen if (asoc->size_on_all_streams >= control->length) {
568728cd0699SMichael Tuexen asoc->size_on_all_streams -= control->length;
568828cd0699SMichael Tuexen } else {
568998d5fd97SMichael Tuexen #ifdef INVARIANTS
569028cd0699SMichael Tuexen panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
569128cd0699SMichael Tuexen #else
569228cd0699SMichael Tuexen asoc->size_on_all_streams = 0;
569398d5fd97SMichael Tuexen #endif
569444249214SRandall Stewart }
569528cd0699SMichael Tuexen sctp_ucount_decr(asoc->cnt_on_all_streams);
569628cd0699SMichael Tuexen } else if (control->on_strm_q == SCTP_ON_UNORDERED) {
569728cd0699SMichael Tuexen TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
569828cd0699SMichael Tuexen #ifdef INVARIANTS
569928cd0699SMichael Tuexen } else if (control->on_strm_q) {
570028cd0699SMichael Tuexen panic("strm: %p ctl: %p unknown %d",
570128cd0699SMichael Tuexen strm, control, control->on_strm_q);
570228cd0699SMichael Tuexen #endif
570328cd0699SMichael Tuexen }
570428cd0699SMichael Tuexen control->on_strm_q = 0;
5705810ec536SMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION,
5706810ec536SMichael Tuexen stcb,
57078933fa13SRandall Stewart SCTP_PARTIAL_DELIVERY_ABORTED,
5708749a7fb5SMichael Tuexen (void *)control,
5709810ec536SMichael Tuexen SCTP_SO_NOT_LOCKED);
57108933fa13SRandall Stewart break;
571128cd0699SMichael Tuexen } else if ((control->sinfo_stream == sid) &&
571228cd0699SMichael Tuexen SCTP_MID_GT(asoc->idata_supported, control->mid, mid)) {
57138933fa13SRandall Stewart /* We are past our victim SSN */
57148933fa13SRandall Stewart break;
57158933fa13SRandall Stewart }
57168933fa13SRandall Stewart }
571749656eefSMichael Tuexen if (SCTP_MID_GT(asoc->idata_supported, mid, strm->last_mid_delivered)) {
5718f8829a4aSRandall Stewart /* Update the sequence number */
571949656eefSMichael Tuexen strm->last_mid_delivered = mid;
5720f8829a4aSRandall Stewart }
5721f8829a4aSRandall Stewart /* now kick the stream the new way */
572204ee05e8SRandall Stewart /* sa_ignore NO_NULL_CHK */
5723f8829a4aSRandall Stewart sctp_kick_prsctp_reorder_queue(stcb, strm);
5724f8829a4aSRandall Stewart }
57258933fa13SRandall Stewart SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
5726f8829a4aSRandall Stewart }
57277898f408SRandall Stewart /*
57287898f408SRandall Stewart * Now slide thing forward.
57297898f408SRandall Stewart */
57307898f408SRandall Stewart sctp_slide_mapping_arrays(stcb);
5731f8829a4aSRandall Stewart }
5732