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, 69d1ea5fa9SMichael Tuexen struct sctp_tmit_chunk *chk, int lock_held); 7044249214SRandall Stewart 71f8829a4aSRandall Stewart 7272fb6fdbSRandall Stewart void 73f8829a4aSRandall Stewart sctp_set_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc) 74f8829a4aSRandall Stewart { 75b3f1ea41SRandall Stewart asoc->my_rwnd = sctp_calc_rwnd(stcb, asoc); 76f8829a4aSRandall Stewart } 77f8829a4aSRandall Stewart 78f8829a4aSRandall Stewart /* Calculate what the rwnd would be */ 7972fb6fdbSRandall Stewart uint32_t 80b0471b4bSMichael Tuexen sctp_calc_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc) 81b0471b4bSMichael Tuexen { 82b3f1ea41SRandall Stewart uint32_t calc = 0; 83f8829a4aSRandall Stewart 84f8829a4aSRandall Stewart /* 85f8829a4aSRandall Stewart * This is really set wrong with respect to a 1-2-m socket. Since 864e88d37aSMichael Tuexen * the sb_cc is the count that everyone as put up. When we re-write 87f8829a4aSRandall Stewart * sctp_soreceive then we will fix this so that ONLY this 88f8829a4aSRandall Stewart * associations data is taken into account. 89f8829a4aSRandall Stewart */ 9044249214SRandall Stewart if (stcb->sctp_socket == NULL) { 91f8829a4aSRandall Stewart return (calc); 9244249214SRandall Stewart } 93*0053ed28SMichael Tuexen 94253a63b8SMichael Tuexen KASSERT(asoc->cnt_on_reasm_queue > 0 || asoc->size_on_reasm_queue == 0, 95253a63b8SMichael Tuexen ("size_on_reasm_queue is %u", asoc->size_on_reasm_queue)); 96253a63b8SMichael Tuexen KASSERT(asoc->cnt_on_all_streams > 0 || asoc->size_on_all_streams == 0, 97253a63b8SMichael Tuexen ("size_on_all_streams is %u", asoc->size_on_all_streams)); 984e88d37aSMichael Tuexen if (stcb->asoc.sb_cc == 0 && 99253a63b8SMichael Tuexen asoc->cnt_on_reasm_queue == 0 && 100253a63b8SMichael Tuexen asoc->cnt_on_all_streams == 0) { 101f8829a4aSRandall Stewart /* Full rwnd granted */ 102b3f1ea41SRandall Stewart calc = max(SCTP_SB_LIMIT_RCV(stcb->sctp_socket), SCTP_MINIMAL_RWND); 103f8829a4aSRandall Stewart return (calc); 104f8829a4aSRandall Stewart } 105f8829a4aSRandall Stewart /* get actual space */ 106f8829a4aSRandall Stewart calc = (uint32_t)sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv); 107f8829a4aSRandall Stewart /* 108f8829a4aSRandall Stewart * take out what has NOT been put on socket queue and we yet hold 109f8829a4aSRandall Stewart * for putting up. 110f8829a4aSRandall Stewart */ 11144fbe462SRandall Stewart calc = sctp_sbspace_sub(calc, (uint32_t)(asoc->size_on_reasm_queue + 11244fbe462SRandall Stewart asoc->cnt_on_reasm_queue * MSIZE)); 11344fbe462SRandall Stewart calc = sctp_sbspace_sub(calc, (uint32_t)(asoc->size_on_all_streams + 11444fbe462SRandall Stewart asoc->cnt_on_all_streams * MSIZE)); 115f8829a4aSRandall Stewart if (calc == 0) { 116f8829a4aSRandall Stewart /* out of space */ 117f8829a4aSRandall Stewart return (calc); 118f8829a4aSRandall Stewart } 119*0053ed28SMichael Tuexen 120f8829a4aSRandall Stewart /* what is the overhead of all these rwnd's */ 1212afb3e84SRandall Stewart calc = sctp_sbspace_sub(calc, stcb->asoc.my_rwnd_control_len); 122b3f1ea41SRandall Stewart /* 123b3f1ea41SRandall Stewart * If the window gets too small due to ctrl-stuff, reduce it to 1, 124b3f1ea41SRandall Stewart * even it is 0. SWS engaged 125f8829a4aSRandall Stewart */ 126b3f1ea41SRandall Stewart if (calc < stcb->asoc.my_rwnd_control_len) { 127b3f1ea41SRandall Stewart calc = 1; 1282afb3e84SRandall Stewart } 129b3f1ea41SRandall Stewart return (calc); 130f8829a4aSRandall Stewart } 131f8829a4aSRandall Stewart 132f8829a4aSRandall Stewart 133f8829a4aSRandall Stewart 134f8829a4aSRandall Stewart /* 135f8829a4aSRandall Stewart * Build out our readq entry based on the incoming packet. 136f8829a4aSRandall Stewart */ 137f8829a4aSRandall Stewart struct sctp_queued_to_read * 138f8829a4aSRandall Stewart sctp_build_readq_entry(struct sctp_tcb *stcb, 139f8829a4aSRandall Stewart struct sctp_nets *net, 140f8829a4aSRandall Stewart uint32_t tsn, uint32_t ppid, 14149656eefSMichael Tuexen uint32_t context, uint16_t sid, 14249656eefSMichael Tuexen uint32_t mid, uint8_t flags, 143f8829a4aSRandall Stewart struct mbuf *dm) 144f8829a4aSRandall Stewart { 145f8829a4aSRandall Stewart struct sctp_queued_to_read *read_queue_e = NULL; 146f8829a4aSRandall Stewart 147f8829a4aSRandall Stewart sctp_alloc_a_readq(stcb, read_queue_e); 148f8829a4aSRandall Stewart if (read_queue_e == NULL) { 149f8829a4aSRandall Stewart goto failed_build; 150f8829a4aSRandall Stewart } 15144249214SRandall Stewart memset(read_queue_e, 0, sizeof(struct sctp_queued_to_read)); 15249656eefSMichael Tuexen read_queue_e->sinfo_stream = sid; 153f8829a4aSRandall Stewart read_queue_e->sinfo_flags = (flags << 8); 154f8829a4aSRandall Stewart read_queue_e->sinfo_ppid = ppid; 1557215cc1bSMichael Tuexen read_queue_e->sinfo_context = context; 156f8829a4aSRandall Stewart read_queue_e->sinfo_tsn = tsn; 157f8829a4aSRandall Stewart read_queue_e->sinfo_cumtsn = tsn; 158f8829a4aSRandall Stewart read_queue_e->sinfo_assoc_id = sctp_get_associd(stcb); 15949656eefSMichael Tuexen read_queue_e->mid = mid; 16044249214SRandall Stewart read_queue_e->top_fsn = read_queue_e->fsn_included = 0xffffffff; 16144249214SRandall Stewart TAILQ_INIT(&read_queue_e->reasm); 162f8829a4aSRandall Stewart read_queue_e->whoFrom = net; 163f8829a4aSRandall Stewart atomic_add_int(&net->ref_count, 1); 164f8829a4aSRandall Stewart read_queue_e->data = dm; 165f8829a4aSRandall Stewart read_queue_e->stcb = stcb; 166f8829a4aSRandall Stewart read_queue_e->port_from = stcb->rport; 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 } 190*0053ed28SMichael 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 285139bc87fSRandall Stewart 28677acdc25SRandall Stewart static void 28777acdc25SRandall Stewart sctp_mark_non_revokable(struct sctp_association *asoc, uint32_t tsn) 28877acdc25SRandall Stewart { 2899b2e0767SRandall Stewart uint32_t gap, i, cumackp1; 29077acdc25SRandall Stewart int fnd = 0; 29144249214SRandall Stewart int in_r = 0, in_nr = 0; 29277acdc25SRandall Stewart 29377acdc25SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_do_drain) == 0) { 29477acdc25SRandall Stewart return; 29577acdc25SRandall Stewart } 2969b2e0767SRandall Stewart cumackp1 = asoc->cumulative_tsn + 1; 29720b07a4dSMichael Tuexen if (SCTP_TSN_GT(cumackp1, tsn)) { 2989b2e0767SRandall Stewart /* 2999b2e0767SRandall Stewart * this tsn is behind the cum ack and thus we don't need to 3009b2e0767SRandall Stewart * worry about it being moved from one to the other. 3019b2e0767SRandall Stewart */ 3029b2e0767SRandall Stewart return; 3039b2e0767SRandall Stewart } 30477acdc25SRandall Stewart SCTP_CALC_TSN_TO_GAP(gap, tsn, asoc->mapping_array_base_tsn); 30544249214SRandall Stewart in_r = SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap); 30644249214SRandall Stewart in_nr = SCTP_IS_TSN_PRESENT(asoc->nr_mapping_array, gap); 30744249214SRandall Stewart if ((in_r == 0) && (in_nr == 0)) { 30844249214SRandall Stewart #ifdef INVARIANTS 30944249214SRandall Stewart panic("Things are really messed up now"); 31044249214SRandall Stewart #else 311cd3fd531SMichael Tuexen SCTP_PRINTF("gap:%x tsn:%x\n", gap, tsn); 31277acdc25SRandall Stewart sctp_print_mapping_array(asoc); 31377acdc25SRandall Stewart #endif 314b5c16493SMichael Tuexen } 31544249214SRandall Stewart if (in_nr == 0) 31677acdc25SRandall Stewart SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap); 31744249214SRandall Stewart if (in_r) 31877acdc25SRandall Stewart SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap); 31920b07a4dSMichael Tuexen if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) { 32077acdc25SRandall Stewart asoc->highest_tsn_inside_nr_map = tsn; 32177acdc25SRandall Stewart } 32277acdc25SRandall Stewart if (tsn == asoc->highest_tsn_inside_map) { 32377acdc25SRandall Stewart /* We must back down to see what the new highest is */ 32420b07a4dSMichael Tuexen for (i = tsn - 1; SCTP_TSN_GE(i, asoc->mapping_array_base_tsn); i--) { 32577acdc25SRandall Stewart SCTP_CALC_TSN_TO_GAP(gap, i, asoc->mapping_array_base_tsn); 32677acdc25SRandall Stewart if (SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap)) { 32777acdc25SRandall Stewart asoc->highest_tsn_inside_map = i; 32877acdc25SRandall Stewart fnd = 1; 32977acdc25SRandall Stewart break; 33077acdc25SRandall Stewart } 33177acdc25SRandall Stewart } 33277acdc25SRandall Stewart if (!fnd) { 33377acdc25SRandall Stewart asoc->highest_tsn_inside_map = asoc->mapping_array_base_tsn - 1; 33477acdc25SRandall Stewart } 33577acdc25SRandall Stewart } 33677acdc25SRandall Stewart } 33777acdc25SRandall Stewart 33844249214SRandall Stewart static int 33944249214SRandall Stewart sctp_place_control_in_stream(struct sctp_stream_in *strm, 34044249214SRandall Stewart struct sctp_association *asoc, 34144249214SRandall Stewart struct sctp_queued_to_read *control) 342f8829a4aSRandall Stewart { 34344249214SRandall Stewart struct sctp_queued_to_read *at; 34444249214SRandall Stewart struct sctp_readhead *q; 3458b9c95f4SMichael Tuexen uint8_t flags, unordered; 346f8829a4aSRandall Stewart 3478b9c95f4SMichael Tuexen flags = (control->sinfo_flags >> 8); 3488b9c95f4SMichael Tuexen unordered = flags & SCTP_DATA_UNORDERED; 34944249214SRandall Stewart if (unordered) { 35044249214SRandall Stewart q = &strm->uno_inqueue; 35144249214SRandall Stewart if (asoc->idata_supported == 0) { 35244249214SRandall Stewart if (!TAILQ_EMPTY(q)) { 353b7b84c0eSMichael Tuexen /* 354b7b84c0eSMichael Tuexen * Only one stream can be here in old style 355b7b84c0eSMichael Tuexen * -- abort 356b7b84c0eSMichael Tuexen */ 35744249214SRandall Stewart return (-1); 35844249214SRandall Stewart } 35944249214SRandall Stewart TAILQ_INSERT_TAIL(q, control, next_instrm); 36044249214SRandall Stewart control->on_strm_q = SCTP_ON_UNORDERED; 36144249214SRandall Stewart return (0); 36244249214SRandall Stewart } 36344249214SRandall Stewart } else { 36444249214SRandall Stewart q = &strm->inqueue; 36544249214SRandall Stewart } 3668b9c95f4SMichael Tuexen if ((flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) { 3678b9c95f4SMichael Tuexen control->end_added = 1; 3688b9c95f4SMichael Tuexen control->first_frag_seen = 1; 3698b9c95f4SMichael Tuexen control->last_frag_seen = 1; 37044249214SRandall Stewart } 37144249214SRandall Stewart if (TAILQ_EMPTY(q)) { 37244249214SRandall Stewart /* Empty queue */ 37344249214SRandall Stewart TAILQ_INSERT_HEAD(q, control, next_instrm); 37444249214SRandall Stewart if (unordered) { 37544249214SRandall Stewart control->on_strm_q = SCTP_ON_UNORDERED; 37644249214SRandall Stewart } else { 37744249214SRandall Stewart control->on_strm_q = SCTP_ON_ORDERED; 37844249214SRandall Stewart } 37944249214SRandall Stewart return (0); 38044249214SRandall Stewart } else { 38144249214SRandall Stewart TAILQ_FOREACH(at, q, next_instrm) { 38249656eefSMichael Tuexen if (SCTP_MID_GT(asoc->idata_supported, at->mid, control->mid)) { 38344249214SRandall Stewart /* 38444249214SRandall Stewart * one in queue is bigger than the new one, 38544249214SRandall Stewart * insert before this one 38644249214SRandall Stewart */ 38744249214SRandall Stewart TAILQ_INSERT_BEFORE(at, control, next_instrm); 38844249214SRandall Stewart if (unordered) { 38944249214SRandall Stewart control->on_strm_q = SCTP_ON_UNORDERED; 39044249214SRandall Stewart } else { 39144249214SRandall Stewart control->on_strm_q = SCTP_ON_ORDERED; 39244249214SRandall Stewart } 39344249214SRandall Stewart break; 39449656eefSMichael Tuexen } else if (SCTP_MID_EQ(asoc->idata_supported, at->mid, control->mid)) { 39544249214SRandall Stewart /* 39644249214SRandall Stewart * Gak, He sent me a duplicate msg id 39744249214SRandall Stewart * number?? return -1 to abort. 39844249214SRandall Stewart */ 39944249214SRandall Stewart return (-1); 40044249214SRandall Stewart } else { 40144249214SRandall Stewart if (TAILQ_NEXT(at, next_instrm) == NULL) { 40244249214SRandall Stewart /* 40344249214SRandall Stewart * We are at the end, insert it 40444249214SRandall Stewart * after this one 40544249214SRandall Stewart */ 40644249214SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { 40744249214SRandall Stewart sctp_log_strm_del(control, at, 40844249214SRandall Stewart SCTP_STR_LOG_FROM_INSERT_TL); 40944249214SRandall Stewart } 4108b9c95f4SMichael Tuexen TAILQ_INSERT_AFTER(q, at, control, next_instrm); 41144249214SRandall Stewart if (unordered) { 41244249214SRandall Stewart control->on_strm_q = SCTP_ON_UNORDERED; 41344249214SRandall Stewart } else { 41444249214SRandall Stewart control->on_strm_q = SCTP_ON_ORDERED; 41544249214SRandall Stewart } 41644249214SRandall Stewart break; 41744249214SRandall Stewart } 41844249214SRandall Stewart } 41944249214SRandall Stewart } 42044249214SRandall Stewart } 42144249214SRandall Stewart return (0); 42244249214SRandall Stewart } 42344249214SRandall Stewart 42444249214SRandall Stewart static void 42544249214SRandall Stewart sctp_abort_in_reasm(struct sctp_tcb *stcb, 42644249214SRandall Stewart struct sctp_queued_to_read *control, 42744249214SRandall Stewart struct sctp_tmit_chunk *chk, 42844249214SRandall Stewart int *abort_flag, int opspot) 42944249214SRandall Stewart { 43044249214SRandall Stewart char msg[SCTP_DIAG_INFO_LEN]; 43144249214SRandall Stewart struct mbuf *oper; 43244249214SRandall Stewart 43344249214SRandall Stewart if (stcb->asoc.idata_supported) { 43444249214SRandall Stewart snprintf(msg, sizeof(msg), 43544249214SRandall Stewart "Reass %x,CF:%x,TSN=%8.8x,SID=%4.4x,FSN=%8.8x,MID:%8.8x", 43644249214SRandall Stewart opspot, 43744249214SRandall Stewart control->fsn_included, 43849656eefSMichael Tuexen chk->rec.data.tsn, 43949656eefSMichael Tuexen chk->rec.data.sid, 44049656eefSMichael Tuexen chk->rec.data.fsn, chk->rec.data.mid); 44144249214SRandall Stewart } else { 44244249214SRandall Stewart snprintf(msg, sizeof(msg), 44344249214SRandall Stewart "Reass %x,CI:%x,TSN=%8.8x,SID=%4.4x,FSN=%4.4x,SSN:%4.4x", 44444249214SRandall Stewart opspot, 44544249214SRandall Stewart control->fsn_included, 44649656eefSMichael Tuexen chk->rec.data.tsn, 44749656eefSMichael Tuexen chk->rec.data.sid, 44849656eefSMichael Tuexen chk->rec.data.fsn, 44949656eefSMichael Tuexen (uint16_t)chk->rec.data.mid); 45044249214SRandall Stewart } 45144249214SRandall Stewart oper = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); 452f8829a4aSRandall Stewart sctp_m_freem(chk->data); 453f8829a4aSRandall Stewart chk->data = NULL; 454689e6a5fSMichael Tuexen sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); 45544249214SRandall Stewart stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_1; 45644249214SRandall Stewart sctp_abort_an_association(stcb->sctp_ep, stcb, oper, SCTP_SO_NOT_LOCKED); 45744249214SRandall Stewart *abort_flag = 1; 458f8829a4aSRandall Stewart } 459f8829a4aSRandall Stewart 46044249214SRandall Stewart static void 461d1ea5fa9SMichael Tuexen sctp_clean_up_control(struct sctp_tcb *stcb, struct sctp_queued_to_read *control) 46244249214SRandall Stewart { 463f8829a4aSRandall Stewart /* 46444249214SRandall Stewart * The control could not be placed and must be cleaned. 465f8829a4aSRandall Stewart */ 46644249214SRandall Stewart struct sctp_tmit_chunk *chk, *nchk; 467df6e0cc3SRandall Stewart 46844249214SRandall Stewart TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) { 46944249214SRandall Stewart TAILQ_REMOVE(&control->reasm, chk, sctp_next); 47044249214SRandall Stewart if (chk->data) 47144249214SRandall Stewart sctp_m_freem(chk->data); 472f8829a4aSRandall Stewart chk->data = NULL; 473689e6a5fSMichael Tuexen sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); 474f8829a4aSRandall Stewart } 47544249214SRandall Stewart sctp_free_a_readq(stcb, control); 476f8829a4aSRandall Stewart } 477f8829a4aSRandall Stewart 478f8829a4aSRandall Stewart /* 479f8829a4aSRandall Stewart * Queue the chunk either right into the socket buffer if it is the next one 480f8829a4aSRandall Stewart * to go OR put it in the correct place in the delivery queue. If we do 48144249214SRandall Stewart * append to the so_buf, keep doing so until we are out of order as 48244249214SRandall Stewart * long as the control's entered are non-fragmented. 483f8829a4aSRandall Stewart */ 484f8829a4aSRandall Stewart static void 48544249214SRandall Stewart sctp_queue_data_to_stream(struct sctp_tcb *stcb, 48644249214SRandall Stewart struct sctp_association *asoc, 48744249214SRandall Stewart struct sctp_queued_to_read *control, int *abort_flag, int *need_reasm) 488f8829a4aSRandall Stewart { 489f8829a4aSRandall Stewart /* 490f8829a4aSRandall Stewart * FIX-ME maybe? What happens when the ssn wraps? If we are getting 491f8829a4aSRandall Stewart * all the data in one stream this could happen quite rapidly. One 492f8829a4aSRandall Stewart * could use the TSN to keep track of things, but this scheme breaks 493cd0a4ff6SPedro F. Giffuni * down in the other type of stream usage that could occur. Send a 494f8829a4aSRandall Stewart * single msg to stream 0, send 4Billion messages to stream 1, now 495f8829a4aSRandall Stewart * send a message to stream 0. You have a situation where the TSN 496f8829a4aSRandall Stewart * has wrapped but not in the stream. Is this worth worrying about 497f8829a4aSRandall Stewart * or should we just change our queue sort at the bottom to be by 498f8829a4aSRandall Stewart * TSN. 499f8829a4aSRandall Stewart * 5005b495f17SMichael Tuexen * Could it also be legal for a peer to send ssn 1 with TSN 2 and 5015b495f17SMichael Tuexen * ssn 2 with TSN 1? If the peer is doing some sort of funky TSN/SSN 502f8829a4aSRandall Stewart * assignment this could happen... and I don't see how this would be 503f8829a4aSRandall Stewart * a violation. So for now I am undecided an will leave the sort by 504f8829a4aSRandall Stewart * SSN alone. Maybe a hybred approach is the answer 505f8829a4aSRandall Stewart * 506f8829a4aSRandall Stewart */ 507f8829a4aSRandall Stewart struct sctp_queued_to_read *at; 508f8829a4aSRandall Stewart int queue_needed; 50944249214SRandall Stewart uint32_t nxt_todel; 510ff1ffd74SMichael Tuexen struct mbuf *op_err; 5113d6fe5d8SMichael Tuexen struct sctp_stream_in *strm; 512ff1ffd74SMichael Tuexen char msg[SCTP_DIAG_INFO_LEN]; 513f8829a4aSRandall Stewart 5143d6fe5d8SMichael Tuexen strm = &asoc->strmin[control->sinfo_stream]; 515b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { 516f8829a4aSRandall Stewart sctp_log_strm_del(control, NULL, SCTP_STR_LOG_FROM_INTO_STRD); 51780fefe0aSRandall Stewart } 51849656eefSMichael Tuexen if (SCTP_MID_GT((asoc->idata_supported), strm->last_mid_delivered, control->mid)) { 519f8829a4aSRandall Stewart /* The incoming sseq is behind where we last delivered? */ 520f2ea2a2dSMichael Tuexen SCTPDBG(SCTP_DEBUG_INDATA1, "Duplicate S-SEQ: %u delivered: %u from peer, Abort association\n", 5213d6fe5d8SMichael Tuexen strm->last_mid_delivered, control->mid); 522f8829a4aSRandall Stewart /* 523f8829a4aSRandall Stewart * throw it in the stream so it gets cleaned up in 524f8829a4aSRandall Stewart * association destruction 525f8829a4aSRandall Stewart */ 52644249214SRandall Stewart TAILQ_INSERT_HEAD(&strm->inqueue, control, next_instrm); 52749656eefSMichael Tuexen if (asoc->idata_supported) { 52849656eefSMichael Tuexen snprintf(msg, sizeof(msg), "Delivered MID=%8.8x, got TSN=%8.8x, SID=%4.4x, MID=%8.8x", 52949656eefSMichael Tuexen strm->last_mid_delivered, control->sinfo_tsn, 53049656eefSMichael Tuexen control->sinfo_stream, control->mid); 53149656eefSMichael Tuexen } else { 532ff1ffd74SMichael Tuexen snprintf(msg, sizeof(msg), "Delivered SSN=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x", 53349656eefSMichael Tuexen (uint16_t)strm->last_mid_delivered, 53449656eefSMichael Tuexen control->sinfo_tsn, 53549656eefSMichael Tuexen control->sinfo_stream, 53649656eefSMichael Tuexen (uint16_t)control->mid); 53749656eefSMichael Tuexen } 538ff1ffd74SMichael Tuexen op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); 53944249214SRandall Stewart stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_2; 540ff1ffd74SMichael Tuexen sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); 541f8829a4aSRandall Stewart *abort_flag = 1; 542f8829a4aSRandall Stewart return; 543f8829a4aSRandall Stewart 544f8829a4aSRandall Stewart } 54544249214SRandall Stewart queue_needed = 1; 54644249214SRandall Stewart asoc->size_on_all_streams += control->length; 54744249214SRandall Stewart sctp_ucount_incr(asoc->cnt_on_all_streams); 54849656eefSMichael Tuexen nxt_todel = strm->last_mid_delivered + 1; 54949656eefSMichael Tuexen if (SCTP_MID_EQ(asoc->idata_supported, nxt_todel, control->mid)) { 550cf9e47b2SMichael Tuexen #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 551cf9e47b2SMichael Tuexen struct socket *so; 552cf9e47b2SMichael Tuexen 553cf9e47b2SMichael Tuexen so = SCTP_INP_SO(stcb->sctp_ep); 554cf9e47b2SMichael Tuexen atomic_add_int(&stcb->asoc.refcnt, 1); 555cf9e47b2SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 556cf9e47b2SMichael Tuexen SCTP_SOCKET_LOCK(so, 1); 557cf9e47b2SMichael Tuexen SCTP_TCB_LOCK(stcb); 558cf9e47b2SMichael Tuexen atomic_subtract_int(&stcb->asoc.refcnt, 1); 559cf9e47b2SMichael Tuexen if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { 560cf9e47b2SMichael Tuexen SCTP_SOCKET_UNLOCK(so, 1); 561cf9e47b2SMichael Tuexen return; 562cf9e47b2SMichael Tuexen } 563cf9e47b2SMichael Tuexen #endif 564f8829a4aSRandall Stewart /* can be delivered right away? */ 565b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { 566f8829a4aSRandall Stewart sctp_log_strm_del(control, NULL, SCTP_STR_LOG_FROM_IMMED_DEL); 56780fefe0aSRandall Stewart } 568830d754dSRandall Stewart /* EY it wont be queued if it could be delivered directly */ 569f8829a4aSRandall Stewart queue_needed = 0; 57028cd0699SMichael Tuexen if (asoc->size_on_all_streams >= control->length) { 571f8829a4aSRandall Stewart asoc->size_on_all_streams -= control->length; 57228cd0699SMichael Tuexen } else { 57328cd0699SMichael Tuexen #ifdef INVARIANTS 57428cd0699SMichael Tuexen panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length); 57528cd0699SMichael Tuexen #else 57628cd0699SMichael Tuexen asoc->size_on_all_streams = 0; 57728cd0699SMichael Tuexen #endif 57828cd0699SMichael Tuexen } 579f8829a4aSRandall Stewart sctp_ucount_decr(asoc->cnt_on_all_streams); 58049656eefSMichael Tuexen strm->last_mid_delivered++; 581b5c16493SMichael Tuexen sctp_mark_non_revokable(asoc, control->sinfo_tsn); 582f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 583f8829a4aSRandall Stewart control, 584cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, 585574679afSMichael Tuexen SCTP_READ_LOCK_NOT_HELD, SCTP_SO_LOCKED); 58644249214SRandall Stewart TAILQ_FOREACH_SAFE(control, &strm->inqueue, next_instrm, at) { 587f8829a4aSRandall Stewart /* all delivered */ 58849656eefSMichael Tuexen nxt_todel = strm->last_mid_delivered + 1; 58949656eefSMichael Tuexen if (SCTP_MID_EQ(asoc->idata_supported, nxt_todel, control->mid) && 59044249214SRandall Stewart (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG)) { 59144249214SRandall Stewart if (control->on_strm_q == SCTP_ON_ORDERED) { 59244249214SRandall Stewart TAILQ_REMOVE(&strm->inqueue, control, next_instrm); 59328cd0699SMichael Tuexen if (asoc->size_on_all_streams >= control->length) { 59428cd0699SMichael Tuexen asoc->size_on_all_streams -= control->length; 59528cd0699SMichael Tuexen } else { 59628cd0699SMichael Tuexen #ifdef INVARIANTS 59728cd0699SMichael Tuexen panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length); 59828cd0699SMichael Tuexen #else 59928cd0699SMichael Tuexen asoc->size_on_all_streams = 0; 60028cd0699SMichael Tuexen #endif 60128cd0699SMichael Tuexen } 60228cd0699SMichael Tuexen sctp_ucount_decr(asoc->cnt_on_all_streams); 60398d5fd97SMichael Tuexen #ifdef INVARIANTS 60444249214SRandall Stewart } else { 60544249214SRandall Stewart panic("Huh control: %p is on_strm_q: %d", 60644249214SRandall Stewart control, control->on_strm_q); 60798d5fd97SMichael Tuexen #endif 60844249214SRandall Stewart } 60944249214SRandall Stewart control->on_strm_q = 0; 61049656eefSMichael Tuexen strm->last_mid_delivered++; 611f8829a4aSRandall Stewart /* 612f8829a4aSRandall Stewart * We ignore the return of deliver_data here 613f8829a4aSRandall Stewart * since we always can hold the chunk on the 614f8829a4aSRandall Stewart * d-queue. And we have a finite number that 615f8829a4aSRandall Stewart * can be delivered from the strq. 616f8829a4aSRandall Stewart */ 617b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { 618f8829a4aSRandall Stewart sctp_log_strm_del(control, NULL, 619f8829a4aSRandall Stewart SCTP_STR_LOG_FROM_IMMED_DEL); 62080fefe0aSRandall Stewart } 621b5c16493SMichael Tuexen sctp_mark_non_revokable(asoc, control->sinfo_tsn); 622f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 623f8829a4aSRandall Stewart control, 624cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, 625cfde3ff7SRandall Stewart SCTP_READ_LOCK_NOT_HELD, 626574679afSMichael Tuexen SCTP_SO_LOCKED); 627f8829a4aSRandall Stewart continue; 62849656eefSMichael Tuexen } else if (SCTP_MID_EQ(asoc->idata_supported, nxt_todel, control->mid)) { 62944249214SRandall Stewart *need_reasm = 1; 630f8829a4aSRandall Stewart } 631f8829a4aSRandall Stewart break; 632f8829a4aSRandall Stewart } 63344249214SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 63444249214SRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 63544249214SRandall Stewart #endif 636f8829a4aSRandall Stewart } 637f8829a4aSRandall Stewart if (queue_needed) { 638f8829a4aSRandall Stewart /* 639f8829a4aSRandall Stewart * Ok, we did not deliver this guy, find the correct place 640f8829a4aSRandall Stewart * to put it on the queue. 641f8829a4aSRandall Stewart */ 64244249214SRandall Stewart if (sctp_place_control_in_stream(strm, asoc, control)) { 64344249214SRandall Stewart snprintf(msg, sizeof(msg), 64449656eefSMichael Tuexen "Queue to str MID: %u duplicate", 64549656eefSMichael Tuexen control->mid); 646d1ea5fa9SMichael Tuexen sctp_clean_up_control(stcb, control); 647b1deed45SMichael Tuexen op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); 64844249214SRandall Stewart stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_3; 649b1deed45SMichael Tuexen sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); 65044249214SRandall Stewart *abort_flag = 1; 651f8829a4aSRandall Stewart } 652f8829a4aSRandall Stewart } 653f8829a4aSRandall Stewart } 654f8829a4aSRandall Stewart 65544249214SRandall Stewart 65644249214SRandall Stewart static void 65744249214SRandall Stewart sctp_setup_tail_pointer(struct sctp_queued_to_read *control) 658f8829a4aSRandall Stewart { 65944249214SRandall Stewart struct mbuf *m, *prev = NULL; 66044249214SRandall Stewart struct sctp_tcb *stcb; 661f8829a4aSRandall Stewart 66244249214SRandall Stewart stcb = control->stcb; 66344249214SRandall Stewart control->held_length = 0; 66444249214SRandall Stewart control->length = 0; 66544249214SRandall Stewart m = control->data; 66644249214SRandall Stewart while (m) { 66744249214SRandall Stewart if (SCTP_BUF_LEN(m) == 0) { 66844249214SRandall Stewart /* Skip mbufs with NO length */ 66944249214SRandall Stewart if (prev == NULL) { 67044249214SRandall Stewart /* First one */ 67144249214SRandall Stewart control->data = sctp_m_free(m); 67244249214SRandall Stewart m = control->data; 67344249214SRandall Stewart } else { 67444249214SRandall Stewart SCTP_BUF_NEXT(prev) = sctp_m_free(m); 67544249214SRandall Stewart m = SCTP_BUF_NEXT(prev); 676f8829a4aSRandall Stewart } 67744249214SRandall Stewart if (m == NULL) { 67844249214SRandall Stewart control->tail_mbuf = prev; 679f8829a4aSRandall Stewart } 68044249214SRandall Stewart continue; 681f8829a4aSRandall Stewart } 68244249214SRandall Stewart prev = m; 68344249214SRandall Stewart atomic_add_int(&control->length, SCTP_BUF_LEN(m)); 68444249214SRandall Stewart if (control->on_read_q) { 68544249214SRandall Stewart /* 68644249214SRandall Stewart * On read queue so we must increment the SB stuff, 68744249214SRandall Stewart * we assume caller has done any locks of SB. 68844249214SRandall Stewart */ 68944249214SRandall Stewart sctp_sballoc(stcb, &stcb->sctp_socket->so_rcv, m); 690f8829a4aSRandall Stewart } 69144249214SRandall Stewart m = SCTP_BUF_NEXT(m); 692f8829a4aSRandall Stewart } 69344249214SRandall Stewart if (prev) { 69444249214SRandall Stewart control->tail_mbuf = prev; 69544249214SRandall Stewart } 696f8829a4aSRandall Stewart } 697f8829a4aSRandall Stewart 698f8829a4aSRandall Stewart static void 69928cd0699SMichael Tuexen sctp_add_to_tail_pointer(struct sctp_queued_to_read *control, struct mbuf *m, uint32_t *added) 700f8829a4aSRandall Stewart { 70144249214SRandall Stewart struct mbuf *prev = NULL; 70244249214SRandall Stewart struct sctp_tcb *stcb; 703f8829a4aSRandall Stewart 70444249214SRandall Stewart stcb = control->stcb; 70544249214SRandall Stewart if (stcb == NULL) { 70698d5fd97SMichael Tuexen #ifdef INVARIANTS 70744249214SRandall Stewart panic("Control broken"); 70898d5fd97SMichael Tuexen #else 70998d5fd97SMichael Tuexen return; 71098d5fd97SMichael Tuexen #endif 71144249214SRandall Stewart } 71244249214SRandall Stewart if (control->tail_mbuf == NULL) { 71344249214SRandall Stewart /* TSNH */ 71444249214SRandall Stewart control->data = m; 71544249214SRandall Stewart sctp_setup_tail_pointer(control); 716f8829a4aSRandall Stewart return; 717f8829a4aSRandall Stewart } 71844249214SRandall Stewart control->tail_mbuf->m_next = m; 71944249214SRandall Stewart while (m) { 72044249214SRandall Stewart if (SCTP_BUF_LEN(m) == 0) { 72144249214SRandall Stewart /* Skip mbufs with NO length */ 72244249214SRandall Stewart if (prev == NULL) { 72344249214SRandall Stewart /* First one */ 72444249214SRandall Stewart control->tail_mbuf->m_next = sctp_m_free(m); 72544249214SRandall Stewart m = control->tail_mbuf->m_next; 72644249214SRandall Stewart } else { 72744249214SRandall Stewart SCTP_BUF_NEXT(prev) = sctp_m_free(m); 72844249214SRandall Stewart m = SCTP_BUF_NEXT(prev); 72944249214SRandall Stewart } 73044249214SRandall Stewart if (m == NULL) { 73144249214SRandall Stewart control->tail_mbuf = prev; 73244249214SRandall Stewart } 73344249214SRandall Stewart continue; 73444249214SRandall Stewart } 73544249214SRandall Stewart prev = m; 73644249214SRandall Stewart if (control->on_read_q) { 737f8829a4aSRandall Stewart /* 73844249214SRandall Stewart * On read queue so we must increment the SB stuff, 73944249214SRandall Stewart * we assume caller has done any locks of SB. 740f8829a4aSRandall Stewart */ 74144249214SRandall Stewart sctp_sballoc(stcb, &stcb->sctp_socket->so_rcv, m); 74244249214SRandall Stewart } 74328cd0699SMichael Tuexen *added += SCTP_BUF_LEN(m); 74444249214SRandall Stewart atomic_add_int(&control->length, SCTP_BUF_LEN(m)); 74544249214SRandall Stewart m = SCTP_BUF_NEXT(m); 74644249214SRandall Stewart } 74744249214SRandall Stewart if (prev) { 74844249214SRandall Stewart control->tail_mbuf = prev; 74944249214SRandall Stewart } 75044249214SRandall Stewart } 75144249214SRandall Stewart 75244249214SRandall Stewart static void 75344249214SRandall Stewart sctp_build_readq_entry_from_ctl(struct sctp_queued_to_read *nc, struct sctp_queued_to_read *control) 75444249214SRandall Stewart { 75544249214SRandall Stewart memset(nc, 0, sizeof(struct sctp_queued_to_read)); 75644249214SRandall Stewart nc->sinfo_stream = control->sinfo_stream; 75749656eefSMichael Tuexen nc->mid = control->mid; 75844249214SRandall Stewart TAILQ_INIT(&nc->reasm); 75944249214SRandall Stewart nc->top_fsn = control->top_fsn; 76049656eefSMichael Tuexen nc->mid = control->mid; 76144249214SRandall Stewart nc->sinfo_flags = control->sinfo_flags; 76244249214SRandall Stewart nc->sinfo_ppid = control->sinfo_ppid; 76344249214SRandall Stewart nc->sinfo_context = control->sinfo_context; 76444249214SRandall Stewart nc->fsn_included = 0xffffffff; 76544249214SRandall Stewart nc->sinfo_tsn = control->sinfo_tsn; 76644249214SRandall Stewart nc->sinfo_cumtsn = control->sinfo_cumtsn; 76744249214SRandall Stewart nc->sinfo_assoc_id = control->sinfo_assoc_id; 76844249214SRandall Stewart nc->whoFrom = control->whoFrom; 76944249214SRandall Stewart atomic_add_int(&nc->whoFrom->ref_count, 1); 77044249214SRandall Stewart nc->stcb = control->stcb; 77144249214SRandall Stewart nc->port_from = control->port_from; 77244249214SRandall Stewart } 77344249214SRandall Stewart 774d1ea5fa9SMichael Tuexen static void 775d1ea5fa9SMichael Tuexen sctp_reset_a_control(struct sctp_queued_to_read *control, 776d1ea5fa9SMichael Tuexen struct sctp_inpcb *inp, uint32_t tsn) 777d1ea5fa9SMichael Tuexen { 778d1ea5fa9SMichael Tuexen control->fsn_included = tsn; 779d1ea5fa9SMichael Tuexen if (control->on_read_q) { 780d1ea5fa9SMichael Tuexen /* 781d1ea5fa9SMichael Tuexen * We have to purge it from there, hopefully this will work 782d1ea5fa9SMichael Tuexen * :-) 783d1ea5fa9SMichael Tuexen */ 784d1ea5fa9SMichael Tuexen TAILQ_REMOVE(&inp->read_queue, control, next); 785d1ea5fa9SMichael Tuexen control->on_read_q = 0; 786d1ea5fa9SMichael Tuexen } 787d1ea5fa9SMichael Tuexen } 788d1ea5fa9SMichael Tuexen 78944249214SRandall Stewart static int 790d1ea5fa9SMichael Tuexen sctp_handle_old_unordered_data(struct sctp_tcb *stcb, 791d1ea5fa9SMichael Tuexen struct sctp_association *asoc, 792d1ea5fa9SMichael Tuexen struct sctp_stream_in *strm, 793d1ea5fa9SMichael Tuexen struct sctp_queued_to_read *control, 794d1ea5fa9SMichael Tuexen uint32_t pd_point, 795d1ea5fa9SMichael Tuexen int inp_read_lock_held) 79644249214SRandall Stewart { 79744249214SRandall Stewart /* 79844249214SRandall Stewart * Special handling for the old un-ordered data chunk. All the 79949656eefSMichael Tuexen * chunks/TSN's go to mid 0. So we have to do the old style watching 80049656eefSMichael Tuexen * to see if we have it all. If you return one, no other control 80149656eefSMichael Tuexen * entries on the un-ordered queue will be looked at. In theory 80249656eefSMichael Tuexen * there should be no others entries in reality, unless the guy is 80349656eefSMichael Tuexen * sending both unordered NDATA and unordered DATA... 80444249214SRandall Stewart */ 80544249214SRandall Stewart struct sctp_tmit_chunk *chk, *lchk, *tchk; 80644249214SRandall Stewart uint32_t fsn; 807643fd575SMichael Tuexen struct sctp_queued_to_read *nc; 80844249214SRandall Stewart int cnt_added; 80944249214SRandall Stewart 81044249214SRandall Stewart if (control->first_frag_seen == 0) { 81144249214SRandall Stewart /* Nothing we can do, we have not seen the first piece yet */ 81244249214SRandall Stewart return (1); 81344249214SRandall Stewart } 81444249214SRandall Stewart /* Collapse any we can */ 81544249214SRandall Stewart cnt_added = 0; 81644249214SRandall Stewart restart: 81744249214SRandall Stewart fsn = control->fsn_included + 1; 81844249214SRandall Stewart /* Now what can we add? */ 81944249214SRandall Stewart TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, lchk) { 82049656eefSMichael Tuexen if (chk->rec.data.fsn == fsn) { 82144249214SRandall Stewart /* Ok lets add it */ 822643fd575SMichael Tuexen sctp_alloc_a_readq(stcb, nc); 823643fd575SMichael Tuexen if (nc == NULL) { 824643fd575SMichael Tuexen break; 825643fd575SMichael Tuexen } 826643fd575SMichael Tuexen memset(nc, 0, sizeof(struct sctp_queued_to_read)); 82744249214SRandall Stewart TAILQ_REMOVE(&control->reasm, chk, sctp_next); 828d1ea5fa9SMichael Tuexen sctp_add_chk_to_control(control, strm, stcb, asoc, chk, SCTP_READ_LOCK_NOT_HELD); 82944249214SRandall Stewart fsn++; 83044249214SRandall Stewart cnt_added++; 83144249214SRandall Stewart chk = NULL; 83244249214SRandall Stewart if (control->end_added) { 83344249214SRandall Stewart /* We are done */ 83444249214SRandall Stewart if (!TAILQ_EMPTY(&control->reasm)) { 83544249214SRandall Stewart /* 83644249214SRandall Stewart * Ok we have to move anything left 83744249214SRandall Stewart * on the control queue to a new 83844249214SRandall Stewart * control. 83944249214SRandall Stewart */ 84044249214SRandall Stewart sctp_build_readq_entry_from_ctl(nc, control); 84144249214SRandall Stewart tchk = TAILQ_FIRST(&control->reasm); 84244249214SRandall Stewart if (tchk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { 84344249214SRandall Stewart TAILQ_REMOVE(&control->reasm, tchk, sctp_next); 84428cd0699SMichael Tuexen if (asoc->size_on_reasm_queue >= tchk->send_size) { 8455cb91655SMichael Tuexen asoc->size_on_reasm_queue -= tchk->send_size; 84628cd0699SMichael Tuexen } else { 84728cd0699SMichael Tuexen #ifdef INVARIANTS 84828cd0699SMichael Tuexen panic("size_on_reasm_queue = %u smaller than chunk length %u", asoc->size_on_reasm_queue, tchk->send_size); 84928cd0699SMichael Tuexen #else 85028cd0699SMichael Tuexen asoc->size_on_reasm_queue = 0; 85128cd0699SMichael Tuexen #endif 85228cd0699SMichael Tuexen } 8535cb91655SMichael Tuexen sctp_ucount_decr(asoc->cnt_on_reasm_queue); 85444249214SRandall Stewart nc->first_frag_seen = 1; 85549656eefSMichael Tuexen nc->fsn_included = tchk->rec.data.fsn; 85644249214SRandall Stewart nc->data = tchk->data; 85749656eefSMichael Tuexen nc->sinfo_ppid = tchk->rec.data.ppid; 85849656eefSMichael Tuexen nc->sinfo_tsn = tchk->rec.data.tsn; 85949656eefSMichael Tuexen sctp_mark_non_revokable(asoc, tchk->rec.data.tsn); 86044249214SRandall Stewart tchk->data = NULL; 86144249214SRandall Stewart sctp_free_a_chunk(stcb, tchk, SCTP_SO_NOT_LOCKED); 86244249214SRandall Stewart sctp_setup_tail_pointer(nc); 86344249214SRandall Stewart tchk = TAILQ_FIRST(&control->reasm); 86444249214SRandall Stewart } 86544249214SRandall Stewart /* Spin the rest onto the queue */ 86644249214SRandall Stewart while (tchk) { 86744249214SRandall Stewart TAILQ_REMOVE(&control->reasm, tchk, sctp_next); 86844249214SRandall Stewart TAILQ_INSERT_TAIL(&nc->reasm, tchk, sctp_next); 86944249214SRandall Stewart tchk = TAILQ_FIRST(&control->reasm); 87044249214SRandall Stewart } 871b7b84c0eSMichael Tuexen /* 872b7b84c0eSMichael Tuexen * Now lets add it to the queue 873b7b84c0eSMichael Tuexen * after removing control 874b7b84c0eSMichael Tuexen */ 87544249214SRandall Stewart TAILQ_INSERT_TAIL(&strm->uno_inqueue, nc, next_instrm); 87644249214SRandall Stewart nc->on_strm_q = SCTP_ON_UNORDERED; 87744249214SRandall Stewart if (control->on_strm_q) { 87844249214SRandall Stewart TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm); 87944249214SRandall Stewart control->on_strm_q = 0; 88044249214SRandall Stewart } 88144249214SRandall Stewart } 88244249214SRandall Stewart if (control->pdapi_started) { 88344249214SRandall Stewart strm->pd_api_started = 0; 88444249214SRandall Stewart control->pdapi_started = 0; 88544249214SRandall Stewart } 88644249214SRandall Stewart if (control->on_strm_q) { 88744249214SRandall Stewart TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm); 88844249214SRandall Stewart control->on_strm_q = 0; 88926f0250aSMichael Tuexen SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs); 89044249214SRandall Stewart } 891c09a1534SMichael Tuexen if (control->on_read_q == 0) { 892c09a1534SMichael Tuexen sctp_add_to_readq(stcb->sctp_ep, stcb, control, 893c09a1534SMichael Tuexen &stcb->sctp_socket->so_rcv, control->end_added, 894d1ea5fa9SMichael Tuexen inp_read_lock_held, SCTP_SO_NOT_LOCKED); 895c09a1534SMichael Tuexen } 896b1deed45SMichael Tuexen sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED); 8970fa7377aSMichael Tuexen if ((nc->first_frag_seen) && !TAILQ_EMPTY(&nc->reasm)) { 898b7b84c0eSMichael Tuexen /* 899b7b84c0eSMichael Tuexen * Switch to the new guy and 900b7b84c0eSMichael Tuexen * continue 901b7b84c0eSMichael Tuexen */ 90244249214SRandall Stewart control = nc; 90344249214SRandall Stewart goto restart; 904643fd575SMichael Tuexen } else { 905d1ea5fa9SMichael Tuexen if (nc->on_strm_q == 0) { 906643fd575SMichael Tuexen sctp_free_a_readq(stcb, nc); 90744249214SRandall Stewart } 908d1ea5fa9SMichael Tuexen } 90944249214SRandall Stewart return (1); 910643fd575SMichael Tuexen } else { 911643fd575SMichael Tuexen sctp_free_a_readq(stcb, nc); 91244249214SRandall Stewart } 91344249214SRandall Stewart } else { 91444249214SRandall Stewart /* Can't add more */ 91544249214SRandall Stewart break; 91644249214SRandall Stewart } 91744249214SRandall Stewart } 91844249214SRandall Stewart if ((control->length > pd_point) && (strm->pd_api_started == 0)) { 919c09a1534SMichael Tuexen strm->pd_api_started = 1; 920c09a1534SMichael Tuexen control->pdapi_started = 1; 92144249214SRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, control, 92244249214SRandall Stewart &stcb->sctp_socket->so_rcv, control->end_added, 923d1ea5fa9SMichael Tuexen inp_read_lock_held, SCTP_SO_NOT_LOCKED); 924b1deed45SMichael Tuexen sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED); 92544249214SRandall Stewart return (0); 92644249214SRandall Stewart } else { 92744249214SRandall Stewart return (1); 92844249214SRandall Stewart } 92944249214SRandall Stewart } 93044249214SRandall Stewart 93144249214SRandall Stewart static void 932d1ea5fa9SMichael Tuexen sctp_inject_old_unordered_data(struct sctp_tcb *stcb, 933d1ea5fa9SMichael Tuexen struct sctp_association *asoc, 93444249214SRandall Stewart struct sctp_queued_to_read *control, 93544249214SRandall Stewart struct sctp_tmit_chunk *chk, 93644249214SRandall Stewart int *abort_flag) 93744249214SRandall Stewart { 93844249214SRandall Stewart struct sctp_tmit_chunk *at; 939d1ea5fa9SMichael Tuexen int inserted; 94044249214SRandall Stewart 94144249214SRandall Stewart /* 94244249214SRandall Stewart * Here we need to place the chunk into the control structure sorted 94344249214SRandall Stewart * in the correct order. 94444249214SRandall Stewart */ 94544249214SRandall Stewart if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { 94644249214SRandall Stewart /* Its the very first one. */ 94744249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX, 948f2ea2a2dSMichael Tuexen "chunk is a first fsn: %u becomes fsn_included\n", 94949656eefSMichael Tuexen chk->rec.data.fsn); 95044249214SRandall Stewart if (control->first_frag_seen) { 95144249214SRandall Stewart /* 95244249214SRandall Stewart * In old un-ordered we can reassembly on one 95344249214SRandall Stewart * control multiple messages. As long as the next 95444249214SRandall Stewart * FIRST is greater then the old first (TSN i.e. FSN 95544249214SRandall Stewart * wise) 95644249214SRandall Stewart */ 95744249214SRandall Stewart struct mbuf *tdata; 95844249214SRandall Stewart uint32_t tmp; 95944249214SRandall Stewart 96049656eefSMichael Tuexen if (SCTP_TSN_GT(chk->rec.data.fsn, control->fsn_included)) { 961b7b84c0eSMichael Tuexen /* 962b7b84c0eSMichael Tuexen * Easy way the start of a new guy beyond 963b7b84c0eSMichael Tuexen * the lowest 964b7b84c0eSMichael Tuexen */ 96544249214SRandall Stewart goto place_chunk; 96644249214SRandall Stewart } 96749656eefSMichael Tuexen if ((chk->rec.data.fsn == control->fsn_included) || 96844249214SRandall Stewart (control->pdapi_started)) { 96944249214SRandall Stewart /* 97044249214SRandall Stewart * Ok this should not happen, if it does we 97144249214SRandall Stewart * started the pd-api on the higher TSN 97244249214SRandall Stewart * (since the equals part is a TSN failure 97344249214SRandall Stewart * it must be that). 97444249214SRandall Stewart * 9755b495f17SMichael Tuexen * We are completly hosed in that case since 9765b495f17SMichael Tuexen * I have no way to recover. This really 9775b495f17SMichael Tuexen * will only happen if we can get more TSN's 97844249214SRandall Stewart * higher before the pd-api-point. 97944249214SRandall Stewart */ 980b1deed45SMichael Tuexen sctp_abort_in_reasm(stcb, control, chk, 98144249214SRandall Stewart abort_flag, 98244249214SRandall Stewart SCTP_FROM_SCTP_INDATA + SCTP_LOC_4); 98344249214SRandall Stewart 98444249214SRandall Stewart return; 98544249214SRandall Stewart } 98644249214SRandall Stewart /* 98744249214SRandall Stewart * Ok we have two firsts and the one we just got is 98844249214SRandall Stewart * smaller than the one we previously placed.. yuck! 98944249214SRandall Stewart * We must swap them out. 99044249214SRandall Stewart */ 99144249214SRandall Stewart /* swap the mbufs */ 99244249214SRandall Stewart tdata = control->data; 99344249214SRandall Stewart control->data = chk->data; 99444249214SRandall Stewart chk->data = tdata; 995d1ea5fa9SMichael Tuexen /* Save the lengths */ 996d1ea5fa9SMichael Tuexen chk->send_size = control->length; 997d1ea5fa9SMichael Tuexen /* Recompute length of control and tail pointer */ 998d1ea5fa9SMichael Tuexen sctp_setup_tail_pointer(control); 99944249214SRandall Stewart /* Fix the FSN included */ 100044249214SRandall Stewart tmp = control->fsn_included; 100149656eefSMichael Tuexen control->fsn_included = chk->rec.data.fsn; 100249656eefSMichael Tuexen chk->rec.data.fsn = tmp; 1003d1ea5fa9SMichael Tuexen /* Fix the TSN included */ 1004d1ea5fa9SMichael Tuexen tmp = control->sinfo_tsn; 100549656eefSMichael Tuexen control->sinfo_tsn = chk->rec.data.tsn; 100649656eefSMichael Tuexen chk->rec.data.tsn = tmp; 1007d1ea5fa9SMichael Tuexen /* Fix the PPID included */ 1008d1ea5fa9SMichael Tuexen tmp = control->sinfo_ppid; 100949656eefSMichael Tuexen control->sinfo_ppid = chk->rec.data.ppid; 101049656eefSMichael Tuexen chk->rec.data.ppid = tmp; 1011d1ea5fa9SMichael Tuexen /* Fix tail pointer */ 101244249214SRandall Stewart goto place_chunk; 101344249214SRandall Stewart } 101444249214SRandall Stewart control->first_frag_seen = 1; 10158b9c95f4SMichael Tuexen control->fsn_included = chk->rec.data.fsn; 10168b9c95f4SMichael Tuexen control->top_fsn = chk->rec.data.fsn; 101749656eefSMichael Tuexen control->sinfo_tsn = chk->rec.data.tsn; 101849656eefSMichael Tuexen control->sinfo_ppid = chk->rec.data.ppid; 101944249214SRandall Stewart control->data = chk->data; 102049656eefSMichael Tuexen sctp_mark_non_revokable(asoc, chk->rec.data.tsn); 102144249214SRandall Stewart chk->data = NULL; 102244249214SRandall Stewart sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); 102344249214SRandall Stewart sctp_setup_tail_pointer(control); 102444249214SRandall Stewart return; 102544249214SRandall Stewart } 102644249214SRandall Stewart place_chunk: 1027d1ea5fa9SMichael Tuexen inserted = 0; 102844249214SRandall Stewart TAILQ_FOREACH(at, &control->reasm, sctp_next) { 102949656eefSMichael Tuexen if (SCTP_TSN_GT(at->rec.data.fsn, chk->rec.data.fsn)) { 103044249214SRandall Stewart /* 103144249214SRandall Stewart * This one in queue is bigger than the new one, 103244249214SRandall Stewart * insert the new one before at. 103344249214SRandall Stewart */ 103444249214SRandall Stewart asoc->size_on_reasm_queue += chk->send_size; 103544249214SRandall Stewart sctp_ucount_incr(asoc->cnt_on_reasm_queue); 103644249214SRandall Stewart inserted = 1; 103744249214SRandall Stewart TAILQ_INSERT_BEFORE(at, chk, sctp_next); 103844249214SRandall Stewart break; 103949656eefSMichael Tuexen } else if (at->rec.data.fsn == chk->rec.data.fsn) { 104044249214SRandall Stewart /* 104144249214SRandall Stewart * They sent a duplicate fsn number. This really 104244249214SRandall Stewart * should not happen since the FSN is a TSN and it 104344249214SRandall Stewart * should have been dropped earlier. 104444249214SRandall Stewart */ 1045b1deed45SMichael Tuexen sctp_abort_in_reasm(stcb, control, chk, 104644249214SRandall Stewart abort_flag, 104744249214SRandall Stewart SCTP_FROM_SCTP_INDATA + SCTP_LOC_5); 104844249214SRandall Stewart return; 104944249214SRandall Stewart } 1050*0053ed28SMichael Tuexen 105144249214SRandall Stewart } 105244249214SRandall Stewart if (inserted == 0) { 105344249214SRandall Stewart /* Its at the end */ 105444249214SRandall Stewart asoc->size_on_reasm_queue += chk->send_size; 105544249214SRandall Stewart sctp_ucount_incr(asoc->cnt_on_reasm_queue); 105649656eefSMichael Tuexen control->top_fsn = chk->rec.data.fsn; 105744249214SRandall Stewart TAILQ_INSERT_TAIL(&control->reasm, chk, sctp_next); 105844249214SRandall Stewart } 105944249214SRandall Stewart } 106044249214SRandall Stewart 106144249214SRandall Stewart static int 1062d1ea5fa9SMichael Tuexen sctp_deliver_reasm_check(struct sctp_tcb *stcb, struct sctp_association *asoc, 1063d1ea5fa9SMichael Tuexen struct sctp_stream_in *strm, int inp_read_lock_held) 106444249214SRandall Stewart { 106544249214SRandall Stewart /* 106644249214SRandall Stewart * Given a stream, strm, see if any of the SSN's on it that are 106744249214SRandall Stewart * fragmented are ready to deliver. If so go ahead and place them on 106844249214SRandall Stewart * the read queue. In so placing if we have hit the end, then we 106944249214SRandall Stewart * need to remove them from the stream's queue. 107044249214SRandall Stewart */ 107144249214SRandall Stewart struct sctp_queued_to_read *control, *nctl = NULL; 107244249214SRandall Stewart uint32_t next_to_del; 107344249214SRandall Stewart uint32_t pd_point; 107444249214SRandall Stewart int ret = 0; 107544249214SRandall Stewart 1076810ec536SMichael Tuexen if (stcb->sctp_socket) { 1077d4d23375SMichael Tuexen pd_point = min(SCTP_SB_LIMIT_RCV(stcb->sctp_socket) >> SCTP_PARTIAL_DELIVERY_SHIFT, 1078810ec536SMichael Tuexen stcb->sctp_ep->partial_delivery_point); 1079810ec536SMichael Tuexen } else { 1080810ec536SMichael Tuexen pd_point = stcb->sctp_ep->partial_delivery_point; 1081810ec536SMichael Tuexen } 108244249214SRandall Stewart control = TAILQ_FIRST(&strm->uno_inqueue); 1083d1ea5fa9SMichael Tuexen 10843d6fe5d8SMichael Tuexen if ((control != NULL) && 108544249214SRandall Stewart (asoc->idata_supported == 0)) { 108644249214SRandall Stewart /* Special handling needed for "old" data format */ 1087d1ea5fa9SMichael Tuexen if (sctp_handle_old_unordered_data(stcb, asoc, strm, control, pd_point, inp_read_lock_held)) { 108844249214SRandall Stewart goto done_un; 1089f8829a4aSRandall Stewart } 1090f8829a4aSRandall Stewart } 109144249214SRandall Stewart if (strm->pd_api_started) { 109244249214SRandall Stewart /* Can't add more */ 109344249214SRandall Stewart return (0); 109444249214SRandall Stewart } 109544249214SRandall Stewart while (control) { 1096f2ea2a2dSMichael Tuexen SCTPDBG(SCTP_DEBUG_XXX, "Looking at control: %p e(%d) ssn: %u top_fsn: %u inc_fsn: %u -uo\n", 109749656eefSMichael Tuexen control, control->end_added, control->mid, control->top_fsn, control->fsn_included); 109844249214SRandall Stewart nctl = TAILQ_NEXT(control, next_instrm); 109944249214SRandall Stewart if (control->end_added) { 110044249214SRandall Stewart /* We just put the last bit on */ 110144249214SRandall Stewart if (control->on_strm_q) { 110298d5fd97SMichael Tuexen #ifdef INVARIANTS 110344249214SRandall Stewart if (control->on_strm_q != SCTP_ON_UNORDERED) { 110444249214SRandall Stewart panic("Huh control: %p on_q: %d -- not unordered?", 110544249214SRandall Stewart control, control->on_strm_q); 110644249214SRandall Stewart } 110798d5fd97SMichael Tuexen #endif 110826f0250aSMichael Tuexen SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs); 110944249214SRandall Stewart TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm); 111044249214SRandall Stewart control->on_strm_q = 0; 111144249214SRandall Stewart } 111244249214SRandall Stewart if (control->on_read_q == 0) { 111344249214SRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 111444249214SRandall Stewart control, 111544249214SRandall Stewart &stcb->sctp_socket->so_rcv, control->end_added, 1116d1ea5fa9SMichael Tuexen inp_read_lock_held, SCTP_SO_NOT_LOCKED); 111744249214SRandall Stewart } 1118f8829a4aSRandall Stewart } else { 111944249214SRandall Stewart /* Can we do a PD-API for this un-ordered guy? */ 112044249214SRandall Stewart if ((control->length >= pd_point) && (strm->pd_api_started == 0)) { 112144249214SRandall Stewart strm->pd_api_started = 1; 112244249214SRandall Stewart control->pdapi_started = 1; 112344249214SRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 112444249214SRandall Stewart control, 112544249214SRandall Stewart &stcb->sctp_socket->so_rcv, control->end_added, 1126d1ea5fa9SMichael Tuexen inp_read_lock_held, SCTP_SO_NOT_LOCKED); 112744249214SRandall Stewart 112844249214SRandall Stewart break; 1129139bc87fSRandall Stewart } 1130f8829a4aSRandall Stewart } 113144249214SRandall Stewart control = nctl; 113244249214SRandall Stewart } 113344249214SRandall Stewart done_un: 113444249214SRandall Stewart control = TAILQ_FIRST(&strm->inqueue); 113544249214SRandall Stewart if (strm->pd_api_started) { 113644249214SRandall Stewart /* Can't add more */ 113744249214SRandall Stewart return (0); 113844249214SRandall Stewart } 113944249214SRandall Stewart if (control == NULL) { 114044249214SRandall Stewart return (ret); 114144249214SRandall Stewart } 114249656eefSMichael Tuexen if (SCTP_MID_EQ(asoc->idata_supported, strm->last_mid_delivered, control->mid)) { 114344249214SRandall Stewart /* 114444249214SRandall Stewart * Ok the guy at the top was being partially delivered 114544249214SRandall Stewart * completed, so we remove it. Note the pd_api flag was 114644249214SRandall Stewart * taken off when the chunk was merged on in 114744249214SRandall Stewart * sctp_queue_data_for_reasm below. 114844249214SRandall Stewart */ 114944249214SRandall Stewart nctl = TAILQ_NEXT(control, next_instrm); 115044249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX, 1151f2ea2a2dSMichael Tuexen "Looking at control: %p e(%d) ssn: %u top_fsn: %u inc_fsn: %u (lastdel: %u)- o\n", 115249656eefSMichael Tuexen control, control->end_added, control->mid, 115344249214SRandall Stewart control->top_fsn, control->fsn_included, 115449656eefSMichael Tuexen strm->last_mid_delivered); 115544249214SRandall Stewart if (control->end_added) { 115644249214SRandall Stewart if (control->on_strm_q) { 115798d5fd97SMichael Tuexen #ifdef INVARIANTS 115844249214SRandall Stewart if (control->on_strm_q != SCTP_ON_ORDERED) { 115944249214SRandall Stewart panic("Huh control: %p on_q: %d -- not ordered?", 116044249214SRandall Stewart control, control->on_strm_q); 116144249214SRandall Stewart } 116298d5fd97SMichael Tuexen #endif 116326f0250aSMichael Tuexen SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs); 116444249214SRandall Stewart TAILQ_REMOVE(&strm->inqueue, control, next_instrm); 116528cd0699SMichael Tuexen if (asoc->size_on_all_streams >= control->length) { 116628cd0699SMichael Tuexen asoc->size_on_all_streams -= control->length; 116728cd0699SMichael Tuexen } else { 116828cd0699SMichael Tuexen #ifdef INVARIANTS 116928cd0699SMichael Tuexen panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length); 117028cd0699SMichael Tuexen #else 117128cd0699SMichael Tuexen asoc->size_on_all_streams = 0; 117228cd0699SMichael Tuexen #endif 117328cd0699SMichael Tuexen } 117428cd0699SMichael Tuexen sctp_ucount_decr(asoc->cnt_on_all_streams); 117544249214SRandall Stewart control->on_strm_q = 0; 117644249214SRandall Stewart } 1177c09a1534SMichael Tuexen if (strm->pd_api_started && control->pdapi_started) { 1178c09a1534SMichael Tuexen control->pdapi_started = 0; 1179c09a1534SMichael Tuexen strm->pd_api_started = 0; 1180c09a1534SMichael Tuexen } 118144249214SRandall Stewart if (control->on_read_q == 0) { 118244249214SRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 118344249214SRandall Stewart control, 118444249214SRandall Stewart &stcb->sctp_socket->so_rcv, control->end_added, 1185d1ea5fa9SMichael Tuexen inp_read_lock_held, SCTP_SO_NOT_LOCKED); 118644249214SRandall Stewart } 118744249214SRandall Stewart control = nctl; 118844249214SRandall Stewart } 118944249214SRandall Stewart } 119044249214SRandall Stewart if (strm->pd_api_started) { 1191b7b84c0eSMichael Tuexen /* 1192b7b84c0eSMichael Tuexen * Can't add more must have gotten an un-ordered above being 1193b7b84c0eSMichael Tuexen * partially delivered. 1194b7b84c0eSMichael Tuexen */ 119544249214SRandall Stewart return (0); 119644249214SRandall Stewart } 119744249214SRandall Stewart deliver_more: 119849656eefSMichael Tuexen next_to_del = strm->last_mid_delivered + 1; 119944249214SRandall Stewart if (control) { 120044249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX, 1201f2ea2a2dSMichael Tuexen "Looking at control: %p e(%d) ssn: %u top_fsn: %u inc_fsn: %u (nxtdel: %u)- o\n", 120249656eefSMichael Tuexen control, control->end_added, control->mid, control->top_fsn, control->fsn_included, 120344249214SRandall Stewart next_to_del); 120444249214SRandall Stewart nctl = TAILQ_NEXT(control, next_instrm); 120549656eefSMichael Tuexen if (SCTP_MID_EQ(asoc->idata_supported, control->mid, next_to_del) && 120644249214SRandall Stewart (control->first_frag_seen)) { 1207c09a1534SMichael Tuexen int done; 1208c09a1534SMichael Tuexen 120944249214SRandall Stewart /* Ok we can deliver it onto the stream. */ 121044249214SRandall Stewart if (control->end_added) { 121144249214SRandall Stewart /* We are done with it afterwards */ 121244249214SRandall Stewart if (control->on_strm_q) { 121398d5fd97SMichael Tuexen #ifdef INVARIANTS 121444249214SRandall Stewart if (control->on_strm_q != SCTP_ON_ORDERED) { 121544249214SRandall Stewart panic("Huh control: %p on_q: %d -- not ordered?", 121644249214SRandall Stewart control, control->on_strm_q); 121744249214SRandall Stewart } 121898d5fd97SMichael Tuexen #endif 121926f0250aSMichael Tuexen SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs); 122044249214SRandall Stewart TAILQ_REMOVE(&strm->inqueue, control, next_instrm); 122128cd0699SMichael Tuexen if (asoc->size_on_all_streams >= control->length) { 122228cd0699SMichael Tuexen asoc->size_on_all_streams -= control->length; 122328cd0699SMichael Tuexen } else { 122428cd0699SMichael Tuexen #ifdef INVARIANTS 122528cd0699SMichael Tuexen panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length); 122628cd0699SMichael Tuexen #else 122728cd0699SMichael Tuexen asoc->size_on_all_streams = 0; 122828cd0699SMichael Tuexen #endif 122928cd0699SMichael Tuexen } 123028cd0699SMichael Tuexen sctp_ucount_decr(asoc->cnt_on_all_streams); 123144249214SRandall Stewart control->on_strm_q = 0; 123244249214SRandall Stewart } 123344249214SRandall Stewart ret++; 123444249214SRandall Stewart } 123544249214SRandall Stewart if (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) { 1236b7b84c0eSMichael Tuexen /* 1237b7b84c0eSMichael Tuexen * A singleton now slipping through - mark 1238b7b84c0eSMichael Tuexen * it non-revokable too 1239b7b84c0eSMichael Tuexen */ 124044249214SRandall Stewart sctp_mark_non_revokable(asoc, control->sinfo_tsn); 124144249214SRandall Stewart } else if (control->end_added == 0) { 1242b7b84c0eSMichael Tuexen /* 1243b7b84c0eSMichael Tuexen * Check if we can defer adding until its 1244b7b84c0eSMichael Tuexen * all there 1245b7b84c0eSMichael Tuexen */ 124644249214SRandall Stewart if ((control->length < pd_point) || (strm->pd_api_started)) { 1247b7b84c0eSMichael Tuexen /* 1248b7b84c0eSMichael Tuexen * Don't need it or cannot add more 1249b7b84c0eSMichael Tuexen * (one being delivered that way) 1250b7b84c0eSMichael Tuexen */ 125144249214SRandall Stewart goto out; 125244249214SRandall Stewart } 125344249214SRandall Stewart } 1254c09a1534SMichael Tuexen done = (control->end_added) && (control->last_frag_seen); 125544249214SRandall Stewart if (control->on_read_q == 0) { 1256253a63b8SMichael Tuexen if (!done) { 1257253a63b8SMichael Tuexen if (asoc->size_on_all_streams >= control->length) { 1258253a63b8SMichael Tuexen asoc->size_on_all_streams -= control->length; 1259253a63b8SMichael Tuexen } else { 1260253a63b8SMichael Tuexen #ifdef INVARIANTS 1261253a63b8SMichael Tuexen panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length); 1262253a63b8SMichael Tuexen #else 1263253a63b8SMichael Tuexen asoc->size_on_all_streams = 0; 1264253a63b8SMichael Tuexen #endif 1265253a63b8SMichael Tuexen } 1266253a63b8SMichael Tuexen strm->pd_api_started = 1; 1267253a63b8SMichael Tuexen control->pdapi_started = 1; 1268253a63b8SMichael Tuexen } 126944249214SRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 127044249214SRandall Stewart control, 127144249214SRandall Stewart &stcb->sctp_socket->so_rcv, control->end_added, 1272d1ea5fa9SMichael Tuexen inp_read_lock_held, SCTP_SO_NOT_LOCKED); 127344249214SRandall Stewart } 127449656eefSMichael Tuexen strm->last_mid_delivered = next_to_del; 1275c09a1534SMichael Tuexen if (done) { 127644249214SRandall Stewart control = nctl; 127744249214SRandall Stewart goto deliver_more; 127844249214SRandall Stewart } 127944249214SRandall Stewart } 128044249214SRandall Stewart } 128144249214SRandall Stewart out: 128244249214SRandall Stewart return (ret); 128344249214SRandall Stewart } 128444249214SRandall Stewart 1285d1ea5fa9SMichael Tuexen 128628cd0699SMichael Tuexen uint32_t 128744249214SRandall Stewart sctp_add_chk_to_control(struct sctp_queued_to_read *control, 128844249214SRandall Stewart struct sctp_stream_in *strm, 128944249214SRandall Stewart struct sctp_tcb *stcb, struct sctp_association *asoc, 1290b0471b4bSMichael Tuexen struct sctp_tmit_chunk *chk, int hold_rlock) 1291b0471b4bSMichael Tuexen { 129244249214SRandall Stewart /* 129344249214SRandall Stewart * Given a control and a chunk, merge the data from the chk onto the 129444249214SRandall Stewart * control and free up the chunk resources. 129544249214SRandall Stewart */ 129628cd0699SMichael Tuexen uint32_t added = 0; 129744249214SRandall Stewart int i_locked = 0; 129844249214SRandall Stewart 1299d1ea5fa9SMichael Tuexen if (control->on_read_q && (hold_rlock == 0)) { 130044249214SRandall Stewart /* 130144249214SRandall Stewart * Its being pd-api'd so we must do some locks. 130244249214SRandall Stewart */ 130344249214SRandall Stewart SCTP_INP_READ_LOCK(stcb->sctp_ep); 130444249214SRandall Stewart i_locked = 1; 130544249214SRandall Stewart } 130644249214SRandall Stewart if (control->data == NULL) { 130744249214SRandall Stewart control->data = chk->data; 130844249214SRandall Stewart sctp_setup_tail_pointer(control); 130944249214SRandall Stewart } else { 131028cd0699SMichael Tuexen sctp_add_to_tail_pointer(control, chk->data, &added); 131144249214SRandall Stewart } 131249656eefSMichael Tuexen control->fsn_included = chk->rec.data.fsn; 131344249214SRandall Stewart asoc->size_on_reasm_queue -= chk->send_size; 131444249214SRandall Stewart sctp_ucount_decr(asoc->cnt_on_reasm_queue); 131549656eefSMichael Tuexen sctp_mark_non_revokable(asoc, chk->rec.data.tsn); 131644249214SRandall Stewart chk->data = NULL; 131744249214SRandall Stewart if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { 131844249214SRandall Stewart control->first_frag_seen = 1; 13198b9c95f4SMichael Tuexen control->sinfo_tsn = chk->rec.data.tsn; 13208b9c95f4SMichael Tuexen control->sinfo_ppid = chk->rec.data.ppid; 132144249214SRandall Stewart } 132244249214SRandall Stewart if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { 132344249214SRandall Stewart /* Its complete */ 132444249214SRandall Stewart if ((control->on_strm_q) && (control->on_read_q)) { 132544249214SRandall Stewart if (control->pdapi_started) { 132644249214SRandall Stewart control->pdapi_started = 0; 132744249214SRandall Stewart strm->pd_api_started = 0; 132844249214SRandall Stewart } 132944249214SRandall Stewart if (control->on_strm_q == SCTP_ON_UNORDERED) { 133044249214SRandall Stewart /* Unordered */ 133144249214SRandall Stewart TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm); 133244249214SRandall Stewart control->on_strm_q = 0; 133344249214SRandall Stewart } else if (control->on_strm_q == SCTP_ON_ORDERED) { 133444249214SRandall Stewart /* Ordered */ 133544249214SRandall Stewart TAILQ_REMOVE(&strm->inqueue, control, next_instrm); 1336253a63b8SMichael Tuexen /* 1337253a63b8SMichael Tuexen * Don't need to decrement 1338253a63b8SMichael Tuexen * size_on_all_streams, since control is on 1339253a63b8SMichael Tuexen * the read queue. 1340253a63b8SMichael Tuexen */ 134128cd0699SMichael Tuexen sctp_ucount_decr(asoc->cnt_on_all_streams); 134244249214SRandall Stewart control->on_strm_q = 0; 134398d5fd97SMichael Tuexen #ifdef INVARIANTS 134444249214SRandall Stewart } else if (control->on_strm_q) { 134544249214SRandall Stewart panic("Unknown state on ctrl: %p on_strm_q: %d", control, 134644249214SRandall Stewart control->on_strm_q); 134798d5fd97SMichael Tuexen #endif 134844249214SRandall Stewart } 134944249214SRandall Stewart } 135044249214SRandall Stewart control->end_added = 1; 135144249214SRandall Stewart control->last_frag_seen = 1; 135244249214SRandall Stewart } 135344249214SRandall Stewart if (i_locked) { 135444249214SRandall Stewart SCTP_INP_READ_UNLOCK(stcb->sctp_ep); 135544249214SRandall Stewart } 135644249214SRandall Stewart sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); 135728cd0699SMichael Tuexen return (added); 1358f8829a4aSRandall Stewart } 1359f8829a4aSRandall Stewart 1360f8829a4aSRandall Stewart /* 1361f8829a4aSRandall Stewart * Dump onto the re-assembly queue, in its proper place. After dumping on the 1362f8829a4aSRandall Stewart * queue, see if anthing can be delivered. If so pull it off (or as much as 1363f8829a4aSRandall Stewart * we can. If we run out of space then we must dump what we can and set the 1364f8829a4aSRandall Stewart * appropriate flag to say we queued what we could. 1365f8829a4aSRandall Stewart */ 1366f8829a4aSRandall Stewart static void 1367f8829a4aSRandall Stewart sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, 136844249214SRandall Stewart struct sctp_queued_to_read *control, 136944249214SRandall Stewart struct sctp_tmit_chunk *chk, 137044249214SRandall Stewart int created_control, 137144249214SRandall Stewart int *abort_flag, uint32_t tsn) 1372f8829a4aSRandall Stewart { 137344249214SRandall Stewart uint32_t next_fsn; 137444249214SRandall Stewart struct sctp_tmit_chunk *at, *nat; 13753d6fe5d8SMichael Tuexen struct sctp_stream_in *strm; 1376c09a1534SMichael Tuexen int do_wakeup, unordered; 137728cd0699SMichael Tuexen uint32_t lenadded; 1378f8829a4aSRandall Stewart 13793d6fe5d8SMichael Tuexen strm = &asoc->strmin[control->sinfo_stream]; 1380f8829a4aSRandall Stewart /* 138144249214SRandall Stewart * For old un-ordered data chunks. 1382f8829a4aSRandall Stewart */ 138344249214SRandall Stewart if ((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED) { 138444249214SRandall Stewart unordered = 1; 1385f8829a4aSRandall Stewart } else { 138644249214SRandall Stewart unordered = 0; 138744249214SRandall Stewart } 138844249214SRandall Stewart /* Must be added to the stream-in queue */ 138944249214SRandall Stewart if (created_control) { 139028cd0699SMichael Tuexen if (unordered == 0) { 139128cd0699SMichael Tuexen sctp_ucount_incr(asoc->cnt_on_all_streams); 139228cd0699SMichael Tuexen } 139344249214SRandall Stewart if (sctp_place_control_in_stream(strm, asoc, control)) { 139444249214SRandall Stewart /* Duplicate SSN? */ 1395b1deed45SMichael Tuexen sctp_abort_in_reasm(stcb, control, chk, 139644249214SRandall Stewart abort_flag, 139744249214SRandall Stewart SCTP_FROM_SCTP_INDATA + SCTP_LOC_6); 139853999485SMichael Tuexen sctp_clean_up_control(stcb, control); 139944249214SRandall Stewart return; 140044249214SRandall Stewart } 140144249214SRandall Stewart if ((tsn == (asoc->cumulative_tsn + 1) && (asoc->idata_supported == 0))) { 1402f8829a4aSRandall Stewart /* 140344249214SRandall Stewart * Ok we created this control and now lets validate 140444249214SRandall Stewart * that its legal i.e. there is a B bit set, if not 140544249214SRandall Stewart * and we have up to the cum-ack then its invalid. 140644249214SRandall Stewart */ 140744249214SRandall Stewart if ((chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) == 0) { 1408b1deed45SMichael Tuexen sctp_abort_in_reasm(stcb, control, chk, 140944249214SRandall Stewart abort_flag, 141044249214SRandall Stewart SCTP_FROM_SCTP_INDATA + SCTP_LOC_7); 141144249214SRandall Stewart return; 141244249214SRandall Stewart } 141344249214SRandall Stewart } 141444249214SRandall Stewart } 1415a39ddef0SMichael Tuexen if ((asoc->idata_supported == 0) && (unordered == 1)) { 1416d1ea5fa9SMichael Tuexen sctp_inject_old_unordered_data(stcb, asoc, control, chk, abort_flag); 141744249214SRandall Stewart return; 141844249214SRandall Stewart } 141944249214SRandall Stewart /* 142044249214SRandall Stewart * Ok we must queue the chunk into the reasembly portion: o if its 142144249214SRandall Stewart * the first it goes to the control mbuf. o if its not first but the 142244249214SRandall Stewart * next in sequence it goes to the control, and each succeeding one 142344249214SRandall Stewart * in order also goes. o if its not in order we place it on the list 142444249214SRandall Stewart * in its place. 142544249214SRandall Stewart */ 142644249214SRandall Stewart if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { 142744249214SRandall Stewart /* Its the very first one. */ 142844249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX, 1429f2ea2a2dSMichael Tuexen "chunk is a first fsn: %u becomes fsn_included\n", 143049656eefSMichael Tuexen chk->rec.data.fsn); 143144249214SRandall Stewart if (control->first_frag_seen) { 143244249214SRandall Stewart /* 143344249214SRandall Stewart * Error on senders part, they either sent us two 143444249214SRandall Stewart * data chunks with FIRST, or they sent two 143544249214SRandall Stewart * un-ordered chunks that were fragmented at the 143644249214SRandall Stewart * same time in the same stream. 143744249214SRandall Stewart */ 1438b1deed45SMichael Tuexen sctp_abort_in_reasm(stcb, control, chk, 143944249214SRandall Stewart abort_flag, 144044249214SRandall Stewart SCTP_FROM_SCTP_INDATA + SCTP_LOC_8); 144144249214SRandall Stewart return; 144244249214SRandall Stewart } 144344249214SRandall Stewart control->first_frag_seen = 1; 14448b9c95f4SMichael Tuexen control->sinfo_ppid = chk->rec.data.ppid; 14458b9c95f4SMichael Tuexen control->sinfo_tsn = chk->rec.data.tsn; 144649656eefSMichael Tuexen control->fsn_included = chk->rec.data.fsn; 144744249214SRandall Stewart control->data = chk->data; 144849656eefSMichael Tuexen sctp_mark_non_revokable(asoc, chk->rec.data.tsn); 144944249214SRandall Stewart chk->data = NULL; 145044249214SRandall Stewart sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); 145144249214SRandall Stewart sctp_setup_tail_pointer(control); 145228cd0699SMichael Tuexen asoc->size_on_all_streams += control->length; 145344249214SRandall Stewart } else { 145444249214SRandall Stewart /* Place the chunk in our list */ 145544249214SRandall Stewart int inserted = 0; 145644249214SRandall Stewart 145744249214SRandall Stewart if (control->last_frag_seen == 0) { 145844249214SRandall Stewart /* Still willing to raise highest FSN seen */ 145949656eefSMichael Tuexen if (SCTP_TSN_GT(chk->rec.data.fsn, control->top_fsn)) { 146044249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX, 1461f2ea2a2dSMichael Tuexen "We have a new top_fsn: %u\n", 146249656eefSMichael Tuexen chk->rec.data.fsn); 146349656eefSMichael Tuexen control->top_fsn = chk->rec.data.fsn; 146444249214SRandall Stewart } 146544249214SRandall Stewart if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { 146644249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX, 1467f2ea2a2dSMichael Tuexen "The last fsn is now in place fsn: %u\n", 146849656eefSMichael Tuexen chk->rec.data.fsn); 146944249214SRandall Stewart control->last_frag_seen = 1; 147044249214SRandall Stewart } 147144249214SRandall Stewart if (asoc->idata_supported || control->first_frag_seen) { 147244249214SRandall Stewart /* 147344249214SRandall Stewart * For IDATA we always check since we know 147444249214SRandall Stewart * that the first fragment is 0. For old 147544249214SRandall Stewart * DATA we have to receive the first before 1476cd0a4ff6SPedro F. Giffuni * we know the first FSN (which is the TSN). 147744249214SRandall Stewart */ 147849656eefSMichael Tuexen if (SCTP_TSN_GE(control->fsn_included, chk->rec.data.fsn)) { 1479b7b84c0eSMichael Tuexen /* 1480b7b84c0eSMichael Tuexen * We have already delivered up to 1481b7b84c0eSMichael Tuexen * this so its a dup 1482b7b84c0eSMichael Tuexen */ 1483b1deed45SMichael Tuexen sctp_abort_in_reasm(stcb, control, chk, 148444249214SRandall Stewart abort_flag, 148544249214SRandall Stewart SCTP_FROM_SCTP_INDATA + SCTP_LOC_9); 148644249214SRandall Stewart return; 148744249214SRandall Stewart } 148844249214SRandall Stewart } 148944249214SRandall Stewart } else { 149044249214SRandall Stewart if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { 149144249214SRandall Stewart /* Second last? huh? */ 149244249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX, 1493f2ea2a2dSMichael Tuexen "Duplicate last fsn: %u (top: %u) -- abort\n", 149449656eefSMichael Tuexen chk->rec.data.fsn, control->top_fsn); 1495b1deed45SMichael Tuexen sctp_abort_in_reasm(stcb, control, 149644249214SRandall Stewart chk, abort_flag, 149744249214SRandall Stewart SCTP_FROM_SCTP_INDATA + SCTP_LOC_10); 149844249214SRandall Stewart return; 149944249214SRandall Stewart } 150044249214SRandall Stewart if (asoc->idata_supported || control->first_frag_seen) { 150144249214SRandall Stewart /* 150244249214SRandall Stewart * For IDATA we always check since we know 150344249214SRandall Stewart * that the first fragment is 0. For old 150444249214SRandall Stewart * DATA we have to receive the first before 1505cd0a4ff6SPedro F. Giffuni * we know the first FSN (which is the TSN). 150644249214SRandall Stewart */ 150744249214SRandall Stewart 150849656eefSMichael Tuexen if (SCTP_TSN_GE(control->fsn_included, chk->rec.data.fsn)) { 1509b7b84c0eSMichael Tuexen /* 1510b7b84c0eSMichael Tuexen * We have already delivered up to 1511b7b84c0eSMichael Tuexen * this so its a dup 1512b7b84c0eSMichael Tuexen */ 151344249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX, 1514f2ea2a2dSMichael Tuexen "New fsn: %u is already seen in included_fsn: %u -- abort\n", 151549656eefSMichael Tuexen chk->rec.data.fsn, control->fsn_included); 1516b1deed45SMichael Tuexen sctp_abort_in_reasm(stcb, control, chk, 151744249214SRandall Stewart abort_flag, 151844249214SRandall Stewart SCTP_FROM_SCTP_INDATA + SCTP_LOC_11); 151944249214SRandall Stewart return; 152044249214SRandall Stewart } 152144249214SRandall Stewart } 1522b7b84c0eSMichael Tuexen /* 1523b7b84c0eSMichael Tuexen * validate not beyond top FSN if we have seen last 1524b7b84c0eSMichael Tuexen * one 1525b7b84c0eSMichael Tuexen */ 152649656eefSMichael Tuexen if (SCTP_TSN_GT(chk->rec.data.fsn, control->top_fsn)) { 152744249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX, 1528f2ea2a2dSMichael Tuexen "New fsn: %u is beyond or at top_fsn: %u -- abort\n", 152949656eefSMichael Tuexen chk->rec.data.fsn, 153044249214SRandall Stewart control->top_fsn); 1531b1deed45SMichael Tuexen sctp_abort_in_reasm(stcb, control, chk, 153244249214SRandall Stewart abort_flag, 153344249214SRandall Stewart SCTP_FROM_SCTP_INDATA + SCTP_LOC_12); 153444249214SRandall Stewart return; 153544249214SRandall Stewart } 153644249214SRandall Stewart } 153744249214SRandall Stewart /* 153844249214SRandall Stewart * If we reach here, we need to place the new chunk in the 153944249214SRandall Stewart * reassembly for this control. 154044249214SRandall Stewart */ 154144249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX, 1542f2ea2a2dSMichael Tuexen "chunk is a not first fsn: %u needs to be inserted\n", 154349656eefSMichael Tuexen chk->rec.data.fsn); 154444249214SRandall Stewart TAILQ_FOREACH(at, &control->reasm, sctp_next) { 154549656eefSMichael Tuexen if (SCTP_TSN_GT(at->rec.data.fsn, chk->rec.data.fsn)) { 154644249214SRandall Stewart /* 154744249214SRandall Stewart * This one in queue is bigger than the new 154844249214SRandall Stewart * one, insert the new one before at. 154944249214SRandall Stewart */ 155044249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX, 1551f2ea2a2dSMichael Tuexen "Insert it before fsn: %u\n", 155249656eefSMichael Tuexen at->rec.data.fsn); 1553f8829a4aSRandall Stewart asoc->size_on_reasm_queue += chk->send_size; 1554f8829a4aSRandall Stewart sctp_ucount_incr(asoc->cnt_on_reasm_queue); 155544249214SRandall Stewart TAILQ_INSERT_BEFORE(at, chk, sctp_next); 155644249214SRandall Stewart inserted = 1; 155744249214SRandall Stewart break; 155849656eefSMichael Tuexen } else if (at->rec.data.fsn == chk->rec.data.fsn) { 1559b7b84c0eSMichael Tuexen /* 1560b7b84c0eSMichael Tuexen * Gak, He sent me a duplicate str seq 1561b7b84c0eSMichael Tuexen * number 1562b7b84c0eSMichael Tuexen */ 156344249214SRandall Stewart /* 156444249214SRandall Stewart * foo bar, I guess I will just free this 156544249214SRandall Stewart * new guy, should we abort too? FIX ME 156644249214SRandall Stewart * MAYBE? Or it COULD be that the SSN's have 156744249214SRandall Stewart * wrapped. Maybe I should compare to TSN 156844249214SRandall Stewart * somehow... sigh for now just blow away 156944249214SRandall Stewart * the chunk! 157044249214SRandall Stewart */ 157144249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX, 1572f2ea2a2dSMichael Tuexen "Duplicate to fsn: %u -- abort\n", 157349656eefSMichael Tuexen at->rec.data.fsn); 1574b1deed45SMichael Tuexen sctp_abort_in_reasm(stcb, control, 157544249214SRandall Stewart chk, abort_flag, 157644249214SRandall Stewart SCTP_FROM_SCTP_INDATA + SCTP_LOC_13); 157744249214SRandall Stewart return; 157844249214SRandall Stewart } 157944249214SRandall Stewart } 158044249214SRandall Stewart if (inserted == 0) { 158144249214SRandall Stewart /* Goes on the end */ 1582f2ea2a2dSMichael Tuexen SCTPDBG(SCTP_DEBUG_XXX, "Inserting at tail of list fsn: %u\n", 158349656eefSMichael Tuexen chk->rec.data.fsn); 158444249214SRandall Stewart asoc->size_on_reasm_queue += chk->send_size; 158544249214SRandall Stewart sctp_ucount_incr(asoc->cnt_on_reasm_queue); 158644249214SRandall Stewart TAILQ_INSERT_TAIL(&control->reasm, chk, sctp_next); 158744249214SRandall Stewart } 158844249214SRandall Stewart } 158944249214SRandall Stewart /* 159044249214SRandall Stewart * Ok lets see if we can suck any up into the control structure that 159144249214SRandall Stewart * are in seq if it makes sense. 159244249214SRandall Stewart */ 1593c09a1534SMichael Tuexen do_wakeup = 0; 159444249214SRandall Stewart /* 159544249214SRandall Stewart * If the first fragment has not been seen there is no sense in 159644249214SRandall Stewart * looking. 159744249214SRandall Stewart */ 159844249214SRandall Stewart if (control->first_frag_seen) { 159944249214SRandall Stewart next_fsn = control->fsn_included + 1; 160044249214SRandall Stewart TAILQ_FOREACH_SAFE(at, &control->reasm, sctp_next, nat) { 160149656eefSMichael Tuexen if (at->rec.data.fsn == next_fsn) { 160244249214SRandall Stewart /* We can add this one now to the control */ 160344249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX, 1604f2ea2a2dSMichael Tuexen "Adding more to control: %p at: %p fsn: %u next_fsn: %u included: %u\n", 160544249214SRandall Stewart control, at, 160649656eefSMichael Tuexen at->rec.data.fsn, 160744249214SRandall Stewart next_fsn, control->fsn_included); 160844249214SRandall Stewart TAILQ_REMOVE(&control->reasm, at, sctp_next); 160928cd0699SMichael Tuexen lenadded = sctp_add_chk_to_control(control, strm, stcb, asoc, at, SCTP_READ_LOCK_NOT_HELD); 1610c09a1534SMichael Tuexen if (control->on_read_q) { 1611c09a1534SMichael Tuexen do_wakeup = 1; 161272e23abaSMichael Tuexen } else { 161372e23abaSMichael Tuexen /* 161472e23abaSMichael Tuexen * We only add to the 161572e23abaSMichael Tuexen * size-on-all-streams if its not on 161672e23abaSMichael Tuexen * the read q. The read q flag will 161772e23abaSMichael Tuexen * cause a sballoc so its accounted 161872e23abaSMichael Tuexen * for there. 161972e23abaSMichael Tuexen */ 162072e23abaSMichael Tuexen asoc->size_on_all_streams += lenadded; 1621c09a1534SMichael Tuexen } 162244249214SRandall Stewart next_fsn++; 162344249214SRandall Stewart if (control->end_added && control->pdapi_started) { 162444249214SRandall Stewart if (strm->pd_api_started) { 162544249214SRandall Stewart strm->pd_api_started = 0; 162644249214SRandall Stewart control->pdapi_started = 0; 162744249214SRandall Stewart } 162844249214SRandall Stewart if (control->on_read_q == 0) { 162944249214SRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 163044249214SRandall Stewart control, 163144249214SRandall Stewart &stcb->sctp_socket->so_rcv, control->end_added, 163244249214SRandall Stewart SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 163344249214SRandall Stewart } 163444249214SRandall Stewart break; 163544249214SRandall Stewart } 163644249214SRandall Stewart } else { 1637f8829a4aSRandall Stewart break; 1638f8829a4aSRandall Stewart } 1639f8829a4aSRandall Stewart } 1640f8829a4aSRandall Stewart } 1641c09a1534SMichael Tuexen if (do_wakeup) { 164244249214SRandall Stewart /* Need to wakeup the reader */ 1643b1deed45SMichael Tuexen sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED); 1644f8829a4aSRandall Stewart } 1645f8829a4aSRandall Stewart } 1646f8829a4aSRandall Stewart 164744249214SRandall Stewart static struct sctp_queued_to_read * 164849656eefSMichael Tuexen sctp_find_reasm_entry(struct sctp_stream_in *strm, uint32_t mid, int ordered, int idata_supported) 1649f8829a4aSRandall Stewart { 1650c09a1534SMichael Tuexen struct sctp_queued_to_read *control; 1651f8829a4aSRandall Stewart 165244249214SRandall Stewart if (ordered) { 1653c09a1534SMichael Tuexen TAILQ_FOREACH(control, &strm->inqueue, next_instrm) { 165449656eefSMichael Tuexen if (SCTP_MID_EQ(idata_supported, control->mid, mid)) { 165544249214SRandall Stewart break; 165644249214SRandall Stewart } 165744249214SRandall Stewart } 1658f8829a4aSRandall Stewart } else { 165949656eefSMichael Tuexen if (idata_supported) { 1660c09a1534SMichael Tuexen TAILQ_FOREACH(control, &strm->uno_inqueue, next_instrm) { 166149656eefSMichael Tuexen if (SCTP_MID_EQ(idata_supported, control->mid, mid)) { 166244249214SRandall Stewart break; 1663f8829a4aSRandall Stewart } 1664f8829a4aSRandall Stewart } 166549656eefSMichael Tuexen } else { 166649656eefSMichael Tuexen control = TAILQ_FIRST(&strm->uno_inqueue); 166749656eefSMichael Tuexen } 1668f8829a4aSRandall Stewart } 1669c09a1534SMichael Tuexen return (control); 1670f8829a4aSRandall Stewart } 167144249214SRandall Stewart 1672f8829a4aSRandall Stewart static int 1673f8829a4aSRandall Stewart sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, 167444249214SRandall Stewart struct mbuf **m, int offset, int chk_length, 1675f8829a4aSRandall Stewart struct sctp_nets *net, uint32_t *high_tsn, int *abort_flag, 16768b9c95f4SMichael Tuexen int *break_flag, int last_chunk, uint8_t chk_type) 1677f8829a4aSRandall Stewart { 167895844fceSMichael Tuexen struct sctp_tmit_chunk *chk = NULL; /* make gcc happy */ 167949656eefSMichael Tuexen uint32_t tsn, fsn, gap, mid; 1680f8829a4aSRandall Stewart struct mbuf *dmbuf; 16817215cc1bSMichael Tuexen int the_len; 1682139bc87fSRandall Stewart int need_reasm_check = 0; 168349656eefSMichael Tuexen uint16_t sid; 1684ff1ffd74SMichael Tuexen struct mbuf *op_err; 1685ff1ffd74SMichael Tuexen char msg[SCTP_DIAG_INFO_LEN]; 168628cd0699SMichael Tuexen struct sctp_queued_to_read *control, *ncontrol; 168749656eefSMichael Tuexen uint32_t ppid; 16888b9c95f4SMichael Tuexen uint8_t chk_flags; 168917205eccSRandall Stewart struct sctp_stream_reset_list *liste; 169044249214SRandall Stewart int ordered; 169144249214SRandall Stewart size_t clen; 169244249214SRandall Stewart int created_control = 0; 1693f8829a4aSRandall Stewart 16948b9c95f4SMichael Tuexen if (chk_type == SCTP_IDATA) { 16958b9c95f4SMichael Tuexen struct sctp_idata_chunk *chunk, chunk_buf; 16968b9c95f4SMichael Tuexen 16978b9c95f4SMichael Tuexen chunk = (struct sctp_idata_chunk *)sctp_m_getptr(*m, offset, 169844249214SRandall Stewart sizeof(struct sctp_idata_chunk), (uint8_t *)&chunk_buf); 16998b9c95f4SMichael Tuexen chk_flags = chunk->ch.chunk_flags; 170044249214SRandall Stewart clen = sizeof(struct sctp_idata_chunk); 17018b9c95f4SMichael Tuexen tsn = ntohl(chunk->dp.tsn); 17028b9c95f4SMichael Tuexen sid = ntohs(chunk->dp.sid); 17038b9c95f4SMichael Tuexen mid = ntohl(chunk->dp.mid); 17048b9c95f4SMichael Tuexen if (chk_flags & SCTP_DATA_FIRST_FRAG) { 170544249214SRandall Stewart fsn = 0; 17068b9c95f4SMichael Tuexen ppid = chunk->dp.ppid_fsn.ppid; 170744249214SRandall Stewart } else { 17088b9c95f4SMichael Tuexen fsn = ntohl(chunk->dp.ppid_fsn.fsn); 17098b9c95f4SMichael Tuexen ppid = 0xffffffff; /* Use as an invalid value. */ 171044249214SRandall Stewart } 17118b9c95f4SMichael Tuexen } else { 17128b9c95f4SMichael Tuexen struct sctp_data_chunk *chunk, chunk_buf; 17138b9c95f4SMichael Tuexen 17148b9c95f4SMichael Tuexen chunk = (struct sctp_data_chunk *)sctp_m_getptr(*m, offset, 17158b9c95f4SMichael Tuexen sizeof(struct sctp_data_chunk), (uint8_t *)&chunk_buf); 17168b9c95f4SMichael Tuexen chk_flags = chunk->ch.chunk_flags; 17178b9c95f4SMichael Tuexen clen = sizeof(struct sctp_data_chunk); 17188b9c95f4SMichael Tuexen tsn = ntohl(chunk->dp.tsn); 17198b9c95f4SMichael Tuexen sid = ntohs(chunk->dp.sid); 17208b9c95f4SMichael Tuexen mid = (uint32_t)(ntohs(chunk->dp.ssn)); 17218b9c95f4SMichael Tuexen fsn = tsn; 17228b9c95f4SMichael Tuexen ppid = chunk->dp.ppid; 17238b9c95f4SMichael Tuexen } 172444249214SRandall Stewart if ((size_t)chk_length == clen) { 172544249214SRandall Stewart /* 172644249214SRandall Stewart * Need to send an abort since we had a empty data chunk. 172744249214SRandall Stewart */ 17288b9c95f4SMichael Tuexen op_err = sctp_generate_no_user_data_cause(tsn); 172944249214SRandall Stewart stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_14; 173044249214SRandall Stewart sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); 173144249214SRandall Stewart *abort_flag = 1; 173244249214SRandall Stewart return (0); 173344249214SRandall Stewart } 17348b9c95f4SMichael Tuexen if ((chk_flags & SCTP_DATA_SACK_IMMEDIATELY) == SCTP_DATA_SACK_IMMEDIATELY) { 1735b3f1ea41SRandall Stewart asoc->send_sack = 1; 1736b3f1ea41SRandall Stewart } 17378b9c95f4SMichael Tuexen ordered = ((chk_flags & SCTP_DATA_UNORDERED) == 0); 1738b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) { 1739c4739e2fSRandall Stewart sctp_log_map(tsn, asoc->cumulative_tsn, asoc->highest_tsn_inside_map, SCTP_MAP_TSN_ENTERS); 174080fefe0aSRandall Stewart } 1741ad81507eSRandall Stewart if (stcb == NULL) { 1742ad81507eSRandall Stewart return (0); 1743ad81507eSRandall Stewart } 17448b9c95f4SMichael Tuexen SCTP_LTRACE_CHK(stcb->sctp_ep, stcb, chk_type, tsn); 174520b07a4dSMichael Tuexen if (SCTP_TSN_GE(asoc->cumulative_tsn, tsn)) { 1746f8829a4aSRandall Stewart /* It is a duplicate */ 1747f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_recvdupdata); 1748f8829a4aSRandall Stewart if (asoc->numduptsns < SCTP_MAX_DUP_TSNS) { 1749f8829a4aSRandall Stewart /* Record a dup for the next outbound sack */ 1750f8829a4aSRandall Stewart asoc->dup_tsns[asoc->numduptsns] = tsn; 1751f8829a4aSRandall Stewart asoc->numduptsns++; 1752f8829a4aSRandall Stewart } 1753b201f536SRandall Stewart asoc->send_sack = 1; 1754f8829a4aSRandall Stewart return (0); 1755f8829a4aSRandall Stewart } 1756f8829a4aSRandall Stewart /* Calculate the number of TSN's between the base and this TSN */ 1757d50c1d79SRandall Stewart SCTP_CALC_TSN_TO_GAP(gap, tsn, asoc->mapping_array_base_tsn); 1758f8829a4aSRandall Stewart if (gap >= (SCTP_MAPPING_ARRAY << 3)) { 1759f8829a4aSRandall Stewart /* Can't hold the bit in the mapping at max array, toss it */ 1760f8829a4aSRandall Stewart return (0); 1761f8829a4aSRandall Stewart } 1762f8829a4aSRandall Stewart if (gap >= (uint32_t)(asoc->mapping_array_size << 3)) { 1763207304d4SRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 17640696e120SRandall Stewart if (sctp_expand_mapping_array(asoc, gap)) { 1765f8829a4aSRandall Stewart /* Can't expand, drop it */ 1766f8829a4aSRandall Stewart return (0); 1767f8829a4aSRandall Stewart } 1768f8829a4aSRandall Stewart } 176920b07a4dSMichael Tuexen if (SCTP_TSN_GT(tsn, *high_tsn)) { 1770f8829a4aSRandall Stewart *high_tsn = tsn; 1771f8829a4aSRandall Stewart } 1772f8829a4aSRandall Stewart /* See if we have received this one already */ 177377acdc25SRandall Stewart if (SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap) || 177477acdc25SRandall Stewart SCTP_IS_TSN_PRESENT(asoc->nr_mapping_array, gap)) { 1775f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_recvdupdata); 1776f8829a4aSRandall Stewart if (asoc->numduptsns < SCTP_MAX_DUP_TSNS) { 1777f8829a4aSRandall Stewart /* Record a dup for the next outbound sack */ 1778f8829a4aSRandall Stewart asoc->dup_tsns[asoc->numduptsns] = tsn; 1779f8829a4aSRandall Stewart asoc->numduptsns++; 1780f8829a4aSRandall Stewart } 178142551e99SRandall Stewart asoc->send_sack = 1; 1782f8829a4aSRandall Stewart return (0); 1783f8829a4aSRandall Stewart } 1784f8829a4aSRandall Stewart /* 1785f8829a4aSRandall Stewart * Check to see about the GONE flag, duplicates would cause a sack 1786f8829a4aSRandall Stewart * to be sent up above 1787f8829a4aSRandall Stewart */ 1788ad81507eSRandall Stewart if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 1789f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 1790ff1ffd74SMichael Tuexen (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET))) { 1791f8829a4aSRandall Stewart /* 1792f8829a4aSRandall Stewart * wait a minute, this guy is gone, there is no longer a 1793f8829a4aSRandall Stewart * receiver. Send peer an ABORT! 1794f8829a4aSRandall Stewart */ 1795ff1ffd74SMichael Tuexen op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, ""); 1796a2b42326SMichael Tuexen sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); 1797f8829a4aSRandall Stewart *abort_flag = 1; 1798f8829a4aSRandall Stewart return (0); 1799f8829a4aSRandall Stewart } 1800f8829a4aSRandall Stewart /* 1801f8829a4aSRandall Stewart * Now before going further we see if there is room. If NOT then we 1802f8829a4aSRandall Stewart * MAY let one through only IF this TSN is the one we are waiting 1803f8829a4aSRandall Stewart * for on a partial delivery API. 1804f8829a4aSRandall Stewart */ 1805f8829a4aSRandall Stewart 180644249214SRandall Stewart /* Is the stream valid? */ 180749656eefSMichael Tuexen if (sid >= asoc->streamincnt) { 180886eda749SMichael Tuexen struct sctp_error_invalid_stream *cause; 1809f8829a4aSRandall Stewart 181086eda749SMichael Tuexen op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_error_invalid_stream), 1811eb1b1807SGleb Smirnoff 0, M_NOWAIT, 1, MT_DATA); 181286eda749SMichael Tuexen if (op_err != NULL) { 1813f8829a4aSRandall Stewart /* add some space up front so prepend will work well */ 181486eda749SMichael Tuexen SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); 181586eda749SMichael Tuexen cause = mtod(op_err, struct sctp_error_invalid_stream *); 1816f8829a4aSRandall Stewart /* 1817f8829a4aSRandall Stewart * Error causes are just param's and this one has 1818f8829a4aSRandall Stewart * two back to back phdr, one with the error type 1819f8829a4aSRandall Stewart * and size, the other with the streamid and a rsvd 1820f8829a4aSRandall Stewart */ 182186eda749SMichael Tuexen SCTP_BUF_LEN(op_err) = sizeof(struct sctp_error_invalid_stream); 182286eda749SMichael Tuexen cause->cause.code = htons(SCTP_CAUSE_INVALID_STREAM); 182386eda749SMichael Tuexen cause->cause.length = htons(sizeof(struct sctp_error_invalid_stream)); 18248b9c95f4SMichael Tuexen cause->stream_id = htons(sid); 182586eda749SMichael Tuexen cause->reserved = htons(0); 182686eda749SMichael Tuexen sctp_queue_op_err(stcb, op_err); 1827f8829a4aSRandall Stewart } 1828f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_badsid); 1829207304d4SRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 1830830d754dSRandall Stewart SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap); 183120b07a4dSMichael Tuexen if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) { 1832830d754dSRandall Stewart asoc->highest_tsn_inside_nr_map = tsn; 1833d06c82f1SRandall Stewart } 1834d06c82f1SRandall Stewart if (tsn == (asoc->cumulative_tsn + 1)) { 1835d06c82f1SRandall Stewart /* Update cum-ack */ 1836d06c82f1SRandall Stewart asoc->cumulative_tsn = tsn; 1837d06c82f1SRandall Stewart } 1838f8829a4aSRandall Stewart return (0); 1839f8829a4aSRandall Stewart } 1840f8829a4aSRandall Stewart /* 184144249214SRandall Stewart * If its a fragmented message, lets see if we can find the control 184244249214SRandall Stewart * on the reassembly queues. 1843f8829a4aSRandall Stewart */ 18448b9c95f4SMichael Tuexen if ((chk_type == SCTP_IDATA) && 18458b9c95f4SMichael Tuexen ((chk_flags & SCTP_DATA_FIRST_FRAG) == 0) && 1846be46a7c5SMichael Tuexen (fsn == 0)) { 184744249214SRandall Stewart /* 184844249214SRandall Stewart * The first *must* be fsn 0, and other (middle/end) pieces 1849be46a7c5SMichael Tuexen * can *not* be fsn 0. XXX: This can happen in case of a 1850be46a7c5SMichael Tuexen * wrap around. Ignore is for now. 185144249214SRandall Stewart */ 1852be46a7c5SMichael Tuexen snprintf(msg, sizeof(msg), "FSN zero for MID=%8.8x, but flags=%2.2x", 18538b9c95f4SMichael Tuexen mid, chk_flags); 185444249214SRandall Stewart goto err_out; 185544249214SRandall Stewart } 18563d6fe5d8SMichael Tuexen control = sctp_find_reasm_entry(&asoc->strmin[sid], mid, ordered, asoc->idata_supported); 185744249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags:0x%x look for control on queues %p\n", 18588b9c95f4SMichael Tuexen chk_flags, control); 18598b9c95f4SMichael Tuexen if ((chk_flags & SCTP_DATA_NOT_FRAG) != SCTP_DATA_NOT_FRAG) { 1860be46a7c5SMichael Tuexen /* See if we can find the re-assembly entity */ 1861be46a7c5SMichael Tuexen if (control != NULL) { 186244249214SRandall Stewart /* We found something, does it belong? */ 186349656eefSMichael Tuexen if (ordered && (mid != control->mid)) { 186449656eefSMichael Tuexen snprintf(msg, sizeof(msg), "Reassembly problem (MID=%8.8x)", mid); 186544249214SRandall Stewart err_out: 186644249214SRandall Stewart op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); 186744249214SRandall Stewart stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_15; 186844249214SRandall Stewart sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); 186944249214SRandall Stewart *abort_flag = 1; 187044249214SRandall Stewart return (0); 187144249214SRandall Stewart } 187244249214SRandall Stewart if (ordered && ((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED)) { 1873b7b84c0eSMichael Tuexen /* 1874b7b84c0eSMichael Tuexen * We can't have a switched order with an 1875b7b84c0eSMichael Tuexen * unordered chunk 1876b7b84c0eSMichael Tuexen */ 1877be46a7c5SMichael Tuexen snprintf(msg, sizeof(msg), "All fragments of a user message must be ordered or unordered (TSN=%8.8x)", 1878be46a7c5SMichael Tuexen tsn); 187944249214SRandall Stewart goto err_out; 188044249214SRandall Stewart } 188144249214SRandall Stewart if (!ordered && (((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED) == 0)) { 1882b7b84c0eSMichael Tuexen /* 1883b7b84c0eSMichael Tuexen * We can't have a switched unordered with a 1884b7b84c0eSMichael Tuexen * ordered chunk 1885b7b84c0eSMichael Tuexen */ 1886be46a7c5SMichael Tuexen snprintf(msg, sizeof(msg), "All fragments of a user message must be ordered or unordered (TSN=%8.8x)", 1887be46a7c5SMichael Tuexen tsn); 188844249214SRandall Stewart goto err_out; 188944249214SRandall Stewart } 189044249214SRandall Stewart } 189144249214SRandall Stewart } else { 189244249214SRandall Stewart /* 189344249214SRandall Stewart * Its a complete segment. Lets validate we don't have a 189444249214SRandall Stewart * re-assembly going on with the same Stream/Seq (for 189544249214SRandall Stewart * ordered) or in the same Stream for unordered. 189644249214SRandall Stewart */ 1897be46a7c5SMichael Tuexen if (control != NULL) { 189849656eefSMichael Tuexen if (ordered || asoc->idata_supported) { 189949656eefSMichael Tuexen SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags: 0x%x dup detected on MID: %u\n", 19008b9c95f4SMichael Tuexen chk_flags, mid); 190149656eefSMichael Tuexen snprintf(msg, sizeof(msg), "Duplicate MID=%8.8x detected.", mid); 190244249214SRandall Stewart goto err_out; 1903be46a7c5SMichael Tuexen } else { 1904be46a7c5SMichael Tuexen if ((tsn == control->fsn_included + 1) && 1905be46a7c5SMichael Tuexen (control->end_added == 0)) { 1906be46a7c5SMichael Tuexen snprintf(msg, sizeof(msg), "Illegal message sequence, missing end for MID: %8.8x", control->fsn_included); 1907be46a7c5SMichael Tuexen goto err_out; 1908be46a7c5SMichael Tuexen } else { 1909be46a7c5SMichael Tuexen control = NULL; 1910be46a7c5SMichael Tuexen } 1911be46a7c5SMichael Tuexen } 191244249214SRandall Stewart } 191344249214SRandall Stewart } 191444249214SRandall Stewart /* now do the tests */ 191544249214SRandall Stewart if (((asoc->cnt_on_all_streams + 191644249214SRandall Stewart asoc->cnt_on_reasm_queue + 191744249214SRandall Stewart asoc->cnt_msg_on_sb) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue)) || 191844249214SRandall Stewart (((int)asoc->my_rwnd) <= 0)) { 191944249214SRandall Stewart /* 192044249214SRandall Stewart * When we have NO room in the rwnd we check to make sure 192144249214SRandall Stewart * the reader is doing its job... 192244249214SRandall Stewart */ 192344249214SRandall Stewart if (stcb->sctp_socket->so_rcv.sb_cc) { 192444249214SRandall Stewart /* some to read, wake-up */ 192544249214SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 192644249214SRandall Stewart struct socket *so; 192744249214SRandall Stewart 192844249214SRandall Stewart so = SCTP_INP_SO(stcb->sctp_ep); 192944249214SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 193044249214SRandall Stewart SCTP_TCB_UNLOCK(stcb); 193144249214SRandall Stewart SCTP_SOCKET_LOCK(so, 1); 193244249214SRandall Stewart SCTP_TCB_LOCK(stcb); 193344249214SRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 193444249214SRandall Stewart if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { 193544249214SRandall Stewart /* assoc was freed while we were unlocked */ 193644249214SRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 193744249214SRandall Stewart return (0); 193844249214SRandall Stewart } 193944249214SRandall Stewart #endif 194044249214SRandall Stewart sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 194144249214SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 194244249214SRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 194344249214SRandall Stewart #endif 194444249214SRandall Stewart } 194544249214SRandall Stewart /* now is it in the mapping array of what we have accepted? */ 19468b9c95f4SMichael Tuexen if (chk_type == SCTP_DATA) { 194744249214SRandall Stewart if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_map) && 194844249214SRandall Stewart SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) { 194944249214SRandall Stewart /* Nope not in the valid range dump it */ 195044249214SRandall Stewart dump_packet: 195144249214SRandall Stewart sctp_set_rwnd(stcb, asoc); 195244249214SRandall Stewart if ((asoc->cnt_on_all_streams + 195344249214SRandall Stewart asoc->cnt_on_reasm_queue + 195444249214SRandall Stewart asoc->cnt_msg_on_sb) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue)) { 195544249214SRandall Stewart SCTP_STAT_INCR(sctps_datadropchklmt); 195644249214SRandall Stewart } else { 195744249214SRandall Stewart SCTP_STAT_INCR(sctps_datadroprwnd); 195844249214SRandall Stewart } 195944249214SRandall Stewart *break_flag = 1; 196044249214SRandall Stewart return (0); 196144249214SRandall Stewart } 196244249214SRandall Stewart } else { 196344249214SRandall Stewart if (control == NULL) { 196444249214SRandall Stewart goto dump_packet; 196544249214SRandall Stewart } 196644249214SRandall Stewart if (SCTP_TSN_GT(fsn, control->top_fsn)) { 196744249214SRandall Stewart goto dump_packet; 196844249214SRandall Stewart } 196944249214SRandall Stewart } 197044249214SRandall Stewart } 1971f42a358aSRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS 197218e198d3SRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 197318e198d3SRandall Stewart if (asoc->tsn_in_at >= SCTP_TSN_LOG_SIZE) { 197418e198d3SRandall Stewart asoc->tsn_in_at = 0; 197518e198d3SRandall Stewart asoc->tsn_in_wrapped = 1; 197618e198d3SRandall Stewart } 1977f42a358aSRandall Stewart asoc->in_tsnlog[asoc->tsn_in_at].tsn = tsn; 197849656eefSMichael Tuexen asoc->in_tsnlog[asoc->tsn_in_at].strm = sid; 197949656eefSMichael Tuexen asoc->in_tsnlog[asoc->tsn_in_at].seq = mid; 1980f1f73e57SRandall Stewart asoc->in_tsnlog[asoc->tsn_in_at].sz = chk_length; 1981f1f73e57SRandall Stewart asoc->in_tsnlog[asoc->tsn_in_at].flgs = chunk_flags; 198218e198d3SRandall Stewart asoc->in_tsnlog[asoc->tsn_in_at].stcb = (void *)stcb; 198318e198d3SRandall Stewart asoc->in_tsnlog[asoc->tsn_in_at].in_pos = asoc->tsn_in_at; 198418e198d3SRandall Stewart asoc->in_tsnlog[asoc->tsn_in_at].in_out = 1; 1985f42a358aSRandall Stewart asoc->tsn_in_at++; 1986f42a358aSRandall Stewart #endif 198744249214SRandall Stewart /* 198844249214SRandall Stewart * Before we continue lets validate that we are not being fooled by 198944249214SRandall Stewart * an evil attacker. We can only have Nk chunks based on our TSN 199044249214SRandall Stewart * spread allowed by the mapping array N * 8 bits, so there is no 199144249214SRandall Stewart * way our stream sequence numbers could have wrapped. We of course 199244249214SRandall Stewart * only validate the FIRST fragment so the bit must be set. 199344249214SRandall Stewart */ 19948b9c95f4SMichael Tuexen if ((chk_flags & SCTP_DATA_FIRST_FRAG) && 1995d61a0ae0SRandall Stewart (TAILQ_EMPTY(&asoc->resetHead)) && 19968b9c95f4SMichael Tuexen (chk_flags & SCTP_DATA_UNORDERED) == 0 && 199749656eefSMichael Tuexen SCTP_MID_GE(asoc->idata_supported, asoc->strmin[sid].last_mid_delivered, mid)) { 1998f8829a4aSRandall Stewart /* The incoming sseq is behind where we last delivered? */ 1999f2ea2a2dSMichael Tuexen SCTPDBG(SCTP_DEBUG_INDATA1, "EVIL/Broken-Dup S-SEQ: %u delivered: %u from peer, Abort!\n", 200049656eefSMichael Tuexen mid, asoc->strmin[sid].last_mid_delivered); 2001f8829a4aSRandall Stewart 200249656eefSMichael Tuexen if (asoc->idata_supported) { 200349656eefSMichael Tuexen snprintf(msg, sizeof(msg), "Delivered MID=%8.8x, got TSN=%8.8x, SID=%4.4x, MID=%8.8x", 200449656eefSMichael Tuexen asoc->strmin[sid].last_mid_delivered, 200549656eefSMichael Tuexen tsn, 200649656eefSMichael Tuexen sid, 200749656eefSMichael Tuexen mid); 200849656eefSMichael Tuexen } else { 2009ff1ffd74SMichael Tuexen snprintf(msg, sizeof(msg), "Delivered SSN=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x", 201049656eefSMichael Tuexen (uint16_t)asoc->strmin[sid].last_mid_delivered, 201149656eefSMichael Tuexen tsn, 201249656eefSMichael Tuexen sid, 201349656eefSMichael Tuexen (uint16_t)mid); 201449656eefSMichael Tuexen } 2015ff1ffd74SMichael Tuexen op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); 2016b7d130beSMichael Tuexen stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_16; 2017ff1ffd74SMichael Tuexen sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); 2018f8829a4aSRandall Stewart *abort_flag = 1; 2019f8829a4aSRandall Stewart return (0); 2020f8829a4aSRandall Stewart } 20218b9c95f4SMichael Tuexen if (chk_type == SCTP_IDATA) { 202244249214SRandall Stewart the_len = (chk_length - sizeof(struct sctp_idata_chunk)); 202344249214SRandall Stewart } else { 2024f8829a4aSRandall Stewart the_len = (chk_length - sizeof(struct sctp_data_chunk)); 202544249214SRandall Stewart } 2026f8829a4aSRandall Stewart if (last_chunk == 0) { 20278b9c95f4SMichael Tuexen if (chk_type == SCTP_IDATA) { 202844249214SRandall Stewart dmbuf = SCTP_M_COPYM(*m, 202944249214SRandall Stewart (offset + sizeof(struct sctp_idata_chunk)), 203044249214SRandall Stewart the_len, M_NOWAIT); 203144249214SRandall Stewart } else { 203244b7479bSRandall Stewart dmbuf = SCTP_M_COPYM(*m, 2033f8829a4aSRandall Stewart (offset + sizeof(struct sctp_data_chunk)), 2034eb1b1807SGleb Smirnoff the_len, M_NOWAIT); 203544249214SRandall Stewart } 2036f8829a4aSRandall Stewart #ifdef SCTP_MBUF_LOGGING 2037b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { 20384be807c4SMichael Tuexen sctp_log_mbc(dmbuf, SCTP_MBUF_ICOPY); 2039f8829a4aSRandall Stewart } 2040f8829a4aSRandall Stewart #endif 2041f8829a4aSRandall Stewart } else { 2042f8829a4aSRandall Stewart /* We can steal the last chunk */ 2043139bc87fSRandall Stewart int l_len; 2044139bc87fSRandall Stewart 2045f8829a4aSRandall Stewart dmbuf = *m; 2046f8829a4aSRandall Stewart /* lop off the top part */ 20478b9c95f4SMichael Tuexen if (chk_type == SCTP_IDATA) { 204844249214SRandall Stewart m_adj(dmbuf, (offset + sizeof(struct sctp_idata_chunk))); 204944249214SRandall Stewart } else { 2050f8829a4aSRandall Stewart m_adj(dmbuf, (offset + sizeof(struct sctp_data_chunk))); 205144249214SRandall Stewart } 2052139bc87fSRandall Stewart if (SCTP_BUF_NEXT(dmbuf) == NULL) { 2053139bc87fSRandall Stewart l_len = SCTP_BUF_LEN(dmbuf); 2054139bc87fSRandall Stewart } else { 2055139bc87fSRandall Stewart /* 2056139bc87fSRandall Stewart * need to count up the size hopefully does not hit 2057139bc87fSRandall Stewart * this to often :-0 2058139bc87fSRandall Stewart */ 2059139bc87fSRandall Stewart struct mbuf *lat; 2060139bc87fSRandall Stewart 2061139bc87fSRandall Stewart l_len = 0; 206260990c0cSMichael Tuexen for (lat = dmbuf; lat; lat = SCTP_BUF_NEXT(lat)) { 2063139bc87fSRandall Stewart l_len += SCTP_BUF_LEN(lat); 2064139bc87fSRandall Stewart } 2065139bc87fSRandall Stewart } 2066139bc87fSRandall Stewart if (l_len > the_len) { 2067f8829a4aSRandall Stewart /* Trim the end round bytes off too */ 2068139bc87fSRandall Stewart m_adj(dmbuf, -(l_len - the_len)); 2069f8829a4aSRandall Stewart } 2070f8829a4aSRandall Stewart } 2071f8829a4aSRandall Stewart if (dmbuf == NULL) { 2072f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_nomem); 2073f8829a4aSRandall Stewart return (0); 2074f8829a4aSRandall Stewart } 207544249214SRandall Stewart /* 20768b9c95f4SMichael Tuexen * Now no matter what, we need a control, get one if we don't have 207744249214SRandall Stewart * one (we may have gotten it above when we found the message was 207844249214SRandall Stewart * fragmented 207944249214SRandall Stewart */ 208044249214SRandall Stewart if (control == NULL) { 208144249214SRandall Stewart sctp_alloc_a_readq(stcb, control); 208244249214SRandall Stewart sctp_build_readq_entry_mac(control, stcb, asoc->context, net, tsn, 208349656eefSMichael Tuexen ppid, 208449656eefSMichael Tuexen sid, 20858b9c95f4SMichael Tuexen chk_flags, 208649656eefSMichael Tuexen NULL, fsn, mid); 208744249214SRandall Stewart if (control == NULL) { 208844249214SRandall Stewart SCTP_STAT_INCR(sctps_nomem); 208944249214SRandall Stewart return (0); 209044249214SRandall Stewart } 20918b9c95f4SMichael Tuexen if ((chk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) { 20921f76872cSMichael Tuexen struct mbuf *mm; 209328cd0699SMichael Tuexen 209444249214SRandall Stewart control->data = dmbuf; 20951f76872cSMichael Tuexen for (mm = control->data; mm; mm = mm->m_next) { 20961f76872cSMichael Tuexen control->length += SCTP_BUF_LEN(mm); 209728cd0699SMichael Tuexen } 209844249214SRandall Stewart control->tail_mbuf = NULL; 20998b9c95f4SMichael Tuexen control->end_added = 1; 21008b9c95f4SMichael Tuexen control->last_frag_seen = 1; 21018b9c95f4SMichael Tuexen control->first_frag_seen = 1; 21028b9c95f4SMichael Tuexen control->fsn_included = fsn; 21038b9c95f4SMichael Tuexen control->top_fsn = fsn; 210444249214SRandall Stewart } 210544249214SRandall Stewart created_control = 1; 210644249214SRandall Stewart } 210749656eefSMichael Tuexen SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags: 0x%x ordered: %d MID: %u control: %p\n", 21088b9c95f4SMichael Tuexen chk_flags, ordered, mid, control); 21098b9c95f4SMichael Tuexen if ((chk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG && 2110f8829a4aSRandall Stewart TAILQ_EMPTY(&asoc->resetHead) && 2111f42a358aSRandall Stewart ((ordered == 0) || 211249656eefSMichael Tuexen (SCTP_MID_EQ(asoc->idata_supported, asoc->strmin[sid].last_mid_delivered + 1, mid) && 211349656eefSMichael Tuexen TAILQ_EMPTY(&asoc->strmin[sid].inqueue)))) { 2114f8829a4aSRandall Stewart /* Candidate for express delivery */ 2115f8829a4aSRandall Stewart /* 2116f8829a4aSRandall Stewart * Its not fragmented, No PD-API is up, Nothing in the 2117f8829a4aSRandall Stewart * delivery queue, Its un-ordered OR ordered and the next to 2118f8829a4aSRandall Stewart * deliver AND nothing else is stuck on the stream queue, 2119f8829a4aSRandall Stewart * And there is room for it in the socket buffer. Lets just 2120f8829a4aSRandall Stewart * stuff it up the buffer.... 2121f8829a4aSRandall Stewart */ 21221ea735c8SMichael Tuexen SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap); 212320b07a4dSMichael Tuexen if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) { 21241ea735c8SMichael Tuexen asoc->highest_tsn_inside_nr_map = tsn; 21251ea735c8SMichael Tuexen } 212649656eefSMichael Tuexen SCTPDBG(SCTP_DEBUG_XXX, "Injecting control: %p to be read (MID: %u)\n", 212749656eefSMichael Tuexen control, mid); 212844249214SRandall Stewart 2129cfde3ff7SRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 2130cfde3ff7SRandall Stewart control, &stcb->sctp_socket->so_rcv, 2131cfde3ff7SRandall Stewart 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 2132830d754dSRandall Stewart 21338b9c95f4SMichael Tuexen if ((chk_flags & SCTP_DATA_UNORDERED) == 0) { 2134f8829a4aSRandall Stewart /* for ordered, bump what we delivered */ 21353d6fe5d8SMichael Tuexen asoc->strmin[sid].last_mid_delivered++; 2136f8829a4aSRandall Stewart } 2137f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_recvexpress); 2138b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { 213949656eefSMichael Tuexen sctp_log_strm_del_alt(stcb, tsn, mid, sid, 2140f8829a4aSRandall Stewart SCTP_STR_LOG_FROM_EXPRS_DEL); 214180fefe0aSRandall Stewart } 2142f8829a4aSRandall Stewart control = NULL; 2143f8829a4aSRandall Stewart goto finish_express_del; 2144f8829a4aSRandall Stewart } 2145*0053ed28SMichael Tuexen 214644249214SRandall Stewart /* Now will we need a chunk too? */ 21478b9c95f4SMichael Tuexen if ((chk_flags & SCTP_DATA_NOT_FRAG) != SCTP_DATA_NOT_FRAG) { 2148f8829a4aSRandall Stewart sctp_alloc_a_chunk(stcb, chk); 2149f8829a4aSRandall Stewart if (chk == NULL) { 2150f8829a4aSRandall Stewart /* No memory so we drop the chunk */ 2151f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_nomem); 2152f8829a4aSRandall Stewart if (last_chunk == 0) { 2153f8829a4aSRandall Stewart /* we copied it, free the copy */ 2154f8829a4aSRandall Stewart sctp_m_freem(dmbuf); 2155f8829a4aSRandall Stewart } 2156f8829a4aSRandall Stewart return (0); 2157f8829a4aSRandall Stewart } 215849656eefSMichael Tuexen chk->rec.data.tsn = tsn; 2159f8829a4aSRandall Stewart chk->no_fr_allowed = 0; 216049656eefSMichael Tuexen chk->rec.data.fsn = fsn; 216149656eefSMichael Tuexen chk->rec.data.mid = mid; 216249656eefSMichael Tuexen chk->rec.data.sid = sid; 216349656eefSMichael Tuexen chk->rec.data.ppid = ppid; 2164f8829a4aSRandall Stewart chk->rec.data.context = stcb->asoc.context; 2165f8829a4aSRandall Stewart chk->rec.data.doing_fast_retransmit = 0; 21668b9c95f4SMichael Tuexen chk->rec.data.rcv_flags = chk_flags; 2167f8829a4aSRandall Stewart chk->asoc = asoc; 2168f8829a4aSRandall Stewart chk->send_size = the_len; 2169f8829a4aSRandall Stewart chk->whoTo = net; 217049656eefSMichael Tuexen SCTPDBG(SCTP_DEBUG_XXX, "Building ck: %p for control: %p to be read (MID: %u)\n", 217144249214SRandall Stewart chk, 217249656eefSMichael Tuexen control, mid); 2173f8829a4aSRandall Stewart atomic_add_int(&net->ref_count, 1); 2174f8829a4aSRandall Stewart chk->data = dmbuf; 217544249214SRandall Stewart } 217644249214SRandall Stewart /* Set the appropriate TSN mark */ 217744249214SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_do_drain) == 0) { 217844249214SRandall Stewart SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap); 217944249214SRandall Stewart if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) { 218044249214SRandall Stewart asoc->highest_tsn_inside_nr_map = tsn; 218144249214SRandall Stewart } 2182f8829a4aSRandall Stewart } else { 218344249214SRandall Stewart SCTP_SET_TSN_PRESENT(asoc->mapping_array, gap); 218444249214SRandall Stewart if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_map)) { 218544249214SRandall Stewart asoc->highest_tsn_inside_map = tsn; 2186f8829a4aSRandall Stewart } 2187f8829a4aSRandall Stewart } 218844249214SRandall Stewart /* Now is it complete (i.e. not fragmented)? */ 21898b9c95f4SMichael Tuexen if ((chk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) { 2190f8829a4aSRandall Stewart /* 219144249214SRandall Stewart * Special check for when streams are resetting. We could be 219244249214SRandall Stewart * more smart about this and check the actual stream to see 219344249214SRandall Stewart * if it is not being reset.. that way we would not create a 219444249214SRandall Stewart * HOLB when amongst streams being reset and those not being 219544249214SRandall Stewart * reset. 2196f8829a4aSRandall Stewart * 2197f8829a4aSRandall Stewart */ 2198f8829a4aSRandall Stewart if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) && 219920b07a4dSMichael Tuexen SCTP_TSN_GT(tsn, liste->tsn)) { 2200f8829a4aSRandall Stewart /* 220144249214SRandall Stewart * yep its past where we need to reset... go ahead 220244249214SRandall Stewart * and queue it. 2203f8829a4aSRandall Stewart */ 2204f8829a4aSRandall Stewart if (TAILQ_EMPTY(&asoc->pending_reply_queue)) { 2205f8829a4aSRandall Stewart /* first one on */ 2206f8829a4aSRandall Stewart TAILQ_INSERT_TAIL(&asoc->pending_reply_queue, control, next); 2207f8829a4aSRandall Stewart } else { 220828cd0699SMichael Tuexen struct sctp_queued_to_read *lcontrol, *nlcontrol; 2209f8829a4aSRandall Stewart unsigned char inserted = 0; 2210f8829a4aSRandall Stewart 221128cd0699SMichael Tuexen TAILQ_FOREACH_SAFE(lcontrol, &asoc->pending_reply_queue, next, nlcontrol) { 221228cd0699SMichael Tuexen if (SCTP_TSN_GT(control->sinfo_tsn, lcontrol->sinfo_tsn)) { 221344249214SRandall Stewart 22144a9ef3f8SMichael Tuexen continue; 2215f8829a4aSRandall Stewart } else { 2216f8829a4aSRandall Stewart /* found it */ 221728cd0699SMichael Tuexen TAILQ_INSERT_BEFORE(lcontrol, control, next); 2218f8829a4aSRandall Stewart inserted = 1; 2219f8829a4aSRandall Stewart break; 2220f8829a4aSRandall Stewart } 2221f8829a4aSRandall Stewart } 2222f8829a4aSRandall Stewart if (inserted == 0) { 2223f8829a4aSRandall Stewart /* 222444249214SRandall Stewart * must be put at end, use prevP 222544249214SRandall Stewart * (all setup from loop) to setup 222644249214SRandall Stewart * nextP. 2227f8829a4aSRandall Stewart */ 2228f8829a4aSRandall Stewart TAILQ_INSERT_TAIL(&asoc->pending_reply_queue, control, next); 2229f8829a4aSRandall Stewart } 2230f8829a4aSRandall Stewart } 223144249214SRandall Stewart goto finish_express_del; 223244249214SRandall Stewart } 22338b9c95f4SMichael Tuexen if (chk_flags & SCTP_DATA_UNORDERED) { 223444249214SRandall Stewart /* queue directly into socket buffer */ 223549656eefSMichael Tuexen SCTPDBG(SCTP_DEBUG_XXX, "Unordered data to be read control: %p MID: %u\n", 223649656eefSMichael Tuexen control, mid); 223744249214SRandall Stewart sctp_mark_non_revokable(asoc, control->sinfo_tsn); 223844249214SRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 223944249214SRandall Stewart control, 224044249214SRandall Stewart &stcb->sctp_socket->so_rcv, 1, 224144249214SRandall Stewart SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 224244249214SRandall Stewart 2243f8829a4aSRandall Stewart } else { 224449656eefSMichael Tuexen SCTPDBG(SCTP_DEBUG_XXX, "Queue control: %p for reordering MID: %u\n", control, 224549656eefSMichael Tuexen mid); 22463d6fe5d8SMichael Tuexen sctp_queue_data_to_stream(stcb, asoc, control, abort_flag, &need_reasm_check); 2247f8829a4aSRandall Stewart if (*abort_flag) { 22488be0fd55SMichael Tuexen if (last_chunk) { 22498be0fd55SMichael Tuexen *m = NULL; 22508be0fd55SMichael Tuexen } 2251f8829a4aSRandall Stewart return (0); 2252f8829a4aSRandall Stewart } 2253f8829a4aSRandall Stewart } 225444249214SRandall Stewart goto finish_express_del; 2255f8829a4aSRandall Stewart } 225644249214SRandall Stewart /* If we reach here its a reassembly */ 225744249214SRandall Stewart need_reasm_check = 1; 225844249214SRandall Stewart SCTPDBG(SCTP_DEBUG_XXX, 225949656eefSMichael Tuexen "Queue data to stream for reasm control: %p MID: %u\n", 226049656eefSMichael Tuexen control, mid); 22613d6fe5d8SMichael Tuexen sctp_queue_data_for_reasm(stcb, asoc, control, chk, created_control, abort_flag, tsn); 2262f8829a4aSRandall Stewart if (*abort_flag) { 2263a5d547adSRandall Stewart /* 226444249214SRandall Stewart * the assoc is now gone and chk was put onto the reasm 226544249214SRandall Stewart * queue, which has all been freed. 2266a5d547adSRandall Stewart */ 22678be0fd55SMichael Tuexen if (last_chunk) { 2268a5d547adSRandall Stewart *m = NULL; 22698be0fd55SMichael Tuexen } 2270f8829a4aSRandall Stewart return (0); 2271f8829a4aSRandall Stewart } 2272f8829a4aSRandall Stewart finish_express_del: 227344249214SRandall Stewart /* Here we tidy up things */ 2274307b49efSMichael Tuexen if (tsn == (asoc->cumulative_tsn + 1)) { 2275307b49efSMichael Tuexen /* Update cum-ack */ 2276307b49efSMichael Tuexen asoc->cumulative_tsn = tsn; 2277307b49efSMichael Tuexen } 2278f8829a4aSRandall Stewart if (last_chunk) { 2279f8829a4aSRandall Stewart *m = NULL; 2280f8829a4aSRandall Stewart } 2281f42a358aSRandall Stewart if (ordered) { 2282f8829a4aSRandall Stewart SCTP_STAT_INCR_COUNTER64(sctps_inorderchunks); 2283f8829a4aSRandall Stewart } else { 2284f8829a4aSRandall Stewart SCTP_STAT_INCR_COUNTER64(sctps_inunorderchunks); 2285f8829a4aSRandall Stewart } 2286f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_recvdata); 2287f8829a4aSRandall Stewart /* Set it present please */ 2288b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { 228949656eefSMichael Tuexen sctp_log_strm_del_alt(stcb, tsn, mid, sid, SCTP_STR_LOG_FROM_MARK_TSN); 229080fefe0aSRandall Stewart } 2291b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) { 2292f8829a4aSRandall Stewart sctp_log_map(asoc->mapping_array_base_tsn, asoc->cumulative_tsn, 2293f8829a4aSRandall Stewart asoc->highest_tsn_inside_map, SCTP_MAP_PREPARE_SLIDE); 229480fefe0aSRandall Stewart } 22953d6fe5d8SMichael Tuexen if (need_reasm_check) { 22963d6fe5d8SMichael Tuexen (void)sctp_deliver_reasm_check(stcb, asoc, &asoc->strmin[sid], SCTP_READ_LOCK_NOT_HELD); 22973d6fe5d8SMichael Tuexen need_reasm_check = 0; 22983d6fe5d8SMichael Tuexen } 229917205eccSRandall Stewart /* check the special flag for stream resets */ 230017205eccSRandall Stewart if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) && 230120b07a4dSMichael Tuexen SCTP_TSN_GE(asoc->cumulative_tsn, liste->tsn)) { 230217205eccSRandall Stewart /* 230317205eccSRandall Stewart * we have finished working through the backlogged TSN's now 230417205eccSRandall Stewart * time to reset streams. 1: call reset function. 2: free 230517205eccSRandall Stewart * pending_reply space 3: distribute any chunks in 230617205eccSRandall Stewart * pending_reply_queue. 230717205eccSRandall Stewart */ 2308a169d6ecSMichael Tuexen sctp_reset_in_stream(stcb, liste->number_entries, liste->list_of_streams); 230917205eccSRandall Stewart TAILQ_REMOVE(&asoc->resetHead, liste, next_resp); 23107cca1775SRandall Stewart sctp_send_deferred_reset_response(stcb, liste, SCTP_STREAM_RESET_RESULT_PERFORMED); 2311207304d4SRandall Stewart SCTP_FREE(liste, SCTP_M_STRESET); 23123c503c28SRandall Stewart /* sa_ignore FREED_MEMORY */ 231317205eccSRandall Stewart liste = TAILQ_FIRST(&asoc->resetHead); 23144a9ef3f8SMichael Tuexen if (TAILQ_EMPTY(&asoc->resetHead)) { 231517205eccSRandall Stewart /* All can be removed */ 231628cd0699SMichael Tuexen TAILQ_FOREACH_SAFE(control, &asoc->pending_reply_queue, next, ncontrol) { 231728cd0699SMichael Tuexen TAILQ_REMOVE(&asoc->pending_reply_queue, control, next); 231828cd0699SMichael Tuexen sctp_queue_data_to_stream(stcb, asoc, control, abort_flag, &need_reasm_check); 231917205eccSRandall Stewart if (*abort_flag) { 232017205eccSRandall Stewart return (0); 232117205eccSRandall Stewart } 23223d6fe5d8SMichael Tuexen if (need_reasm_check) { 232328cd0699SMichael Tuexen (void)sctp_deliver_reasm_check(stcb, asoc, &asoc->strmin[control->sinfo_stream], SCTP_READ_LOCK_NOT_HELD); 23243d6fe5d8SMichael Tuexen need_reasm_check = 0; 23253d6fe5d8SMichael Tuexen } 232617205eccSRandall Stewart } 23274a9ef3f8SMichael Tuexen } else { 232828cd0699SMichael Tuexen TAILQ_FOREACH_SAFE(control, &asoc->pending_reply_queue, next, ncontrol) { 232928cd0699SMichael Tuexen if (SCTP_TSN_GT(control->sinfo_tsn, liste->tsn)) { 23304a9ef3f8SMichael Tuexen break; 23314a9ef3f8SMichael Tuexen } 233217205eccSRandall Stewart /* 233328cd0699SMichael Tuexen * if control->sinfo_tsn is <= liste->tsn we 233428cd0699SMichael Tuexen * can process it which is the NOT of 233528cd0699SMichael Tuexen * control->sinfo_tsn > liste->tsn 233617205eccSRandall Stewart */ 233728cd0699SMichael Tuexen TAILQ_REMOVE(&asoc->pending_reply_queue, control, next); 233828cd0699SMichael Tuexen sctp_queue_data_to_stream(stcb, asoc, control, abort_flag, &need_reasm_check); 233917205eccSRandall Stewart if (*abort_flag) { 234017205eccSRandall Stewart return (0); 234117205eccSRandall Stewart } 23423d6fe5d8SMichael Tuexen if (need_reasm_check) { 234328cd0699SMichael Tuexen (void)sctp_deliver_reasm_check(stcb, asoc, &asoc->strmin[control->sinfo_stream], SCTP_READ_LOCK_NOT_HELD); 234417205eccSRandall Stewart need_reasm_check = 0; 234517205eccSRandall Stewart } 23463d6fe5d8SMichael Tuexen } 23473d6fe5d8SMichael Tuexen } 2348139bc87fSRandall Stewart } 2349f8829a4aSRandall Stewart return (1); 2350f8829a4aSRandall Stewart } 2351f8829a4aSRandall Stewart 2352ed654363SMichael Tuexen static const int8_t sctp_map_lookup_tab[256] = { 2353b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3, 2354b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 4, 2355b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3, 2356b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 5, 2357b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3, 2358b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 4, 2359b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3, 2360b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 6, 2361b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3, 2362b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 4, 2363b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3, 2364b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 5, 2365b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3, 2366b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 4, 2367b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3, 2368b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 7, 2369b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3, 2370b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 4, 2371b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3, 2372b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 5, 2373b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3, 2374b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 4, 2375b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3, 2376b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 6, 2377b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3, 2378b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 4, 2379b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3, 2380b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 5, 2381b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3, 2382b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 4, 2383b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 3, 2384b5c16493SMichael Tuexen 0, 1, 0, 2, 0, 1, 0, 8 2385f8829a4aSRandall Stewart }; 2386f8829a4aSRandall Stewart 2387f8829a4aSRandall Stewart 2388f8829a4aSRandall Stewart void 2389b5c16493SMichael Tuexen sctp_slide_mapping_arrays(struct sctp_tcb *stcb) 2390f8829a4aSRandall Stewart { 2391f8829a4aSRandall Stewart /* 2392f8829a4aSRandall Stewart * Now we also need to check the mapping array in a couple of ways. 2393f8829a4aSRandall Stewart * 1) Did we move the cum-ack point? 239466bd30bdSRandall Stewart * 23955b495f17SMichael Tuexen * When you first glance at this you might think that all entries 23965b495f17SMichael Tuexen * that make up the position of the cum-ack would be in the 23975b495f17SMichael Tuexen * nr-mapping array only.. i.e. things up to the cum-ack are always 239866bd30bdSRandall Stewart * deliverable. Thats true with one exception, when its a fragmented 239966bd30bdSRandall Stewart * message we may not deliver the data until some threshold (or all 240066bd30bdSRandall Stewart * of it) is in place. So we must OR the nr_mapping_array and 240166bd30bdSRandall Stewart * mapping_array to get a true picture of the cum-ack. 2402f8829a4aSRandall Stewart */ 2403f8829a4aSRandall Stewart struct sctp_association *asoc; 2404b3f1ea41SRandall Stewart int at; 240566bd30bdSRandall Stewart uint8_t val; 2406f8829a4aSRandall Stewart int slide_from, slide_end, lgap, distance; 240777acdc25SRandall Stewart uint32_t old_cumack, old_base, old_highest, highest_tsn; 2408f8829a4aSRandall Stewart 2409f8829a4aSRandall Stewart asoc = &stcb->asoc; 2410f8829a4aSRandall Stewart 2411f8829a4aSRandall Stewart old_cumack = asoc->cumulative_tsn; 2412f8829a4aSRandall Stewart old_base = asoc->mapping_array_base_tsn; 2413f8829a4aSRandall Stewart old_highest = asoc->highest_tsn_inside_map; 2414f8829a4aSRandall Stewart /* 2415f8829a4aSRandall Stewart * We could probably improve this a small bit by calculating the 2416f8829a4aSRandall Stewart * offset of the current cum-ack as the starting point. 2417f8829a4aSRandall Stewart */ 2418f8829a4aSRandall Stewart at = 0; 2419b5c16493SMichael Tuexen for (slide_from = 0; slide_from < stcb->asoc.mapping_array_size; slide_from++) { 242066bd30bdSRandall Stewart val = asoc->nr_mapping_array[slide_from] | asoc->mapping_array[slide_from]; 242166bd30bdSRandall Stewart if (val == 0xff) { 2422f8829a4aSRandall Stewart at += 8; 2423f8829a4aSRandall Stewart } else { 2424f8829a4aSRandall Stewart /* there is a 0 bit */ 242566bd30bdSRandall Stewart at += sctp_map_lookup_tab[val]; 2426f8829a4aSRandall Stewart break; 2427f8829a4aSRandall Stewart } 2428f8829a4aSRandall Stewart } 2429b5c16493SMichael Tuexen asoc->cumulative_tsn = asoc->mapping_array_base_tsn + (at - 1); 2430f8829a4aSRandall Stewart 243120b07a4dSMichael Tuexen if (SCTP_TSN_GT(asoc->cumulative_tsn, asoc->highest_tsn_inside_map) && 243220b07a4dSMichael Tuexen SCTP_TSN_GT(asoc->cumulative_tsn, asoc->highest_tsn_inside_nr_map)) { 2433a5d547adSRandall Stewart #ifdef INVARIANTS 2434ceaad40aSRandall Stewart panic("huh, cumack 0x%x greater than high-tsn 0x%x in map", 2435ceaad40aSRandall Stewart asoc->cumulative_tsn, asoc->highest_tsn_inside_map); 2436f8829a4aSRandall Stewart #else 2437ceaad40aSRandall Stewart SCTP_PRINTF("huh, cumack 0x%x greater than high-tsn 0x%x in map - should panic?\n", 2438ceaad40aSRandall Stewart asoc->cumulative_tsn, asoc->highest_tsn_inside_map); 24390e13104dSRandall Stewart sctp_print_mapping_array(asoc); 2440b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) { 2441b3f1ea41SRandall Stewart sctp_log_map(0, 6, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT); 2442b3f1ea41SRandall Stewart } 2443f8829a4aSRandall Stewart asoc->highest_tsn_inside_map = asoc->cumulative_tsn; 2444830d754dSRandall Stewart asoc->highest_tsn_inside_nr_map = asoc->cumulative_tsn; 2445f8829a4aSRandall Stewart #endif 2446f8829a4aSRandall Stewart } 244720b07a4dSMichael Tuexen if (SCTP_TSN_GT(asoc->highest_tsn_inside_nr_map, asoc->highest_tsn_inside_map)) { 244877acdc25SRandall Stewart highest_tsn = asoc->highest_tsn_inside_nr_map; 244977acdc25SRandall Stewart } else { 245077acdc25SRandall Stewart highest_tsn = asoc->highest_tsn_inside_map; 245177acdc25SRandall Stewart } 245277acdc25SRandall Stewart if ((asoc->cumulative_tsn == highest_tsn) && (at >= 8)) { 2453f8829a4aSRandall Stewart /* The complete array was completed by a single FR */ 245477acdc25SRandall Stewart /* highest becomes the cum-ack */ 245537f144ebSMichael Tuexen int clr; 245637f144ebSMichael Tuexen #ifdef INVARIANTS 245737f144ebSMichael Tuexen unsigned int i; 245837f144ebSMichael Tuexen #endif 2459f8829a4aSRandall Stewart 2460f8829a4aSRandall Stewart /* clear the array */ 2461b5c16493SMichael Tuexen clr = ((at + 7) >> 3); 2462c4739e2fSRandall Stewart if (clr > asoc->mapping_array_size) { 2463f8829a4aSRandall Stewart clr = asoc->mapping_array_size; 2464f8829a4aSRandall Stewart } 2465f8829a4aSRandall Stewart memset(asoc->mapping_array, 0, clr); 2466830d754dSRandall Stewart memset(asoc->nr_mapping_array, 0, clr); 246737f144ebSMichael Tuexen #ifdef INVARIANTS 2468b5c16493SMichael Tuexen for (i = 0; i < asoc->mapping_array_size; i++) { 2469b5c16493SMichael Tuexen if ((asoc->mapping_array[i]) || (asoc->nr_mapping_array[i])) { 2470cd3fd531SMichael Tuexen SCTP_PRINTF("Error Mapping array's not clean at clear\n"); 2471b5c16493SMichael Tuexen sctp_print_mapping_array(asoc); 2472b5c16493SMichael Tuexen } 2473b5c16493SMichael Tuexen } 247437f144ebSMichael Tuexen #endif 247577acdc25SRandall Stewart asoc->mapping_array_base_tsn = asoc->cumulative_tsn + 1; 247677acdc25SRandall Stewart asoc->highest_tsn_inside_nr_map = asoc->highest_tsn_inside_map = asoc->cumulative_tsn; 2477f8829a4aSRandall Stewart } else if (at >= 8) { 2478f8829a4aSRandall Stewart /* we can slide the mapping array down */ 2479b3f1ea41SRandall Stewart /* slide_from holds where we hit the first NON 0xff byte */ 2480b3f1ea41SRandall Stewart 2481f8829a4aSRandall Stewart /* 2482f8829a4aSRandall Stewart * now calculate the ceiling of the move using our highest 2483f8829a4aSRandall Stewart * TSN value 2484f8829a4aSRandall Stewart */ 248577acdc25SRandall Stewart SCTP_CALC_TSN_TO_GAP(lgap, highest_tsn, asoc->mapping_array_base_tsn); 248677acdc25SRandall Stewart slide_end = (lgap >> 3); 2487f8829a4aSRandall Stewart if (slide_end < slide_from) { 248877acdc25SRandall Stewart sctp_print_mapping_array(asoc); 2489d55b0b1bSRandall Stewart #ifdef INVARIANTS 2490f8829a4aSRandall Stewart panic("impossible slide"); 2491d55b0b1bSRandall Stewart #else 2492cd3fd531SMichael Tuexen SCTP_PRINTF("impossible slide lgap: %x slide_end: %x slide_from: %x? at: %d\n", 249377acdc25SRandall Stewart lgap, slide_end, slide_from, at); 2494d55b0b1bSRandall Stewart return; 2495d55b0b1bSRandall Stewart #endif 2496f8829a4aSRandall Stewart } 2497b3f1ea41SRandall Stewart if (slide_end > asoc->mapping_array_size) { 2498b3f1ea41SRandall Stewart #ifdef INVARIANTS 2499b3f1ea41SRandall Stewart panic("would overrun buffer"); 2500b3f1ea41SRandall Stewart #else 2501cd3fd531SMichael Tuexen SCTP_PRINTF("Gak, would have overrun map end: %d slide_end: %d\n", 2502b3f1ea41SRandall Stewart asoc->mapping_array_size, slide_end); 2503b3f1ea41SRandall Stewart slide_end = asoc->mapping_array_size; 2504b3f1ea41SRandall Stewart #endif 2505b3f1ea41SRandall Stewart } 2506f8829a4aSRandall Stewart distance = (slide_end - slide_from) + 1; 2507b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) { 2508f8829a4aSRandall Stewart sctp_log_map(old_base, old_cumack, old_highest, 2509f8829a4aSRandall Stewart SCTP_MAP_PREPARE_SLIDE); 2510f8829a4aSRandall Stewart sctp_log_map((uint32_t)slide_from, (uint32_t)slide_end, 2511f8829a4aSRandall Stewart (uint32_t)lgap, SCTP_MAP_SLIDE_FROM); 251280fefe0aSRandall Stewart } 2513f8829a4aSRandall Stewart if (distance + slide_from > asoc->mapping_array_size || 2514f8829a4aSRandall Stewart distance < 0) { 2515f8829a4aSRandall Stewart /* 2516f8829a4aSRandall Stewart * Here we do NOT slide forward the array so that 2517f8829a4aSRandall Stewart * hopefully when more data comes in to fill it up 2518f8829a4aSRandall Stewart * we will be able to slide it forward. Really I 2519f8829a4aSRandall Stewart * don't think this should happen :-0 2520f8829a4aSRandall Stewart */ 2521f8829a4aSRandall Stewart 2522b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) { 2523f8829a4aSRandall Stewart sctp_log_map((uint32_t)distance, (uint32_t)slide_from, 2524f8829a4aSRandall Stewart (uint32_t)asoc->mapping_array_size, 2525f8829a4aSRandall Stewart SCTP_MAP_SLIDE_NONE); 252680fefe0aSRandall Stewart } 2527f8829a4aSRandall Stewart } else { 2528f8829a4aSRandall Stewart int ii; 2529f8829a4aSRandall Stewart 2530f8829a4aSRandall Stewart for (ii = 0; ii < distance; ii++) { 253137f144ebSMichael Tuexen asoc->mapping_array[ii] = asoc->mapping_array[slide_from + ii]; 253237f144ebSMichael Tuexen asoc->nr_mapping_array[ii] = asoc->nr_mapping_array[slide_from + ii]; 253377acdc25SRandall Stewart 2534f8829a4aSRandall Stewart } 2535aed5947cSMichael Tuexen for (ii = distance; ii < asoc->mapping_array_size; ii++) { 2536f8829a4aSRandall Stewart asoc->mapping_array[ii] = 0; 253777acdc25SRandall Stewart asoc->nr_mapping_array[ii] = 0; 2538f8829a4aSRandall Stewart } 2539ee94f0a2SMichael Tuexen if (asoc->highest_tsn_inside_map + 1 == asoc->mapping_array_base_tsn) { 2540ee94f0a2SMichael Tuexen asoc->highest_tsn_inside_map += (slide_from << 3); 2541ee94f0a2SMichael Tuexen } 2542ee94f0a2SMichael Tuexen if (asoc->highest_tsn_inside_nr_map + 1 == asoc->mapping_array_base_tsn) { 2543ee94f0a2SMichael Tuexen asoc->highest_tsn_inside_nr_map += (slide_from << 3); 2544ee94f0a2SMichael Tuexen } 2545f8829a4aSRandall Stewart asoc->mapping_array_base_tsn += (slide_from << 3); 2546b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) { 2547f8829a4aSRandall Stewart sctp_log_map(asoc->mapping_array_base_tsn, 2548f8829a4aSRandall Stewart asoc->cumulative_tsn, asoc->highest_tsn_inside_map, 2549f8829a4aSRandall Stewart SCTP_MAP_SLIDE_RESULT); 255080fefe0aSRandall Stewart } 2551830d754dSRandall Stewart } 2552830d754dSRandall Stewart } 2553b5c16493SMichael Tuexen } 2554b5c16493SMichael Tuexen 2555b5c16493SMichael Tuexen void 25567215cc1bSMichael Tuexen sctp_sack_check(struct sctp_tcb *stcb, int was_a_gap) 2557b5c16493SMichael Tuexen { 2558b5c16493SMichael Tuexen struct sctp_association *asoc; 2559b5c16493SMichael Tuexen uint32_t highest_tsn; 2560ebecdad8SMichael Tuexen int is_a_gap; 2561b5c16493SMichael Tuexen 2562ebecdad8SMichael Tuexen sctp_slide_mapping_arrays(stcb); 2563b5c16493SMichael Tuexen asoc = &stcb->asoc; 256420b07a4dSMichael Tuexen if (SCTP_TSN_GT(asoc->highest_tsn_inside_nr_map, asoc->highest_tsn_inside_map)) { 2565b5c16493SMichael Tuexen highest_tsn = asoc->highest_tsn_inside_nr_map; 2566b5c16493SMichael Tuexen } else { 2567b5c16493SMichael Tuexen highest_tsn = asoc->highest_tsn_inside_map; 2568b5c16493SMichael Tuexen } 2569ebecdad8SMichael Tuexen /* Is there a gap now? */ 2570ebecdad8SMichael Tuexen is_a_gap = SCTP_TSN_GT(highest_tsn, stcb->asoc.cumulative_tsn); 2571b5c16493SMichael Tuexen 2572830d754dSRandall Stewart /* 2573f8829a4aSRandall Stewart * Now we need to see if we need to queue a sack or just start the 2574f8829a4aSRandall Stewart * timer (if allowed). 2575f8829a4aSRandall Stewart */ 2576f8829a4aSRandall Stewart if (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_SENT) { 2577f8829a4aSRandall Stewart /* 2578b5c16493SMichael Tuexen * Ok special case, in SHUTDOWN-SENT case. here we maker 2579b5c16493SMichael Tuexen * sure SACK timer is off and instead send a SHUTDOWN and a 2580b5c16493SMichael Tuexen * SACK 2581f8829a4aSRandall Stewart */ 2582139bc87fSRandall Stewart if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) { 2583f8829a4aSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_RECV, 2584b7d130beSMichael Tuexen stcb->sctp_ep, stcb, NULL, 258544249214SRandall Stewart SCTP_FROM_SCTP_INDATA + SCTP_LOC_17); 2586f8829a4aSRandall Stewart } 2587ca85e948SMichael Tuexen sctp_send_shutdown(stcb, 2588ca85e948SMichael Tuexen ((stcb->asoc.alternate) ? stcb->asoc.alternate : stcb->asoc.primary_destination)); 2589ebecdad8SMichael Tuexen if (is_a_gap) { 2590689e6a5fSMichael Tuexen sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED); 2591ebecdad8SMichael Tuexen } 2592f8829a4aSRandall Stewart } else { 2593f8829a4aSRandall Stewart /* 2594b5c16493SMichael Tuexen * CMT DAC algorithm: increase number of packets received 2595b5c16493SMichael Tuexen * since last ack 2596f8829a4aSRandall Stewart */ 2597f8829a4aSRandall Stewart stcb->asoc.cmt_dac_pkts_rcvd++; 2598f8829a4aSRandall Stewart 259942551e99SRandall Stewart if ((stcb->asoc.send_sack == 1) || /* We need to send a 260042551e99SRandall Stewart * SACK */ 2601f8829a4aSRandall Stewart ((was_a_gap) && (is_a_gap == 0)) || /* was a gap, but no 2602f8829a4aSRandall Stewart * longer is one */ 2603f8829a4aSRandall Stewart (stcb->asoc.numduptsns) || /* we have dup's */ 2604f8829a4aSRandall Stewart (is_a_gap) || /* is still a gap */ 260542551e99SRandall Stewart (stcb->asoc.delayed_ack == 0) || /* Delayed sack disabled */ 2606b7b84c0eSMichael Tuexen (stcb->asoc.data_pkts_seen >= stcb->asoc.sack_freq) /* hit limit of pkts */ 2607b7b84c0eSMichael Tuexen ) { 2608f8829a4aSRandall Stewart 26097c99d56fSMichael Tuexen if ((stcb->asoc.sctp_cmt_on_off > 0) && 2610b3f1ea41SRandall Stewart (SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) && 261142551e99SRandall Stewart (stcb->asoc.send_sack == 0) && 2612f8829a4aSRandall Stewart (stcb->asoc.numduptsns == 0) && 2613f8829a4aSRandall Stewart (stcb->asoc.delayed_ack) && 2614139bc87fSRandall Stewart (!SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer))) { 2615f8829a4aSRandall Stewart 2616f8829a4aSRandall Stewart /* 2617b5c16493SMichael Tuexen * CMT DAC algorithm: With CMT, delay acks 2618b5c16493SMichael Tuexen * even in the face of 2619f8829a4aSRandall Stewart * 26205b495f17SMichael Tuexen * reordering. Therefore, if acks that do 26215b495f17SMichael Tuexen * not have to be sent because of the above 2622b5c16493SMichael Tuexen * reasons, will be delayed. That is, acks 2623b5c16493SMichael Tuexen * that would have been sent due to gap 2624b5c16493SMichael Tuexen * reports will be delayed with DAC. Start 2625f8829a4aSRandall Stewart * the delayed ack timer. 2626f8829a4aSRandall Stewart */ 2627f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_RECV, 2628f8829a4aSRandall Stewart stcb->sctp_ep, stcb, NULL); 2629f8829a4aSRandall Stewart } else { 2630f8829a4aSRandall Stewart /* 2631b5c16493SMichael Tuexen * Ok we must build a SACK since the timer 2632b5c16493SMichael Tuexen * is pending, we got our first packet OR 2633b5c16493SMichael Tuexen * there are gaps or duplicates. 2634f8829a4aSRandall Stewart */ 2635ad81507eSRandall Stewart (void)SCTP_OS_TIMER_STOP(&stcb->asoc.dack_timer.timer); 2636689e6a5fSMichael Tuexen sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED); 2637f8829a4aSRandall Stewart } 2638f8829a4aSRandall Stewart } else { 263942551e99SRandall Stewart if (!SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) { 2640f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_RECV, 2641f8829a4aSRandall Stewart stcb->sctp_ep, stcb, NULL); 2642f8829a4aSRandall Stewart } 2643f8829a4aSRandall Stewart } 2644f8829a4aSRandall Stewart } 2645f8829a4aSRandall Stewart } 2646f8829a4aSRandall Stewart 2647f8829a4aSRandall Stewart int 2648f8829a4aSRandall Stewart sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, 2649e7e71dd7SMichael Tuexen struct sctp_inpcb *inp, struct sctp_tcb *stcb, 2650e7e71dd7SMichael Tuexen struct sctp_nets *net, uint32_t *high_tsn) 2651f8829a4aSRandall Stewart { 265244249214SRandall Stewart struct sctp_chunkhdr *ch, chunk_buf; 2653f8829a4aSRandall Stewart struct sctp_association *asoc; 2654f8829a4aSRandall Stewart int num_chunks = 0; /* number of control chunks processed */ 2655f8829a4aSRandall Stewart int stop_proc = 0; 2656af03054cSMichael Tuexen int break_flag, last_chunk; 26578f777478SMichael Tuexen int abort_flag = 0, was_a_gap; 2658f8829a4aSRandall Stewart struct mbuf *m; 26598f777478SMichael Tuexen uint32_t highest_tsn; 2660af03054cSMichael Tuexen uint16_t chk_length; 2661f8829a4aSRandall Stewart 2662f8829a4aSRandall Stewart /* set the rwnd */ 2663f8829a4aSRandall Stewart sctp_set_rwnd(stcb, &stcb->asoc); 2664f8829a4aSRandall Stewart 2665f8829a4aSRandall Stewart m = *mm; 2666f8829a4aSRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 2667f8829a4aSRandall Stewart asoc = &stcb->asoc; 266820b07a4dSMichael Tuexen if (SCTP_TSN_GT(asoc->highest_tsn_inside_nr_map, asoc->highest_tsn_inside_map)) { 26698f777478SMichael Tuexen highest_tsn = asoc->highest_tsn_inside_nr_map; 26708f777478SMichael Tuexen } else { 26718f777478SMichael Tuexen highest_tsn = asoc->highest_tsn_inside_map; 2672f8829a4aSRandall Stewart } 267320b07a4dSMichael Tuexen was_a_gap = SCTP_TSN_GT(highest_tsn, stcb->asoc.cumulative_tsn); 2674f8829a4aSRandall Stewart /* 2675f8829a4aSRandall Stewart * setup where we got the last DATA packet from for any SACK that 2676f8829a4aSRandall Stewart * may need to go out. Don't bump the net. This is done ONLY when a 2677f8829a4aSRandall Stewart * chunk is assigned. 2678f8829a4aSRandall Stewart */ 2679f8829a4aSRandall Stewart asoc->last_data_chunk_from = net; 2680f8829a4aSRandall Stewart 2681d06c82f1SRandall Stewart /*- 2682f8829a4aSRandall Stewart * Now before we proceed we must figure out if this is a wasted 2683f8829a4aSRandall Stewart * cluster... i.e. it is a small packet sent in and yet the driver 2684f8829a4aSRandall Stewart * underneath allocated a full cluster for it. If so we must copy it 2685f8829a4aSRandall Stewart * to a smaller mbuf and free up the cluster mbuf. This will help 2686d06c82f1SRandall Stewart * with cluster starvation. Note for __Panda__ we don't do this 2687d06c82f1SRandall Stewart * since it has clusters all the way down to 64 bytes. 2688f8829a4aSRandall Stewart */ 268944b7479bSRandall Stewart if (SCTP_BUF_LEN(m) < (long)MLEN && SCTP_BUF_NEXT(m) == NULL) { 2690f8829a4aSRandall Stewart /* we only handle mbufs that are singletons.. not chains */ 2691eb1b1807SGleb Smirnoff m = sctp_get_mbuf_for_msg(SCTP_BUF_LEN(m), 0, M_NOWAIT, 1, MT_DATA); 2692f8829a4aSRandall Stewart if (m) { 2693f8829a4aSRandall Stewart /* ok lets see if we can copy the data up */ 2694f8829a4aSRandall Stewart caddr_t *from, *to; 2695f8829a4aSRandall Stewart 2696f8829a4aSRandall Stewart /* get the pointers and copy */ 2697f8829a4aSRandall Stewart to = mtod(m, caddr_t *); 2698f8829a4aSRandall Stewart from = mtod((*mm), caddr_t *); 2699139bc87fSRandall Stewart memcpy(to, from, SCTP_BUF_LEN((*mm))); 2700f8829a4aSRandall Stewart /* copy the length and free up the old */ 2701139bc87fSRandall Stewart SCTP_BUF_LEN(m) = SCTP_BUF_LEN((*mm)); 2702f8829a4aSRandall Stewart sctp_m_freem(*mm); 2703cd0a4ff6SPedro F. Giffuni /* success, back copy */ 2704f8829a4aSRandall Stewart *mm = m; 2705f8829a4aSRandall Stewart } else { 2706f8829a4aSRandall Stewart /* We are in trouble in the mbuf world .. yikes */ 2707f8829a4aSRandall Stewart m = *mm; 2708f8829a4aSRandall Stewart } 2709f8829a4aSRandall Stewart } 2710f8829a4aSRandall Stewart /* get pointer to the first chunk header */ 271144249214SRandall Stewart ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset, 27127f75695aSMichael Tuexen sizeof(struct sctp_chunkhdr), 27137f75695aSMichael Tuexen (uint8_t *)&chunk_buf); 2714f8829a4aSRandall Stewart if (ch == NULL) { 2715f8829a4aSRandall Stewart return (1); 2716f8829a4aSRandall Stewart } 2717f8829a4aSRandall Stewart /* 2718f8829a4aSRandall Stewart * process all DATA chunks... 2719f8829a4aSRandall Stewart */ 2720f8829a4aSRandall Stewart *high_tsn = asoc->cumulative_tsn; 2721f8829a4aSRandall Stewart break_flag = 0; 272242551e99SRandall Stewart asoc->data_pkts_seen++; 2723f8829a4aSRandall Stewart while (stop_proc == 0) { 2724f8829a4aSRandall Stewart /* validate chunk length */ 272544249214SRandall Stewart chk_length = ntohs(ch->chunk_length); 2726f8829a4aSRandall Stewart if (length - *offset < chk_length) { 2727f8829a4aSRandall Stewart /* all done, mutulated chunk */ 2728f8829a4aSRandall Stewart stop_proc = 1; 272960990c0cSMichael Tuexen continue; 2730f8829a4aSRandall Stewart } 273144249214SRandall Stewart if ((asoc->idata_supported == 1) && 273244249214SRandall Stewart (ch->chunk_type == SCTP_DATA)) { 273344249214SRandall Stewart struct mbuf *op_err; 273444249214SRandall Stewart char msg[SCTP_DIAG_INFO_LEN]; 273544249214SRandall Stewart 2736e7f232a0SMichael Tuexen snprintf(msg, sizeof(msg), "%s", "I-DATA chunk received when DATA was negotiated"); 273744249214SRandall Stewart op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); 273844249214SRandall Stewart stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_18; 273944249214SRandall Stewart sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); 274044249214SRandall Stewart return (2); 274144249214SRandall Stewart } 274244249214SRandall Stewart if ((asoc->idata_supported == 0) && 274344249214SRandall Stewart (ch->chunk_type == SCTP_IDATA)) { 274444249214SRandall Stewart struct mbuf *op_err; 274544249214SRandall Stewart char msg[SCTP_DIAG_INFO_LEN]; 274644249214SRandall Stewart 2747e7f232a0SMichael Tuexen snprintf(msg, sizeof(msg), "%s", "DATA chunk received when I-DATA was negotiated"); 274844249214SRandall Stewart op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); 274944249214SRandall Stewart stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_19; 275044249214SRandall Stewart sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); 275144249214SRandall Stewart return (2); 275244249214SRandall Stewart } 275344249214SRandall Stewart if ((ch->chunk_type == SCTP_DATA) || 275444249214SRandall Stewart (ch->chunk_type == SCTP_IDATA)) { 2755af03054cSMichael Tuexen uint16_t clen; 275644249214SRandall Stewart 275744249214SRandall Stewart if (ch->chunk_type == SCTP_DATA) { 275844249214SRandall Stewart clen = sizeof(struct sctp_data_chunk); 275944249214SRandall Stewart } else { 276044249214SRandall Stewart clen = sizeof(struct sctp_idata_chunk); 276144249214SRandall Stewart } 2762f8ee69bfSMichael Tuexen if (chk_length < clen) { 2763f8829a4aSRandall Stewart /* 2764f8829a4aSRandall Stewart * Need to send an abort since we had a 2765f8829a4aSRandall Stewart * invalid data chunk. 2766f8829a4aSRandall Stewart */ 2767f8829a4aSRandall Stewart struct mbuf *op_err; 2768ff1ffd74SMichael Tuexen char msg[SCTP_DIAG_INFO_LEN]; 2769f8829a4aSRandall Stewart 2770af03054cSMichael Tuexen snprintf(msg, sizeof(msg), "%s chunk of length %u", 27717f75695aSMichael Tuexen ch->chunk_type == SCTP_DATA ? "DATA" : "I-DATA", 2772ff1ffd74SMichael Tuexen chk_length); 2773ff1ffd74SMichael Tuexen op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); 277444249214SRandall Stewart stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_20; 2775e7e71dd7SMichael Tuexen sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); 277632451da4SMichael Tuexen return (2); 277732451da4SMichael Tuexen } 2778f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 2779f8829a4aSRandall Stewart sctp_audit_log(0xB1, 0); 2780f8829a4aSRandall Stewart #endif 2781f8829a4aSRandall Stewart if (SCTP_SIZE32(chk_length) == (length - *offset)) { 2782f8829a4aSRandall Stewart last_chunk = 1; 2783f8829a4aSRandall Stewart } else { 2784f8829a4aSRandall Stewart last_chunk = 0; 2785f8829a4aSRandall Stewart } 278644249214SRandall Stewart if (sctp_process_a_data_chunk(stcb, asoc, mm, *offset, 2787f8829a4aSRandall Stewart chk_length, net, high_tsn, &abort_flag, &break_flag, 278844249214SRandall Stewart last_chunk, ch->chunk_type)) { 2789f8829a4aSRandall Stewart num_chunks++; 2790f8829a4aSRandall Stewart } 2791f8829a4aSRandall Stewart if (abort_flag) 2792f8829a4aSRandall Stewart return (2); 2793f8829a4aSRandall Stewart 2794f8829a4aSRandall Stewart if (break_flag) { 2795f8829a4aSRandall Stewart /* 2796f8829a4aSRandall Stewart * Set because of out of rwnd space and no 2797f8829a4aSRandall Stewart * drop rep space left. 2798f8829a4aSRandall Stewart */ 2799f8829a4aSRandall Stewart stop_proc = 1; 280060990c0cSMichael Tuexen continue; 2801f8829a4aSRandall Stewart } 2802f8829a4aSRandall Stewart } else { 2803f8829a4aSRandall Stewart /* not a data chunk in the data region */ 280444249214SRandall Stewart switch (ch->chunk_type) { 2805f8829a4aSRandall Stewart case SCTP_INITIATION: 2806f8829a4aSRandall Stewart case SCTP_INITIATION_ACK: 2807f8829a4aSRandall Stewart case SCTP_SELECTIVE_ACK: 280860990c0cSMichael Tuexen case SCTP_NR_SELECTIVE_ACK: 2809f8829a4aSRandall Stewart case SCTP_HEARTBEAT_REQUEST: 2810f8829a4aSRandall Stewart case SCTP_HEARTBEAT_ACK: 2811f8829a4aSRandall Stewart case SCTP_ABORT_ASSOCIATION: 2812f8829a4aSRandall Stewart case SCTP_SHUTDOWN: 2813f8829a4aSRandall Stewart case SCTP_SHUTDOWN_ACK: 2814f8829a4aSRandall Stewart case SCTP_OPERATION_ERROR: 2815f8829a4aSRandall Stewart case SCTP_COOKIE_ECHO: 2816f8829a4aSRandall Stewart case SCTP_COOKIE_ACK: 2817f8829a4aSRandall Stewart case SCTP_ECN_ECHO: 2818f8829a4aSRandall Stewart case SCTP_ECN_CWR: 2819f8829a4aSRandall Stewart case SCTP_SHUTDOWN_COMPLETE: 2820f8829a4aSRandall Stewart case SCTP_AUTHENTICATION: 2821f8829a4aSRandall Stewart case SCTP_ASCONF_ACK: 2822f8829a4aSRandall Stewart case SCTP_PACKET_DROPPED: 2823f8829a4aSRandall Stewart case SCTP_STREAM_RESET: 2824f8829a4aSRandall Stewart case SCTP_FORWARD_CUM_TSN: 2825f8829a4aSRandall Stewart case SCTP_ASCONF: 2826fd60718dSMichael Tuexen { 2827f8829a4aSRandall Stewart /* 2828fd60718dSMichael Tuexen * Now, what do we do with KNOWN 2829fd60718dSMichael Tuexen * chunks that are NOT in the right 2830fd60718dSMichael Tuexen * place? 2831f8829a4aSRandall Stewart * 2832fd60718dSMichael Tuexen * For now, I do nothing but ignore 2833fd60718dSMichael Tuexen * them. We may later want to add 2834fd60718dSMichael Tuexen * sysctl stuff to switch out and do 2835fd60718dSMichael Tuexen * either an ABORT() or possibly 2836fd60718dSMichael Tuexen * process them. 2837f8829a4aSRandall Stewart */ 2838f8829a4aSRandall Stewart struct mbuf *op_err; 2839267dbe63SMichael Tuexen char msg[SCTP_DIAG_INFO_LEN]; 2840f8829a4aSRandall Stewart 28419ae56375SMichael Tuexen snprintf(msg, sizeof(msg), "DATA chunk followed by chunk of type %2.2x", 284244249214SRandall Stewart ch->chunk_type); 2843267dbe63SMichael Tuexen op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); 2844e7e71dd7SMichael Tuexen sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); 2845f8829a4aSRandall Stewart return (2); 2846f8829a4aSRandall Stewart } 2847f8829a4aSRandall Stewart default: 28487f75695aSMichael Tuexen /* 28497f75695aSMichael Tuexen * Unknown chunk type: use bit rules after 28507f75695aSMichael Tuexen * checking length 28517f75695aSMichael Tuexen */ 28527f75695aSMichael Tuexen if (chk_length < sizeof(struct sctp_chunkhdr)) { 28537f75695aSMichael Tuexen /* 28547f75695aSMichael Tuexen * Need to send an abort since we 28557f75695aSMichael Tuexen * had a invalid chunk. 28567f75695aSMichael Tuexen */ 28577f75695aSMichael Tuexen struct mbuf *op_err; 28587f75695aSMichael Tuexen char msg[SCTP_DIAG_INFO_LEN]; 28597f75695aSMichael Tuexen 2860af03054cSMichael Tuexen snprintf(msg, sizeof(msg), "Chunk of length %u", 28617f75695aSMichael Tuexen chk_length); 28627f75695aSMichael Tuexen op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); 28637f75695aSMichael Tuexen stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_20; 28647f75695aSMichael Tuexen sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); 28657f75695aSMichael Tuexen return (2); 28667f75695aSMichael Tuexen } 286744249214SRandall Stewart if (ch->chunk_type & 0x40) { 2868f8829a4aSRandall Stewart /* Add a error report to the queue */ 286986eda749SMichael Tuexen struct mbuf *op_err; 287086eda749SMichael Tuexen struct sctp_gen_error_cause *cause; 2871f8829a4aSRandall Stewart 287286eda749SMichael Tuexen op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_gen_error_cause), 287386eda749SMichael Tuexen 0, M_NOWAIT, 1, MT_DATA); 287486eda749SMichael Tuexen if (op_err != NULL) { 287586eda749SMichael Tuexen cause = mtod(op_err, struct sctp_gen_error_cause *); 287686eda749SMichael Tuexen cause->code = htons(SCTP_CAUSE_UNRECOG_CHUNK); 28779a8e3088SMichael Tuexen cause->length = htons((uint16_t)(chk_length + sizeof(struct sctp_gen_error_cause))); 287886eda749SMichael Tuexen SCTP_BUF_LEN(op_err) = sizeof(struct sctp_gen_error_cause); 287986eda749SMichael Tuexen SCTP_BUF_NEXT(op_err) = SCTP_M_COPYM(m, *offset, chk_length, M_NOWAIT); 288086eda749SMichael Tuexen if (SCTP_BUF_NEXT(op_err) != NULL) { 288186eda749SMichael Tuexen sctp_queue_op_err(stcb, op_err); 2882f8829a4aSRandall Stewart } else { 288386eda749SMichael Tuexen sctp_m_freem(op_err); 2884f8829a4aSRandall Stewart } 2885f8829a4aSRandall Stewart } 2886f8829a4aSRandall Stewart } 288744249214SRandall Stewart if ((ch->chunk_type & 0x80) == 0) { 2888f8829a4aSRandall Stewart /* discard the rest of this packet */ 2889f8829a4aSRandall Stewart stop_proc = 1; 2890f8829a4aSRandall Stewart } /* else skip this bad chunk and 2891b7b84c0eSMichael Tuexen * continue... */ 2892b7b84c0eSMichael Tuexen break; 289360990c0cSMichael Tuexen } /* switch of chunk type */ 2894f8829a4aSRandall Stewart } 2895f8829a4aSRandall Stewart *offset += SCTP_SIZE32(chk_length); 2896f8829a4aSRandall Stewart if ((*offset >= length) || stop_proc) { 2897f8829a4aSRandall Stewart /* no more data left in the mbuf chain */ 2898f8829a4aSRandall Stewart stop_proc = 1; 2899f8829a4aSRandall Stewart continue; 2900f8829a4aSRandall Stewart } 290144249214SRandall Stewart ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset, 29027f75695aSMichael Tuexen sizeof(struct sctp_chunkhdr), 29037f75695aSMichael Tuexen (uint8_t *)&chunk_buf); 2904f8829a4aSRandall Stewart if (ch == NULL) { 2905f8829a4aSRandall Stewart *offset = length; 2906f8829a4aSRandall Stewart stop_proc = 1; 290760990c0cSMichael Tuexen continue; 2908f8829a4aSRandall Stewart } 290960990c0cSMichael Tuexen } 2910f8829a4aSRandall Stewart if (break_flag) { 2911f8829a4aSRandall Stewart /* 2912f8829a4aSRandall Stewart * we need to report rwnd overrun drops. 2913f8829a4aSRandall Stewart */ 291420cc2188SMichael Tuexen sctp_send_packet_dropped(stcb, net, *mm, length, iphlen, 0); 2915f8829a4aSRandall Stewart } 2916f8829a4aSRandall Stewart if (num_chunks) { 2917f8829a4aSRandall Stewart /* 2918ceaad40aSRandall Stewart * Did we get data, if so update the time for auto-close and 2919f8829a4aSRandall Stewart * give peer credit for being alive. 2920f8829a4aSRandall Stewart */ 2921f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_recvpktwithdata); 2922b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { 2923c4739e2fSRandall Stewart sctp_misc_ints(SCTP_THRESHOLD_CLEAR, 2924c4739e2fSRandall Stewart stcb->asoc.overall_error_count, 2925c4739e2fSRandall Stewart 0, 2926c4739e2fSRandall Stewart SCTP_FROM_SCTP_INDATA, 2927c4739e2fSRandall Stewart __LINE__); 2928c4739e2fSRandall Stewart } 2929f8829a4aSRandall Stewart stcb->asoc.overall_error_count = 0; 29306e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_last_rcvd); 2931f8829a4aSRandall Stewart } 2932f8829a4aSRandall Stewart /* now service all of the reassm queue if needed */ 2933f8829a4aSRandall Stewart if (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_SENT) { 293442551e99SRandall Stewart /* Assure that we ack right away */ 293542551e99SRandall Stewart stcb->asoc.send_sack = 1; 2936f8829a4aSRandall Stewart } 2937f8829a4aSRandall Stewart /* Start a sack timer or QUEUE a SACK for sending */ 29387215cc1bSMichael Tuexen sctp_sack_check(stcb, was_a_gap); 2939f8829a4aSRandall Stewart return (0); 2940f8829a4aSRandall Stewart } 2941f8829a4aSRandall Stewart 29420fa753b3SRandall Stewart static int 29430fa753b3SRandall Stewart sctp_process_segment_range(struct sctp_tcb *stcb, struct sctp_tmit_chunk **p_tp1, uint32_t last_tsn, 29440fa753b3SRandall Stewart uint16_t frag_strt, uint16_t frag_end, int nr_sacking, 29450fa753b3SRandall Stewart int *num_frs, 29460fa753b3SRandall Stewart uint32_t *biggest_newly_acked_tsn, 29470fa753b3SRandall Stewart uint32_t *this_sack_lowest_newack, 29487215cc1bSMichael Tuexen int *rto_ok) 29490fa753b3SRandall Stewart { 29500fa753b3SRandall Stewart struct sctp_tmit_chunk *tp1; 29510fa753b3SRandall Stewart unsigned int theTSN; 2952b5c16493SMichael Tuexen int j, wake_him = 0, circled = 0; 29530fa753b3SRandall Stewart 29540fa753b3SRandall Stewart /* Recover the tp1 we last saw */ 29550fa753b3SRandall Stewart tp1 = *p_tp1; 29560fa753b3SRandall Stewart if (tp1 == NULL) { 29570fa753b3SRandall Stewart tp1 = TAILQ_FIRST(&stcb->asoc.sent_queue); 29580fa753b3SRandall Stewart } 29590fa753b3SRandall Stewart for (j = frag_strt; j <= frag_end; j++) { 29600fa753b3SRandall Stewart theTSN = j + last_tsn; 29610fa753b3SRandall Stewart while (tp1) { 29620fa753b3SRandall Stewart if (tp1->rec.data.doing_fast_retransmit) 29630fa753b3SRandall Stewart (*num_frs) += 1; 29640fa753b3SRandall Stewart 29650fa753b3SRandall Stewart /*- 29660fa753b3SRandall Stewart * CMT: CUCv2 algorithm. For each TSN being 29670fa753b3SRandall Stewart * processed from the sent queue, track the 29680fa753b3SRandall Stewart * next expected pseudo-cumack, or 29690fa753b3SRandall Stewart * rtx_pseudo_cumack, if required. Separate 29700fa753b3SRandall Stewart * cumack trackers for first transmissions, 29710fa753b3SRandall Stewart * and retransmissions. 29720fa753b3SRandall Stewart */ 29738427b3fdSMichael Tuexen if ((tp1->sent < SCTP_DATAGRAM_RESEND) && 29748427b3fdSMichael Tuexen (tp1->whoTo->find_pseudo_cumack == 1) && 29750fa753b3SRandall Stewart (tp1->snd_count == 1)) { 297649656eefSMichael Tuexen tp1->whoTo->pseudo_cumack = tp1->rec.data.tsn; 29770fa753b3SRandall Stewart tp1->whoTo->find_pseudo_cumack = 0; 29780fa753b3SRandall Stewart } 29798427b3fdSMichael Tuexen if ((tp1->sent < SCTP_DATAGRAM_RESEND) && 29808427b3fdSMichael Tuexen (tp1->whoTo->find_rtx_pseudo_cumack == 1) && 29810fa753b3SRandall Stewart (tp1->snd_count > 1)) { 298249656eefSMichael Tuexen tp1->whoTo->rtx_pseudo_cumack = tp1->rec.data.tsn; 29830fa753b3SRandall Stewart tp1->whoTo->find_rtx_pseudo_cumack = 0; 29840fa753b3SRandall Stewart } 298549656eefSMichael Tuexen if (tp1->rec.data.tsn == theTSN) { 29860fa753b3SRandall Stewart if (tp1->sent != SCTP_DATAGRAM_UNSENT) { 29870fa753b3SRandall Stewart /*- 29880fa753b3SRandall Stewart * must be held until 29890fa753b3SRandall Stewart * cum-ack passes 29900fa753b3SRandall Stewart */ 29910fa753b3SRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND) { 29920fa753b3SRandall Stewart /*- 29930fa753b3SRandall Stewart * If it is less than RESEND, it is 29940fa753b3SRandall Stewart * now no-longer in flight. 29950fa753b3SRandall Stewart * Higher values may already be set 29960fa753b3SRandall Stewart * via previous Gap Ack Blocks... 29970fa753b3SRandall Stewart * i.e. ACKED or RESEND. 29980fa753b3SRandall Stewart */ 299949656eefSMichael Tuexen if (SCTP_TSN_GT(tp1->rec.data.tsn, 300020b07a4dSMichael Tuexen *biggest_newly_acked_tsn)) { 300149656eefSMichael Tuexen *biggest_newly_acked_tsn = tp1->rec.data.tsn; 30020fa753b3SRandall Stewart } 30030fa753b3SRandall Stewart /*- 30040fa753b3SRandall Stewart * CMT: SFR algo (and HTNA) - set 30050fa753b3SRandall Stewart * saw_newack to 1 for dest being 30060fa753b3SRandall Stewart * newly acked. update 30070fa753b3SRandall Stewart * this_sack_highest_newack if 30080fa753b3SRandall Stewart * appropriate. 30090fa753b3SRandall Stewart */ 30100fa753b3SRandall Stewart if (tp1->rec.data.chunk_was_revoked == 0) 30110fa753b3SRandall Stewart tp1->whoTo->saw_newack = 1; 30120fa753b3SRandall Stewart 301349656eefSMichael Tuexen if (SCTP_TSN_GT(tp1->rec.data.tsn, 301420b07a4dSMichael Tuexen tp1->whoTo->this_sack_highest_newack)) { 30150fa753b3SRandall Stewart tp1->whoTo->this_sack_highest_newack = 301649656eefSMichael Tuexen tp1->rec.data.tsn; 30170fa753b3SRandall Stewart } 30180fa753b3SRandall Stewart /*- 30190fa753b3SRandall Stewart * CMT DAC algo: also update 30200fa753b3SRandall Stewart * this_sack_lowest_newack 30210fa753b3SRandall Stewart */ 30220fa753b3SRandall Stewart if (*this_sack_lowest_newack == 0) { 30230fa753b3SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) { 30240fa753b3SRandall Stewart sctp_log_sack(*this_sack_lowest_newack, 30250fa753b3SRandall Stewart last_tsn, 302649656eefSMichael Tuexen tp1->rec.data.tsn, 30270fa753b3SRandall Stewart 0, 30280fa753b3SRandall Stewart 0, 30290fa753b3SRandall Stewart SCTP_LOG_TSN_ACKED); 30300fa753b3SRandall Stewart } 303149656eefSMichael Tuexen *this_sack_lowest_newack = tp1->rec.data.tsn; 30320fa753b3SRandall Stewart } 30330fa753b3SRandall Stewart /*- 30340fa753b3SRandall Stewart * CMT: CUCv2 algorithm. If (rtx-)pseudo-cumack for corresp 30350fa753b3SRandall Stewart * dest is being acked, then we have a new (rtx-)pseudo-cumack. Set 30360fa753b3SRandall Stewart * new_(rtx_)pseudo_cumack to TRUE so that the cwnd for this dest can be 30370fa753b3SRandall Stewart * updated. Also trigger search for the next expected (rtx-)pseudo-cumack. 30380fa753b3SRandall Stewart * Separate pseudo_cumack trackers for first transmissions and 30390fa753b3SRandall Stewart * retransmissions. 30400fa753b3SRandall Stewart */ 304149656eefSMichael Tuexen if (tp1->rec.data.tsn == tp1->whoTo->pseudo_cumack) { 30420fa753b3SRandall Stewart if (tp1->rec.data.chunk_was_revoked == 0) { 30430fa753b3SRandall Stewart tp1->whoTo->new_pseudo_cumack = 1; 30440fa753b3SRandall Stewart } 30450fa753b3SRandall Stewart tp1->whoTo->find_pseudo_cumack = 1; 30460fa753b3SRandall Stewart } 30470fa753b3SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 304849656eefSMichael Tuexen sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.tsn, SCTP_CWND_LOG_FROM_SACK); 30490fa753b3SRandall Stewart } 305049656eefSMichael Tuexen if (tp1->rec.data.tsn == tp1->whoTo->rtx_pseudo_cumack) { 30510fa753b3SRandall Stewart if (tp1->rec.data.chunk_was_revoked == 0) { 30520fa753b3SRandall Stewart tp1->whoTo->new_pseudo_cumack = 1; 30530fa753b3SRandall Stewart } 30540fa753b3SRandall Stewart tp1->whoTo->find_rtx_pseudo_cumack = 1; 30550fa753b3SRandall Stewart } 30560fa753b3SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) { 30570fa753b3SRandall Stewart sctp_log_sack(*biggest_newly_acked_tsn, 30580fa753b3SRandall Stewart last_tsn, 305949656eefSMichael Tuexen tp1->rec.data.tsn, 30600fa753b3SRandall Stewart frag_strt, 30610fa753b3SRandall Stewart frag_end, 30620fa753b3SRandall Stewart SCTP_LOG_TSN_ACKED); 30630fa753b3SRandall Stewart } 30640fa753b3SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { 30650fa753b3SRandall Stewart sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_GAP, 30660fa753b3SRandall Stewart tp1->whoTo->flight_size, 30670fa753b3SRandall Stewart tp1->book_size, 30689a8e3088SMichael Tuexen (uint32_t)(uintptr_t)tp1->whoTo, 306949656eefSMichael Tuexen tp1->rec.data.tsn); 30700fa753b3SRandall Stewart } 30710fa753b3SRandall Stewart sctp_flight_size_decrease(tp1); 3072299108c5SRandall Stewart if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) { 3073299108c5SRandall Stewart (*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) (tp1->whoTo, 3074299108c5SRandall Stewart tp1); 3075299108c5SRandall Stewart } 30760fa753b3SRandall Stewart sctp_total_flight_decrease(stcb, tp1); 30770fa753b3SRandall Stewart 30780fa753b3SRandall Stewart tp1->whoTo->net_ack += tp1->send_size; 30790fa753b3SRandall Stewart if (tp1->snd_count < 2) { 30800fa753b3SRandall Stewart /*- 30810fa753b3SRandall Stewart * True non-retransmited chunk 30820fa753b3SRandall Stewart */ 30830fa753b3SRandall Stewart tp1->whoTo->net_ack2 += tp1->send_size; 30840fa753b3SRandall Stewart 30850fa753b3SRandall Stewart /*- 30860fa753b3SRandall Stewart * update RTO too ? 30870fa753b3SRandall Stewart */ 30880fa753b3SRandall Stewart if (tp1->do_rtt) { 3089f79aab18SRandall Stewart if (*rto_ok) { 30900fa753b3SRandall Stewart tp1->whoTo->RTO = 30910fa753b3SRandall Stewart sctp_calculate_rto(stcb, 30920fa753b3SRandall Stewart &stcb->asoc, 30930fa753b3SRandall Stewart tp1->whoTo, 30940fa753b3SRandall Stewart &tp1->sent_rcv_time, 3095f79aab18SRandall Stewart SCTP_RTT_FROM_DATA); 3096f79aab18SRandall Stewart *rto_ok = 0; 3097f79aab18SRandall Stewart } 3098f79aab18SRandall Stewart if (tp1->whoTo->rto_needed == 0) { 3099f79aab18SRandall Stewart tp1->whoTo->rto_needed = 1; 3100f79aab18SRandall Stewart } 31010fa753b3SRandall Stewart tp1->do_rtt = 0; 31020fa753b3SRandall Stewart } 31030fa753b3SRandall Stewart } 3104*0053ed28SMichael Tuexen 31050fa753b3SRandall Stewart } 31060fa753b3SRandall Stewart if (tp1->sent <= SCTP_DATAGRAM_RESEND) { 310749656eefSMichael Tuexen if (SCTP_TSN_GT(tp1->rec.data.tsn, 310820b07a4dSMichael Tuexen stcb->asoc.this_sack_highest_gap)) { 31090fa753b3SRandall Stewart stcb->asoc.this_sack_highest_gap = 311049656eefSMichael Tuexen tp1->rec.data.tsn; 31110fa753b3SRandall Stewart } 31120fa753b3SRandall Stewart if (tp1->sent == SCTP_DATAGRAM_RESEND) { 31130fa753b3SRandall Stewart sctp_ucount_decr(stcb->asoc.sent_queue_retran_cnt); 31140fa753b3SRandall Stewart #ifdef SCTP_AUDITING_ENABLED 31150fa753b3SRandall Stewart sctp_audit_log(0xB2, 31160fa753b3SRandall Stewart (stcb->asoc.sent_queue_retran_cnt & 0x000000ff)); 31170fa753b3SRandall Stewart #endif 31180fa753b3SRandall Stewart } 31190fa753b3SRandall Stewart } 31200fa753b3SRandall Stewart /*- 31210fa753b3SRandall Stewart * All chunks NOT UNSENT fall through here and are marked 31220fa753b3SRandall Stewart * (leave PR-SCTP ones that are to skip alone though) 31230fa753b3SRandall Stewart */ 31242a498584SMichael Tuexen if ((tp1->sent != SCTP_FORWARD_TSN_SKIP) && 3125325c8c46SMichael Tuexen (tp1->sent != SCTP_DATAGRAM_NR_ACKED)) { 31260fa753b3SRandall Stewart tp1->sent = SCTP_DATAGRAM_MARKED; 31272a498584SMichael Tuexen } 31280fa753b3SRandall Stewart if (tp1->rec.data.chunk_was_revoked) { 31290fa753b3SRandall Stewart /* deflate the cwnd */ 31300fa753b3SRandall Stewart tp1->whoTo->cwnd -= tp1->book_size; 31310fa753b3SRandall Stewart tp1->rec.data.chunk_was_revoked = 0; 31320fa753b3SRandall Stewart } 31330fa753b3SRandall Stewart /* NR Sack code here */ 3134325c8c46SMichael Tuexen if (nr_sacking && 3135325c8c46SMichael Tuexen (tp1->sent != SCTP_DATAGRAM_NR_ACKED)) { 313649656eefSMichael Tuexen if (stcb->asoc.strmout[tp1->rec.data.sid].chunks_on_queues > 0) { 313749656eefSMichael Tuexen stcb->asoc.strmout[tp1->rec.data.sid].chunks_on_queues--; 3138325c8c46SMichael Tuexen #ifdef INVARIANTS 3139325c8c46SMichael Tuexen } else { 314049656eefSMichael Tuexen panic("No chunks on the queues for sid %u.", tp1->rec.data.sid); 3141325c8c46SMichael Tuexen #endif 3142325c8c46SMichael Tuexen } 314349656eefSMichael Tuexen if ((stcb->asoc.strmout[tp1->rec.data.sid].chunks_on_queues == 0) && 314449656eefSMichael Tuexen (stcb->asoc.strmout[tp1->rec.data.sid].state == SCTP_STREAM_RESET_PENDING) && 314549656eefSMichael Tuexen TAILQ_EMPTY(&stcb->asoc.strmout[tp1->rec.data.sid].outqueue)) { 3146d96bef9cSMichael Tuexen stcb->asoc.trigger_reset = 1; 3147d96bef9cSMichael Tuexen } 3148325c8c46SMichael Tuexen tp1->sent = SCTP_DATAGRAM_NR_ACKED; 31490fa753b3SRandall Stewart if (tp1->data) { 3150b7b84c0eSMichael Tuexen /* 3151b7b84c0eSMichael Tuexen * sa_ignore 3152b7b84c0eSMichael Tuexen * NO_NULL_CHK 3153b7b84c0eSMichael Tuexen */ 31540fa753b3SRandall Stewart sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1); 31550fa753b3SRandall Stewart sctp_m_freem(tp1->data); 31560fa753b3SRandall Stewart tp1->data = NULL; 3157b5c16493SMichael Tuexen } 31580fa753b3SRandall Stewart wake_him++; 31590fa753b3SRandall Stewart } 31600fa753b3SRandall Stewart } 31610fa753b3SRandall Stewart break; 3162b7b84c0eSMichael Tuexen } /* if (tp1->tsn == theTSN) */ 3163b7b84c0eSMichael Tuexen if (SCTP_TSN_GT(tp1->rec.data.tsn, theTSN)) { 31640fa753b3SRandall Stewart break; 316520b07a4dSMichael Tuexen } 31660fa753b3SRandall Stewart tp1 = TAILQ_NEXT(tp1, sctp_next); 3167b5c16493SMichael Tuexen if ((tp1 == NULL) && (circled == 0)) { 3168b5c16493SMichael Tuexen circled++; 31690fa753b3SRandall Stewart tp1 = TAILQ_FIRST(&stcb->asoc.sent_queue); 31700fa753b3SRandall Stewart } 3171b5c16493SMichael Tuexen } /* end while (tp1) */ 3172b5c16493SMichael Tuexen if (tp1 == NULL) { 3173b5c16493SMichael Tuexen circled = 0; 3174b5c16493SMichael Tuexen tp1 = TAILQ_FIRST(&stcb->asoc.sent_queue); 3175b5c16493SMichael Tuexen } 3176b5c16493SMichael Tuexen /* In case the fragments were not in order we must reset */ 31770fa753b3SRandall Stewart } /* end for (j = fragStart */ 31780fa753b3SRandall Stewart *p_tp1 = tp1; 31790fa753b3SRandall Stewart return (wake_him); /* Return value only used for nr-sack */ 31800fa753b3SRandall Stewart } 31810fa753b3SRandall Stewart 31820fa753b3SRandall Stewart 3183cd554309SMichael Tuexen static int 3184458303daSRandall Stewart sctp_handle_segments(struct mbuf *m, int *offset, struct sctp_tcb *stcb, struct sctp_association *asoc, 3185cd554309SMichael Tuexen uint32_t last_tsn, uint32_t *biggest_tsn_acked, 3186139bc87fSRandall Stewart uint32_t *biggest_newly_acked_tsn, uint32_t *this_sack_lowest_newack, 31877215cc1bSMichael Tuexen int num_seg, int num_nr_seg, int *rto_ok) 3188f8829a4aSRandall Stewart { 3189458303daSRandall Stewart struct sctp_gap_ack_block *frag, block; 3190f8829a4aSRandall Stewart struct sctp_tmit_chunk *tp1; 31910fa753b3SRandall Stewart int i; 3192f8829a4aSRandall Stewart int num_frs = 0; 3193cd554309SMichael Tuexen int chunk_freed; 3194cd554309SMichael Tuexen int non_revocable; 3195d9c5cfeaSMichael Tuexen uint16_t frag_strt, frag_end, prev_frag_end; 3196f8829a4aSRandall Stewart 3197d9c5cfeaSMichael Tuexen tp1 = TAILQ_FIRST(&asoc->sent_queue); 3198d9c5cfeaSMichael Tuexen prev_frag_end = 0; 3199cd554309SMichael Tuexen chunk_freed = 0; 3200f8829a4aSRandall Stewart 3201cd554309SMichael Tuexen for (i = 0; i < (num_seg + num_nr_seg); i++) { 3202d9c5cfeaSMichael Tuexen if (i == num_seg) { 3203d9c5cfeaSMichael Tuexen prev_frag_end = 0; 3204d9c5cfeaSMichael Tuexen tp1 = TAILQ_FIRST(&asoc->sent_queue); 3205d9c5cfeaSMichael Tuexen } 3206458303daSRandall Stewart frag = (struct sctp_gap_ack_block *)sctp_m_getptr(m, *offset, 3207458303daSRandall Stewart sizeof(struct sctp_gap_ack_block), (uint8_t *)&block); 3208458303daSRandall Stewart *offset += sizeof(block); 3209458303daSRandall Stewart if (frag == NULL) { 3210cd554309SMichael Tuexen return (chunk_freed); 3211458303daSRandall Stewart } 3212f8829a4aSRandall Stewart frag_strt = ntohs(frag->start); 3213f8829a4aSRandall Stewart frag_end = ntohs(frag->end); 3214d9c5cfeaSMichael Tuexen 3215f8829a4aSRandall Stewart if (frag_strt > frag_end) { 3216d9c5cfeaSMichael Tuexen /* This gap report is malformed, skip it. */ 3217f8829a4aSRandall Stewart continue; 3218f8829a4aSRandall Stewart } 3219d9c5cfeaSMichael Tuexen if (frag_strt <= prev_frag_end) { 3220d9c5cfeaSMichael Tuexen /* This gap report is not in order, so restart. */ 3221f8829a4aSRandall Stewart tp1 = TAILQ_FIRST(&asoc->sent_queue); 3222f8829a4aSRandall Stewart } 322320b07a4dSMichael Tuexen if (SCTP_TSN_GT((last_tsn + frag_end), *biggest_tsn_acked)) { 3224d9c5cfeaSMichael Tuexen *biggest_tsn_acked = last_tsn + frag_end; 3225f8829a4aSRandall Stewart } 3226cd554309SMichael Tuexen if (i < num_seg) { 3227cd554309SMichael Tuexen non_revocable = 0; 3228cd554309SMichael Tuexen } else { 3229cd554309SMichael Tuexen non_revocable = 1; 3230cd554309SMichael Tuexen } 3231cd554309SMichael Tuexen if (sctp_process_segment_range(stcb, &tp1, last_tsn, frag_strt, frag_end, 3232cd554309SMichael Tuexen non_revocable, &num_frs, biggest_newly_acked_tsn, 32337215cc1bSMichael Tuexen this_sack_lowest_newack, rto_ok)) { 3234cd554309SMichael Tuexen chunk_freed = 1; 3235458303daSRandall Stewart } 3236d9c5cfeaSMichael Tuexen prev_frag_end = frag_end; 3237f8829a4aSRandall Stewart } 3238b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { 323980fefe0aSRandall Stewart if (num_frs) 324080fefe0aSRandall Stewart sctp_log_fr(*biggest_tsn_acked, 324180fefe0aSRandall Stewart *biggest_newly_acked_tsn, 324280fefe0aSRandall Stewart last_tsn, SCTP_FR_LOG_BIGGEST_TSNS); 324380fefe0aSRandall Stewart } 3244cd554309SMichael Tuexen return (chunk_freed); 3245f8829a4aSRandall Stewart } 3246f8829a4aSRandall Stewart 3247f8829a4aSRandall Stewart static void 3248c105859eSRandall Stewart sctp_check_for_revoked(struct sctp_tcb *stcb, 3249c105859eSRandall Stewart struct sctp_association *asoc, uint32_t cumack, 325063eda93dSMichael Tuexen uint32_t biggest_tsn_acked) 3251f8829a4aSRandall Stewart { 3252f8829a4aSRandall Stewart struct sctp_tmit_chunk *tp1; 3253f8829a4aSRandall Stewart 32544a9ef3f8SMichael Tuexen TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) { 325549656eefSMichael Tuexen if (SCTP_TSN_GT(tp1->rec.data.tsn, cumack)) { 3256f8829a4aSRandall Stewart /* 3257f8829a4aSRandall Stewart * ok this guy is either ACK or MARKED. If it is 3258f8829a4aSRandall Stewart * ACKED it has been previously acked but not this 3259f8829a4aSRandall Stewart * time i.e. revoked. If it is MARKED it was ACK'ed 3260f8829a4aSRandall Stewart * again. 3261f8829a4aSRandall Stewart */ 326249656eefSMichael Tuexen if (SCTP_TSN_GT(tp1->rec.data.tsn, biggest_tsn_acked)) { 3263d06c82f1SRandall Stewart break; 326420b07a4dSMichael Tuexen } 3265f8829a4aSRandall Stewart if (tp1->sent == SCTP_DATAGRAM_ACKED) { 3266f8829a4aSRandall Stewart /* it has been revoked */ 3267f8829a4aSRandall Stewart tp1->sent = SCTP_DATAGRAM_SENT; 3268f8829a4aSRandall Stewart tp1->rec.data.chunk_was_revoked = 1; 3269a5d547adSRandall Stewart /* 327042551e99SRandall Stewart * We must add this stuff back in to assure 327142551e99SRandall Stewart * timers and such get started. 3272a5d547adSRandall Stewart */ 3273b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { 3274c105859eSRandall Stewart sctp_misc_ints(SCTP_FLIGHT_LOG_UP_REVOKE, 3275c105859eSRandall Stewart tp1->whoTo->flight_size, 3276c105859eSRandall Stewart tp1->book_size, 32779a8e3088SMichael Tuexen (uint32_t)(uintptr_t)tp1->whoTo, 327849656eefSMichael Tuexen tp1->rec.data.tsn); 327980fefe0aSRandall Stewart } 3280c105859eSRandall Stewart sctp_flight_size_increase(tp1); 3281c105859eSRandall Stewart sctp_total_flight_increase(stcb, tp1); 328242551e99SRandall Stewart /* 328342551e99SRandall Stewart * We inflate the cwnd to compensate for our 328442551e99SRandall Stewart * artificial inflation of the flight_size. 328542551e99SRandall Stewart */ 328642551e99SRandall Stewart tp1->whoTo->cwnd += tp1->book_size; 3287b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) { 3288f8829a4aSRandall Stewart sctp_log_sack(asoc->last_acked_seq, 3289f8829a4aSRandall Stewart cumack, 329049656eefSMichael Tuexen tp1->rec.data.tsn, 3291f8829a4aSRandall Stewart 0, 3292f8829a4aSRandall Stewart 0, 3293f8829a4aSRandall Stewart SCTP_LOG_TSN_REVOKED); 329480fefe0aSRandall Stewart } 3295f8829a4aSRandall Stewart } else if (tp1->sent == SCTP_DATAGRAM_MARKED) { 3296f8829a4aSRandall Stewart /* it has been re-acked in this SACK */ 3297f8829a4aSRandall Stewart tp1->sent = SCTP_DATAGRAM_ACKED; 3298f8829a4aSRandall Stewart } 3299f8829a4aSRandall Stewart } 3300f8829a4aSRandall Stewart if (tp1->sent == SCTP_DATAGRAM_UNSENT) 3301f8829a4aSRandall Stewart break; 3302f8829a4aSRandall Stewart } 3303f8829a4aSRandall Stewart } 3304f8829a4aSRandall Stewart 3305830d754dSRandall Stewart 3306f8829a4aSRandall Stewart static void 3307f8829a4aSRandall Stewart sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, 330863eda93dSMichael Tuexen uint32_t biggest_tsn_acked, uint32_t biggest_tsn_newly_acked, uint32_t this_sack_lowest_newack, int accum_moved) 3309f8829a4aSRandall Stewart { 3310f8829a4aSRandall Stewart struct sctp_tmit_chunk *tp1; 3311f8829a4aSRandall Stewart int strike_flag = 0; 3312f8829a4aSRandall Stewart struct timeval now; 3313f8829a4aSRandall Stewart int tot_retrans = 0; 3314f8829a4aSRandall Stewart uint32_t sending_seq; 3315f8829a4aSRandall Stewart struct sctp_nets *net; 3316f8829a4aSRandall Stewart int num_dests_sacked = 0; 3317f8829a4aSRandall Stewart 3318f8829a4aSRandall Stewart /* 3319f8829a4aSRandall Stewart * select the sending_seq, this is either the next thing ready to be 3320f8829a4aSRandall Stewart * sent but not transmitted, OR, the next seq we assign. 3321f8829a4aSRandall Stewart */ 3322f8829a4aSRandall Stewart tp1 = TAILQ_FIRST(&stcb->asoc.send_queue); 3323f8829a4aSRandall Stewart if (tp1 == NULL) { 3324f8829a4aSRandall Stewart sending_seq = asoc->sending_seq; 3325f8829a4aSRandall Stewart } else { 332649656eefSMichael Tuexen sending_seq = tp1->rec.data.tsn; 3327f8829a4aSRandall Stewart } 3328f8829a4aSRandall Stewart 3329f8829a4aSRandall Stewart /* CMT DAC algo: finding out if SACK is a mixed SACK */ 33307c99d56fSMichael Tuexen if ((asoc->sctp_cmt_on_off > 0) && 333120083c2eSMichael Tuexen SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) { 3332f8829a4aSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 3333f8829a4aSRandall Stewart if (net->saw_newack) 3334f8829a4aSRandall Stewart num_dests_sacked++; 3335f8829a4aSRandall Stewart } 3336f8829a4aSRandall Stewart } 3337dd973b0eSMichael Tuexen if (stcb->asoc.prsctp_supported) { 33386e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&now); 3339f8829a4aSRandall Stewart } 33404a9ef3f8SMichael Tuexen TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) { 3341f8829a4aSRandall Stewart strike_flag = 0; 3342f8829a4aSRandall Stewart if (tp1->no_fr_allowed) { 3343f8829a4aSRandall Stewart /* this one had a timeout or something */ 3344f8829a4aSRandall Stewart continue; 3345f8829a4aSRandall Stewart } 3346b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { 3347f8829a4aSRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND) 3348f8829a4aSRandall Stewart sctp_log_fr(biggest_tsn_newly_acked, 334949656eefSMichael Tuexen tp1->rec.data.tsn, 3350f8829a4aSRandall Stewart tp1->sent, 3351f8829a4aSRandall Stewart SCTP_FR_LOG_CHECK_STRIKE); 335280fefe0aSRandall Stewart } 335349656eefSMichael Tuexen if (SCTP_TSN_GT(tp1->rec.data.tsn, biggest_tsn_acked) || 3354f8829a4aSRandall Stewart tp1->sent == SCTP_DATAGRAM_UNSENT) { 3355f8829a4aSRandall Stewart /* done */ 3356f8829a4aSRandall Stewart break; 3357f8829a4aSRandall Stewart } 3358dd973b0eSMichael Tuexen if (stcb->asoc.prsctp_supported) { 3359f8829a4aSRandall Stewart if ((PR_SCTP_TTL_ENABLED(tp1->flags)) && tp1->sent < SCTP_DATAGRAM_ACKED) { 3360f8829a4aSRandall Stewart /* Is it expired? */ 336199ddc825SMichael Tuexen if (timevalcmp(&now, &tp1->rec.data.timetodrop, >)) { 3362f8829a4aSRandall Stewart /* Yes so drop it */ 3363f8829a4aSRandall Stewart if (tp1->data != NULL) { 33641edc9dbaSMichael Tuexen (void)sctp_release_pr_sctp_chunk(stcb, tp1, 1, 33650c0982b8SRandall Stewart SCTP_SO_NOT_LOCKED); 3366f8829a4aSRandall Stewart } 3367f8829a4aSRandall Stewart continue; 3368f8829a4aSRandall Stewart } 3369f8829a4aSRandall Stewart } 3370*0053ed28SMichael Tuexen 3371f8829a4aSRandall Stewart } 3372e9a3a1b1SMichael Tuexen if (SCTP_TSN_GT(tp1->rec.data.tsn, asoc->this_sack_highest_gap) && 3373e9a3a1b1SMichael Tuexen !(accum_moved && asoc->fast_retran_loss_recovery)) { 3374f8829a4aSRandall Stewart /* we are beyond the tsn in the sack */ 3375f8829a4aSRandall Stewart break; 3376f8829a4aSRandall Stewart } 3377f8829a4aSRandall Stewart if (tp1->sent >= SCTP_DATAGRAM_RESEND) { 3378f8829a4aSRandall Stewart /* either a RESEND, ACKED, or MARKED */ 3379f8829a4aSRandall Stewart /* skip */ 338044fbe462SRandall Stewart if (tp1->sent == SCTP_FORWARD_TSN_SKIP) { 338144fbe462SRandall Stewart /* Continue strikin FWD-TSN chunks */ 338244fbe462SRandall Stewart tp1->rec.data.fwd_tsn_cnt++; 338344fbe462SRandall Stewart } 3384f8829a4aSRandall Stewart continue; 3385f8829a4aSRandall Stewart } 3386f8829a4aSRandall Stewart /* 3387f8829a4aSRandall Stewart * CMT : SFR algo (covers part of DAC and HTNA as well) 3388f8829a4aSRandall Stewart */ 3389ad81507eSRandall Stewart if (tp1->whoTo && tp1->whoTo->saw_newack == 0) { 3390f8829a4aSRandall Stewart /* 3391f8829a4aSRandall Stewart * No new acks were receieved for data sent to this 3392f8829a4aSRandall Stewart * dest. Therefore, according to the SFR algo for 3393f8829a4aSRandall Stewart * CMT, no data sent to this dest can be marked for 3394c105859eSRandall Stewart * FR using this SACK. 3395f8829a4aSRandall Stewart */ 3396f8829a4aSRandall Stewart continue; 3397e9a3a1b1SMichael Tuexen } else if (tp1->whoTo && 3398e9a3a1b1SMichael Tuexen SCTP_TSN_GT(tp1->rec.data.tsn, 3399e9a3a1b1SMichael Tuexen tp1->whoTo->this_sack_highest_newack) && 3400e9a3a1b1SMichael Tuexen !(accum_moved && asoc->fast_retran_loss_recovery)) { 3401f8829a4aSRandall Stewart /* 3402f8829a4aSRandall Stewart * CMT: New acks were receieved for data sent to 3403f8829a4aSRandall Stewart * this dest. But no new acks were seen for data 3404f8829a4aSRandall Stewart * sent after tp1. Therefore, according to the SFR 3405f8829a4aSRandall Stewart * algo for CMT, tp1 cannot be marked for FR using 3406f8829a4aSRandall Stewart * this SACK. This step covers part of the DAC algo 3407f8829a4aSRandall Stewart * and the HTNA algo as well. 3408f8829a4aSRandall Stewart */ 3409f8829a4aSRandall Stewart continue; 3410f8829a4aSRandall Stewart } 3411f8829a4aSRandall Stewart /* 3412f8829a4aSRandall Stewart * Here we check to see if we were have already done a FR 3413f8829a4aSRandall Stewart * and if so we see if the biggest TSN we saw in the sack is 3414f8829a4aSRandall Stewart * smaller than the recovery point. If so we don't strike 3415f8829a4aSRandall Stewart * the tsn... otherwise we CAN strike the TSN. 3416f8829a4aSRandall Stewart */ 3417f8829a4aSRandall Stewart /* 341842551e99SRandall Stewart * @@@ JRI: Check for CMT if (accum_moved && 341942551e99SRandall Stewart * asoc->fast_retran_loss_recovery && (sctp_cmt_on_off == 342042551e99SRandall Stewart * 0)) { 3421f8829a4aSRandall Stewart */ 342242551e99SRandall Stewart if (accum_moved && asoc->fast_retran_loss_recovery) { 3423f8829a4aSRandall Stewart /* 3424f8829a4aSRandall Stewart * Strike the TSN if in fast-recovery and cum-ack 3425f8829a4aSRandall Stewart * moved. 3426f8829a4aSRandall Stewart */ 3427b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { 3428f8829a4aSRandall Stewart sctp_log_fr(biggest_tsn_newly_acked, 342949656eefSMichael Tuexen tp1->rec.data.tsn, 3430f8829a4aSRandall Stewart tp1->sent, 3431f8829a4aSRandall Stewart SCTP_FR_LOG_STRIKE_CHUNK); 343280fefe0aSRandall Stewart } 34335e54f665SRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND) { 3434f8829a4aSRandall Stewart tp1->sent++; 34355e54f665SRandall Stewart } 34367c99d56fSMichael Tuexen if ((asoc->sctp_cmt_on_off > 0) && 343720083c2eSMichael Tuexen SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) { 3438f8829a4aSRandall Stewart /* 3439f8829a4aSRandall Stewart * CMT DAC algorithm: If SACK flag is set to 3440f8829a4aSRandall Stewart * 0, then lowest_newack test will not pass 3441f8829a4aSRandall Stewart * because it would have been set to the 3442f8829a4aSRandall Stewart * cumack earlier. If not already to be 3443f8829a4aSRandall Stewart * rtx'd, If not a mixed sack and if tp1 is 3444f8829a4aSRandall Stewart * not between two sacked TSNs, then mark by 3445c105859eSRandall Stewart * one more. NOTE that we are marking by one 3446c105859eSRandall Stewart * additional time since the SACK DAC flag 3447c105859eSRandall Stewart * indicates that two packets have been 3448c105859eSRandall Stewart * received after this missing TSN. 34495e54f665SRandall Stewart */ 34505e54f665SRandall Stewart if ((tp1->sent < SCTP_DATAGRAM_RESEND) && (num_dests_sacked == 1) && 345149656eefSMichael Tuexen SCTP_TSN_GT(this_sack_lowest_newack, tp1->rec.data.tsn)) { 3452b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { 3453f8829a4aSRandall Stewart sctp_log_fr(16 + num_dests_sacked, 345449656eefSMichael Tuexen tp1->rec.data.tsn, 3455f8829a4aSRandall Stewart tp1->sent, 3456f8829a4aSRandall Stewart SCTP_FR_LOG_STRIKE_CHUNK); 345780fefe0aSRandall Stewart } 3458f8829a4aSRandall Stewart tp1->sent++; 3459f8829a4aSRandall Stewart } 3460f8829a4aSRandall Stewart } 346120083c2eSMichael Tuexen } else if ((tp1->rec.data.doing_fast_retransmit) && 346220083c2eSMichael Tuexen (asoc->sctp_cmt_on_off == 0)) { 3463f8829a4aSRandall Stewart /* 3464f8829a4aSRandall Stewart * For those that have done a FR we must take 3465f8829a4aSRandall Stewart * special consideration if we strike. I.e the 3466f8829a4aSRandall Stewart * biggest_newly_acked must be higher than the 3467f8829a4aSRandall Stewart * sending_seq at the time we did the FR. 3468f8829a4aSRandall Stewart */ 34695e54f665SRandall Stewart if ( 3470f8829a4aSRandall Stewart #ifdef SCTP_FR_TO_ALTERNATE 3471f8829a4aSRandall Stewart /* 3472f8829a4aSRandall Stewart * If FR's go to new networks, then we must only do 3473f8829a4aSRandall Stewart * this for singly homed asoc's. However if the FR's 3474f8829a4aSRandall Stewart * go to the same network (Armando's work) then its 3475f8829a4aSRandall Stewart * ok to FR multiple times. 3476f8829a4aSRandall Stewart */ 34775e54f665SRandall Stewart (asoc->numnets < 2) 3478f8829a4aSRandall Stewart #else 34795e54f665SRandall Stewart (1) 3480f8829a4aSRandall Stewart #endif 34815e54f665SRandall Stewart ) { 34825e54f665SRandall Stewart 348320b07a4dSMichael Tuexen if (SCTP_TSN_GE(biggest_tsn_newly_acked, 3484f8829a4aSRandall Stewart tp1->rec.data.fast_retran_tsn)) { 3485f8829a4aSRandall Stewart /* 3486f8829a4aSRandall Stewart * Strike the TSN, since this ack is 3487f8829a4aSRandall Stewart * beyond where things were when we 3488f8829a4aSRandall Stewart * did a FR. 3489f8829a4aSRandall Stewart */ 3490b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { 3491f8829a4aSRandall Stewart sctp_log_fr(biggest_tsn_newly_acked, 349249656eefSMichael Tuexen tp1->rec.data.tsn, 3493f8829a4aSRandall Stewart tp1->sent, 3494f8829a4aSRandall Stewart SCTP_FR_LOG_STRIKE_CHUNK); 349580fefe0aSRandall Stewart } 34965e54f665SRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND) { 3497f8829a4aSRandall Stewart tp1->sent++; 34985e54f665SRandall Stewart } 3499f8829a4aSRandall Stewart strike_flag = 1; 35007c99d56fSMichael Tuexen if ((asoc->sctp_cmt_on_off > 0) && 350120083c2eSMichael Tuexen SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) { 3502f8829a4aSRandall Stewart /* 3503f8829a4aSRandall Stewart * CMT DAC algorithm: If 3504f8829a4aSRandall Stewart * SACK flag is set to 0, 3505f8829a4aSRandall Stewart * then lowest_newack test 3506f8829a4aSRandall Stewart * will not pass because it 3507f8829a4aSRandall Stewart * would have been set to 3508f8829a4aSRandall Stewart * the cumack earlier. If 3509f8829a4aSRandall Stewart * not already to be rtx'd, 3510f8829a4aSRandall Stewart * If not a mixed sack and 3511f8829a4aSRandall Stewart * if tp1 is not between two 3512f8829a4aSRandall Stewart * sacked TSNs, then mark by 3513c105859eSRandall Stewart * one more. NOTE that we 3514c105859eSRandall Stewart * are marking by one 3515c105859eSRandall Stewart * additional time since the 3516c105859eSRandall Stewart * SACK DAC flag indicates 3517c105859eSRandall Stewart * that two packets have 3518c105859eSRandall Stewart * been received after this 3519c105859eSRandall Stewart * missing TSN. 3520f8829a4aSRandall Stewart */ 35215e54f665SRandall Stewart if ((tp1->sent < SCTP_DATAGRAM_RESEND) && 35225e54f665SRandall Stewart (num_dests_sacked == 1) && 352320b07a4dSMichael Tuexen SCTP_TSN_GT(this_sack_lowest_newack, 352449656eefSMichael Tuexen tp1->rec.data.tsn)) { 3525b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { 3526f8829a4aSRandall Stewart sctp_log_fr(32 + num_dests_sacked, 352749656eefSMichael Tuexen tp1->rec.data.tsn, 3528f8829a4aSRandall Stewart tp1->sent, 3529f8829a4aSRandall Stewart SCTP_FR_LOG_STRIKE_CHUNK); 353080fefe0aSRandall Stewart } 35315e54f665SRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND) { 3532f8829a4aSRandall Stewart tp1->sent++; 35335e54f665SRandall Stewart } 3534f8829a4aSRandall Stewart } 3535f8829a4aSRandall Stewart } 3536f8829a4aSRandall Stewart } 3537f8829a4aSRandall Stewart } 3538f8829a4aSRandall Stewart /* 353942551e99SRandall Stewart * JRI: TODO: remove code for HTNA algo. CMT's SFR 354042551e99SRandall Stewart * algo covers HTNA. 3541f8829a4aSRandall Stewart */ 354249656eefSMichael Tuexen } else if (SCTP_TSN_GT(tp1->rec.data.tsn, 354320b07a4dSMichael Tuexen biggest_tsn_newly_acked)) { 3544f8829a4aSRandall Stewart /* 3545f8829a4aSRandall Stewart * We don't strike these: This is the HTNA 3546f8829a4aSRandall Stewart * algorithm i.e. we don't strike If our TSN is 3547f8829a4aSRandall Stewart * larger than the Highest TSN Newly Acked. 3548f8829a4aSRandall Stewart */ 3549f8829a4aSRandall Stewart ; 3550f8829a4aSRandall Stewart } else { 3551f8829a4aSRandall Stewart /* Strike the TSN */ 3552b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { 3553f8829a4aSRandall Stewart sctp_log_fr(biggest_tsn_newly_acked, 355449656eefSMichael Tuexen tp1->rec.data.tsn, 3555f8829a4aSRandall Stewart tp1->sent, 3556f8829a4aSRandall Stewart SCTP_FR_LOG_STRIKE_CHUNK); 355780fefe0aSRandall Stewart } 35585e54f665SRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND) { 3559f8829a4aSRandall Stewart tp1->sent++; 35605e54f665SRandall Stewart } 35617c99d56fSMichael Tuexen if ((asoc->sctp_cmt_on_off > 0) && 356220083c2eSMichael Tuexen SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) { 3563f8829a4aSRandall Stewart /* 3564f8829a4aSRandall Stewart * CMT DAC algorithm: If SACK flag is set to 3565f8829a4aSRandall Stewart * 0, then lowest_newack test will not pass 3566f8829a4aSRandall Stewart * because it would have been set to the 3567f8829a4aSRandall Stewart * cumack earlier. If not already to be 3568f8829a4aSRandall Stewart * rtx'd, If not a mixed sack and if tp1 is 3569f8829a4aSRandall Stewart * not between two sacked TSNs, then mark by 3570c105859eSRandall Stewart * one more. NOTE that we are marking by one 3571c105859eSRandall Stewart * additional time since the SACK DAC flag 3572c105859eSRandall Stewart * indicates that two packets have been 3573c105859eSRandall Stewart * received after this missing TSN. 3574f8829a4aSRandall Stewart */ 35755e54f665SRandall Stewart if ((tp1->sent < SCTP_DATAGRAM_RESEND) && (num_dests_sacked == 1) && 357649656eefSMichael Tuexen SCTP_TSN_GT(this_sack_lowest_newack, tp1->rec.data.tsn)) { 3577b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { 3578f8829a4aSRandall Stewart sctp_log_fr(48 + num_dests_sacked, 357949656eefSMichael Tuexen tp1->rec.data.tsn, 3580f8829a4aSRandall Stewart tp1->sent, 3581f8829a4aSRandall Stewart SCTP_FR_LOG_STRIKE_CHUNK); 358280fefe0aSRandall Stewart } 3583f8829a4aSRandall Stewart tp1->sent++; 3584f8829a4aSRandall Stewart } 3585f8829a4aSRandall Stewart } 3586f8829a4aSRandall Stewart } 3587f8829a4aSRandall Stewart if (tp1->sent == SCTP_DATAGRAM_RESEND) { 3588f8829a4aSRandall Stewart struct sctp_nets *alt; 3589f8829a4aSRandall Stewart 3590544e35bdSRandall Stewart /* fix counts and things */ 3591544e35bdSRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { 3592544e35bdSRandall Stewart sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_RSND, 3593544e35bdSRandall Stewart (tp1->whoTo ? (tp1->whoTo->flight_size) : 0), 3594544e35bdSRandall Stewart tp1->book_size, 35959a8e3088SMichael Tuexen (uint32_t)(uintptr_t)tp1->whoTo, 359649656eefSMichael Tuexen tp1->rec.data.tsn); 3597544e35bdSRandall Stewart } 3598544e35bdSRandall Stewart if (tp1->whoTo) { 3599544e35bdSRandall Stewart tp1->whoTo->net_ack++; 3600544e35bdSRandall Stewart sctp_flight_size_decrease(tp1); 3601299108c5SRandall Stewart if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) { 3602299108c5SRandall Stewart (*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) (tp1->whoTo, 3603299108c5SRandall Stewart tp1); 3604299108c5SRandall Stewart } 3605544e35bdSRandall Stewart } 3606*0053ed28SMichael Tuexen 3607544e35bdSRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) { 3608544e35bdSRandall Stewart sctp_log_rwnd(SCTP_INCREASE_PEER_RWND, 3609544e35bdSRandall Stewart asoc->peers_rwnd, tp1->send_size, SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)); 3610544e35bdSRandall Stewart } 3611544e35bdSRandall Stewart /* add back to the rwnd */ 3612544e35bdSRandall Stewart asoc->peers_rwnd += (tp1->send_size + SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)); 3613544e35bdSRandall Stewart 3614544e35bdSRandall Stewart /* remove from the total flight */ 3615544e35bdSRandall Stewart sctp_total_flight_decrease(stcb, tp1); 3616544e35bdSRandall Stewart 3617dd973b0eSMichael Tuexen if ((stcb->asoc.prsctp_supported) && 3618475d0674SMichael Tuexen (PR_SCTP_RTX_ENABLED(tp1->flags))) { 3619b7b84c0eSMichael Tuexen /* 3620b7b84c0eSMichael Tuexen * Has it been retransmitted tv_sec times? - 3621b7b84c0eSMichael Tuexen * we store the retran count there. 3622b7b84c0eSMichael Tuexen */ 3623475d0674SMichael Tuexen if (tp1->snd_count > tp1->rec.data.timetodrop.tv_sec) { 3624475d0674SMichael Tuexen /* Yes, so drop it */ 3625475d0674SMichael Tuexen if (tp1->data != NULL) { 36261edc9dbaSMichael Tuexen (void)sctp_release_pr_sctp_chunk(stcb, tp1, 1, 3627475d0674SMichael Tuexen SCTP_SO_NOT_LOCKED); 3628475d0674SMichael Tuexen } 3629475d0674SMichael Tuexen /* Make sure to flag we had a FR */ 363067e8b08bSMichael Tuexen if (tp1->whoTo != NULL) { 3631475d0674SMichael Tuexen tp1->whoTo->net_ack++; 363267e8b08bSMichael Tuexen } 3633475d0674SMichael Tuexen continue; 3634475d0674SMichael Tuexen } 3635475d0674SMichael Tuexen } 3636b7b84c0eSMichael Tuexen /* 3637b7b84c0eSMichael Tuexen * SCTP_PRINTF("OK, we are now ready to FR this 3638b7b84c0eSMichael Tuexen * guy\n"); 3639b7b84c0eSMichael Tuexen */ 3640b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { 364149656eefSMichael Tuexen sctp_log_fr(tp1->rec.data.tsn, tp1->snd_count, 3642f8829a4aSRandall Stewart 0, SCTP_FR_MARKED); 364380fefe0aSRandall Stewart } 3644f8829a4aSRandall Stewart if (strike_flag) { 3645f8829a4aSRandall Stewart /* This is a subsequent FR */ 3646f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_sendmultfastretrans); 3647f8829a4aSRandall Stewart } 36485e54f665SRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 36497c99d56fSMichael Tuexen if (asoc->sctp_cmt_on_off > 0) { 3650f8829a4aSRandall Stewart /* 3651f8829a4aSRandall Stewart * CMT: Using RTX_SSTHRESH policy for CMT. 3652f8829a4aSRandall Stewart * If CMT is being used, then pick dest with 3653f8829a4aSRandall Stewart * largest ssthresh for any retransmission. 3654f8829a4aSRandall Stewart */ 3655f8829a4aSRandall Stewart tp1->no_fr_allowed = 1; 3656f8829a4aSRandall Stewart alt = tp1->whoTo; 36573c503c28SRandall Stewart /* sa_ignore NO_NULL_CHK */ 365820083c2eSMichael Tuexen if (asoc->sctp_cmt_pf > 0) { 3659b7b84c0eSMichael Tuexen /* 3660b7b84c0eSMichael Tuexen * JRS 5/18/07 - If CMT PF is on, 3661b54d3a6cSRandall Stewart * use the PF version of 3662b7b84c0eSMichael Tuexen * find_alt_net() 3663b7b84c0eSMichael Tuexen */ 3664b54d3a6cSRandall Stewart alt = sctp_find_alternate_net(stcb, alt, 2); 3665b54d3a6cSRandall Stewart } else { 3666b7b84c0eSMichael Tuexen /* 3667b7b84c0eSMichael Tuexen * JRS 5/18/07 - If only CMT is on, 3668b54d3a6cSRandall Stewart * use the CMT version of 3669b7b84c0eSMichael Tuexen * find_alt_net() 3670b7b84c0eSMichael Tuexen */ 367152be287eSRandall Stewart /* sa_ignore NO_NULL_CHK */ 3672f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, alt, 1); 3673b54d3a6cSRandall Stewart } 3674ad81507eSRandall Stewart if (alt == NULL) { 3675ad81507eSRandall Stewart alt = tp1->whoTo; 3676ad81507eSRandall Stewart } 3677f8829a4aSRandall Stewart /* 3678f8829a4aSRandall Stewart * CUCv2: If a different dest is picked for 3679f8829a4aSRandall Stewart * the retransmission, then new 3680f8829a4aSRandall Stewart * (rtx-)pseudo_cumack needs to be tracked 3681f8829a4aSRandall Stewart * for orig dest. Let CUCv2 track new (rtx-) 3682f8829a4aSRandall Stewart * pseudo-cumack always. 3683f8829a4aSRandall Stewart */ 3684ad81507eSRandall Stewart if (tp1->whoTo) { 3685f8829a4aSRandall Stewart tp1->whoTo->find_pseudo_cumack = 1; 3686f8829a4aSRandall Stewart tp1->whoTo->find_rtx_pseudo_cumack = 1; 3687ad81507eSRandall Stewart } 3688*0053ed28SMichael Tuexen 3689f8829a4aSRandall Stewart } else { /* CMT is OFF */ 3690f8829a4aSRandall Stewart 3691f8829a4aSRandall Stewart #ifdef SCTP_FR_TO_ALTERNATE 3692f8829a4aSRandall Stewart /* Can we find an alternate? */ 3693f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, tp1->whoTo, 0); 3694f8829a4aSRandall Stewart #else 3695f8829a4aSRandall Stewart /* 3696f8829a4aSRandall Stewart * default behavior is to NOT retransmit 3697f8829a4aSRandall Stewart * FR's to an alternate. Armando Caro's 3698f8829a4aSRandall Stewart * paper details why. 3699f8829a4aSRandall Stewart */ 3700f8829a4aSRandall Stewart alt = tp1->whoTo; 3701f8829a4aSRandall Stewart #endif 3702f8829a4aSRandall Stewart } 3703f8829a4aSRandall Stewart 3704f8829a4aSRandall Stewart tp1->rec.data.doing_fast_retransmit = 1; 3705f8829a4aSRandall Stewart tot_retrans++; 3706f8829a4aSRandall Stewart /* mark the sending seq for possible subsequent FR's */ 3707f8829a4aSRandall Stewart /* 3708cd3fd531SMichael Tuexen * SCTP_PRINTF("Marking TSN for FR new value %x\n", 370949656eefSMichael Tuexen * (uint32_t)tpi->rec.data.tsn); 3710f8829a4aSRandall Stewart */ 3711f8829a4aSRandall Stewart if (TAILQ_EMPTY(&asoc->send_queue)) { 3712f8829a4aSRandall Stewart /* 3713f8829a4aSRandall Stewart * If the queue of send is empty then its 3714f8829a4aSRandall Stewart * the next sequence number that will be 3715f8829a4aSRandall Stewart * assigned so we subtract one from this to 3716f8829a4aSRandall Stewart * get the one we last sent. 3717f8829a4aSRandall Stewart */ 3718f8829a4aSRandall Stewart tp1->rec.data.fast_retran_tsn = sending_seq; 3719f8829a4aSRandall Stewart } else { 3720f8829a4aSRandall Stewart /* 3721f8829a4aSRandall Stewart * If there are chunks on the send queue 3722f8829a4aSRandall Stewart * (unsent data that has made it from the 3723f8829a4aSRandall Stewart * stream queues but not out the door, we 3724f8829a4aSRandall Stewart * take the first one (which will have the 3725f8829a4aSRandall Stewart * lowest TSN) and subtract one to get the 3726f8829a4aSRandall Stewart * one we last sent. 3727f8829a4aSRandall Stewart */ 3728f8829a4aSRandall Stewart struct sctp_tmit_chunk *ttt; 3729f8829a4aSRandall Stewart 3730f8829a4aSRandall Stewart ttt = TAILQ_FIRST(&asoc->send_queue); 3731f8829a4aSRandall Stewart tp1->rec.data.fast_retran_tsn = 373249656eefSMichael Tuexen ttt->rec.data.tsn; 3733f8829a4aSRandall Stewart } 3734f8829a4aSRandall Stewart 3735f8829a4aSRandall Stewart if (tp1->do_rtt) { 3736f8829a4aSRandall Stewart /* 3737f8829a4aSRandall Stewart * this guy had a RTO calculation pending on 3738f8829a4aSRandall Stewart * it, cancel it 3739f8829a4aSRandall Stewart */ 374060990c0cSMichael Tuexen if ((tp1->whoTo != NULL) && 374160990c0cSMichael Tuexen (tp1->whoTo->rto_needed == 0)) { 3742f79aab18SRandall Stewart tp1->whoTo->rto_needed = 1; 3743f79aab18SRandall Stewart } 3744f8829a4aSRandall Stewart tp1->do_rtt = 0; 3745f8829a4aSRandall Stewart } 3746f8829a4aSRandall Stewart if (alt != tp1->whoTo) { 3747f8829a4aSRandall Stewart /* yes, there is an alternate. */ 3748f8829a4aSRandall Stewart sctp_free_remote_addr(tp1->whoTo); 37493c503c28SRandall Stewart /* sa_ignore FREED_MEMORY */ 3750f8829a4aSRandall Stewart tp1->whoTo = alt; 3751f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 3752f8829a4aSRandall Stewart } 3753f8829a4aSRandall Stewart } 37544a9ef3f8SMichael Tuexen } 3755f8829a4aSRandall Stewart } 3756f8829a4aSRandall Stewart 3757f8829a4aSRandall Stewart struct sctp_tmit_chunk * 3758f8829a4aSRandall Stewart sctp_try_advance_peer_ack_point(struct sctp_tcb *stcb, 3759f8829a4aSRandall Stewart struct sctp_association *asoc) 3760f8829a4aSRandall Stewart { 3761f8829a4aSRandall Stewart struct sctp_tmit_chunk *tp1, *tp2, *a_adv = NULL; 3762f8829a4aSRandall Stewart struct timeval now; 3763f8829a4aSRandall Stewart int now_filled = 0; 3764f8829a4aSRandall Stewart 3765dd973b0eSMichael Tuexen if (asoc->prsctp_supported == 0) { 3766f8829a4aSRandall Stewart return (NULL); 3767f8829a4aSRandall Stewart } 37684a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(tp1, &asoc->sent_queue, sctp_next, tp2) { 3769f8829a4aSRandall Stewart if (tp1->sent != SCTP_FORWARD_TSN_SKIP && 377098f2956cSMichael Tuexen tp1->sent != SCTP_DATAGRAM_RESEND && 3771325c8c46SMichael Tuexen tp1->sent != SCTP_DATAGRAM_NR_ACKED) { 3772f8829a4aSRandall Stewart /* no chance to advance, out of here */ 3773f8829a4aSRandall Stewart break; 3774f8829a4aSRandall Stewart } 37750c0982b8SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) { 37762a498584SMichael Tuexen if ((tp1->sent == SCTP_FORWARD_TSN_SKIP) || 3777325c8c46SMichael Tuexen (tp1->sent == SCTP_DATAGRAM_NR_ACKED)) { 37780c0982b8SRandall Stewart sctp_misc_ints(SCTP_FWD_TSN_CHECK, 37790c0982b8SRandall Stewart asoc->advanced_peer_ack_point, 378049656eefSMichael Tuexen tp1->rec.data.tsn, 0, 0); 37810c0982b8SRandall Stewart } 37820c0982b8SRandall Stewart } 3783f8829a4aSRandall Stewart if (!PR_SCTP_ENABLED(tp1->flags)) { 3784f8829a4aSRandall Stewart /* 3785f8829a4aSRandall Stewart * We can't fwd-tsn past any that are reliable aka 3786f8829a4aSRandall Stewart * retransmitted until the asoc fails. 3787f8829a4aSRandall Stewart */ 3788f8829a4aSRandall Stewart break; 3789f8829a4aSRandall Stewart } 3790f8829a4aSRandall Stewart if (!now_filled) { 37916e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&now); 3792f8829a4aSRandall Stewart now_filled = 1; 3793f8829a4aSRandall Stewart } 3794f8829a4aSRandall Stewart /* 3795f8829a4aSRandall Stewart * now we got a chunk which is marked for another 3796f8829a4aSRandall Stewart * retransmission to a PR-stream but has run out its chances 3797f8829a4aSRandall Stewart * already maybe OR has been marked to skip now. Can we skip 3798f8829a4aSRandall Stewart * it if its a resend? 3799f8829a4aSRandall Stewart */ 3800f8829a4aSRandall Stewart if (tp1->sent == SCTP_DATAGRAM_RESEND && 3801f8829a4aSRandall Stewart (PR_SCTP_TTL_ENABLED(tp1->flags))) { 3802f8829a4aSRandall Stewart /* 3803f8829a4aSRandall Stewart * Now is this one marked for resend and its time is 3804f8829a4aSRandall Stewart * now up? 3805f8829a4aSRandall Stewart */ 3806f8829a4aSRandall Stewart if (timevalcmp(&now, &tp1->rec.data.timetodrop, >)) { 3807f8829a4aSRandall Stewart /* Yes so drop it */ 3808f8829a4aSRandall Stewart if (tp1->data) { 3809ad81507eSRandall Stewart (void)sctp_release_pr_sctp_chunk(stcb, tp1, 38101edc9dbaSMichael Tuexen 1, SCTP_SO_NOT_LOCKED); 3811f8829a4aSRandall Stewart } 3812f8829a4aSRandall Stewart } else { 3813f8829a4aSRandall Stewart /* 3814f8829a4aSRandall Stewart * No, we are done when hit one for resend 3815f8829a4aSRandall Stewart * whos time as not expired. 3816f8829a4aSRandall Stewart */ 3817f8829a4aSRandall Stewart break; 3818f8829a4aSRandall Stewart } 3819f8829a4aSRandall Stewart } 3820f8829a4aSRandall Stewart /* 3821f8829a4aSRandall Stewart * Ok now if this chunk is marked to drop it we can clean up 3822f8829a4aSRandall Stewart * the chunk, advance our peer ack point and we can check 3823f8829a4aSRandall Stewart * the next chunk. 3824f8829a4aSRandall Stewart */ 382598f2956cSMichael Tuexen if ((tp1->sent == SCTP_FORWARD_TSN_SKIP) || 3826325c8c46SMichael Tuexen (tp1->sent == SCTP_DATAGRAM_NR_ACKED)) { 3827f8829a4aSRandall Stewart /* advance PeerAckPoint goes forward */ 382849656eefSMichael Tuexen if (SCTP_TSN_GT(tp1->rec.data.tsn, asoc->advanced_peer_ack_point)) { 382949656eefSMichael Tuexen asoc->advanced_peer_ack_point = tp1->rec.data.tsn; 3830f8829a4aSRandall Stewart a_adv = tp1; 383149656eefSMichael Tuexen } else if (tp1->rec.data.tsn == asoc->advanced_peer_ack_point) { 38320c0982b8SRandall Stewart /* No update but we do save the chk */ 38330c0982b8SRandall Stewart a_adv = tp1; 38340c0982b8SRandall Stewart } 3835f8829a4aSRandall Stewart } else { 3836f8829a4aSRandall Stewart /* 3837f8829a4aSRandall Stewart * If it is still in RESEND we can advance no 3838f8829a4aSRandall Stewart * further 3839f8829a4aSRandall Stewart */ 3840f8829a4aSRandall Stewart break; 3841f8829a4aSRandall Stewart } 3842f8829a4aSRandall Stewart } 3843f8829a4aSRandall Stewart return (a_adv); 3844f8829a4aSRandall Stewart } 3845f8829a4aSRandall Stewart 38460c0982b8SRandall Stewart static int 3847c105859eSRandall Stewart sctp_fs_audit(struct sctp_association *asoc) 3848bff64a4dSRandall Stewart { 3849bff64a4dSRandall Stewart struct sctp_tmit_chunk *chk; 3850afd67482SMichael Tuexen int inflight = 0, resend = 0, inbetween = 0, acked = 0, above = 0; 3851548f47a8SMichael Tuexen int ret; 3852548f47a8SMichael Tuexen #ifndef INVARIANTS 3853548f47a8SMichael Tuexen int entry_flight, entry_cnt; 3854548f47a8SMichael Tuexen #endif 3855548f47a8SMichael Tuexen 3856548f47a8SMichael Tuexen ret = 0; 3857548f47a8SMichael Tuexen #ifndef INVARIANTS 38580c0982b8SRandall Stewart entry_flight = asoc->total_flight; 38590c0982b8SRandall Stewart entry_cnt = asoc->total_flight_count; 3860548f47a8SMichael Tuexen #endif 38610c0982b8SRandall Stewart if (asoc->pr_sctp_cnt >= asoc->sent_queue_cnt) 38620c0982b8SRandall Stewart return (0); 3863bff64a4dSRandall Stewart 3864bff64a4dSRandall Stewart TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { 3865bff64a4dSRandall Stewart if (chk->sent < SCTP_DATAGRAM_RESEND) { 3866cd3fd531SMichael Tuexen SCTP_PRINTF("Chk TSN: %u size: %d inflight cnt: %d\n", 386749656eefSMichael Tuexen chk->rec.data.tsn, 38680c0982b8SRandall Stewart chk->send_size, 3869cd3fd531SMichael Tuexen chk->snd_count); 3870bff64a4dSRandall Stewart inflight++; 3871bff64a4dSRandall Stewart } else if (chk->sent == SCTP_DATAGRAM_RESEND) { 3872bff64a4dSRandall Stewart resend++; 3873bff64a4dSRandall Stewart } else if (chk->sent < SCTP_DATAGRAM_ACKED) { 3874bff64a4dSRandall Stewart inbetween++; 3875bff64a4dSRandall Stewart } else if (chk->sent > SCTP_DATAGRAM_ACKED) { 3876bff64a4dSRandall Stewart above++; 3877bff64a4dSRandall Stewart } else { 3878bff64a4dSRandall Stewart acked++; 3879bff64a4dSRandall Stewart } 3880bff64a4dSRandall Stewart } 3881f1f73e57SRandall Stewart 3882c105859eSRandall Stewart if ((inflight > 0) || (inbetween > 0)) { 3883f1f73e57SRandall Stewart #ifdef INVARIANTS 3884c105859eSRandall Stewart panic("Flight size-express incorrect? \n"); 3885f1f73e57SRandall Stewart #else 3886cd3fd531SMichael Tuexen SCTP_PRINTF("asoc->total_flight: %d cnt: %d\n", 38870c0982b8SRandall Stewart entry_flight, entry_cnt); 38880c0982b8SRandall Stewart 38890c0982b8SRandall Stewart SCTP_PRINTF("Flight size-express incorrect F: %d I: %d R: %d Ab: %d ACK: %d\n", 38900c0982b8SRandall Stewart inflight, inbetween, resend, above, acked); 38910c0982b8SRandall Stewart ret = 1; 3892f1f73e57SRandall Stewart #endif 3893bff64a4dSRandall Stewart } 38940c0982b8SRandall Stewart return (ret); 3895c105859eSRandall Stewart } 3896c105859eSRandall Stewart 3897c105859eSRandall Stewart 3898c105859eSRandall Stewart static void 3899c105859eSRandall Stewart sctp_window_probe_recovery(struct sctp_tcb *stcb, 3900c105859eSRandall Stewart struct sctp_association *asoc, 3901c105859eSRandall Stewart struct sctp_tmit_chunk *tp1) 3902c105859eSRandall Stewart { 3903dfb11ef8SRandall Stewart tp1->window_probe = 0; 39045171328bSRandall Stewart if ((tp1->sent >= SCTP_DATAGRAM_ACKED) || (tp1->data == NULL)) { 3905dfb11ef8SRandall Stewart /* TSN's skipped we do NOT move back. */ 3906dfb11ef8SRandall Stewart sctp_misc_ints(SCTP_FLIGHT_LOG_DWN_WP_FWD, 39078427b3fdSMichael Tuexen tp1->whoTo ? tp1->whoTo->flight_size : 0, 3908dfb11ef8SRandall Stewart tp1->book_size, 39099a8e3088SMichael Tuexen (uint32_t)(uintptr_t)tp1->whoTo, 391049656eefSMichael Tuexen tp1->rec.data.tsn); 3911dfb11ef8SRandall Stewart return; 3912dfb11ef8SRandall Stewart } 39135171328bSRandall Stewart /* First setup this by shrinking flight */ 3914299108c5SRandall Stewart if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) { 3915299108c5SRandall Stewart (*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) (tp1->whoTo, 3916299108c5SRandall Stewart tp1); 3917299108c5SRandall Stewart } 39185171328bSRandall Stewart sctp_flight_size_decrease(tp1); 39195171328bSRandall Stewart sctp_total_flight_decrease(stcb, tp1); 39205171328bSRandall Stewart /* Now mark for resend */ 39215171328bSRandall Stewart tp1->sent = SCTP_DATAGRAM_RESEND; 3922791437b5SRandall Stewart sctp_ucount_incr(asoc->sent_queue_retran_cnt); 3923791437b5SRandall Stewart 3924b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { 3925c105859eSRandall Stewart sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_WP, 3926c105859eSRandall Stewart tp1->whoTo->flight_size, 3927c105859eSRandall Stewart tp1->book_size, 39289a8e3088SMichael Tuexen (uint32_t)(uintptr_t)tp1->whoTo, 392949656eefSMichael Tuexen tp1->rec.data.tsn); 393080fefe0aSRandall Stewart } 3931c105859eSRandall Stewart } 3932c105859eSRandall Stewart 3933f8829a4aSRandall Stewart void 3934f8829a4aSRandall Stewart sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, 3935899288aeSRandall Stewart uint32_t rwnd, int *abort_now, int ecne_seen) 3936f8829a4aSRandall Stewart { 3937f8829a4aSRandall Stewart struct sctp_nets *net; 3938f8829a4aSRandall Stewart struct sctp_association *asoc; 3939f8829a4aSRandall Stewart struct sctp_tmit_chunk *tp1, *tp2; 39405e54f665SRandall Stewart uint32_t old_rwnd; 39415e54f665SRandall Stewart int win_probe_recovery = 0; 3942c105859eSRandall Stewart int win_probe_recovered = 0; 3943d06c82f1SRandall Stewart int j, done_once = 0; 3944f79aab18SRandall Stewart int rto_ok = 1; 3945fd60718dSMichael Tuexen uint32_t send_s; 3946f8829a4aSRandall Stewart 3947b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_SACK_ARRIVALS_ENABLE) { 3948d06c82f1SRandall Stewart sctp_misc_ints(SCTP_SACK_LOG_EXPRESS, cumack, 3949d06c82f1SRandall Stewart rwnd, stcb->asoc.last_acked_seq, stcb->asoc.peers_rwnd); 395080fefe0aSRandall Stewart } 3951f8829a4aSRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 395218e198d3SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS 395318e198d3SRandall Stewart stcb->asoc.cumack_log[stcb->asoc.cumack_log_at] = cumack; 395418e198d3SRandall Stewart stcb->asoc.cumack_log_at++; 395518e198d3SRandall Stewart if (stcb->asoc.cumack_log_at > SCTP_TSN_LOG_SIZE) { 395618e198d3SRandall Stewart stcb->asoc.cumack_log_at = 0; 395718e198d3SRandall Stewart } 395818e198d3SRandall Stewart #endif 3959f8829a4aSRandall Stewart asoc = &stcb->asoc; 3960d06c82f1SRandall Stewart old_rwnd = asoc->peers_rwnd; 396120b07a4dSMichael Tuexen if (SCTP_TSN_GT(asoc->last_acked_seq, cumack)) { 39625e54f665SRandall Stewart /* old ack */ 39635e54f665SRandall Stewart return; 3964d06c82f1SRandall Stewart } else if (asoc->last_acked_seq == cumack) { 3965d06c82f1SRandall Stewart /* Window update sack */ 3966d06c82f1SRandall Stewart asoc->peers_rwnd = sctp_sbspace_sub(rwnd, 396744fbe462SRandall Stewart (uint32_t)(asoc->total_flight + (asoc->total_flight_count * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)))); 3968d06c82f1SRandall Stewart if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) { 3969d06c82f1SRandall Stewart /* SWS sender side engages */ 3970d06c82f1SRandall Stewart asoc->peers_rwnd = 0; 3971d06c82f1SRandall Stewart } 3972d06c82f1SRandall Stewart if (asoc->peers_rwnd > old_rwnd) { 3973d06c82f1SRandall Stewart goto again; 3974d06c82f1SRandall Stewart } 3975d06c82f1SRandall Stewart return; 39765e54f665SRandall Stewart } 3977*0053ed28SMichael Tuexen 3978f8829a4aSRandall Stewart /* First setup for CC stuff */ 3979f8829a4aSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 3980a21779f0SRandall Stewart if (SCTP_TSN_GT(cumack, net->cwr_window_tsn)) { 3981a21779f0SRandall Stewart /* Drag along the window_tsn for cwr's */ 3982a21779f0SRandall Stewart net->cwr_window_tsn = cumack; 3983a21779f0SRandall Stewart } 3984f8829a4aSRandall Stewart net->prev_cwnd = net->cwnd; 3985f8829a4aSRandall Stewart net->net_ack = 0; 3986f8829a4aSRandall Stewart net->net_ack2 = 0; 3987132dea7dSRandall Stewart 3988132dea7dSRandall Stewart /* 3989132dea7dSRandall Stewart * CMT: Reset CUC and Fast recovery algo variables before 3990132dea7dSRandall Stewart * SACK processing 3991132dea7dSRandall Stewart */ 3992132dea7dSRandall Stewart net->new_pseudo_cumack = 0; 3993132dea7dSRandall Stewart net->will_exit_fast_recovery = 0; 3994299108c5SRandall Stewart if (stcb->asoc.cc_functions.sctp_cwnd_prepare_net_for_sack) { 3995299108c5SRandall Stewart (*stcb->asoc.cc_functions.sctp_cwnd_prepare_net_for_sack) (stcb, net); 3996299108c5SRandall Stewart } 3997f8829a4aSRandall Stewart } 3998c105859eSRandall Stewart if (!TAILQ_EMPTY(&asoc->sent_queue)) { 3999c105859eSRandall Stewart tp1 = TAILQ_LAST(&asoc->sent_queue, 4000c105859eSRandall Stewart sctpchunk_listhead); 400149656eefSMichael Tuexen send_s = tp1->rec.data.tsn + 1; 4002139bc87fSRandall Stewart } else { 4003c105859eSRandall Stewart send_s = asoc->sending_seq; 4004139bc87fSRandall Stewart } 400520b07a4dSMichael Tuexen if (SCTP_TSN_GE(cumack, send_s)) { 4006ff1ffd74SMichael Tuexen struct mbuf *op_err; 4007ff1ffd74SMichael Tuexen char msg[SCTP_DIAG_INFO_LEN]; 4008139bc87fSRandall Stewart 4009139bc87fSRandall Stewart *abort_now = 1; 4010139bc87fSRandall Stewart /* XXX */ 401155f8a4bbSMichael Tuexen snprintf(msg, sizeof(msg), "Cum ack %8.8x greater or equal than TSN %8.8x", 4012ff1ffd74SMichael Tuexen cumack, send_s); 4013ff1ffd74SMichael Tuexen op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); 401444249214SRandall Stewart stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_21; 4015ff1ffd74SMichael Tuexen sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); 4016139bc87fSRandall Stewart return; 4017139bc87fSRandall Stewart } 4018f8829a4aSRandall Stewart asoc->this_sack_highest_gap = cumack; 4019b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { 4020c4739e2fSRandall Stewart sctp_misc_ints(SCTP_THRESHOLD_CLEAR, 4021c4739e2fSRandall Stewart stcb->asoc.overall_error_count, 4022c4739e2fSRandall Stewart 0, 4023c4739e2fSRandall Stewart SCTP_FROM_SCTP_INDATA, 4024c4739e2fSRandall Stewart __LINE__); 4025c4739e2fSRandall Stewart } 4026f8829a4aSRandall Stewart stcb->asoc.overall_error_count = 0; 402720b07a4dSMichael Tuexen if (SCTP_TSN_GT(cumack, asoc->last_acked_seq)) { 4028f8829a4aSRandall Stewart /* process the new consecutive TSN first */ 40294a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(tp1, &asoc->sent_queue, sctp_next, tp2) { 403049656eefSMichael Tuexen if (SCTP_TSN_GE(cumack, tp1->rec.data.tsn)) { 403118e198d3SRandall Stewart if (tp1->sent == SCTP_DATAGRAM_UNSENT) { 4032cd3fd531SMichael Tuexen SCTP_PRINTF("Warning, an unsent is now acked?\n"); 403318e198d3SRandall Stewart } 4034f8829a4aSRandall Stewart if (tp1->sent < SCTP_DATAGRAM_ACKED) { 4035f8829a4aSRandall Stewart /* 403618e198d3SRandall Stewart * If it is less than ACKED, it is 403718e198d3SRandall Stewart * now no-longer in flight. Higher 403818e198d3SRandall Stewart * values may occur during marking 4039f8829a4aSRandall Stewart */ 4040c105859eSRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND) { 4041b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { 4042c105859eSRandall Stewart sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_CA, 4043a5d547adSRandall Stewart tp1->whoTo->flight_size, 4044a5d547adSRandall Stewart tp1->book_size, 40459a8e3088SMichael Tuexen (uint32_t)(uintptr_t)tp1->whoTo, 404649656eefSMichael Tuexen tp1->rec.data.tsn); 404780fefe0aSRandall Stewart } 4048c105859eSRandall Stewart sctp_flight_size_decrease(tp1); 4049299108c5SRandall Stewart if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) { 4050299108c5SRandall Stewart (*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) (tp1->whoTo, 4051299108c5SRandall Stewart tp1); 4052299108c5SRandall Stewart } 405304ee05e8SRandall Stewart /* sa_ignore NO_NULL_CHK */ 4054c105859eSRandall Stewart sctp_total_flight_decrease(stcb, tp1); 4055f8829a4aSRandall Stewart } 4056f8829a4aSRandall Stewart tp1->whoTo->net_ack += tp1->send_size; 4057f8829a4aSRandall Stewart if (tp1->snd_count < 2) { 4058f8829a4aSRandall Stewart /* 405918e198d3SRandall Stewart * True non-retransmited 4060f8829a4aSRandall Stewart * chunk 4061f8829a4aSRandall Stewart */ 4062f8829a4aSRandall Stewart tp1->whoTo->net_ack2 += 4063f8829a4aSRandall Stewart tp1->send_size; 4064f8829a4aSRandall Stewart 4065f8829a4aSRandall Stewart /* update RTO too? */ 406662c1ff9cSRandall Stewart if (tp1->do_rtt) { 4067f79aab18SRandall Stewart if (rto_ok) { 4068f8829a4aSRandall Stewart tp1->whoTo->RTO = 406904ee05e8SRandall Stewart /* 407004ee05e8SRandall Stewart * sa_ignore 40715b495f17SMichael Tuexen * NO_NULL_CHK 407204ee05e8SRandall Stewart */ 4073f8829a4aSRandall Stewart sctp_calculate_rto(stcb, 4074f8829a4aSRandall Stewart asoc, tp1->whoTo, 407518e198d3SRandall Stewart &tp1->sent_rcv_time, 4076f79aab18SRandall Stewart SCTP_RTT_FROM_DATA); 4077f79aab18SRandall Stewart rto_ok = 0; 4078f79aab18SRandall Stewart } 4079f79aab18SRandall Stewart if (tp1->whoTo->rto_needed == 0) { 4080f79aab18SRandall Stewart tp1->whoTo->rto_needed = 1; 4081f79aab18SRandall Stewart } 4082f8829a4aSRandall Stewart tp1->do_rtt = 0; 4083f8829a4aSRandall Stewart } 4084f8829a4aSRandall Stewart } 4085132dea7dSRandall Stewart /* 408618e198d3SRandall Stewart * CMT: CUCv2 algorithm. From the 408718e198d3SRandall Stewart * cumack'd TSNs, for each TSN being 408818e198d3SRandall Stewart * acked for the first time, set the 408918e198d3SRandall Stewart * following variables for the 409018e198d3SRandall Stewart * corresp destination. 409118e198d3SRandall Stewart * new_pseudo_cumack will trigger a 409218e198d3SRandall Stewart * cwnd update. 409318e198d3SRandall Stewart * find_(rtx_)pseudo_cumack will 409418e198d3SRandall Stewart * trigger search for the next 409518e198d3SRandall Stewart * expected (rtx-)pseudo-cumack. 4096132dea7dSRandall Stewart */ 4097132dea7dSRandall Stewart tp1->whoTo->new_pseudo_cumack = 1; 4098132dea7dSRandall Stewart tp1->whoTo->find_pseudo_cumack = 1; 4099132dea7dSRandall Stewart tp1->whoTo->find_rtx_pseudo_cumack = 1; 4100132dea7dSRandall Stewart 4101b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 410204ee05e8SRandall Stewart /* sa_ignore NO_NULL_CHK */ 410349656eefSMichael Tuexen sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.tsn, SCTP_CWND_LOG_FROM_SACK); 410480fefe0aSRandall Stewart } 4105f8829a4aSRandall Stewart } 4106f8829a4aSRandall Stewart if (tp1->sent == SCTP_DATAGRAM_RESEND) { 4107f8829a4aSRandall Stewart sctp_ucount_decr(asoc->sent_queue_retran_cnt); 4108f8829a4aSRandall Stewart } 410942551e99SRandall Stewart if (tp1->rec.data.chunk_was_revoked) { 411042551e99SRandall Stewart /* deflate the cwnd */ 411142551e99SRandall Stewart tp1->whoTo->cwnd -= tp1->book_size; 411242551e99SRandall Stewart tp1->rec.data.chunk_was_revoked = 0; 411342551e99SRandall Stewart } 4114325c8c46SMichael Tuexen if (tp1->sent != SCTP_DATAGRAM_NR_ACKED) { 411549656eefSMichael Tuexen if (asoc->strmout[tp1->rec.data.sid].chunks_on_queues > 0) { 411649656eefSMichael Tuexen asoc->strmout[tp1->rec.data.sid].chunks_on_queues--; 4117a7ad6026SMichael Tuexen #ifdef INVARIANTS 4118a7ad6026SMichael Tuexen } else { 411949656eefSMichael Tuexen panic("No chunks on the queues for sid %u.", tp1->rec.data.sid); 4120a7ad6026SMichael Tuexen #endif 4121a7ad6026SMichael Tuexen } 4122a7ad6026SMichael Tuexen } 412349656eefSMichael Tuexen if ((asoc->strmout[tp1->rec.data.sid].chunks_on_queues == 0) && 412449656eefSMichael Tuexen (asoc->strmout[tp1->rec.data.sid].state == SCTP_STREAM_RESET_PENDING) && 412549656eefSMichael Tuexen TAILQ_EMPTY(&asoc->strmout[tp1->rec.data.sid].outqueue)) { 4126d96bef9cSMichael Tuexen asoc->trigger_reset = 1; 4127d96bef9cSMichael Tuexen } 4128f8829a4aSRandall Stewart TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next); 4129f8829a4aSRandall Stewart if (tp1->data) { 413004ee05e8SRandall Stewart /* sa_ignore NO_NULL_CHK */ 4131f8829a4aSRandall Stewart sctp_free_bufspace(stcb, asoc, tp1, 1); 4132f8829a4aSRandall Stewart sctp_m_freem(tp1->data); 41334a9ef3f8SMichael Tuexen tp1->data = NULL; 4134f8829a4aSRandall Stewart } 4135b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) { 4136f8829a4aSRandall Stewart sctp_log_sack(asoc->last_acked_seq, 4137f8829a4aSRandall Stewart cumack, 413849656eefSMichael Tuexen tp1->rec.data.tsn, 4139f8829a4aSRandall Stewart 0, 4140f8829a4aSRandall Stewart 0, 4141f8829a4aSRandall Stewart SCTP_LOG_FREE_SENT); 414280fefe0aSRandall Stewart } 4143f8829a4aSRandall Stewart asoc->sent_queue_cnt--; 4144689e6a5fSMichael Tuexen sctp_free_a_chunk(stcb, tp1, SCTP_SO_NOT_LOCKED); 414518e198d3SRandall Stewart } else { 414618e198d3SRandall Stewart break; 4147f8829a4aSRandall Stewart } 41485e54f665SRandall Stewart } 414918e198d3SRandall Stewart 415018e198d3SRandall Stewart } 415104ee05e8SRandall Stewart /* sa_ignore NO_NULL_CHK */ 4152f8829a4aSRandall Stewart if (stcb->sctp_socket) { 4153ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4154ceaad40aSRandall Stewart struct socket *so; 4155ceaad40aSRandall Stewart 4156ceaad40aSRandall Stewart #endif 4157f8829a4aSRandall Stewart SOCKBUF_LOCK(&stcb->sctp_socket->so_snd); 4158b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_WAKE_LOGGING_ENABLE) { 415904ee05e8SRandall Stewart /* sa_ignore NO_NULL_CHK */ 41607215cc1bSMichael Tuexen sctp_wakeup_log(stcb, 1, SCTP_WAKESND_FROM_SACK); 416180fefe0aSRandall Stewart } 4162ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4163ceaad40aSRandall Stewart so = SCTP_INP_SO(stcb->sctp_ep); 4164ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 4165ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 4166ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 4167ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 4168ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 4169ceaad40aSRandall Stewart if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { 4170ceaad40aSRandall Stewart /* assoc was freed while we were unlocked */ 4171ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 4172ceaad40aSRandall Stewart return; 4173ceaad40aSRandall Stewart } 4174ceaad40aSRandall Stewart #endif 4175f8829a4aSRandall Stewart sctp_sowwakeup_locked(stcb->sctp_ep, stcb->sctp_socket); 4176ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4177ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 4178ceaad40aSRandall Stewart #endif 4179f8829a4aSRandall Stewart } else { 4180b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_WAKE_LOGGING_ENABLE) { 41817215cc1bSMichael Tuexen sctp_wakeup_log(stcb, 1, SCTP_NOWAKE_FROM_SACK); 418280fefe0aSRandall Stewart } 4183f8829a4aSRandall Stewart } 4184f8829a4aSRandall Stewart 4185b54d3a6cSRandall Stewart /* JRS - Use the congestion control given in the CC module */ 4186ca85e948SMichael Tuexen if ((asoc->last_acked_seq != cumack) && (ecne_seen == 0)) { 4187ca85e948SMichael Tuexen TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 4188ca85e948SMichael Tuexen if (net->net_ack2 > 0) { 4189ca85e948SMichael Tuexen /* 4190ca85e948SMichael Tuexen * Karn's rule applies to clearing error 4191ca85e948SMichael Tuexen * count, this is optional. 4192ca85e948SMichael Tuexen */ 4193ca85e948SMichael Tuexen net->error_count = 0; 4194ca85e948SMichael Tuexen if (!(net->dest_state & SCTP_ADDR_REACHABLE)) { 4195ca85e948SMichael Tuexen /* addr came good */ 4196ca85e948SMichael Tuexen net->dest_state |= SCTP_ADDR_REACHABLE; 4197ca85e948SMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 41984b1f78e1SMichael Tuexen 0, (void *)net, SCTP_SO_NOT_LOCKED); 4199ca85e948SMichael Tuexen } 4200ca85e948SMichael Tuexen if (net == stcb->asoc.primary_destination) { 4201ca85e948SMichael Tuexen if (stcb->asoc.alternate) { 4202b7b84c0eSMichael Tuexen /* 4203b7b84c0eSMichael Tuexen * release the alternate, 4204b7b84c0eSMichael Tuexen * primary is good 4205b7b84c0eSMichael Tuexen */ 4206ca85e948SMichael Tuexen sctp_free_remote_addr(stcb->asoc.alternate); 4207ca85e948SMichael Tuexen stcb->asoc.alternate = NULL; 4208ca85e948SMichael Tuexen } 4209ca85e948SMichael Tuexen } 4210ca85e948SMichael Tuexen if (net->dest_state & SCTP_ADDR_PF) { 4211ca85e948SMichael Tuexen net->dest_state &= ~SCTP_ADDR_PF; 4212b7d130beSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, 4213b7d130beSMichael Tuexen stcb->sctp_ep, stcb, net, 421444249214SRandall Stewart SCTP_FROM_SCTP_INDATA + SCTP_LOC_22); 4215ca85e948SMichael Tuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); 4216ca85e948SMichael Tuexen asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net); 4217ca85e948SMichael Tuexen /* Done with this net */ 4218ca85e948SMichael Tuexen net->net_ack = 0; 4219ca85e948SMichael Tuexen } 4220ca85e948SMichael Tuexen /* restore any doubled timers */ 4221ca85e948SMichael Tuexen net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv; 4222ca85e948SMichael Tuexen if (net->RTO < stcb->asoc.minrto) { 4223ca85e948SMichael Tuexen net->RTO = stcb->asoc.minrto; 4224ca85e948SMichael Tuexen } 4225ca85e948SMichael Tuexen if (net->RTO > stcb->asoc.maxrto) { 4226ca85e948SMichael Tuexen net->RTO = stcb->asoc.maxrto; 4227ca85e948SMichael Tuexen } 4228ca85e948SMichael Tuexen } 4229ca85e948SMichael Tuexen } 4230b54d3a6cSRandall Stewart asoc->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, 1, 0, 0); 4231ca85e948SMichael Tuexen } 4232f8829a4aSRandall Stewart asoc->last_acked_seq = cumack; 42335e54f665SRandall Stewart 4234f8829a4aSRandall Stewart if (TAILQ_EMPTY(&asoc->sent_queue)) { 4235f8829a4aSRandall Stewart /* nothing left in-flight */ 4236f8829a4aSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 4237f8829a4aSRandall Stewart net->flight_size = 0; 4238f8829a4aSRandall Stewart net->partial_bytes_acked = 0; 4239f8829a4aSRandall Stewart } 4240f8829a4aSRandall Stewart asoc->total_flight = 0; 4241f8829a4aSRandall Stewart asoc->total_flight_count = 0; 4242f8829a4aSRandall Stewart } 4243*0053ed28SMichael Tuexen 4244f8829a4aSRandall Stewart /* RWND update */ 4245f8829a4aSRandall Stewart asoc->peers_rwnd = sctp_sbspace_sub(rwnd, 424644fbe462SRandall Stewart (uint32_t)(asoc->total_flight + (asoc->total_flight_count * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)))); 4247f8829a4aSRandall Stewart if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) { 4248f8829a4aSRandall Stewart /* SWS sender side engages */ 4249f8829a4aSRandall Stewart asoc->peers_rwnd = 0; 4250f8829a4aSRandall Stewart } 42515e54f665SRandall Stewart if (asoc->peers_rwnd > old_rwnd) { 42525e54f665SRandall Stewart win_probe_recovery = 1; 42535e54f665SRandall Stewart } 4254f8829a4aSRandall Stewart /* Now assure a timer where data is queued at */ 4255a5d547adSRandall Stewart again: 4256a5d547adSRandall Stewart j = 0; 4257f8829a4aSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 42585e54f665SRandall Stewart if (win_probe_recovery && (net->window_probe)) { 4259c105859eSRandall Stewart win_probe_recovered = 1; 42605e54f665SRandall Stewart /* 42615e54f665SRandall Stewart * Find first chunk that was used with window probe 42625e54f665SRandall Stewart * and clear the sent 42635e54f665SRandall Stewart */ 42643c503c28SRandall Stewart /* sa_ignore FREED_MEMORY */ 42655e54f665SRandall Stewart TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) { 42665e54f665SRandall Stewart if (tp1->window_probe) { 4267cd554309SMichael Tuexen /* move back to data send queue */ 42687215cc1bSMichael Tuexen sctp_window_probe_recovery(stcb, asoc, tp1); 42695e54f665SRandall Stewart break; 42705e54f665SRandall Stewart } 42715e54f665SRandall Stewart } 42725e54f665SRandall Stewart } 42735171328bSRandall Stewart if (net->flight_size) { 4274a5d547adSRandall Stewart j++; 427572e23abaSMichael Tuexen sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net); 42765171328bSRandall Stewart if (net->window_probe) { 42775171328bSRandall Stewart net->window_probe = 0; 42785171328bSRandall Stewart } 4279f8829a4aSRandall Stewart } else { 42805171328bSRandall Stewart if (net->window_probe) { 4281b7b84c0eSMichael Tuexen /* 4282b7b84c0eSMichael Tuexen * In window probes we must assure a timer 4283b7b84c0eSMichael Tuexen * is still running there 4284b7b84c0eSMichael Tuexen */ 42855171328bSRandall Stewart net->window_probe = 0; 42865171328bSRandall Stewart if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { 428772e23abaSMichael Tuexen sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net); 42885171328bSRandall Stewart } 42895171328bSRandall Stewart } else if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { 4290f8829a4aSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, 4291a5d547adSRandall Stewart stcb, net, 429244249214SRandall Stewart SCTP_FROM_SCTP_INDATA + SCTP_LOC_23); 4293f8829a4aSRandall Stewart } 4294f8829a4aSRandall Stewart } 4295f8829a4aSRandall Stewart } 4296bff64a4dSRandall Stewart if ((j == 0) && 4297bff64a4dSRandall Stewart (!TAILQ_EMPTY(&asoc->sent_queue)) && 4298bff64a4dSRandall Stewart (asoc->sent_queue_retran_cnt == 0) && 4299c105859eSRandall Stewart (win_probe_recovered == 0) && 4300bff64a4dSRandall Stewart (done_once == 0)) { 43010c0982b8SRandall Stewart /* 43020c0982b8SRandall Stewart * huh, this should not happen unless all packets are 43030c0982b8SRandall Stewart * PR-SCTP and marked to skip of course. 43040c0982b8SRandall Stewart */ 43050c0982b8SRandall Stewart if (sctp_fs_audit(asoc)) { 4306a5d547adSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 4307a5d547adSRandall Stewart net->flight_size = 0; 4308a5d547adSRandall Stewart } 4309a5d547adSRandall Stewart asoc->total_flight = 0; 4310a5d547adSRandall Stewart asoc->total_flight_count = 0; 4311a5d547adSRandall Stewart asoc->sent_queue_retran_cnt = 0; 4312a5d547adSRandall Stewart TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) { 4313a5d547adSRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND) { 4314c105859eSRandall Stewart sctp_flight_size_increase(tp1); 4315c105859eSRandall Stewart sctp_total_flight_increase(stcb, tp1); 4316a5d547adSRandall Stewart } else if (tp1->sent == SCTP_DATAGRAM_RESEND) { 4317791437b5SRandall Stewart sctp_ucount_incr(asoc->sent_queue_retran_cnt); 4318a5d547adSRandall Stewart } 4319a5d547adSRandall Stewart } 43200c0982b8SRandall Stewart } 4321bff64a4dSRandall Stewart done_once = 1; 4322a5d547adSRandall Stewart goto again; 4323a5d547adSRandall Stewart } 4324f8829a4aSRandall Stewart /**********************************/ 4325f8829a4aSRandall Stewart /* Now what about shutdown issues */ 4326f8829a4aSRandall Stewart /**********************************/ 4327f8829a4aSRandall Stewart if (TAILQ_EMPTY(&asoc->send_queue) && TAILQ_EMPTY(&asoc->sent_queue)) { 4328f8829a4aSRandall Stewart /* nothing left on sendqueue.. consider done */ 4329f8829a4aSRandall Stewart /* clean up */ 4330f8829a4aSRandall Stewart if ((asoc->stream_queue_cnt == 1) && 4331f8829a4aSRandall Stewart ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) || 4332f8829a4aSRandall Stewart (asoc->state & SCTP_STATE_SHUTDOWN_RECEIVED)) && 4333d1ea5fa9SMichael Tuexen ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc))) { 4334f8829a4aSRandall Stewart asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; 43352afb3e84SRandall Stewart } 4336bbc9dfbcSMichael Tuexen if (((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) || 4337bbc9dfbcSMichael Tuexen (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) && 4338bbc9dfbcSMichael Tuexen (asoc->stream_queue_cnt == 1) && 4339bbc9dfbcSMichael Tuexen (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { 4340ff1ffd74SMichael Tuexen struct mbuf *op_err; 4341f8829a4aSRandall Stewart 4342f8829a4aSRandall Stewart *abort_now = 1; 4343f8829a4aSRandall Stewart /* XXX */ 4344ff1ffd74SMichael Tuexen op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, ""); 434544249214SRandall Stewart stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_24; 4346ff1ffd74SMichael Tuexen sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); 4347fe4a59b3SMichael Tuexen return; 4348bbc9dfbcSMichael Tuexen } 4349bbc9dfbcSMichael Tuexen if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) && 4350bbc9dfbcSMichael Tuexen (asoc->stream_queue_cnt == 0)) { 4351ca85e948SMichael Tuexen struct sctp_nets *netp; 4352ca85e948SMichael Tuexen 4353f42a358aSRandall Stewart if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || 4354f42a358aSRandall Stewart (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 4355f8829a4aSRandall Stewart SCTP_STAT_DECR_GAUGE32(sctps_currestab); 4356f42a358aSRandall Stewart } 4357c4739e2fSRandall Stewart SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); 4358b201f536SRandall Stewart SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); 4359f8829a4aSRandall Stewart sctp_stop_timers_for_shutdown(stcb); 4360ca85e948SMichael Tuexen if (asoc->alternate) { 4361ca85e948SMichael Tuexen netp = asoc->alternate; 4362ca85e948SMichael Tuexen } else { 4363ca85e948SMichael Tuexen netp = asoc->primary_destination; 4364ca85e948SMichael Tuexen } 4365ca85e948SMichael Tuexen sctp_send_shutdown(stcb, netp); 4366f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 4367ca85e948SMichael Tuexen stcb->sctp_ep, stcb, netp); 4368f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 4369ca85e948SMichael Tuexen stcb->sctp_ep, stcb, netp); 4370f8829a4aSRandall Stewart } else if ((SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) && 4371f8829a4aSRandall Stewart (asoc->stream_queue_cnt == 0)) { 4372ca85e948SMichael Tuexen struct sctp_nets *netp; 4373ca85e948SMichael Tuexen 4374f8829a4aSRandall Stewart SCTP_STAT_DECR_GAUGE32(sctps_currestab); 4375c4739e2fSRandall Stewart SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT); 4376b201f536SRandall Stewart SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); 437712af6654SMichael Tuexen sctp_stop_timers_for_shutdown(stcb); 4378c39cfa1fSMichael Tuexen if (asoc->alternate) { 4379c39cfa1fSMichael Tuexen netp = asoc->alternate; 4380c39cfa1fSMichael Tuexen } else { 4381c39cfa1fSMichael Tuexen netp = asoc->primary_destination; 4382c39cfa1fSMichael Tuexen } 4383c39cfa1fSMichael Tuexen sctp_send_shutdown_ack(stcb, netp); 4384f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, 4385ca85e948SMichael Tuexen stcb->sctp_ep, stcb, netp); 4386f8829a4aSRandall Stewart } 4387f8829a4aSRandall Stewart } 4388dfb11ef8SRandall Stewart /*********************************************/ 4389dfb11ef8SRandall Stewart /* Here we perform PR-SCTP procedures */ 4390dfb11ef8SRandall Stewart /* (section 4.2) */ 4391dfb11ef8SRandall Stewart /*********************************************/ 4392dfb11ef8SRandall Stewart /* C1. update advancedPeerAckPoint */ 439320b07a4dSMichael Tuexen if (SCTP_TSN_GT(cumack, asoc->advanced_peer_ack_point)) { 4394dfb11ef8SRandall Stewart asoc->advanced_peer_ack_point = cumack; 4395dfb11ef8SRandall Stewart } 4396830d754dSRandall Stewart /* PR-Sctp issues need to be addressed too */ 4397dd973b0eSMichael Tuexen if ((asoc->prsctp_supported) && (asoc->pr_sctp_cnt > 0)) { 4398830d754dSRandall Stewart struct sctp_tmit_chunk *lchk; 4399830d754dSRandall Stewart uint32_t old_adv_peer_ack_point; 4400830d754dSRandall Stewart 4401830d754dSRandall Stewart old_adv_peer_ack_point = asoc->advanced_peer_ack_point; 4402830d754dSRandall Stewart lchk = sctp_try_advance_peer_ack_point(stcb, asoc); 4403830d754dSRandall Stewart /* C3. See if we need to send a Fwd-TSN */ 440420b07a4dSMichael Tuexen if (SCTP_TSN_GT(asoc->advanced_peer_ack_point, cumack)) { 4405830d754dSRandall Stewart /* 4406493d8e5aSRandall Stewart * ISSUE with ECN, see FWD-TSN processing. 4407830d754dSRandall Stewart */ 440820b07a4dSMichael Tuexen if (SCTP_TSN_GT(asoc->advanced_peer_ack_point, old_adv_peer_ack_point)) { 4409830d754dSRandall Stewart send_forward_tsn(stcb, asoc); 44100c0982b8SRandall Stewart } else if (lchk) { 44110c0982b8SRandall Stewart /* try to FR fwd-tsn's that get lost too */ 441244fbe462SRandall Stewart if (lchk->rec.data.fwd_tsn_cnt >= 3) { 44130c0982b8SRandall Stewart send_forward_tsn(stcb, asoc); 44140c0982b8SRandall Stewart } 4415830d754dSRandall Stewart } 4416830d754dSRandall Stewart } 4417830d754dSRandall Stewart if (lchk) { 4418830d754dSRandall Stewart /* Assure a timer is up */ 4419830d754dSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SEND, 4420830d754dSRandall Stewart stcb->sctp_ep, stcb, lchk->whoTo); 4421830d754dSRandall Stewart } 4422830d754dSRandall Stewart } 4423b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_RWND_LOGGING_ENABLE) { 4424f8829a4aSRandall Stewart sctp_misc_ints(SCTP_SACK_RWND_UPDATE, 4425f8829a4aSRandall Stewart rwnd, 4426f8829a4aSRandall Stewart stcb->asoc.peers_rwnd, 4427f8829a4aSRandall Stewart stcb->asoc.total_flight, 4428f8829a4aSRandall Stewart stcb->asoc.total_output_queue_size); 442980fefe0aSRandall Stewart } 4430f8829a4aSRandall Stewart } 4431f8829a4aSRandall Stewart 4432f8829a4aSRandall Stewart void 4433cd554309SMichael Tuexen sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, 44347215cc1bSMichael Tuexen struct sctp_tcb *stcb, 4435cd554309SMichael Tuexen uint16_t num_seg, uint16_t num_nr_seg, uint16_t num_dup, 4436cd554309SMichael Tuexen int *abort_now, uint8_t flags, 4437899288aeSRandall Stewart uint32_t cum_ack, uint32_t rwnd, int ecne_seen) 4438f8829a4aSRandall Stewart { 4439f8829a4aSRandall Stewart struct sctp_association *asoc; 4440f8829a4aSRandall Stewart struct sctp_tmit_chunk *tp1, *tp2; 4441cd554309SMichael Tuexen uint32_t last_tsn, biggest_tsn_acked, biggest_tsn_newly_acked, this_sack_lowest_newack; 4442f8829a4aSRandall Stewart uint16_t wake_him = 0; 4443c105859eSRandall Stewart uint32_t send_s = 0; 4444f8829a4aSRandall Stewart long j; 4445f8829a4aSRandall Stewart int accum_moved = 0; 4446f8829a4aSRandall Stewart int will_exit_fast_recovery = 0; 44475e54f665SRandall Stewart uint32_t a_rwnd, old_rwnd; 44485e54f665SRandall Stewart int win_probe_recovery = 0; 4449c105859eSRandall Stewart int win_probe_recovered = 0; 4450f8829a4aSRandall Stewart struct sctp_nets *net = NULL; 4451bff64a4dSRandall Stewart int done_once; 4452f79aab18SRandall Stewart int rto_ok = 1; 4453f8829a4aSRandall Stewart uint8_t reneged_all = 0; 4454f8829a4aSRandall Stewart uint8_t cmt_dac_flag; 4455f8829a4aSRandall Stewart 4456f8829a4aSRandall Stewart /* 4457f8829a4aSRandall Stewart * we take any chance we can to service our queues since we cannot 4458f8829a4aSRandall Stewart * get awoken when the socket is read from :< 4459f8829a4aSRandall Stewart */ 4460f8829a4aSRandall Stewart /* 4461f8829a4aSRandall Stewart * Now perform the actual SACK handling: 1) Verify that it is not an 4462f8829a4aSRandall Stewart * old sack, if so discard. 2) If there is nothing left in the send 4463f8829a4aSRandall Stewart * queue (cum-ack is equal to last acked) then you have a duplicate 4464f8829a4aSRandall Stewart * too, update any rwnd change and verify no timers are running. 4465f8829a4aSRandall Stewart * then return. 3) Process any new consequtive data i.e. cum-ack 4466f8829a4aSRandall Stewart * moved process these first and note that it moved. 4) Process any 4467f8829a4aSRandall Stewart * sack blocks. 5) Drop any acked from the queue. 6) Check for any 4468f8829a4aSRandall Stewart * revoked blocks and mark. 7) Update the cwnd. 8) Nothing left, 4469f8829a4aSRandall Stewart * sync up flightsizes and things, stop all timers and also check 4470f8829a4aSRandall Stewart * for shutdown_pending state. If so then go ahead and send off the 4471f8829a4aSRandall Stewart * shutdown. If in shutdown recv, send off the shutdown-ack and 4472f8829a4aSRandall Stewart * start that timer, Ret. 9) Strike any non-acked things and do FR 4473f8829a4aSRandall Stewart * procedure if needed being sure to set the FR flag. 10) Do pr-sctp 4474f8829a4aSRandall Stewart * procedures. 11) Apply any FR penalties. 12) Assure we will SACK 4475f8829a4aSRandall Stewart * if in shutdown_recv state. 4476f8829a4aSRandall Stewart */ 4477f8829a4aSRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 4478f8829a4aSRandall Stewart /* CMT DAC algo */ 4479f8829a4aSRandall Stewart this_sack_lowest_newack = 0; 4480f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_slowpath_sack); 4481cd554309SMichael Tuexen last_tsn = cum_ack; 4482cd554309SMichael Tuexen cmt_dac_flag = flags & SCTP_SACK_CMT_DAC; 448318e198d3SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS 448418e198d3SRandall Stewart stcb->asoc.cumack_log[stcb->asoc.cumack_log_at] = cum_ack; 448518e198d3SRandall Stewart stcb->asoc.cumack_log_at++; 448618e198d3SRandall Stewart if (stcb->asoc.cumack_log_at > SCTP_TSN_LOG_SIZE) { 448718e198d3SRandall Stewart stcb->asoc.cumack_log_at = 0; 448818e198d3SRandall Stewart } 448918e198d3SRandall Stewart #endif 4490d06c82f1SRandall Stewart a_rwnd = rwnd; 4491f8829a4aSRandall Stewart 4492cd554309SMichael Tuexen if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_SACK_ARRIVALS_ENABLE) { 4493cd554309SMichael Tuexen sctp_misc_ints(SCTP_SACK_LOG_NORMAL, cum_ack, 4494cd554309SMichael Tuexen rwnd, stcb->asoc.last_acked_seq, stcb->asoc.peers_rwnd); 4495cd554309SMichael Tuexen } 4496*0053ed28SMichael Tuexen 44975e54f665SRandall Stewart old_rwnd = stcb->asoc.peers_rwnd; 4498b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { 4499c4739e2fSRandall Stewart sctp_misc_ints(SCTP_THRESHOLD_CLEAR, 4500c4739e2fSRandall Stewart stcb->asoc.overall_error_count, 4501c4739e2fSRandall Stewart 0, 4502c4739e2fSRandall Stewart SCTP_FROM_SCTP_INDATA, 4503c4739e2fSRandall Stewart __LINE__); 4504c4739e2fSRandall Stewart } 4505f8829a4aSRandall Stewart stcb->asoc.overall_error_count = 0; 4506f8829a4aSRandall Stewart asoc = &stcb->asoc; 4507b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) { 4508f8829a4aSRandall Stewart sctp_log_sack(asoc->last_acked_seq, 4509f8829a4aSRandall Stewart cum_ack, 4510f8829a4aSRandall Stewart 0, 4511f8829a4aSRandall Stewart num_seg, 4512f8829a4aSRandall Stewart num_dup, 4513f8829a4aSRandall Stewart SCTP_LOG_NEW_SACK); 451480fefe0aSRandall Stewart } 4515ca85e948SMichael Tuexen if ((num_dup) && (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE)) { 4516cd554309SMichael Tuexen uint16_t i; 4517458303daSRandall Stewart uint32_t *dupdata, dblock; 4518f8829a4aSRandall Stewart 4519cd554309SMichael Tuexen for (i = 0; i < num_dup; i++) { 4520cd554309SMichael Tuexen dupdata = (uint32_t *)sctp_m_getptr(m, offset_dup + i * sizeof(uint32_t), 4521458303daSRandall Stewart sizeof(uint32_t), (uint8_t *)&dblock); 4522cd554309SMichael Tuexen if (dupdata == NULL) { 4523458303daSRandall Stewart break; 4524458303daSRandall Stewart } 4525cd554309SMichael Tuexen sctp_log_fr(*dupdata, 0, 0, SCTP_FR_DUPED); 4526f8829a4aSRandall Stewart } 4527f8829a4aSRandall Stewart } 4528c105859eSRandall Stewart /* reality check */ 4529c105859eSRandall Stewart if (!TAILQ_EMPTY(&asoc->sent_queue)) { 4530c105859eSRandall Stewart tp1 = TAILQ_LAST(&asoc->sent_queue, 4531c105859eSRandall Stewart sctpchunk_listhead); 453249656eefSMichael Tuexen send_s = tp1->rec.data.tsn + 1; 4533c105859eSRandall Stewart } else { 4534b5c16493SMichael Tuexen tp1 = NULL; 4535c105859eSRandall Stewart send_s = asoc->sending_seq; 4536c105859eSRandall Stewart } 453720b07a4dSMichael Tuexen if (SCTP_TSN_GE(cum_ack, send_s)) { 4538ff1ffd74SMichael Tuexen struct mbuf *op_err; 4539ff1ffd74SMichael Tuexen char msg[SCTP_DIAG_INFO_LEN]; 4540c105859eSRandall Stewart 4541f8829a4aSRandall Stewart /* 4542fd60718dSMichael Tuexen * no way, we have not even sent this TSN out yet. Peer is 4543fd60718dSMichael Tuexen * hopelessly messed up with us. 4544f8829a4aSRandall Stewart */ 4545cd3fd531SMichael Tuexen SCTP_PRINTF("NEW cum_ack:%x send_s:%x is smaller or equal\n", 4546b5c16493SMichael Tuexen cum_ack, send_s); 4547b5c16493SMichael Tuexen if (tp1) { 4548cd3fd531SMichael Tuexen SCTP_PRINTF("Got send_s from tsn:%x + 1 of tp1: %p\n", 454949656eefSMichael Tuexen tp1->rec.data.tsn, (void *)tp1); 4550b5c16493SMichael Tuexen } 4551f8829a4aSRandall Stewart hopeless_peer: 4552f8829a4aSRandall Stewart *abort_now = 1; 4553f8829a4aSRandall Stewart /* XXX */ 455455f8a4bbSMichael Tuexen snprintf(msg, sizeof(msg), "Cum ack %8.8x greater or equal than TSN %8.8x", 4555ff1ffd74SMichael Tuexen cum_ack, send_s); 4556ff1ffd74SMichael Tuexen op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); 455744249214SRandall Stewart stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_25; 4558ff1ffd74SMichael Tuexen sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); 4559f8829a4aSRandall Stewart return; 4560f8829a4aSRandall Stewart } 4561f8829a4aSRandall Stewart /**********************/ 4562f8829a4aSRandall Stewart /* 1) check the range */ 4563f8829a4aSRandall Stewart /**********************/ 456420b07a4dSMichael Tuexen if (SCTP_TSN_GT(asoc->last_acked_seq, last_tsn)) { 4565f8829a4aSRandall Stewart /* acking something behind */ 4566f8829a4aSRandall Stewart return; 4567f8829a4aSRandall Stewart } 4568*0053ed28SMichael Tuexen 4569f8829a4aSRandall Stewart /* update the Rwnd of the peer */ 4570f8829a4aSRandall Stewart if (TAILQ_EMPTY(&asoc->sent_queue) && 4571f8829a4aSRandall Stewart TAILQ_EMPTY(&asoc->send_queue) && 4572cd554309SMichael Tuexen (asoc->stream_queue_cnt == 0)) { 4573f8829a4aSRandall Stewart /* nothing left on send/sent and strmq */ 4574b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) { 4575f8829a4aSRandall Stewart sctp_log_rwnd_set(SCTP_SET_PEER_RWND_VIA_SACK, 4576f8829a4aSRandall Stewart asoc->peers_rwnd, 0, 0, a_rwnd); 457780fefe0aSRandall Stewart } 4578f8829a4aSRandall Stewart asoc->peers_rwnd = a_rwnd; 4579f8829a4aSRandall Stewart if (asoc->sent_queue_retran_cnt) { 4580f8829a4aSRandall Stewart asoc->sent_queue_retran_cnt = 0; 4581f8829a4aSRandall Stewart } 4582f8829a4aSRandall Stewart if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) { 4583f8829a4aSRandall Stewart /* SWS sender side engages */ 4584f8829a4aSRandall Stewart asoc->peers_rwnd = 0; 4585f8829a4aSRandall Stewart } 4586f8829a4aSRandall Stewart /* stop any timers */ 4587f8829a4aSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 4588f8829a4aSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, 458944249214SRandall Stewart stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_26); 4590f8829a4aSRandall Stewart net->partial_bytes_acked = 0; 4591f8829a4aSRandall Stewart net->flight_size = 0; 4592f8829a4aSRandall Stewart } 4593f8829a4aSRandall Stewart asoc->total_flight = 0; 4594f8829a4aSRandall Stewart asoc->total_flight_count = 0; 4595f8829a4aSRandall Stewart return; 4596f8829a4aSRandall Stewart } 4597f8829a4aSRandall Stewart /* 4598f8829a4aSRandall Stewart * We init netAckSz and netAckSz2 to 0. These are used to track 2 4599f8829a4aSRandall Stewart * things. The total byte count acked is tracked in netAckSz AND 4600f8829a4aSRandall Stewart * netAck2 is used to track the total bytes acked that are un- 4601f8829a4aSRandall Stewart * amibguious and were never retransmitted. We track these on a per 4602f8829a4aSRandall Stewart * destination address basis. 4603f8829a4aSRandall Stewart */ 4604f8829a4aSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 4605a21779f0SRandall Stewart if (SCTP_TSN_GT(cum_ack, net->cwr_window_tsn)) { 4606a21779f0SRandall Stewart /* Drag along the window_tsn for cwr's */ 4607a21779f0SRandall Stewart net->cwr_window_tsn = cum_ack; 4608a21779f0SRandall Stewart } 4609f8829a4aSRandall Stewart net->prev_cwnd = net->cwnd; 4610f8829a4aSRandall Stewart net->net_ack = 0; 4611f8829a4aSRandall Stewart net->net_ack2 = 0; 4612f8829a4aSRandall Stewart 4613f8829a4aSRandall Stewart /* 461442551e99SRandall Stewart * CMT: Reset CUC and Fast recovery algo variables before 461542551e99SRandall Stewart * SACK processing 4616f8829a4aSRandall Stewart */ 4617f8829a4aSRandall Stewart net->new_pseudo_cumack = 0; 4618f8829a4aSRandall Stewart net->will_exit_fast_recovery = 0; 4619299108c5SRandall Stewart if (stcb->asoc.cc_functions.sctp_cwnd_prepare_net_for_sack) { 4620299108c5SRandall Stewart (*stcb->asoc.cc_functions.sctp_cwnd_prepare_net_for_sack) (stcb, net); 4621299108c5SRandall Stewart } 4622*0053ed28SMichael Tuexen 4623e9a3a1b1SMichael Tuexen /* 4624e9a3a1b1SMichael Tuexen * CMT: SFR algo (and HTNA) - this_sack_highest_newack has 4625e9a3a1b1SMichael Tuexen * to be greater than the cumack. Also reset saw_newack to 0 4626e9a3a1b1SMichael Tuexen * for all dests. 4627e9a3a1b1SMichael Tuexen */ 4628e9a3a1b1SMichael Tuexen net->saw_newack = 0; 4629e9a3a1b1SMichael Tuexen net->this_sack_highest_newack = last_tsn; 4630f8829a4aSRandall Stewart } 4631f8829a4aSRandall Stewart /* process the new consecutive TSN first */ 46324a9ef3f8SMichael Tuexen TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) { 463349656eefSMichael Tuexen if (SCTP_TSN_GE(last_tsn, tp1->rec.data.tsn)) { 4634f8829a4aSRandall Stewart if (tp1->sent != SCTP_DATAGRAM_UNSENT) { 4635f8829a4aSRandall Stewart accum_moved = 1; 4636f8829a4aSRandall Stewart if (tp1->sent < SCTP_DATAGRAM_ACKED) { 4637f8829a4aSRandall Stewart /* 4638f8829a4aSRandall Stewart * If it is less than ACKED, it is 4639f8829a4aSRandall Stewart * now no-longer in flight. Higher 4640f8829a4aSRandall Stewart * values may occur during marking 4641f8829a4aSRandall Stewart */ 4642f8829a4aSRandall Stewart if ((tp1->whoTo->dest_state & 4643f8829a4aSRandall Stewart SCTP_ADDR_UNCONFIRMED) && 4644f8829a4aSRandall Stewart (tp1->snd_count < 2)) { 4645f8829a4aSRandall Stewart /* 4646f8829a4aSRandall Stewart * If there was no retran 4647f8829a4aSRandall Stewart * and the address is 4648f8829a4aSRandall Stewart * un-confirmed and we sent 4649f8829a4aSRandall Stewart * there and are now 4650f8829a4aSRandall Stewart * sacked.. its confirmed, 4651f8829a4aSRandall Stewart * mark it so. 4652f8829a4aSRandall Stewart */ 4653f8829a4aSRandall Stewart tp1->whoTo->dest_state &= 4654f8829a4aSRandall Stewart ~SCTP_ADDR_UNCONFIRMED; 4655f8829a4aSRandall Stewart } 4656c105859eSRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND) { 4657b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { 4658c105859eSRandall Stewart sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_CA, 4659a5d547adSRandall Stewart tp1->whoTo->flight_size, 4660a5d547adSRandall Stewart tp1->book_size, 46619a8e3088SMichael Tuexen (uint32_t)(uintptr_t)tp1->whoTo, 466249656eefSMichael Tuexen tp1->rec.data.tsn); 466380fefe0aSRandall Stewart } 4664c105859eSRandall Stewart sctp_flight_size_decrease(tp1); 4665c105859eSRandall Stewart sctp_total_flight_decrease(stcb, tp1); 4666299108c5SRandall Stewart if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) { 4667299108c5SRandall Stewart (*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) (tp1->whoTo, 4668299108c5SRandall Stewart tp1); 4669299108c5SRandall Stewart } 4670f8829a4aSRandall Stewart } 4671f8829a4aSRandall Stewart tp1->whoTo->net_ack += tp1->send_size; 4672f8829a4aSRandall Stewart 4673f8829a4aSRandall Stewart /* CMT SFR and DAC algos */ 467449656eefSMichael Tuexen this_sack_lowest_newack = tp1->rec.data.tsn; 4675f8829a4aSRandall Stewart tp1->whoTo->saw_newack = 1; 4676f8829a4aSRandall Stewart 4677f8829a4aSRandall Stewart if (tp1->snd_count < 2) { 4678f8829a4aSRandall Stewart /* 4679f8829a4aSRandall Stewart * True non-retransmited 4680f8829a4aSRandall Stewart * chunk 4681f8829a4aSRandall Stewart */ 4682f8829a4aSRandall Stewart tp1->whoTo->net_ack2 += 4683f8829a4aSRandall Stewart tp1->send_size; 4684f8829a4aSRandall Stewart 4685f8829a4aSRandall Stewart /* update RTO too? */ 4686f8829a4aSRandall Stewart if (tp1->do_rtt) { 4687f79aab18SRandall Stewart if (rto_ok) { 4688f8829a4aSRandall Stewart tp1->whoTo->RTO = 4689f8829a4aSRandall Stewart sctp_calculate_rto(stcb, 4690f8829a4aSRandall Stewart asoc, tp1->whoTo, 469118e198d3SRandall Stewart &tp1->sent_rcv_time, 4692f79aab18SRandall Stewart SCTP_RTT_FROM_DATA); 4693f79aab18SRandall Stewart rto_ok = 0; 4694f79aab18SRandall Stewart } 4695f79aab18SRandall Stewart if (tp1->whoTo->rto_needed == 0) { 4696f79aab18SRandall Stewart tp1->whoTo->rto_needed = 1; 4697f79aab18SRandall Stewart } 4698f8829a4aSRandall Stewart tp1->do_rtt = 0; 4699f8829a4aSRandall Stewart } 4700f8829a4aSRandall Stewart } 4701f8829a4aSRandall Stewart /* 4702f8829a4aSRandall Stewart * CMT: CUCv2 algorithm. From the 4703f8829a4aSRandall Stewart * cumack'd TSNs, for each TSN being 4704f8829a4aSRandall Stewart * acked for the first time, set the 4705f8829a4aSRandall Stewart * following variables for the 4706f8829a4aSRandall Stewart * corresp destination. 4707f8829a4aSRandall Stewart * new_pseudo_cumack will trigger a 4708f8829a4aSRandall Stewart * cwnd update. 4709f8829a4aSRandall Stewart * find_(rtx_)pseudo_cumack will 4710f8829a4aSRandall Stewart * trigger search for the next 4711f8829a4aSRandall Stewart * expected (rtx-)pseudo-cumack. 4712f8829a4aSRandall Stewart */ 4713f8829a4aSRandall Stewart tp1->whoTo->new_pseudo_cumack = 1; 4714f8829a4aSRandall Stewart tp1->whoTo->find_pseudo_cumack = 1; 4715f8829a4aSRandall Stewart tp1->whoTo->find_rtx_pseudo_cumack = 1; 4716f8829a4aSRandall Stewart 4717f8829a4aSRandall Stewart 4718b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) { 4719f8829a4aSRandall Stewart sctp_log_sack(asoc->last_acked_seq, 4720f8829a4aSRandall Stewart cum_ack, 472149656eefSMichael Tuexen tp1->rec.data.tsn, 4722f8829a4aSRandall Stewart 0, 4723f8829a4aSRandall Stewart 0, 4724f8829a4aSRandall Stewart SCTP_LOG_TSN_ACKED); 472580fefe0aSRandall Stewart } 4726b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 472749656eefSMichael Tuexen sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.tsn, SCTP_CWND_LOG_FROM_SACK); 472880fefe0aSRandall Stewart } 4729f8829a4aSRandall Stewart } 4730f8829a4aSRandall Stewart if (tp1->sent == SCTP_DATAGRAM_RESEND) { 4731f8829a4aSRandall Stewart sctp_ucount_decr(asoc->sent_queue_retran_cnt); 4732f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 4733f8829a4aSRandall Stewart sctp_audit_log(0xB3, 4734f8829a4aSRandall Stewart (asoc->sent_queue_retran_cnt & 0x000000ff)); 4735f8829a4aSRandall Stewart #endif 4736f8829a4aSRandall Stewart } 473742551e99SRandall Stewart if (tp1->rec.data.chunk_was_revoked) { 473842551e99SRandall Stewart /* deflate the cwnd */ 473942551e99SRandall Stewart tp1->whoTo->cwnd -= tp1->book_size; 474042551e99SRandall Stewart tp1->rec.data.chunk_was_revoked = 0; 474142551e99SRandall Stewart } 4742325c8c46SMichael Tuexen if (tp1->sent != SCTP_DATAGRAM_NR_ACKED) { 4743f8829a4aSRandall Stewart tp1->sent = SCTP_DATAGRAM_ACKED; 4744f8829a4aSRandall Stewart } 4745325c8c46SMichael Tuexen } 4746f8829a4aSRandall Stewart } else { 4747f8829a4aSRandall Stewart break; 4748f8829a4aSRandall Stewart } 4749f8829a4aSRandall Stewart } 4750f8829a4aSRandall Stewart biggest_tsn_newly_acked = biggest_tsn_acked = last_tsn; 4751f8829a4aSRandall Stewart /* always set this up to cum-ack */ 4752f8829a4aSRandall Stewart asoc->this_sack_highest_gap = last_tsn; 4753f8829a4aSRandall Stewart 4754cd554309SMichael Tuexen if ((num_seg > 0) || (num_nr_seg > 0)) { 4755f8829a4aSRandall Stewart 4756f8829a4aSRandall Stewart /* 4757f8829a4aSRandall Stewart * thisSackHighestGap will increase while handling NEW 4758f8829a4aSRandall Stewart * segments this_sack_highest_newack will increase while 4759f8829a4aSRandall Stewart * handling NEWLY ACKED chunks. this_sack_lowest_newack is 4760f8829a4aSRandall Stewart * used for CMT DAC algo. saw_newack will also change. 4761f8829a4aSRandall Stewart */ 4762cd554309SMichael Tuexen if (sctp_handle_segments(m, &offset_seg, stcb, asoc, last_tsn, &biggest_tsn_acked, 4763cd554309SMichael Tuexen &biggest_tsn_newly_acked, &this_sack_lowest_newack, 47647215cc1bSMichael Tuexen num_seg, num_nr_seg, &rto_ok)) { 4765cd554309SMichael Tuexen wake_him++; 4766cd554309SMichael Tuexen } 4767f8829a4aSRandall Stewart /* 4768fd60718dSMichael Tuexen * validate the biggest_tsn_acked in the gap acks if strict 4769fd60718dSMichael Tuexen * adherence is wanted. 4770f8829a4aSRandall Stewart */ 477120b07a4dSMichael Tuexen if (SCTP_TSN_GE(biggest_tsn_acked, send_s)) { 4772f8829a4aSRandall Stewart /* 4773fd60718dSMichael Tuexen * peer is either confused or we are under attack. 4774fd60718dSMichael Tuexen * We must abort. 4775f8829a4aSRandall Stewart */ 4776cd3fd531SMichael Tuexen SCTP_PRINTF("Hopeless peer! biggest_tsn_acked:%x largest seq:%x\n", 4777cd3fd531SMichael Tuexen biggest_tsn_acked, send_s); 4778f8829a4aSRandall Stewart goto hopeless_peer; 4779f8829a4aSRandall Stewart } 4780f8829a4aSRandall Stewart } 4781f8829a4aSRandall Stewart /*******************************************/ 4782f8829a4aSRandall Stewart /* cancel ALL T3-send timer if accum moved */ 4783f8829a4aSRandall Stewart /*******************************************/ 47847c99d56fSMichael Tuexen if (asoc->sctp_cmt_on_off > 0) { 4785f8829a4aSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 4786f8829a4aSRandall Stewart if (net->new_pseudo_cumack) 4787f8829a4aSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, 4788a5d547adSRandall Stewart stcb, net, 478944249214SRandall Stewart SCTP_FROM_SCTP_INDATA + SCTP_LOC_27); 4790f8829a4aSRandall Stewart 4791f8829a4aSRandall Stewart } 4792f8829a4aSRandall Stewart } else { 4793f8829a4aSRandall Stewart if (accum_moved) { 4794f8829a4aSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 4795f8829a4aSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, 479644249214SRandall Stewart stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_28); 4797f8829a4aSRandall Stewart } 4798f8829a4aSRandall Stewart } 4799f8829a4aSRandall Stewart } 4800f8829a4aSRandall Stewart /********************************************/ 4801d9c5cfeaSMichael Tuexen /* drop the acked chunks from the sentqueue */ 4802f8829a4aSRandall Stewart /********************************************/ 4803f8829a4aSRandall Stewart asoc->last_acked_seq = cum_ack; 4804f8829a4aSRandall Stewart 48057c99d56fSMichael Tuexen TAILQ_FOREACH_SAFE(tp1, &asoc->sent_queue, sctp_next, tp2) { 480649656eefSMichael Tuexen if (SCTP_TSN_GT(tp1->rec.data.tsn, cum_ack)) { 4807f8829a4aSRandall Stewart break; 4808f8829a4aSRandall Stewart } 4809325c8c46SMichael Tuexen if (tp1->sent != SCTP_DATAGRAM_NR_ACKED) { 481049656eefSMichael Tuexen if (asoc->strmout[tp1->rec.data.sid].chunks_on_queues > 0) { 481149656eefSMichael Tuexen asoc->strmout[tp1->rec.data.sid].chunks_on_queues--; 4812a7ad6026SMichael Tuexen #ifdef INVARIANTS 4813a7ad6026SMichael Tuexen } else { 481449656eefSMichael Tuexen panic("No chunks on the queues for sid %u.", tp1->rec.data.sid); 4815a7ad6026SMichael Tuexen #endif 4816a7ad6026SMichael Tuexen } 4817f8829a4aSRandall Stewart } 481849656eefSMichael Tuexen if ((asoc->strmout[tp1->rec.data.sid].chunks_on_queues == 0) && 481949656eefSMichael Tuexen (asoc->strmout[tp1->rec.data.sid].state == SCTP_STREAM_RESET_PENDING) && 482049656eefSMichael Tuexen TAILQ_EMPTY(&asoc->strmout[tp1->rec.data.sid].outqueue)) { 4821d96bef9cSMichael Tuexen asoc->trigger_reset = 1; 4822d96bef9cSMichael Tuexen } 4823f8829a4aSRandall Stewart TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next); 48240ddb4299SMichael Tuexen if (PR_SCTP_ENABLED(tp1->flags)) { 4825f8829a4aSRandall Stewart if (asoc->pr_sctp_cnt != 0) 4826f8829a4aSRandall Stewart asoc->pr_sctp_cnt--; 4827f8829a4aSRandall Stewart } 48287c99d56fSMichael Tuexen asoc->sent_queue_cnt--; 4829f8829a4aSRandall Stewart if (tp1->data) { 483004ee05e8SRandall Stewart /* sa_ignore NO_NULL_CHK */ 4831f8829a4aSRandall Stewart sctp_free_bufspace(stcb, asoc, tp1, 1); 4832f8829a4aSRandall Stewart sctp_m_freem(tp1->data); 48337c99d56fSMichael Tuexen tp1->data = NULL; 4834dd973b0eSMichael Tuexen if (asoc->prsctp_supported && PR_SCTP_BUF_ENABLED(tp1->flags)) { 4835f8829a4aSRandall Stewart asoc->sent_queue_cnt_removeable--; 4836f8829a4aSRandall Stewart } 4837f8829a4aSRandall Stewart } 4838b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) { 4839f8829a4aSRandall Stewart sctp_log_sack(asoc->last_acked_seq, 4840f8829a4aSRandall Stewart cum_ack, 484149656eefSMichael Tuexen tp1->rec.data.tsn, 4842f8829a4aSRandall Stewart 0, 4843f8829a4aSRandall Stewart 0, 4844f8829a4aSRandall Stewart SCTP_LOG_FREE_SENT); 484580fefe0aSRandall Stewart } 4846689e6a5fSMichael Tuexen sctp_free_a_chunk(stcb, tp1, SCTP_SO_NOT_LOCKED); 4847f8829a4aSRandall Stewart wake_him++; 48487c99d56fSMichael Tuexen } 48497c99d56fSMichael Tuexen if (TAILQ_EMPTY(&asoc->sent_queue) && (asoc->total_flight > 0)) { 48507c99d56fSMichael Tuexen #ifdef INVARIANTS 4851cd0a4ff6SPedro F. Giffuni panic("Warning flight size is positive and should be 0"); 48527c99d56fSMichael Tuexen #else 48537c99d56fSMichael Tuexen SCTP_PRINTF("Warning flight size incorrect should be 0 is %d\n", 48547c99d56fSMichael Tuexen asoc->total_flight); 48557c99d56fSMichael Tuexen #endif 48567c99d56fSMichael Tuexen asoc->total_flight = 0; 48577c99d56fSMichael Tuexen } 4858*0053ed28SMichael Tuexen 485904ee05e8SRandall Stewart /* sa_ignore NO_NULL_CHK */ 4860f8829a4aSRandall Stewart if ((wake_him) && (stcb->sctp_socket)) { 4861ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4862ceaad40aSRandall Stewart struct socket *so; 4863ceaad40aSRandall Stewart 4864ceaad40aSRandall Stewart #endif 4865f8829a4aSRandall Stewart SOCKBUF_LOCK(&stcb->sctp_socket->so_snd); 4866b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_WAKE_LOGGING_ENABLE) { 48677215cc1bSMichael Tuexen sctp_wakeup_log(stcb, wake_him, SCTP_WAKESND_FROM_SACK); 486880fefe0aSRandall Stewart } 4869ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4870ceaad40aSRandall Stewart so = SCTP_INP_SO(stcb->sctp_ep); 4871ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 4872ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 4873ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 4874ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 4875ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 4876ceaad40aSRandall Stewart if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { 4877ceaad40aSRandall Stewart /* assoc was freed while we were unlocked */ 4878ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 4879ceaad40aSRandall Stewart return; 4880ceaad40aSRandall Stewart } 4881ceaad40aSRandall Stewart #endif 4882f8829a4aSRandall Stewart sctp_sowwakeup_locked(stcb->sctp_ep, stcb->sctp_socket); 4883ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4884ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 4885ceaad40aSRandall Stewart #endif 4886f8829a4aSRandall Stewart } else { 4887b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_WAKE_LOGGING_ENABLE) { 48887215cc1bSMichael Tuexen sctp_wakeup_log(stcb, wake_him, SCTP_NOWAKE_FROM_SACK); 488980fefe0aSRandall Stewart } 4890f8829a4aSRandall Stewart } 4891f8829a4aSRandall Stewart 489242551e99SRandall Stewart if (asoc->fast_retran_loss_recovery && accum_moved) { 489320b07a4dSMichael Tuexen if (SCTP_TSN_GE(asoc->last_acked_seq, asoc->fast_recovery_tsn)) { 4894f8829a4aSRandall Stewart /* Setup so we will exit RFC2582 fast recovery */ 4895f8829a4aSRandall Stewart will_exit_fast_recovery = 1; 4896f8829a4aSRandall Stewart } 4897f8829a4aSRandall Stewart } 4898f8829a4aSRandall Stewart /* 4899f8829a4aSRandall Stewart * Check for revoked fragments: 4900f8829a4aSRandall Stewart * 4901f8829a4aSRandall Stewart * if Previous sack - Had no frags then we can't have any revoked if 4902f8829a4aSRandall Stewart * Previous sack - Had frag's then - If we now have frags aka 4903f8829a4aSRandall Stewart * num_seg > 0 call sctp_check_for_revoked() to tell if peer revoked 4904f8829a4aSRandall Stewart * some of them. else - The peer revoked all ACKED fragments, since 4905f8829a4aSRandall Stewart * we had some before and now we have NONE. 4906f8829a4aSRandall Stewart */ 4907f8829a4aSRandall Stewart 4908d9c5cfeaSMichael Tuexen if (num_seg) { 4909c105859eSRandall Stewart sctp_check_for_revoked(stcb, asoc, cum_ack, biggest_tsn_acked); 4910d9c5cfeaSMichael Tuexen asoc->saw_sack_with_frags = 1; 4911d9c5cfeaSMichael Tuexen } else if (asoc->saw_sack_with_frags) { 4912f8829a4aSRandall Stewart int cnt_revoked = 0; 4913f8829a4aSRandall Stewart 4914f8829a4aSRandall Stewart /* Peer revoked all dg's marked or acked */ 4915f8829a4aSRandall Stewart TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) { 4916b5c16493SMichael Tuexen if (tp1->sent == SCTP_DATAGRAM_ACKED) { 4917f8829a4aSRandall Stewart tp1->sent = SCTP_DATAGRAM_SENT; 4918b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { 4919c105859eSRandall Stewart sctp_misc_ints(SCTP_FLIGHT_LOG_UP_REVOKE, 4920c105859eSRandall Stewart tp1->whoTo->flight_size, 4921c105859eSRandall Stewart tp1->book_size, 49229a8e3088SMichael Tuexen (uint32_t)(uintptr_t)tp1->whoTo, 492349656eefSMichael Tuexen tp1->rec.data.tsn); 492480fefe0aSRandall Stewart } 4925c105859eSRandall Stewart sctp_flight_size_increase(tp1); 4926c105859eSRandall Stewart sctp_total_flight_increase(stcb, tp1); 4927a5d547adSRandall Stewart tp1->rec.data.chunk_was_revoked = 1; 492842551e99SRandall Stewart /* 492942551e99SRandall Stewart * To ensure that this increase in 49304a9ef3f8SMichael Tuexen * flightsize, which is artificial, does not 49314a9ef3f8SMichael Tuexen * throttle the sender, we also increase the 49324a9ef3f8SMichael Tuexen * cwnd artificially. 493342551e99SRandall Stewart */ 493442551e99SRandall Stewart tp1->whoTo->cwnd += tp1->book_size; 4935f8829a4aSRandall Stewart cnt_revoked++; 4936f8829a4aSRandall Stewart } 4937f8829a4aSRandall Stewart } 4938f8829a4aSRandall Stewart if (cnt_revoked) { 4939f8829a4aSRandall Stewart reneged_all = 1; 4940f8829a4aSRandall Stewart } 4941f8829a4aSRandall Stewart asoc->saw_sack_with_frags = 0; 4942f8829a4aSRandall Stewart } 4943d9c5cfeaSMichael Tuexen if (num_nr_seg > 0) 4944d9c5cfeaSMichael Tuexen asoc->saw_sack_with_nr_frags = 1; 4945f8829a4aSRandall Stewart else 4946d9c5cfeaSMichael Tuexen asoc->saw_sack_with_nr_frags = 0; 4947f8829a4aSRandall Stewart 4948b54d3a6cSRandall Stewart /* JRS - Use the congestion control given in the CC module */ 4949ca85e948SMichael Tuexen if (ecne_seen == 0) { 4950ca85e948SMichael Tuexen TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 4951ca85e948SMichael Tuexen if (net->net_ack2 > 0) { 4952ca85e948SMichael Tuexen /* 4953ca85e948SMichael Tuexen * Karn's rule applies to clearing error 4954ca85e948SMichael Tuexen * count, this is optional. 4955ca85e948SMichael Tuexen */ 4956ca85e948SMichael Tuexen net->error_count = 0; 4957ca85e948SMichael Tuexen if (!(net->dest_state & SCTP_ADDR_REACHABLE)) { 4958ca85e948SMichael Tuexen /* addr came good */ 4959ca85e948SMichael Tuexen net->dest_state |= SCTP_ADDR_REACHABLE; 4960ca85e948SMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 49614b1f78e1SMichael Tuexen 0, (void *)net, SCTP_SO_NOT_LOCKED); 4962ca85e948SMichael Tuexen } 4963*0053ed28SMichael Tuexen 4964ca85e948SMichael Tuexen if (net == stcb->asoc.primary_destination) { 4965ca85e948SMichael Tuexen if (stcb->asoc.alternate) { 4966b7b84c0eSMichael Tuexen /* 4967b7b84c0eSMichael Tuexen * release the alternate, 4968b7b84c0eSMichael Tuexen * primary is good 4969b7b84c0eSMichael Tuexen */ 4970ca85e948SMichael Tuexen sctp_free_remote_addr(stcb->asoc.alternate); 4971ca85e948SMichael Tuexen stcb->asoc.alternate = NULL; 4972ca85e948SMichael Tuexen } 4973ca85e948SMichael Tuexen } 4974*0053ed28SMichael Tuexen 4975ca85e948SMichael Tuexen if (net->dest_state & SCTP_ADDR_PF) { 4976ca85e948SMichael Tuexen net->dest_state &= ~SCTP_ADDR_PF; 4977b7d130beSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, 4978b7d130beSMichael Tuexen stcb->sctp_ep, stcb, net, 497944249214SRandall Stewart SCTP_FROM_SCTP_INDATA + SCTP_LOC_29); 4980ca85e948SMichael Tuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); 4981ca85e948SMichael Tuexen asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net); 4982ca85e948SMichael Tuexen /* Done with this net */ 4983ca85e948SMichael Tuexen net->net_ack = 0; 4984ca85e948SMichael Tuexen } 4985ca85e948SMichael Tuexen /* restore any doubled timers */ 4986ca85e948SMichael Tuexen net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv; 4987ca85e948SMichael Tuexen if (net->RTO < stcb->asoc.minrto) { 4988ca85e948SMichael Tuexen net->RTO = stcb->asoc.minrto; 4989ca85e948SMichael Tuexen } 4990ca85e948SMichael Tuexen if (net->RTO > stcb->asoc.maxrto) { 4991ca85e948SMichael Tuexen net->RTO = stcb->asoc.maxrto; 4992ca85e948SMichael Tuexen } 4993ca85e948SMichael Tuexen } 4994ca85e948SMichael Tuexen } 4995b54d3a6cSRandall Stewart asoc->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, accum_moved, reneged_all, will_exit_fast_recovery); 4996ca85e948SMichael Tuexen } 4997*0053ed28SMichael Tuexen 4998f8829a4aSRandall Stewart if (TAILQ_EMPTY(&asoc->sent_queue)) { 4999f8829a4aSRandall Stewart /* nothing left in-flight */ 5000f8829a4aSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 5001f8829a4aSRandall Stewart /* stop all timers */ 5002f8829a4aSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, 5003b7d130beSMichael Tuexen stcb, net, 500444249214SRandall Stewart SCTP_FROM_SCTP_INDATA + SCTP_LOC_30); 5005f8829a4aSRandall Stewart net->flight_size = 0; 5006f8829a4aSRandall Stewart net->partial_bytes_acked = 0; 5007f8829a4aSRandall Stewart } 5008f8829a4aSRandall Stewart asoc->total_flight = 0; 5009f8829a4aSRandall Stewart asoc->total_flight_count = 0; 5010f8829a4aSRandall Stewart } 5011*0053ed28SMichael Tuexen 5012f8829a4aSRandall Stewart /**********************************/ 5013f8829a4aSRandall Stewart /* Now what about shutdown issues */ 5014f8829a4aSRandall Stewart /**********************************/ 5015f8829a4aSRandall Stewart if (TAILQ_EMPTY(&asoc->send_queue) && TAILQ_EMPTY(&asoc->sent_queue)) { 5016f8829a4aSRandall Stewart /* nothing left on sendqueue.. consider done */ 5017b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) { 5018f8829a4aSRandall Stewart sctp_log_rwnd_set(SCTP_SET_PEER_RWND_VIA_SACK, 5019f8829a4aSRandall Stewart asoc->peers_rwnd, 0, 0, a_rwnd); 502080fefe0aSRandall Stewart } 5021f8829a4aSRandall Stewart asoc->peers_rwnd = a_rwnd; 5022f8829a4aSRandall Stewart if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) { 5023f8829a4aSRandall Stewart /* SWS sender side engages */ 5024f8829a4aSRandall Stewart asoc->peers_rwnd = 0; 5025f8829a4aSRandall Stewart } 5026f8829a4aSRandall Stewart /* clean up */ 5027f8829a4aSRandall Stewart if ((asoc->stream_queue_cnt == 1) && 5028f8829a4aSRandall Stewart ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) || 5029f8829a4aSRandall Stewart (asoc->state & SCTP_STATE_SHUTDOWN_RECEIVED)) && 5030d1ea5fa9SMichael Tuexen ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc))) { 50312afb3e84SRandall Stewart asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; 5032f8829a4aSRandall Stewart } 5033bbc9dfbcSMichael Tuexen if (((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) || 5034bbc9dfbcSMichael Tuexen (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) && 5035bbc9dfbcSMichael Tuexen (asoc->stream_queue_cnt == 1) && 5036bbc9dfbcSMichael Tuexen (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { 5037ff1ffd74SMichael Tuexen struct mbuf *op_err; 5038f8829a4aSRandall Stewart 5039f8829a4aSRandall Stewart *abort_now = 1; 5040f8829a4aSRandall Stewart /* XXX */ 5041ff1ffd74SMichael Tuexen op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, ""); 5042bbc9dfbcSMichael Tuexen stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_24; 5043ff1ffd74SMichael Tuexen sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); 5044f8829a4aSRandall Stewart return; 5045bbc9dfbcSMichael Tuexen } 5046bbc9dfbcSMichael Tuexen if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) && 5047bbc9dfbcSMichael Tuexen (asoc->stream_queue_cnt == 0)) { 5048ca85e948SMichael Tuexen struct sctp_nets *netp; 5049ca85e948SMichael Tuexen 5050f42a358aSRandall Stewart if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || 5051f42a358aSRandall Stewart (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 5052f8829a4aSRandall Stewart SCTP_STAT_DECR_GAUGE32(sctps_currestab); 5053f42a358aSRandall Stewart } 5054c4739e2fSRandall Stewart SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); 5055b201f536SRandall Stewart SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); 5056f8829a4aSRandall Stewart sctp_stop_timers_for_shutdown(stcb); 5057c39cfa1fSMichael Tuexen if (asoc->alternate) { 5058c39cfa1fSMichael Tuexen netp = asoc->alternate; 5059c39cfa1fSMichael Tuexen } else { 5060c39cfa1fSMichael Tuexen netp = asoc->primary_destination; 5061c39cfa1fSMichael Tuexen } 5062ca85e948SMichael Tuexen sctp_send_shutdown(stcb, netp); 5063f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 5064ca85e948SMichael Tuexen stcb->sctp_ep, stcb, netp); 5065f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 5066ca85e948SMichael Tuexen stcb->sctp_ep, stcb, netp); 5067f8829a4aSRandall Stewart return; 5068f8829a4aSRandall Stewart } else if ((SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) && 5069f8829a4aSRandall Stewart (asoc->stream_queue_cnt == 0)) { 5070ca85e948SMichael Tuexen struct sctp_nets *netp; 5071ca85e948SMichael Tuexen 5072f8829a4aSRandall Stewart SCTP_STAT_DECR_GAUGE32(sctps_currestab); 5073c4739e2fSRandall Stewart SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT); 5074b201f536SRandall Stewart SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); 507512af6654SMichael Tuexen sctp_stop_timers_for_shutdown(stcb); 5076c39cfa1fSMichael Tuexen if (asoc->alternate) { 5077c39cfa1fSMichael Tuexen netp = asoc->alternate; 5078c39cfa1fSMichael Tuexen } else { 5079c39cfa1fSMichael Tuexen netp = asoc->primary_destination; 5080c39cfa1fSMichael Tuexen } 5081c39cfa1fSMichael Tuexen sctp_send_shutdown_ack(stcb, netp); 5082f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, 5083ca85e948SMichael Tuexen stcb->sctp_ep, stcb, netp); 5084f8829a4aSRandall Stewart return; 5085f8829a4aSRandall Stewart } 5086f8829a4aSRandall Stewart } 5087f8829a4aSRandall Stewart /* 5088f8829a4aSRandall Stewart * Now here we are going to recycle net_ack for a different use... 5089f8829a4aSRandall Stewart * HEADS UP. 5090f8829a4aSRandall Stewart */ 5091f8829a4aSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 5092f8829a4aSRandall Stewart net->net_ack = 0; 5093f8829a4aSRandall Stewart } 5094f8829a4aSRandall Stewart 5095f8829a4aSRandall Stewart /* 5096f8829a4aSRandall Stewart * CMT DAC algorithm: If SACK DAC flag was 0, then no extra marking 5097f8829a4aSRandall Stewart * to be done. Setting this_sack_lowest_newack to the cum_ack will 5098f8829a4aSRandall Stewart * automatically ensure that. 5099f8829a4aSRandall Stewart */ 51007c99d56fSMichael Tuexen if ((asoc->sctp_cmt_on_off > 0) && 510120083c2eSMichael Tuexen SCTP_BASE_SYSCTL(sctp_cmt_use_dac) && 510220083c2eSMichael Tuexen (cmt_dac_flag == 0)) { 5103f8829a4aSRandall Stewart this_sack_lowest_newack = cum_ack; 5104f8829a4aSRandall Stewart } 5105cd554309SMichael Tuexen if ((num_seg > 0) || (num_nr_seg > 0)) { 5106f8829a4aSRandall Stewart sctp_strike_gap_ack_chunks(stcb, asoc, biggest_tsn_acked, 5107f8829a4aSRandall Stewart biggest_tsn_newly_acked, this_sack_lowest_newack, accum_moved); 5108f8829a4aSRandall Stewart } 5109b54d3a6cSRandall Stewart /* JRS - Use the congestion control given in the CC module */ 5110b54d3a6cSRandall Stewart asoc->cc_functions.sctp_cwnd_update_after_fr(stcb, asoc); 5111f8829a4aSRandall Stewart 5112f8829a4aSRandall Stewart /* Now are we exiting loss recovery ? */ 5113f8829a4aSRandall Stewart if (will_exit_fast_recovery) { 5114f8829a4aSRandall Stewart /* Ok, we must exit fast recovery */ 5115f8829a4aSRandall Stewart asoc->fast_retran_loss_recovery = 0; 5116f8829a4aSRandall Stewart } 5117f8829a4aSRandall Stewart if ((asoc->sat_t3_loss_recovery) && 511820b07a4dSMichael Tuexen SCTP_TSN_GE(asoc->last_acked_seq, asoc->sat_t3_recovery_tsn)) { 5119f8829a4aSRandall Stewart /* end satellite t3 loss recovery */ 5120f8829a4aSRandall Stewart asoc->sat_t3_loss_recovery = 0; 5121f8829a4aSRandall Stewart } 512242551e99SRandall Stewart /* 512342551e99SRandall Stewart * CMT Fast recovery 512442551e99SRandall Stewart */ 5125f8829a4aSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 5126f8829a4aSRandall Stewart if (net->will_exit_fast_recovery) { 5127f8829a4aSRandall Stewart /* Ok, we must exit fast recovery */ 5128f8829a4aSRandall Stewart net->fast_retran_loss_recovery = 0; 5129f8829a4aSRandall Stewart } 5130f8829a4aSRandall Stewart } 5131f8829a4aSRandall Stewart 5132f8829a4aSRandall Stewart /* Adjust and set the new rwnd value */ 5133b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) { 5134f8829a4aSRandall Stewart sctp_log_rwnd_set(SCTP_SET_PEER_RWND_VIA_SACK, 513544fbe462SRandall Stewart asoc->peers_rwnd, asoc->total_flight, (asoc->total_flight_count * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)), a_rwnd); 513680fefe0aSRandall Stewart } 5137f8829a4aSRandall Stewart asoc->peers_rwnd = sctp_sbspace_sub(a_rwnd, 513844fbe462SRandall Stewart (uint32_t)(asoc->total_flight + (asoc->total_flight_count * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)))); 5139f8829a4aSRandall Stewart if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) { 5140f8829a4aSRandall Stewart /* SWS sender side engages */ 5141f8829a4aSRandall Stewart asoc->peers_rwnd = 0; 5142f8829a4aSRandall Stewart } 51435e54f665SRandall Stewart if (asoc->peers_rwnd > old_rwnd) { 51445e54f665SRandall Stewart win_probe_recovery = 1; 51455e54f665SRandall Stewart } 5146*0053ed28SMichael Tuexen 5147f8829a4aSRandall Stewart /* 5148f8829a4aSRandall Stewart * Now we must setup so we have a timer up for anyone with 5149f8829a4aSRandall Stewart * outstanding data. 5150f8829a4aSRandall Stewart */ 5151bff64a4dSRandall Stewart done_once = 0; 5152a5d547adSRandall Stewart again: 5153a5d547adSRandall Stewart j = 0; 5154f8829a4aSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 51555e54f665SRandall Stewart if (win_probe_recovery && (net->window_probe)) { 5156c105859eSRandall Stewart win_probe_recovered = 1; 51575e54f665SRandall Stewart /*- 51585e54f665SRandall Stewart * Find first chunk that was used with 51595e54f665SRandall Stewart * window probe and clear the event. Put 51605e54f665SRandall Stewart * it back into the send queue as if has 51615e54f665SRandall Stewart * not been sent. 51625e54f665SRandall Stewart */ 51635e54f665SRandall Stewart TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) { 51645e54f665SRandall Stewart if (tp1->window_probe) { 51657215cc1bSMichael Tuexen sctp_window_probe_recovery(stcb, asoc, tp1); 51665e54f665SRandall Stewart break; 51675e54f665SRandall Stewart } 51685e54f665SRandall Stewart } 51695e54f665SRandall Stewart } 5170f8829a4aSRandall Stewart if (net->flight_size) { 5171a5d547adSRandall Stewart j++; 5172cd554309SMichael Tuexen if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { 5173f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SEND, 5174f8829a4aSRandall Stewart stcb->sctp_ep, stcb, net); 5175cd554309SMichael Tuexen } 51765171328bSRandall Stewart if (net->window_probe) { 5177cd554309SMichael Tuexen net->window_probe = 0; 51785171328bSRandall Stewart } 5179c105859eSRandall Stewart } else { 51805171328bSRandall Stewart if (net->window_probe) { 5181b7b84c0eSMichael Tuexen /* 5182b7b84c0eSMichael Tuexen * In window probes we must assure a timer 5183b7b84c0eSMichael Tuexen * is still running there 5184b7b84c0eSMichael Tuexen */ 51855171328bSRandall Stewart if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { 51865171328bSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SEND, 51875171328bSRandall Stewart stcb->sctp_ep, stcb, net); 51885171328bSRandall Stewart 51895171328bSRandall Stewart } 51905171328bSRandall Stewart } else if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { 5191c105859eSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, 5192c105859eSRandall Stewart stcb, net, 519344249214SRandall Stewart SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); 5194c105859eSRandall Stewart } 5195f8829a4aSRandall Stewart } 5196f8829a4aSRandall Stewart } 5197bff64a4dSRandall Stewart if ((j == 0) && 5198bff64a4dSRandall Stewart (!TAILQ_EMPTY(&asoc->sent_queue)) && 5199bff64a4dSRandall Stewart (asoc->sent_queue_retran_cnt == 0) && 5200c105859eSRandall Stewart (win_probe_recovered == 0) && 5201bff64a4dSRandall Stewart (done_once == 0)) { 52020c0982b8SRandall Stewart /* 52030c0982b8SRandall Stewart * huh, this should not happen unless all packets are 52040c0982b8SRandall Stewart * PR-SCTP and marked to skip of course. 52050c0982b8SRandall Stewart */ 52060c0982b8SRandall Stewart if (sctp_fs_audit(asoc)) { 5207a5d547adSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 5208a5d547adSRandall Stewart net->flight_size = 0; 5209a5d547adSRandall Stewart } 5210a5d547adSRandall Stewart asoc->total_flight = 0; 5211a5d547adSRandall Stewart asoc->total_flight_count = 0; 5212a5d547adSRandall Stewart asoc->sent_queue_retran_cnt = 0; 5213a5d547adSRandall Stewart TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) { 5214a5d547adSRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND) { 5215c105859eSRandall Stewart sctp_flight_size_increase(tp1); 5216c105859eSRandall Stewart sctp_total_flight_increase(stcb, tp1); 5217a5d547adSRandall Stewart } else if (tp1->sent == SCTP_DATAGRAM_RESEND) { 5218791437b5SRandall Stewart sctp_ucount_incr(asoc->sent_queue_retran_cnt); 5219a5d547adSRandall Stewart } 5220a5d547adSRandall Stewart } 52210c0982b8SRandall Stewart } 5222bff64a4dSRandall Stewart done_once = 1; 5223a5d547adSRandall Stewart goto again; 5224a5d547adSRandall Stewart } 5225cd554309SMichael Tuexen /*********************************************/ 5226cd554309SMichael Tuexen /* Here we perform PR-SCTP procedures */ 5227cd554309SMichael Tuexen /* (section 4.2) */ 5228cd554309SMichael Tuexen /*********************************************/ 5229cd554309SMichael Tuexen /* C1. update advancedPeerAckPoint */ 523020b07a4dSMichael Tuexen if (SCTP_TSN_GT(cum_ack, asoc->advanced_peer_ack_point)) { 5231dfb11ef8SRandall Stewart asoc->advanced_peer_ack_point = cum_ack; 5232dfb11ef8SRandall Stewart } 5233830d754dSRandall Stewart /* C2. try to further move advancedPeerAckPoint ahead */ 5234dd973b0eSMichael Tuexen if ((asoc->prsctp_supported) && (asoc->pr_sctp_cnt > 0)) { 5235830d754dSRandall Stewart struct sctp_tmit_chunk *lchk; 5236830d754dSRandall Stewart uint32_t old_adv_peer_ack_point; 5237830d754dSRandall Stewart 5238830d754dSRandall Stewart old_adv_peer_ack_point = asoc->advanced_peer_ack_point; 5239830d754dSRandall Stewart lchk = sctp_try_advance_peer_ack_point(stcb, asoc); 5240830d754dSRandall Stewart /* C3. See if we need to send a Fwd-TSN */ 524120b07a4dSMichael Tuexen if (SCTP_TSN_GT(asoc->advanced_peer_ack_point, cum_ack)) { 5242830d754dSRandall Stewart /* 5243493d8e5aSRandall Stewart * ISSUE with ECN, see FWD-TSN processing. 5244830d754dSRandall Stewart */ 52450c0982b8SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) { 52460c0982b8SRandall Stewart sctp_misc_ints(SCTP_FWD_TSN_CHECK, 52470c0982b8SRandall Stewart 0xee, cum_ack, asoc->advanced_peer_ack_point, 52480c0982b8SRandall Stewart old_adv_peer_ack_point); 52490c0982b8SRandall Stewart } 525020b07a4dSMichael Tuexen if (SCTP_TSN_GT(asoc->advanced_peer_ack_point, old_adv_peer_ack_point)) { 5251830d754dSRandall Stewart send_forward_tsn(stcb, asoc); 52520c0982b8SRandall Stewart } else if (lchk) { 52530c0982b8SRandall Stewart /* try to FR fwd-tsn's that get lost too */ 525444fbe462SRandall Stewart if (lchk->rec.data.fwd_tsn_cnt >= 3) { 52550c0982b8SRandall Stewart send_forward_tsn(stcb, asoc); 52560c0982b8SRandall Stewart } 5257830d754dSRandall Stewart } 5258830d754dSRandall Stewart } 5259830d754dSRandall Stewart if (lchk) { 5260830d754dSRandall Stewart /* Assure a timer is up */ 5261830d754dSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SEND, 5262830d754dSRandall Stewart stcb->sctp_ep, stcb, lchk->whoTo); 5263830d754dSRandall Stewart } 5264830d754dSRandall Stewart } 5265b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_RWND_LOGGING_ENABLE) { 5266f8829a4aSRandall Stewart sctp_misc_ints(SCTP_SACK_RWND_UPDATE, 5267f8829a4aSRandall Stewart a_rwnd, 5268f8829a4aSRandall Stewart stcb->asoc.peers_rwnd, 5269f8829a4aSRandall Stewart stcb->asoc.total_flight, 5270f8829a4aSRandall Stewart stcb->asoc.total_output_queue_size); 527180fefe0aSRandall Stewart } 5272f8829a4aSRandall Stewart } 5273f8829a4aSRandall Stewart 5274f8829a4aSRandall Stewart void 52757215cc1bSMichael Tuexen sctp_update_acked(struct sctp_tcb *stcb, struct sctp_shutdown_chunk *cp, int *abort_flag) 5276f8829a4aSRandall Stewart { 5277f8829a4aSRandall Stewart /* Copy cum-ack */ 5278f8829a4aSRandall Stewart uint32_t cum_ack, a_rwnd; 5279f8829a4aSRandall Stewart 5280f8829a4aSRandall Stewart cum_ack = ntohl(cp->cumulative_tsn_ack); 5281f8829a4aSRandall Stewart /* Arrange so a_rwnd does NOT change */ 5282f8829a4aSRandall Stewart a_rwnd = stcb->asoc.peers_rwnd + stcb->asoc.total_flight; 5283f8829a4aSRandall Stewart 5284f8829a4aSRandall Stewart /* Now call the express sack handling */ 5285899288aeSRandall Stewart sctp_express_handle_sack(stcb, cum_ack, a_rwnd, abort_flag, 0); 5286f8829a4aSRandall Stewart } 5287f8829a4aSRandall Stewart 5288f8829a4aSRandall Stewart static void 5289f8829a4aSRandall Stewart sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb, 5290f8829a4aSRandall Stewart struct sctp_stream_in *strmin) 5291f8829a4aSRandall Stewart { 529228cd0699SMichael Tuexen struct sctp_queued_to_read *control, *ncontrol; 5293f8829a4aSRandall Stewart struct sctp_association *asoc; 529449656eefSMichael Tuexen uint32_t mid; 529549656eefSMichael Tuexen int need_reasm_check = 0; 5296f8829a4aSRandall Stewart 5297f8829a4aSRandall Stewart asoc = &stcb->asoc; 529849656eefSMichael Tuexen mid = strmin->last_mid_delivered; 5299f8829a4aSRandall Stewart /* 5300f8829a4aSRandall Stewart * First deliver anything prior to and including the stream no that 530144249214SRandall Stewart * came in. 5302f8829a4aSRandall Stewart */ 530328cd0699SMichael Tuexen TAILQ_FOREACH_SAFE(control, &strmin->inqueue, next_instrm, ncontrol) { 530428cd0699SMichael Tuexen if (SCTP_MID_GE(asoc->idata_supported, mid, control->mid)) { 5305f8829a4aSRandall Stewart /* this is deliverable now */ 530628cd0699SMichael Tuexen if (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) { 530728cd0699SMichael Tuexen if (control->on_strm_q) { 530828cd0699SMichael Tuexen if (control->on_strm_q == SCTP_ON_ORDERED) { 530928cd0699SMichael Tuexen TAILQ_REMOVE(&strmin->inqueue, control, next_instrm); 531028cd0699SMichael Tuexen } else if (control->on_strm_q == SCTP_ON_UNORDERED) { 531128cd0699SMichael Tuexen TAILQ_REMOVE(&strmin->uno_inqueue, control, next_instrm); 531298d5fd97SMichael Tuexen #ifdef INVARIANTS 531344249214SRandall Stewart } else { 531444249214SRandall Stewart panic("strmin: %p ctl: %p unknown %d", 531528cd0699SMichael Tuexen strmin, control, control->on_strm_q); 531698d5fd97SMichael Tuexen #endif 531744249214SRandall Stewart } 531828cd0699SMichael Tuexen control->on_strm_q = 0; 531944249214SRandall Stewart } 5320f8829a4aSRandall Stewart /* subtract pending on streams */ 532128cd0699SMichael Tuexen if (asoc->size_on_all_streams >= control->length) { 532228cd0699SMichael Tuexen asoc->size_on_all_streams -= control->length; 532328cd0699SMichael Tuexen } else { 532428cd0699SMichael Tuexen #ifdef INVARIANTS 532528cd0699SMichael Tuexen panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length); 532628cd0699SMichael Tuexen #else 532728cd0699SMichael Tuexen asoc->size_on_all_streams = 0; 532828cd0699SMichael Tuexen #endif 532928cd0699SMichael Tuexen } 5330f8829a4aSRandall Stewart sctp_ucount_decr(asoc->cnt_on_all_streams); 5331f8829a4aSRandall Stewart /* deliver it to at least the delivery-q */ 5332f8829a4aSRandall Stewart if (stcb->sctp_socket) { 533328cd0699SMichael Tuexen sctp_mark_non_revokable(asoc, control->sinfo_tsn); 5334f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 533528cd0699SMichael Tuexen control, 533644249214SRandall Stewart &stcb->sctp_socket->so_rcv, 533744249214SRandall Stewart 1, SCTP_READ_LOCK_HELD, 533844249214SRandall Stewart SCTP_SO_NOT_LOCKED); 533944249214SRandall Stewart } 534044249214SRandall Stewart } else { 534144249214SRandall Stewart /* Its a fragmented message */ 534228cd0699SMichael Tuexen if (control->first_frag_seen) { 5343b7b84c0eSMichael Tuexen /* 5344b7b84c0eSMichael Tuexen * Make it so this is next to 5345b7b84c0eSMichael Tuexen * deliver, we restore later 5346b7b84c0eSMichael Tuexen */ 534728cd0699SMichael Tuexen strmin->last_mid_delivered = control->mid - 1; 534844249214SRandall Stewart need_reasm_check = 1; 534944249214SRandall Stewart break; 535044249214SRandall Stewart } 5351f8829a4aSRandall Stewart } 5352f8829a4aSRandall Stewart } else { 5353f8829a4aSRandall Stewart /* no more delivery now. */ 5354f8829a4aSRandall Stewart break; 5355f8829a4aSRandall Stewart } 5356f8829a4aSRandall Stewart } 535744249214SRandall Stewart if (need_reasm_check) { 535844249214SRandall Stewart int ret; 535944249214SRandall Stewart 5360d1ea5fa9SMichael Tuexen ret = sctp_deliver_reasm_check(stcb, &stcb->asoc, strmin, SCTP_READ_LOCK_HELD); 536149656eefSMichael Tuexen if (SCTP_MID_GT(asoc->idata_supported, mid, strmin->last_mid_delivered)) { 536244249214SRandall Stewart /* Restore the next to deliver unless we are ahead */ 536349656eefSMichael Tuexen strmin->last_mid_delivered = mid; 536444249214SRandall Stewart } 536544249214SRandall Stewart if (ret == 0) { 536644249214SRandall Stewart /* Left the front Partial one on */ 536744249214SRandall Stewart return; 536844249214SRandall Stewart } 536944249214SRandall Stewart need_reasm_check = 0; 537044249214SRandall Stewart } 5371f8829a4aSRandall Stewart /* 5372f8829a4aSRandall Stewart * now we must deliver things in queue the normal way if any are 5373f8829a4aSRandall Stewart * now ready. 5374f8829a4aSRandall Stewart */ 537549656eefSMichael Tuexen mid = strmin->last_mid_delivered + 1; 537628cd0699SMichael Tuexen TAILQ_FOREACH_SAFE(control, &strmin->inqueue, next_instrm, ncontrol) { 537728cd0699SMichael Tuexen if (SCTP_MID_EQ(asoc->idata_supported, mid, control->mid)) { 537828cd0699SMichael Tuexen if (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) { 5379f8829a4aSRandall Stewart /* this is deliverable now */ 538028cd0699SMichael Tuexen if (control->on_strm_q) { 538128cd0699SMichael Tuexen if (control->on_strm_q == SCTP_ON_ORDERED) { 538228cd0699SMichael Tuexen TAILQ_REMOVE(&strmin->inqueue, control, next_instrm); 538328cd0699SMichael Tuexen } else if (control->on_strm_q == SCTP_ON_UNORDERED) { 538428cd0699SMichael Tuexen TAILQ_REMOVE(&strmin->uno_inqueue, control, next_instrm); 538598d5fd97SMichael Tuexen #ifdef INVARIANTS 538644249214SRandall Stewart } else { 538744249214SRandall Stewart panic("strmin: %p ctl: %p unknown %d", 538828cd0699SMichael Tuexen strmin, control, control->on_strm_q); 538998d5fd97SMichael Tuexen #endif 539044249214SRandall Stewart } 539128cd0699SMichael Tuexen control->on_strm_q = 0; 539244249214SRandall Stewart } 5393f8829a4aSRandall Stewart /* subtract pending on streams */ 539428cd0699SMichael Tuexen if (asoc->size_on_all_streams >= control->length) { 539528cd0699SMichael Tuexen asoc->size_on_all_streams -= control->length; 539628cd0699SMichael Tuexen } else { 539728cd0699SMichael Tuexen #ifdef INVARIANTS 539828cd0699SMichael Tuexen panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length); 539928cd0699SMichael Tuexen #else 540028cd0699SMichael Tuexen asoc->size_on_all_streams = 0; 540128cd0699SMichael Tuexen #endif 540228cd0699SMichael Tuexen } 5403f8829a4aSRandall Stewart sctp_ucount_decr(asoc->cnt_on_all_streams); 5404f8829a4aSRandall Stewart /* deliver it to at least the delivery-q */ 540528cd0699SMichael Tuexen strmin->last_mid_delivered = control->mid; 5406f8829a4aSRandall Stewart if (stcb->sctp_socket) { 540728cd0699SMichael Tuexen sctp_mark_non_revokable(asoc, control->sinfo_tsn); 5408f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 540928cd0699SMichael Tuexen control, 541044249214SRandall Stewart &stcb->sctp_socket->so_rcv, 1, 541144249214SRandall Stewart SCTP_READ_LOCK_HELD, SCTP_SO_NOT_LOCKED); 541277acdc25SRandall Stewart 5413f8829a4aSRandall Stewart } 541449656eefSMichael Tuexen mid = strmin->last_mid_delivered + 1; 5415f8829a4aSRandall Stewart } else { 541644249214SRandall Stewart /* Its a fragmented message */ 541728cd0699SMichael Tuexen if (control->first_frag_seen) { 5418b7b84c0eSMichael Tuexen /* 5419b7b84c0eSMichael Tuexen * Make it so this is next to 5420b7b84c0eSMichael Tuexen * deliver 5421b7b84c0eSMichael Tuexen */ 542228cd0699SMichael Tuexen strmin->last_mid_delivered = control->mid - 1; 542344249214SRandall Stewart need_reasm_check = 1; 5424f8829a4aSRandall Stewart break; 5425f8829a4aSRandall Stewart } 5426f8829a4aSRandall Stewart } 542744249214SRandall Stewart } else { 542844249214SRandall Stewart break; 542944249214SRandall Stewart } 543044249214SRandall Stewart } 543144249214SRandall Stewart if (need_reasm_check) { 5432d1ea5fa9SMichael Tuexen (void)sctp_deliver_reasm_check(stcb, &stcb->asoc, strmin, SCTP_READ_LOCK_HELD); 543344249214SRandall Stewart } 5434f8829a4aSRandall Stewart } 5435f8829a4aSRandall Stewart 54368e1b295fSMichael Tuexen 5437d1ea5fa9SMichael Tuexen 54388933fa13SRandall Stewart static void 54398933fa13SRandall Stewart sctp_flush_reassm_for_str_seq(struct sctp_tcb *stcb, 54408933fa13SRandall Stewart struct sctp_association *asoc, 544149656eefSMichael Tuexen uint16_t stream, uint32_t mid, int ordered, uint32_t cumtsn) 54428933fa13SRandall Stewart { 544344249214SRandall Stewart struct sctp_queued_to_read *control; 544444249214SRandall Stewart struct sctp_stream_in *strm; 54454a9ef3f8SMichael Tuexen struct sctp_tmit_chunk *chk, *nchk; 5446d1ea5fa9SMichael Tuexen int cnt_removed = 0; 54478933fa13SRandall Stewart 54488933fa13SRandall Stewart /* 544944249214SRandall Stewart * For now large messages held on the stream reasm that are complete 54504a9ef3f8SMichael Tuexen * will be tossed too. We could in theory do more work to spin 54514a9ef3f8SMichael Tuexen * through and stop after dumping one msg aka seeing the start of a 54524a9ef3f8SMichael Tuexen * new msg at the head, and call the delivery function... to see if 54534a9ef3f8SMichael Tuexen * it can be delivered... But for now we just dump everything on the 54544a9ef3f8SMichael Tuexen * queue. 54558933fa13SRandall Stewart */ 545644249214SRandall Stewart strm = &asoc->strmin[stream]; 545749656eefSMichael Tuexen control = sctp_find_reasm_entry(strm, mid, ordered, asoc->idata_supported); 545844249214SRandall Stewart if (control == NULL) { 545944249214SRandall Stewart /* Not found */ 546044249214SRandall Stewart return; 54618933fa13SRandall Stewart } 546249656eefSMichael Tuexen if (!asoc->idata_supported && !ordered && SCTP_TSN_GT(control->fsn_included, cumtsn)) { 54635cb91655SMichael Tuexen return; 54645cb91655SMichael Tuexen } 546544249214SRandall Stewart TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) { 546644249214SRandall Stewart /* Purge hanging chunks */ 546749656eefSMichael Tuexen if (!asoc->idata_supported && (ordered == 0)) { 546849656eefSMichael Tuexen if (SCTP_TSN_GT(chk->rec.data.tsn, cumtsn)) { 5469d1ea5fa9SMichael Tuexen break; 5470d1ea5fa9SMichael Tuexen } 5471d1ea5fa9SMichael Tuexen } 5472d1ea5fa9SMichael Tuexen cnt_removed++; 547344249214SRandall Stewart TAILQ_REMOVE(&control->reasm, chk, sctp_next); 547428cd0699SMichael Tuexen if (asoc->size_on_reasm_queue >= chk->send_size) { 54758933fa13SRandall Stewart asoc->size_on_reasm_queue -= chk->send_size; 547628cd0699SMichael Tuexen } else { 547728cd0699SMichael Tuexen #ifdef INVARIANTS 547828cd0699SMichael Tuexen panic("size_on_reasm_queue = %u smaller than chunk length %u", asoc->size_on_reasm_queue, chk->send_size); 547928cd0699SMichael Tuexen #else 548028cd0699SMichael Tuexen asoc->size_on_reasm_queue = 0; 548128cd0699SMichael Tuexen #endif 548228cd0699SMichael Tuexen } 54838933fa13SRandall Stewart sctp_ucount_decr(asoc->cnt_on_reasm_queue); 54848933fa13SRandall Stewart if (chk->data) { 54858933fa13SRandall Stewart sctp_m_freem(chk->data); 54868933fa13SRandall Stewart chk->data = NULL; 54878933fa13SRandall Stewart } 5488689e6a5fSMichael Tuexen sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); 54898933fa13SRandall Stewart } 5490d1ea5fa9SMichael Tuexen if (!TAILQ_EMPTY(&control->reasm)) { 5491d1ea5fa9SMichael Tuexen /* This has to be old data, unordered */ 5492d1ea5fa9SMichael Tuexen if (control->data) { 5493d1ea5fa9SMichael Tuexen sctp_m_freem(control->data); 5494d1ea5fa9SMichael Tuexen control->data = NULL; 5495d1ea5fa9SMichael Tuexen } 5496d1ea5fa9SMichael Tuexen sctp_reset_a_control(control, stcb->sctp_ep, cumtsn); 5497d1ea5fa9SMichael Tuexen chk = TAILQ_FIRST(&control->reasm); 5498d1ea5fa9SMichael Tuexen if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { 5499d1ea5fa9SMichael Tuexen TAILQ_REMOVE(&control->reasm, chk, sctp_next); 5500d1ea5fa9SMichael Tuexen sctp_add_chk_to_control(control, strm, stcb, asoc, 5501d1ea5fa9SMichael Tuexen chk, SCTP_READ_LOCK_HELD); 5502d1ea5fa9SMichael Tuexen } 5503d1ea5fa9SMichael Tuexen sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_HELD); 5504d1ea5fa9SMichael Tuexen return; 5505d1ea5fa9SMichael Tuexen } 5506d1ea5fa9SMichael Tuexen if (control->on_strm_q == SCTP_ON_ORDERED) { 550744249214SRandall Stewart TAILQ_REMOVE(&strm->inqueue, control, next_instrm); 550828cd0699SMichael Tuexen if (asoc->size_on_all_streams >= control->length) { 550928cd0699SMichael Tuexen asoc->size_on_all_streams -= control->length; 551028cd0699SMichael Tuexen } else { 551128cd0699SMichael Tuexen #ifdef INVARIANTS 551228cd0699SMichael Tuexen panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length); 551328cd0699SMichael Tuexen #else 551428cd0699SMichael Tuexen asoc->size_on_all_streams = 0; 551528cd0699SMichael Tuexen #endif 551628cd0699SMichael Tuexen } 551728cd0699SMichael Tuexen sctp_ucount_decr(asoc->cnt_on_all_streams); 5518d1ea5fa9SMichael Tuexen control->on_strm_q = 0; 5519d1ea5fa9SMichael Tuexen } else if (control->on_strm_q == SCTP_ON_UNORDERED) { 5520d1ea5fa9SMichael Tuexen TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm); 5521d1ea5fa9SMichael Tuexen control->on_strm_q = 0; 5522d1ea5fa9SMichael Tuexen #ifdef INVARIANTS 5523d1ea5fa9SMichael Tuexen } else if (control->on_strm_q) { 5524d1ea5fa9SMichael Tuexen panic("strm: %p ctl: %p unknown %d", 5525d1ea5fa9SMichael Tuexen strm, control, control->on_strm_q); 5526d1ea5fa9SMichael Tuexen #endif 5527d1ea5fa9SMichael Tuexen } 5528d1ea5fa9SMichael Tuexen control->on_strm_q = 0; 552944249214SRandall Stewart if (control->on_read_q == 0) { 553044249214SRandall Stewart sctp_free_remote_addr(control->whoFrom); 553144249214SRandall Stewart if (control->data) { 553244249214SRandall Stewart sctp_m_freem(control->data); 553344249214SRandall Stewart control->data = NULL; 553444249214SRandall Stewart } 553544249214SRandall Stewart sctp_free_a_readq(stcb, control); 55368933fa13SRandall Stewart } 55378933fa13SRandall Stewart } 55388933fa13SRandall Stewart 5539f8829a4aSRandall Stewart void 5540f8829a4aSRandall Stewart sctp_handle_forward_tsn(struct sctp_tcb *stcb, 5541b5c16493SMichael Tuexen struct sctp_forward_tsn_chunk *fwd, 5542b5c16493SMichael Tuexen int *abort_flag, struct mbuf *m, int offset) 5543f8829a4aSRandall Stewart { 5544f8829a4aSRandall Stewart /* The pr-sctp fwd tsn */ 5545f8829a4aSRandall Stewart /* 5546f8829a4aSRandall Stewart * here we will perform all the data receiver side steps for 5547f8829a4aSRandall Stewart * processing FwdTSN, as required in by pr-sctp draft: 5548f8829a4aSRandall Stewart * 5549f8829a4aSRandall Stewart * Assume we get FwdTSN(x): 5550f8829a4aSRandall Stewart * 55515b495f17SMichael Tuexen * 1) update local cumTSN to x 2) try to further advance cumTSN to x 55525b495f17SMichael Tuexen * + others we have 3) examine and update re-ordering queue on 5553f8829a4aSRandall Stewart * pr-in-streams 4) clean up re-assembly queue 5) Send a sack to 5554f8829a4aSRandall Stewart * report where we are. 5555f8829a4aSRandall Stewart */ 5556f8829a4aSRandall Stewart struct sctp_association *asoc; 55577898f408SRandall Stewart uint32_t new_cum_tsn, gap; 55587215cc1bSMichael Tuexen unsigned int i, fwd_sz, m_size; 55598933fa13SRandall Stewart uint32_t str_seq; 5560f8829a4aSRandall Stewart struct sctp_stream_in *strm; 556128cd0699SMichael Tuexen struct sctp_queued_to_read *control, *sv; 5562f8829a4aSRandall Stewart 5563f8829a4aSRandall Stewart asoc = &stcb->asoc; 5564f8829a4aSRandall Stewart if ((fwd_sz = ntohs(fwd->ch.chunk_length)) < sizeof(struct sctp_forward_tsn_chunk)) { 5565ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_INDATA1, 5566ad81507eSRandall Stewart "Bad size too small/big fwd-tsn\n"); 5567f8829a4aSRandall Stewart return; 5568f8829a4aSRandall Stewart } 5569f8829a4aSRandall Stewart m_size = (stcb->asoc.mapping_array_size << 3); 5570f8829a4aSRandall Stewart /*************************************************************/ 5571f8829a4aSRandall Stewart /* 1. Here we update local cumTSN and shift the bitmap array */ 5572f8829a4aSRandall Stewart /*************************************************************/ 5573f8829a4aSRandall Stewart new_cum_tsn = ntohl(fwd->new_cumulative_tsn); 5574f8829a4aSRandall Stewart 557520b07a4dSMichael Tuexen if (SCTP_TSN_GE(asoc->cumulative_tsn, new_cum_tsn)) { 5576f8829a4aSRandall Stewart /* Already got there ... */ 5577f8829a4aSRandall Stewart return; 5578f8829a4aSRandall Stewart } 5579f8829a4aSRandall Stewart /* 5580f8829a4aSRandall Stewart * now we know the new TSN is more advanced, let's find the actual 5581f8829a4aSRandall Stewart * gap 5582f8829a4aSRandall Stewart */ 5583b5c16493SMichael Tuexen SCTP_CALC_TSN_TO_GAP(gap, new_cum_tsn, asoc->mapping_array_base_tsn); 558477acdc25SRandall Stewart asoc->cumulative_tsn = new_cum_tsn; 55852afb3e84SRandall Stewart if (gap >= m_size) { 5586f8829a4aSRandall Stewart if ((long)gap > sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv)) { 5587ff1ffd74SMichael Tuexen struct mbuf *op_err; 5588ff1ffd74SMichael Tuexen char msg[SCTP_DIAG_INFO_LEN]; 558917205eccSRandall Stewart 5590f8829a4aSRandall Stewart /* 5591f8829a4aSRandall Stewart * out of range (of single byte chunks in the rwnd I 559217205eccSRandall Stewart * give out). This must be an attacker. 5593f8829a4aSRandall Stewart */ 559417205eccSRandall Stewart *abort_flag = 1; 5595ff1ffd74SMichael Tuexen snprintf(msg, sizeof(msg), 5596ff1ffd74SMichael Tuexen "New cum ack %8.8x too high, highest TSN %8.8x", 5597ff1ffd74SMichael Tuexen new_cum_tsn, asoc->highest_tsn_inside_map); 5598ff1ffd74SMichael Tuexen op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); 559944249214SRandall Stewart stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_33; 5600ff1ffd74SMichael Tuexen sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); 5601f8829a4aSRandall Stewart return; 5602f8829a4aSRandall Stewart } 5603207304d4SRandall Stewart SCTP_STAT_INCR(sctps_fwdtsn_map_over); 560477acdc25SRandall Stewart 56052afb3e84SRandall Stewart memset(stcb->asoc.mapping_array, 0, stcb->asoc.mapping_array_size); 56062afb3e84SRandall Stewart asoc->mapping_array_base_tsn = new_cum_tsn + 1; 560777acdc25SRandall Stewart asoc->highest_tsn_inside_map = new_cum_tsn; 560877acdc25SRandall Stewart 5609b5c16493SMichael Tuexen memset(stcb->asoc.nr_mapping_array, 0, stcb->asoc.mapping_array_size); 5610830d754dSRandall Stewart asoc->highest_tsn_inside_nr_map = new_cum_tsn; 561177acdc25SRandall Stewart 5612b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) { 5613f8829a4aSRandall Stewart sctp_log_map(0, 3, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT); 561480fefe0aSRandall Stewart } 56152afb3e84SRandall Stewart } else { 56162afb3e84SRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 56172afb3e84SRandall Stewart for (i = 0; i <= gap; i++) { 56187898f408SRandall Stewart if (!SCTP_IS_TSN_PRESENT(asoc->mapping_array, i) && 56197898f408SRandall Stewart !SCTP_IS_TSN_PRESENT(asoc->nr_mapping_array, i)) { 56208933fa13SRandall Stewart SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, i); 562120b07a4dSMichael Tuexen if (SCTP_TSN_GT(asoc->mapping_array_base_tsn + i, asoc->highest_tsn_inside_nr_map)) { 56227898f408SRandall Stewart asoc->highest_tsn_inside_nr_map = asoc->mapping_array_base_tsn + i; 5623b5c16493SMichael Tuexen } 5624b5c16493SMichael Tuexen } 5625b5c16493SMichael Tuexen } 5626f8829a4aSRandall Stewart } 5627f8829a4aSRandall Stewart /*************************************************************/ 5628f8829a4aSRandall Stewart /* 2. Clear up re-assembly queue */ 5629f8829a4aSRandall Stewart /*************************************************************/ 5630f8829a4aSRandall Stewart 563144249214SRandall Stewart /* This is now done as part of clearing up the stream/seq */ 5632d1ea5fa9SMichael Tuexen if (asoc->idata_supported == 0) { 5633d1ea5fa9SMichael Tuexen uint16_t sid; 563444249214SRandall Stewart 5635d1ea5fa9SMichael Tuexen /* Flush all the un-ordered data based on cum-tsn */ 5636d1ea5fa9SMichael Tuexen SCTP_INP_READ_LOCK(stcb->sctp_ep); 5637d1ea5fa9SMichael Tuexen for (sid = 0; sid < asoc->streamincnt; sid++) { 563849656eefSMichael Tuexen sctp_flush_reassm_for_str_seq(stcb, asoc, sid, 0, 0, new_cum_tsn); 5639d1ea5fa9SMichael Tuexen } 5640d1ea5fa9SMichael Tuexen SCTP_INP_READ_UNLOCK(stcb->sctp_ep); 5641d1ea5fa9SMichael Tuexen } 56428933fa13SRandall Stewart /*******************************************************/ 56438933fa13SRandall Stewart /* 3. Update the PR-stream re-ordering queues and fix */ 56448933fa13SRandall Stewart /* delivery issues as needed. */ 56458933fa13SRandall Stewart /*******************************************************/ 5646f8829a4aSRandall Stewart fwd_sz -= sizeof(*fwd); 5647671d309cSRandall Stewart if (m && fwd_sz) { 5648f8829a4aSRandall Stewart /* New method. */ 5649d61a0ae0SRandall Stewart unsigned int num_str; 565049656eefSMichael Tuexen uint32_t mid, cur_mid; 565149656eefSMichael Tuexen uint16_t sid; 56528e1b295fSMichael Tuexen uint16_t ordered, flags; 5653671d309cSRandall Stewart struct sctp_strseq *stseq, strseqbuf; 565444249214SRandall Stewart struct sctp_strseq_mid *stseq_m, strseqbuf_m; 5655671d309cSRandall Stewart 5656671d309cSRandall Stewart offset += sizeof(*fwd); 5657f8829a4aSRandall Stewart 56588933fa13SRandall Stewart SCTP_INP_READ_LOCK(stcb->sctp_ep); 565944249214SRandall Stewart if (asoc->idata_supported) { 566044249214SRandall Stewart num_str = fwd_sz / sizeof(struct sctp_strseq_mid); 566144249214SRandall Stewart } else { 5662f8829a4aSRandall Stewart num_str = fwd_sz / sizeof(struct sctp_strseq); 566344249214SRandall Stewart } 5664f8829a4aSRandall Stewart for (i = 0; i < num_str; i++) { 566544249214SRandall Stewart if (asoc->idata_supported) { 566644249214SRandall Stewart stseq_m = (struct sctp_strseq_mid *)sctp_m_getptr(m, offset, 566744249214SRandall Stewart sizeof(struct sctp_strseq_mid), 566844249214SRandall Stewart (uint8_t *)&strseqbuf_m); 566944249214SRandall Stewart offset += sizeof(struct sctp_strseq_mid); 567044249214SRandall Stewart if (stseq_m == NULL) { 567144249214SRandall Stewart break; 567244249214SRandall Stewart } 567349656eefSMichael Tuexen sid = ntohs(stseq_m->sid); 567449656eefSMichael Tuexen mid = ntohl(stseq_m->mid); 56758e1b295fSMichael Tuexen flags = ntohs(stseq_m->flags); 56768e1b295fSMichael Tuexen if (flags & PR_SCTP_UNORDERED_FLAG) { 56778e1b295fSMichael Tuexen ordered = 0; 56788e1b295fSMichael Tuexen } else { 56798e1b295fSMichael Tuexen ordered = 1; 56808e1b295fSMichael Tuexen } 568144249214SRandall Stewart } else { 5682671d309cSRandall Stewart stseq = (struct sctp_strseq *)sctp_m_getptr(m, offset, 5683671d309cSRandall Stewart sizeof(struct sctp_strseq), 5684671d309cSRandall Stewart (uint8_t *)&strseqbuf); 5685671d309cSRandall Stewart offset += sizeof(struct sctp_strseq); 56862afb3e84SRandall Stewart if (stseq == NULL) { 5687671d309cSRandall Stewart break; 56882afb3e84SRandall Stewart } 568949656eefSMichael Tuexen sid = ntohs(stseq->sid); 569049656eefSMichael Tuexen mid = (uint32_t)ntohs(stseq->ssn); 56918e1b295fSMichael Tuexen ordered = 1; 569244249214SRandall Stewart } 5693f8829a4aSRandall Stewart /* Convert */ 56948933fa13SRandall Stewart 5695f8829a4aSRandall Stewart /* now process */ 56968933fa13SRandall Stewart 56978933fa13SRandall Stewart /* 56988933fa13SRandall Stewart * Ok we now look for the stream/seq on the read 56998933fa13SRandall Stewart * queue where its not all delivered. If we find it 57008933fa13SRandall Stewart * we transmute the read entry into a PDI_ABORTED. 57018933fa13SRandall Stewart */ 570249656eefSMichael Tuexen if (sid >= asoc->streamincnt) { 57032afb3e84SRandall Stewart /* screwed up streams, stop! */ 57042afb3e84SRandall Stewart break; 5705f8829a4aSRandall Stewart } 570649656eefSMichael Tuexen if ((asoc->str_of_pdapi == sid) && 570749656eefSMichael Tuexen (asoc->ssn_of_pdapi == mid)) { 57088933fa13SRandall Stewart /* 57098933fa13SRandall Stewart * If this is the one we were partially 57108933fa13SRandall Stewart * delivering now then we no longer are. 57118933fa13SRandall Stewart * Note this will change with the reassembly 57128933fa13SRandall Stewart * re-write. 57138933fa13SRandall Stewart */ 57148933fa13SRandall Stewart asoc->fragmented_delivery_inprogress = 0; 57158933fa13SRandall Stewart } 571649656eefSMichael Tuexen strm = &asoc->strmin[sid]; 571749656eefSMichael Tuexen for (cur_mid = strm->last_mid_delivered; SCTP_MID_GE(asoc->idata_supported, mid, cur_mid); cur_mid++) { 571849656eefSMichael Tuexen sctp_flush_reassm_for_str_seq(stcb, asoc, sid, cur_mid, ordered, new_cum_tsn); 5719d1ea5fa9SMichael Tuexen } 572028cd0699SMichael Tuexen TAILQ_FOREACH(control, &stcb->sctp_ep->read_queue, next) { 572128cd0699SMichael Tuexen if ((control->sinfo_stream == sid) && 572228cd0699SMichael Tuexen (SCTP_MID_EQ(asoc->idata_supported, control->mid, mid))) { 572349656eefSMichael Tuexen str_seq = (sid << 16) | (0x0000ffff & mid); 572428cd0699SMichael Tuexen control->pdapi_aborted = 1; 57258933fa13SRandall Stewart sv = stcb->asoc.control_pdapi; 572628cd0699SMichael Tuexen control->end_added = 1; 572728cd0699SMichael Tuexen if (control->on_strm_q == SCTP_ON_ORDERED) { 572828cd0699SMichael Tuexen TAILQ_REMOVE(&strm->inqueue, control, next_instrm); 572928cd0699SMichael Tuexen if (asoc->size_on_all_streams >= control->length) { 573028cd0699SMichael Tuexen asoc->size_on_all_streams -= control->length; 573128cd0699SMichael Tuexen } else { 573298d5fd97SMichael Tuexen #ifdef INVARIANTS 573328cd0699SMichael Tuexen panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length); 573428cd0699SMichael Tuexen #else 573528cd0699SMichael Tuexen asoc->size_on_all_streams = 0; 573698d5fd97SMichael Tuexen #endif 573744249214SRandall Stewart } 573828cd0699SMichael Tuexen sctp_ucount_decr(asoc->cnt_on_all_streams); 573928cd0699SMichael Tuexen } else if (control->on_strm_q == SCTP_ON_UNORDERED) { 574028cd0699SMichael Tuexen TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm); 574128cd0699SMichael Tuexen #ifdef INVARIANTS 574228cd0699SMichael Tuexen } else if (control->on_strm_q) { 574328cd0699SMichael Tuexen panic("strm: %p ctl: %p unknown %d", 574428cd0699SMichael Tuexen strm, control, control->on_strm_q); 574528cd0699SMichael Tuexen #endif 574628cd0699SMichael Tuexen } 574728cd0699SMichael Tuexen control->on_strm_q = 0; 574828cd0699SMichael Tuexen stcb->asoc.control_pdapi = control; 5749810ec536SMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION, 5750810ec536SMichael Tuexen stcb, 57518933fa13SRandall Stewart SCTP_PARTIAL_DELIVERY_ABORTED, 5752810ec536SMichael Tuexen (void *)&str_seq, 5753810ec536SMichael Tuexen SCTP_SO_NOT_LOCKED); 57548933fa13SRandall Stewart stcb->asoc.control_pdapi = sv; 57558933fa13SRandall Stewart break; 575628cd0699SMichael Tuexen } else if ((control->sinfo_stream == sid) && 575728cd0699SMichael Tuexen SCTP_MID_GT(asoc->idata_supported, control->mid, mid)) { 57588933fa13SRandall Stewart /* We are past our victim SSN */ 57598933fa13SRandall Stewart break; 57608933fa13SRandall Stewart } 57618933fa13SRandall Stewart } 576249656eefSMichael Tuexen if (SCTP_MID_GT(asoc->idata_supported, mid, strm->last_mid_delivered)) { 5763f8829a4aSRandall Stewart /* Update the sequence number */ 576449656eefSMichael Tuexen strm->last_mid_delivered = mid; 5765f8829a4aSRandall Stewart } 5766f8829a4aSRandall Stewart /* now kick the stream the new way */ 576704ee05e8SRandall Stewart /* sa_ignore NO_NULL_CHK */ 5768f8829a4aSRandall Stewart sctp_kick_prsctp_reorder_queue(stcb, strm); 5769f8829a4aSRandall Stewart } 57708933fa13SRandall Stewart SCTP_INP_READ_UNLOCK(stcb->sctp_ep); 5771f8829a4aSRandall Stewart } 57727898f408SRandall Stewart /* 57737898f408SRandall Stewart * Now slide thing forward. 57747898f408SRandall Stewart */ 57757898f408SRandall Stewart sctp_slide_mapping_arrays(stcb); 5776f8829a4aSRandall Stewart } 5777