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