1*bc2d92a5Smaxv /* $NetBSD: sctp_indata.c,v 1.8 2018/12/22 13:11:38 maxv Exp $ */ 2c05f20fbSrjs /* $KAME: sctp_indata.c,v 1.36 2005/03/06 16:04:17 itojun Exp $ */ 3c05f20fbSrjs 4c05f20fbSrjs /* 5c05f20fbSrjs * Copyright (C) 2002, 2003, 2004 Cisco Systems Inc, 6c05f20fbSrjs * All rights reserved. 7c05f20fbSrjs * 8c05f20fbSrjs * Redistribution and use in source and binary forms, with or without 9c05f20fbSrjs * modification, are permitted provided that the following conditions 10c05f20fbSrjs * are met: 11c05f20fbSrjs * 1. Redistributions of source code must retain the above copyright 12c05f20fbSrjs * notice, this list of conditions and the following disclaimer. 13c05f20fbSrjs * 2. Redistributions in binary form must reproduce the above copyright 14c05f20fbSrjs * notice, this list of conditions and the following disclaimer in the 15c05f20fbSrjs * documentation and/or other materials provided with the distribution. 16c05f20fbSrjs * 3. Neither the name of the project nor the names of its contributors 17c05f20fbSrjs * may be used to endorse or promote products derived from this software 18c05f20fbSrjs * without specific prior written permission. 19c05f20fbSrjs * 20c05f20fbSrjs * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21c05f20fbSrjs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22c05f20fbSrjs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23c05f20fbSrjs * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24c05f20fbSrjs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25c05f20fbSrjs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26c05f20fbSrjs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27c05f20fbSrjs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28c05f20fbSrjs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29c05f20fbSrjs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30c05f20fbSrjs * SUCH DAMAGE. 31c05f20fbSrjs */ 32c05f20fbSrjs 33c05f20fbSrjs #include <sys/cdefs.h> 34*bc2d92a5Smaxv __KERNEL_RCSID(0, "$NetBSD: sctp_indata.c,v 1.8 2018/12/22 13:11:38 maxv Exp $"); 35c05f20fbSrjs 36c05f20fbSrjs #ifdef _KERNEL_OPT 37c05f20fbSrjs #include "opt_ipsec.h" 38c05f20fbSrjs #include "opt_inet.h" 39c05f20fbSrjs #include "opt_sctp.h" 40c05f20fbSrjs #endif /* _KERNEL_OPT */ 41c05f20fbSrjs 42c05f20fbSrjs #include <sys/param.h> 43c05f20fbSrjs #include <sys/systm.h> 44c05f20fbSrjs #include <sys/mbuf.h> 45c05f20fbSrjs #include <sys/malloc.h> 46c05f20fbSrjs #include <sys/socket.h> 47c05f20fbSrjs #include <sys/socketvar.h> 48c05f20fbSrjs #include <sys/sysctl.h> 49c05f20fbSrjs 50c05f20fbSrjs #include <net/if.h> 51c05f20fbSrjs #include <net/route.h> 52c05f20fbSrjs 53c05f20fbSrjs 54c05f20fbSrjs #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 55c05f20fbSrjs #include <sys/limits.h> 56c05f20fbSrjs #else 57c05f20fbSrjs #include <machine/limits.h> 58c05f20fbSrjs #endif 59c05f20fbSrjs #include <machine/cpu.h> 60c05f20fbSrjs 61c05f20fbSrjs #include <netinet/in.h> 62c05f20fbSrjs #include <netinet/in_systm.h> 63c05f20fbSrjs #include <netinet/ip.h> 64c05f20fbSrjs #ifdef INET6 65c05f20fbSrjs #include <netinet/ip6.h> 66c05f20fbSrjs #endif /* INET6 */ 67c05f20fbSrjs #include <netinet/in_pcb.h> 68c05f20fbSrjs #include <netinet/in_var.h> 69c05f20fbSrjs #include <netinet/ip_var.h> 70c05f20fbSrjs #ifdef INET6 71c05f20fbSrjs #include <netinet6/ip6_var.h> 72c05f20fbSrjs #endif /* INET6 */ 73c05f20fbSrjs #include <netinet/ip_icmp.h> 74c05f20fbSrjs #include <netinet/icmp_var.h> 75c05f20fbSrjs #include <netinet/sctp_var.h> 76c05f20fbSrjs #include <netinet/sctp_pcb.h> 77c05f20fbSrjs #include <netinet/sctp_header.h> 78c05f20fbSrjs #include <netinet/sctputil.h> 79c05f20fbSrjs #include <netinet/sctp_output.h> 80c05f20fbSrjs #include <netinet/sctp_input.h> 81c05f20fbSrjs #include <netinet/sctp_hashdriver.h> 82c05f20fbSrjs #include <netinet/sctp_indata.h> 83c05f20fbSrjs #include <netinet/sctp_uio.h> 84c05f20fbSrjs #include <netinet/sctp_timer.h> 85c05f20fbSrjs #ifdef IPSEC 86bc8fd953Srjs #include <netipsec/ipsec.h> 87bc8fd953Srjs #include <netipsec/key.h> 88c05f20fbSrjs #endif /*IPSEC*/ 89c05f20fbSrjs 90c05f20fbSrjs #ifdef SCTP_DEBUG 91c05f20fbSrjs extern u_int32_t sctp_debug_on; 92c05f20fbSrjs #endif 93c05f20fbSrjs 94c05f20fbSrjs /* 95c05f20fbSrjs * NOTES: On the outbound side of things I need to check the sack timer to 96c05f20fbSrjs * see if I should generate a sack into the chunk queue (if I have data to 97c05f20fbSrjs * send that is and will be sending it .. for bundling. 98c05f20fbSrjs * 99c05f20fbSrjs * The callback in sctp_usrreq.c will get called when the socket is read 100c05f20fbSrjs * from. This will cause sctp_service_queues() to get called on the top 101c05f20fbSrjs * entry in the list. 102c05f20fbSrjs */ 103c05f20fbSrjs 104c05f20fbSrjs extern int sctp_strict_sacks; 105c05f20fbSrjs 106c05f20fbSrjs void 107c05f20fbSrjs sctp_set_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc) 108c05f20fbSrjs { 109c05f20fbSrjs u_int32_t calc, calc_w_oh; 110c05f20fbSrjs 111c05f20fbSrjs #ifdef SCTP_DEBUG 112c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA4) { 113c05f20fbSrjs printf("cc:%lu hiwat:%lu lowat:%lu mbcnt:%lu mbmax:%lu\n", 114c05f20fbSrjs (u_long)stcb->sctp_socket->so_rcv.sb_cc, 115c05f20fbSrjs (u_long)stcb->sctp_socket->so_rcv.sb_hiwat, 116c05f20fbSrjs (u_long)stcb->sctp_socket->so_rcv.sb_lowat, 117c05f20fbSrjs (u_long)stcb->sctp_socket->so_rcv.sb_mbcnt, 118c05f20fbSrjs (u_long)stcb->sctp_socket->so_rcv.sb_mbmax); 119c05f20fbSrjs printf("Setting rwnd to: sb:%ld - (del:%d + reasm:%d str:%d)\n", 120c05f20fbSrjs sctp_sbspace(&stcb->sctp_socket->so_rcv), 121c05f20fbSrjs asoc->size_on_delivery_queue, 122c05f20fbSrjs asoc->size_on_reasm_queue, 123c05f20fbSrjs asoc->size_on_all_streams); 124c05f20fbSrjs } 125c05f20fbSrjs #endif 126c05f20fbSrjs if (stcb->sctp_socket->so_rcv.sb_cc == 0 && 127c05f20fbSrjs asoc->size_on_delivery_queue == 0 && 128c05f20fbSrjs asoc->size_on_reasm_queue == 0 && 129c05f20fbSrjs asoc->size_on_all_streams == 0) { 130c05f20fbSrjs /* Full rwnd granted */ 131a8a5c538Sriastradh asoc->my_rwnd = uimax(stcb->sctp_socket->so_rcv.sb_hiwat, 132c05f20fbSrjs SCTP_MINIMAL_RWND); 133c05f20fbSrjs return; 134c05f20fbSrjs } 135c05f20fbSrjs /* get actual space */ 136c05f20fbSrjs calc = (u_int32_t)sctp_sbspace(&stcb->sctp_socket->so_rcv); 137c05f20fbSrjs 138c05f20fbSrjs /* take out what has NOT been put on socket queue and 139c05f20fbSrjs * we yet hold for putting up. 140c05f20fbSrjs */ 141c05f20fbSrjs calc = sctp_sbspace_sub(calc, (u_int32_t)asoc->size_on_delivery_queue); 142c05f20fbSrjs calc = sctp_sbspace_sub(calc, (u_int32_t)asoc->size_on_reasm_queue); 143c05f20fbSrjs calc = sctp_sbspace_sub(calc, (u_int32_t)asoc->size_on_all_streams); 144c05f20fbSrjs 145c05f20fbSrjs /* what is the overhead of all these rwnd's */ 146c05f20fbSrjs calc_w_oh = sctp_sbspace_sub(calc, stcb->asoc.my_rwnd_control_len); 147c05f20fbSrjs 148c05f20fbSrjs asoc->my_rwnd = calc; 149c05f20fbSrjs if (calc_w_oh == 0) { 150c05f20fbSrjs /* If our overhead is greater than the advertised 151c05f20fbSrjs * rwnd, we clamp the rwnd to 1. This lets us 152c05f20fbSrjs * still accept inbound segments, but hopefully will 153c05f20fbSrjs * shut the sender down when he finally gets the message. 154c05f20fbSrjs */ 155c05f20fbSrjs asoc->my_rwnd = 1; 156c05f20fbSrjs } else { 157c05f20fbSrjs /* SWS threshold */ 158c05f20fbSrjs if (asoc->my_rwnd && 159c05f20fbSrjs (asoc->my_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_receiver)) { 160c05f20fbSrjs /* SWS engaged, tell peer none left */ 161c05f20fbSrjs asoc->my_rwnd = 1; 162c05f20fbSrjs #ifdef SCTP_DEBUG 163c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA4) { 164c05f20fbSrjs printf(" - SWS zeros\n"); 165c05f20fbSrjs } 166c05f20fbSrjs } else { 167c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA4) { 168c05f20fbSrjs printf("\n"); 169c05f20fbSrjs } 170c05f20fbSrjs #endif 171c05f20fbSrjs } 172c05f20fbSrjs } 173c05f20fbSrjs } 174c05f20fbSrjs 175c05f20fbSrjs /* 176c05f20fbSrjs * Take a chk structure and build it into an mbuf. Hmm should we change things 177c05f20fbSrjs * so that instead we store the data side in a chunk? 178c05f20fbSrjs */ 179c05f20fbSrjs static struct mbuf * 180c05f20fbSrjs sctp_build_ctl_nchunk(struct sctp_tcb *stcb, uint32_t tsn, uint32_t ppid, 181c05f20fbSrjs uint32_t context, uint16_t stream_no, uint16_t stream_seq, uint8_t flags) 182c05f20fbSrjs { 183c05f20fbSrjs struct sctp_sndrcvinfo *outinfo; 184c05f20fbSrjs struct cmsghdr *cmh; 185c05f20fbSrjs struct mbuf *ret; 186c05f20fbSrjs 187c05f20fbSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_RECVDATAIOEVNT) == 0) { 188c05f20fbSrjs /* user does not want the sndrcv ctl */ 189c05f20fbSrjs return (NULL); 190c05f20fbSrjs } 191c05f20fbSrjs 192c05f20fbSrjs MGETHDR(ret, M_DONTWAIT, MT_CONTROL); 193c05f20fbSrjs if (ret == NULL) { 194c05f20fbSrjs /* No space */ 195c05f20fbSrjs return (ret); 196c05f20fbSrjs } 197c05f20fbSrjs /* We need a CMSG header followed by the struct */ 198c05f20fbSrjs cmh = mtod(ret, struct cmsghdr *); 199c05f20fbSrjs outinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmh); 200c05f20fbSrjs cmh->cmsg_level = IPPROTO_SCTP; 201c05f20fbSrjs cmh->cmsg_type = SCTP_SNDRCV; 202c05f20fbSrjs cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 203c05f20fbSrjs outinfo->sinfo_stream = stream_no; 204c05f20fbSrjs outinfo->sinfo_ssn = stream_seq; 205c05f20fbSrjs if (flags & SCTP_DATA_UNORDERED) { 2065a349a09Srjs outinfo->sinfo_flags = SCTP_UNORDERED; 207c05f20fbSrjs } else { 208c05f20fbSrjs outinfo->sinfo_flags = 0; 209c05f20fbSrjs } 210c05f20fbSrjs outinfo->sinfo_ppid = ppid; 211c05f20fbSrjs outinfo->sinfo_context = context; 212c05f20fbSrjs outinfo->sinfo_assoc_id = sctp_get_associd(stcb); 213c05f20fbSrjs outinfo->sinfo_tsn = tsn; 214c05f20fbSrjs outinfo->sinfo_cumtsn = stcb->asoc.cumulative_tsn; 215c05f20fbSrjs ret->m_len = cmh->cmsg_len; 216c05f20fbSrjs ret->m_pkthdr.len = ret->m_len; 217c05f20fbSrjs /* 218c05f20fbSrjs * We track how many control len's have gone upon the sb 219c05f20fbSrjs * and do not count these in the rwnd calculation. 220c05f20fbSrjs */ 221c05f20fbSrjs stcb->asoc.my_rwnd_control_len += 222c05f20fbSrjs CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 223c05f20fbSrjs 224c05f20fbSrjs return (ret); 225c05f20fbSrjs } 226c05f20fbSrjs 227c05f20fbSrjs /* 228c05f20fbSrjs * Take a chk structure and build it into an mbuf. Should we change things 229c05f20fbSrjs * so that instead we store the data side in a chunk? 230c05f20fbSrjs */ 231c05f20fbSrjs static 232c05f20fbSrjs struct mbuf * 233c05f20fbSrjs sctp_build_ctl(struct sctp_tcb *stcb, struct sctp_tmit_chunk *chk) 234c05f20fbSrjs { 235c05f20fbSrjs struct sctp_sndrcvinfo *outinfo; 236c05f20fbSrjs struct cmsghdr *cmh; 237c05f20fbSrjs struct mbuf *ret; 238c05f20fbSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_RECVDATAIOEVNT) == 0) { 239c05f20fbSrjs /* user does not want the sndrcv ctl */ 240c05f20fbSrjs return (NULL); 241c05f20fbSrjs } 242c05f20fbSrjs MGET(ret, M_DONTWAIT, MT_CONTROL); 243c05f20fbSrjs if (ret == NULL) { 244c05f20fbSrjs /* No space */ 245c05f20fbSrjs return (ret); 246c05f20fbSrjs } 247c05f20fbSrjs 248c05f20fbSrjs /* We need a CMSG header followed by the struct */ 249c05f20fbSrjs cmh = mtod(ret, struct cmsghdr *); 250c05f20fbSrjs outinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmh); 251c05f20fbSrjs cmh->cmsg_level = IPPROTO_SCTP; 252c05f20fbSrjs cmh->cmsg_type = SCTP_SNDRCV; 253c05f20fbSrjs cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 254c05f20fbSrjs outinfo->sinfo_stream = chk->rec.data.stream_number; 255c05f20fbSrjs outinfo->sinfo_ssn = chk->rec.data.stream_seq; 256c05f20fbSrjs if (chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) { 2575a349a09Srjs outinfo->sinfo_flags = SCTP_UNORDERED; 258c05f20fbSrjs } else { 259c05f20fbSrjs outinfo->sinfo_flags = 0; 260c05f20fbSrjs } 261c05f20fbSrjs outinfo->sinfo_ppid = chk->rec.data.payloadtype; 262c05f20fbSrjs outinfo->sinfo_context = chk->rec.data.context; 263c05f20fbSrjs outinfo->sinfo_assoc_id = sctp_get_associd(stcb); 264c05f20fbSrjs outinfo->sinfo_tsn = chk->rec.data.TSN_seq; 265c05f20fbSrjs outinfo->sinfo_cumtsn = stcb->asoc.cumulative_tsn; 266c05f20fbSrjs ret->m_len = cmh->cmsg_len; 267c05f20fbSrjs stcb->asoc.my_rwnd_control_len += 268c05f20fbSrjs CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 269c05f20fbSrjs 270c05f20fbSrjs return (ret); 271c05f20fbSrjs } 272c05f20fbSrjs 273c05f20fbSrjs int 274c05f20fbSrjs sctp_deliver_data(struct sctp_tcb *stcb, struct sctp_association *asoc, 275c05f20fbSrjs struct sctp_tmit_chunk *chk, int hold_locks) 276c05f20fbSrjs { 277c05f20fbSrjs struct mbuf *control, *m; 278c05f20fbSrjs int free_it; 279c05f20fbSrjs struct sockaddr_in6 sin6; 280c05f20fbSrjs const struct sockaddr *to; 281c05f20fbSrjs 282c05f20fbSrjs #ifdef SCTP_DEBUG 283c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 284c05f20fbSrjs printf("I am now in Deliver data! (%p)\n", chk); 285c05f20fbSrjs } 286c05f20fbSrjs #endif 287c05f20fbSrjs /* get a write lock on the inp if not already */ 288c05f20fbSrjs if (hold_locks == 0) { 289c05f20fbSrjs SCTP_TCB_UNLOCK(stcb); 290c05f20fbSrjs SCTP_INP_WLOCK(stcb->sctp_ep); 291c05f20fbSrjs SCTP_TCB_LOCK(stcb); 292c05f20fbSrjs } 293c05f20fbSrjs free_it = 0; 294c05f20fbSrjs /* We always add it to the queue */ 295c05f20fbSrjs if (stcb && (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 296c05f20fbSrjs /* socket above is long gone */ 297c05f20fbSrjs #ifdef SCTP_DEBUG 298c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 299c05f20fbSrjs printf("gone is gone!\n"); 300c05f20fbSrjs } 301c05f20fbSrjs #endif 302c05f20fbSrjs if (chk != NULL) { 303c05f20fbSrjs if (chk->data) 304c05f20fbSrjs sctp_m_freem(chk->data); 305c05f20fbSrjs chk->data = NULL; 306c05f20fbSrjs sctp_free_remote_addr(chk->whoTo); 307c05f20fbSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk); 308c05f20fbSrjs sctppcbinfo.ipi_count_chunk--; 309c05f20fbSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) { 310c05f20fbSrjs panic("Chunk count is negative"); 311c05f20fbSrjs } 312c05f20fbSrjs sctppcbinfo.ipi_gencnt_chunk++; 313c05f20fbSrjs } 314c05f20fbSrjs TAILQ_FOREACH(chk, &asoc->delivery_queue, sctp_next) { 315c05f20fbSrjs asoc->size_on_delivery_queue -= chk->send_size; 316c05f20fbSrjs asoc->cnt_on_delivery_queue--; 317c05f20fbSrjs /* 318c05f20fbSrjs * Lose the data pointer, since its in the socket buffer 319c05f20fbSrjs */ 320c05f20fbSrjs if (chk->data) 321c05f20fbSrjs sctp_m_freem(chk->data); 322c05f20fbSrjs chk->data = NULL; 323c05f20fbSrjs /* Now free the address and data */ 324c05f20fbSrjs sctp_free_remote_addr(chk->whoTo); 325c05f20fbSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk); 326c05f20fbSrjs sctppcbinfo.ipi_count_chunk--; 327c05f20fbSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) { 328c05f20fbSrjs panic("Chunk count is negative"); 329c05f20fbSrjs } 330c05f20fbSrjs sctppcbinfo.ipi_gencnt_chunk++; 331c05f20fbSrjs } 332c05f20fbSrjs if (hold_locks == 0) { 333c05f20fbSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 334c05f20fbSrjs } 335c05f20fbSrjs return (0); 336c05f20fbSrjs } 337c05f20fbSrjs if (chk != NULL) { 338c05f20fbSrjs TAILQ_INSERT_TAIL(&asoc->delivery_queue, chk, sctp_next); 339c05f20fbSrjs asoc->size_on_delivery_queue += chk->send_size; 340c05f20fbSrjs asoc->cnt_on_delivery_queue++; 341c05f20fbSrjs } 342c05f20fbSrjs if (asoc->fragmented_delivery_inprogress) { 343c05f20fbSrjs /* 344c05f20fbSrjs * oh oh, fragmented delivery in progress 345c05f20fbSrjs * return out of here. 346c05f20fbSrjs */ 347c05f20fbSrjs #ifdef SCTP_DEBUG 348c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 349c05f20fbSrjs printf("Fragmented delivery in progress?\n"); 350c05f20fbSrjs } 351c05f20fbSrjs #endif 352c05f20fbSrjs if (hold_locks == 0) { 353c05f20fbSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 354c05f20fbSrjs } 355c05f20fbSrjs return (0); 356c05f20fbSrjs } 357c05f20fbSrjs /* Now grab the first one */ 358c05f20fbSrjs chk = TAILQ_FIRST(&asoc->delivery_queue); 359c05f20fbSrjs if (chk == NULL) { 360c05f20fbSrjs /* Nothing in queue */ 361c05f20fbSrjs #ifdef SCTP_DEBUG 362c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 363c05f20fbSrjs printf("Nothing in queue?\n"); 364c05f20fbSrjs } 365c05f20fbSrjs #endif 366c05f20fbSrjs asoc->size_on_delivery_queue = 0; 367c05f20fbSrjs asoc->cnt_on_delivery_queue = 0; 368c05f20fbSrjs if (hold_locks == 0) { 369c05f20fbSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 370c05f20fbSrjs } 371c05f20fbSrjs return (0); 372c05f20fbSrjs } 373c05f20fbSrjs 374c05f20fbSrjs if (stcb->sctp_socket->so_rcv.sb_cc >= stcb->sctp_socket->so_rcv.sb_hiwat) { 375c05f20fbSrjs /* Boy, there really is NO room */ 376c05f20fbSrjs if (hold_locks == 0) { 377c05f20fbSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 378c05f20fbSrjs } 379c05f20fbSrjs return (0); 380c05f20fbSrjs } 381c05f20fbSrjs #ifdef SCTP_DEBUG 382c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 383c05f20fbSrjs printf("Now to the delivery with chk(%p)!\n", chk); 384c05f20fbSrjs } 385c05f20fbSrjs #endif 386c05f20fbSrjs /* XXX need to append PKTHDR to the socket buffer first */ 387c05f20fbSrjs if ((chk->data->m_flags & M_PKTHDR) == 0) { 388c05f20fbSrjs MGETHDR(m, M_DONTWAIT, MT_DATA); 389c05f20fbSrjs if (m == NULL) { 390c05f20fbSrjs /* no room! */ 391c05f20fbSrjs if (hold_locks == 0) { 392c05f20fbSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 393c05f20fbSrjs } 394c05f20fbSrjs return (0); 395c05f20fbSrjs } 396c05f20fbSrjs m->m_pkthdr.len = chk->send_size; 397c05f20fbSrjs m->m_len = 0; 398c05f20fbSrjs m->m_next = chk->data; 399c05f20fbSrjs chk->data = m; 400c05f20fbSrjs } 401c05f20fbSrjs if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { 402c05f20fbSrjs if (chk->data->m_next == NULL) { 403c05f20fbSrjs /* hopefully we hit here most of the time */ 404c05f20fbSrjs chk->data->m_flags |= M_EOR; 405c05f20fbSrjs } else { 406c05f20fbSrjs /* Add the flag to the LAST mbuf in the chain */ 407c05f20fbSrjs m = chk->data; 408c05f20fbSrjs while (m->m_next != NULL) { 409c05f20fbSrjs m = m->m_next; 410c05f20fbSrjs } 411c05f20fbSrjs m->m_flags |= M_EOR; 412c05f20fbSrjs } 413c05f20fbSrjs } 414c05f20fbSrjs 415c05f20fbSrjs if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { 416c05f20fbSrjs struct sockaddr_in6 lsa6; 417c05f20fbSrjs 418c05f20fbSrjs control = sctp_build_ctl(stcb, chk); 419c05f20fbSrjs to = rtcache_getdst(&chk->whoTo->ro); 420c05f20fbSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) && 421c05f20fbSrjs to->sa_family == AF_INET) { 422c05f20fbSrjs const struct sockaddr_in *sin; 423c05f20fbSrjs 424c05f20fbSrjs sin = (const struct sockaddr_in *)to; 4257231b0cdSrtr in6_sin_2_v4mapsin6(sin, &sin6); 426c05f20fbSrjs to = (struct sockaddr *)&sin6; 427c05f20fbSrjs } 428c05f20fbSrjs /* check and strip embedded scope junk */ 429c05f20fbSrjs to = (const struct sockaddr *)sctp_recover_scope((const struct sockaddr_in6 *)to, 430c05f20fbSrjs &lsa6); 431c05f20fbSrjs if (((const struct sockaddr_in *)to)->sin_port == 0) { 432c05f20fbSrjs printf("Huh a, port is %d not net:%p %d?\n", 433c05f20fbSrjs ((const struct sockaddr_in *)to)->sin_port, 434c05f20fbSrjs chk->whoTo, 435c05f20fbSrjs (int)(ntohs(stcb->rport))); 436c05f20fbSrjs /*((struct sockaddr_in *)to)->sin_port = stcb->rport;*/ 437c05f20fbSrjs /* XXX */ 438c05f20fbSrjs } 439c05f20fbSrjs if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < (long)chk->send_size) { 440c05f20fbSrjs /* Gak not enough room */ 441c05f20fbSrjs if (control) { 442c05f20fbSrjs sctp_m_freem(control); 443c05f20fbSrjs stcb->asoc.my_rwnd_control_len -= 444c05f20fbSrjs CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 445c05f20fbSrjs } 446c05f20fbSrjs goto skip; 447c05f20fbSrjs } 448c05f20fbSrjs if (!sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv, 449c05f20fbSrjs to, chk->data, control, stcb->asoc.my_vtag, 450c05f20fbSrjs stcb->sctp_ep)) { 451c05f20fbSrjs /* Gak not enough room */ 452c05f20fbSrjs if (control) { 453c05f20fbSrjs sctp_m_freem(control); 454c05f20fbSrjs stcb->asoc.my_rwnd_control_len -= 455c05f20fbSrjs CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 456c05f20fbSrjs } 457c05f20fbSrjs } else { 458c05f20fbSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) { 459c05f20fbSrjs if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) { 460c05f20fbSrjs stcb->asoc.my_rwnd_control_len += 461c05f20fbSrjs sizeof(struct mbuf); 462c05f20fbSrjs } 463c05f20fbSrjs } else { 464c05f20fbSrjs stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf); 465c05f20fbSrjs } 466c05f20fbSrjs free_it = 1; 467c05f20fbSrjs } 468c05f20fbSrjs } else { 469c05f20fbSrjs /* append to a already started message. */ 470c05f20fbSrjs if (sctp_sbspace(&stcb->sctp_socket->so_rcv) >= 471c05f20fbSrjs (long)chk->send_size) { 472c05f20fbSrjs sbappend(&stcb->sctp_socket->so_rcv, chk->data); 473c05f20fbSrjs free_it = 1; 474c05f20fbSrjs } 475c05f20fbSrjs } 476c05f20fbSrjs skip: 477c05f20fbSrjs if (hold_locks == 0) { 478c05f20fbSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 479c05f20fbSrjs } 480c05f20fbSrjs /* free up the one we inserted */ 481c05f20fbSrjs if (free_it) { 482c05f20fbSrjs /* Pull it off the queue */ 483c05f20fbSrjs #ifdef SCTP_DEBUG 484c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 485c05f20fbSrjs printf("Free_it true, doing tickle wakeup\n"); 486c05f20fbSrjs } 487c05f20fbSrjs #endif 488c05f20fbSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 489c05f20fbSrjs TAILQ_REMOVE(&asoc->delivery_queue, chk, sctp_next); 490c05f20fbSrjs asoc->size_on_delivery_queue -= chk->send_size; 491c05f20fbSrjs asoc->cnt_on_delivery_queue--; 492c05f20fbSrjs /* Lose the data pointer, since its in the socket buffer */ 493c05f20fbSrjs chk->data = NULL; 494c05f20fbSrjs /* Now free the address and data */ 495c05f20fbSrjs sctp_free_remote_addr(chk->whoTo); 496c05f20fbSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk); 497c05f20fbSrjs sctppcbinfo.ipi_count_chunk--; 498c05f20fbSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) { 499c05f20fbSrjs panic("Chunk count is negative"); 500c05f20fbSrjs } 501c05f20fbSrjs sctppcbinfo.ipi_gencnt_chunk++; 502c05f20fbSrjs } 503c05f20fbSrjs return (free_it); 504c05f20fbSrjs } 505c05f20fbSrjs 506c05f20fbSrjs /* 507c05f20fbSrjs * We are delivering currently from the reassembly queue. We must continue to 508c05f20fbSrjs * deliver until we either: 509c05f20fbSrjs * 1) run out of space. 510c05f20fbSrjs * 2) run out of sequential TSN's 511c05f20fbSrjs * 3) hit the SCTP_DATA_LAST_FRAG flag. 512c05f20fbSrjs */ 513c05f20fbSrjs static void 514c05f20fbSrjs sctp_service_reassembly(struct sctp_tcb *stcb, struct sctp_association *asoc, int hold_locks) 515c05f20fbSrjs { 516c05f20fbSrjs const struct sockaddr *to; 517c05f20fbSrjs struct sockaddr_in6 sin6; 518c05f20fbSrjs struct sctp_tmit_chunk *chk, *at; 519c05f20fbSrjs struct mbuf *control, *m; 520c05f20fbSrjs u_int16_t nxt_todel; 521c05f20fbSrjs u_int16_t stream_no; 522c05f20fbSrjs int cntDel; 523c05f20fbSrjs cntDel = stream_no = 0; 524c05f20fbSrjs if (hold_locks == 0) { 525c05f20fbSrjs /* 526c05f20fbSrjs * you always have the TCB lock, we need 527c05f20fbSrjs * to have the inp write lock as well. 528c05f20fbSrjs */ 529c05f20fbSrjs SCTP_TCB_UNLOCK(stcb); 530c05f20fbSrjs SCTP_INP_WLOCK(stcb->sctp_ep); 531c05f20fbSrjs SCTP_TCB_LOCK(stcb); 532c05f20fbSrjs } 533c05f20fbSrjs if (stcb && (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 534c05f20fbSrjs /* socket above is long gone */ 535c05f20fbSrjs asoc->fragmented_delivery_inprogress = 0; 536c05f20fbSrjs TAILQ_FOREACH(chk, &asoc->reasmqueue, sctp_next) { 537c05f20fbSrjs asoc->size_on_delivery_queue -= chk->send_size; 538c05f20fbSrjs asoc->cnt_on_delivery_queue--; 539c05f20fbSrjs /* 540c05f20fbSrjs * Lose the data pointer, since its in the socket buffer 541c05f20fbSrjs */ 542c05f20fbSrjs if (chk->data) 543c05f20fbSrjs sctp_m_freem(chk->data); 544c05f20fbSrjs chk->data = NULL; 545c05f20fbSrjs /* Now free the address and data */ 546c05f20fbSrjs sctp_free_remote_addr(chk->whoTo); 547c05f20fbSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk); 548c05f20fbSrjs sctppcbinfo.ipi_count_chunk--; 549c05f20fbSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) { 550c05f20fbSrjs panic("Chunk count is negative"); 551c05f20fbSrjs } 552c05f20fbSrjs sctppcbinfo.ipi_gencnt_chunk++; 553c05f20fbSrjs } 554c05f20fbSrjs if (hold_locks == 0) { 555c05f20fbSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 556c05f20fbSrjs } 557c05f20fbSrjs return; 558c05f20fbSrjs } 559c05f20fbSrjs do { 560c05f20fbSrjs if (stcb->sctp_socket->so_rcv.sb_cc >= 561c05f20fbSrjs stcb->sctp_socket->so_rcv.sb_hiwat) { 562c05f20fbSrjs if (cntDel) { 563c05f20fbSrjs sctp_sorwakeup(stcb->sctp_ep, 564c05f20fbSrjs stcb->sctp_socket); 565c05f20fbSrjs } 566c05f20fbSrjs if (hold_locks == 0) { 567c05f20fbSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 568c05f20fbSrjs } 569c05f20fbSrjs return; 570c05f20fbSrjs } 571c05f20fbSrjs chk = TAILQ_FIRST(&asoc->reasmqueue); 572c05f20fbSrjs if (chk == NULL) { 573c05f20fbSrjs if (cntDel) { 574c05f20fbSrjs sctp_sorwakeup(stcb->sctp_ep, 575c05f20fbSrjs stcb->sctp_socket); 576c05f20fbSrjs } 577c05f20fbSrjs if (hold_locks == 0) { 578c05f20fbSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 579c05f20fbSrjs } 580c05f20fbSrjs return; 581c05f20fbSrjs } 582c05f20fbSrjs if (chk->rec.data.TSN_seq != (asoc->tsn_last_delivered + 1)) { 583c05f20fbSrjs /* Can't deliver more :< */ 584c05f20fbSrjs if (cntDel) { 585c05f20fbSrjs sctp_sorwakeup(stcb->sctp_ep, 586c05f20fbSrjs stcb->sctp_socket); 587c05f20fbSrjs } 588c05f20fbSrjs if (hold_locks == 0) { 589c05f20fbSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 590c05f20fbSrjs } 591c05f20fbSrjs return; 592c05f20fbSrjs } 593c05f20fbSrjs stream_no = chk->rec.data.stream_number; 594c05f20fbSrjs nxt_todel = asoc->strmin[stream_no].last_sequence_delivered + 1; 595c05f20fbSrjs if (nxt_todel != chk->rec.data.stream_seq && 596c05f20fbSrjs (chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) == 0) { 597c05f20fbSrjs /* 598c05f20fbSrjs * Not the next sequence to deliver in its stream OR 599c05f20fbSrjs * unordered 600c05f20fbSrjs */ 601c05f20fbSrjs if (cntDel) { 602c05f20fbSrjs sctp_sorwakeup(stcb->sctp_ep, 603c05f20fbSrjs stcb->sctp_socket); 604c05f20fbSrjs } 605c05f20fbSrjs if (hold_locks == 0) { 606c05f20fbSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 607c05f20fbSrjs } 608c05f20fbSrjs return; 609c05f20fbSrjs } 610c05f20fbSrjs 611c05f20fbSrjs if ((chk->data->m_flags & M_PKTHDR) == 0) { 612c05f20fbSrjs MGETHDR(m, M_DONTWAIT, MT_DATA); 613c05f20fbSrjs if (m == NULL) { 614c05f20fbSrjs /* no room! */ 615c05f20fbSrjs if (hold_locks == 0) { 616c05f20fbSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 617c05f20fbSrjs } 618c05f20fbSrjs return; 619c05f20fbSrjs } 620c05f20fbSrjs m->m_pkthdr.len = chk->send_size; 621c05f20fbSrjs m->m_len = 0; 622c05f20fbSrjs m->m_next = chk->data; 623c05f20fbSrjs chk->data = m; 624c05f20fbSrjs } 625c05f20fbSrjs if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { 626c05f20fbSrjs if (chk->data->m_next == NULL) { 627c05f20fbSrjs /* hopefully we hit here most of the time */ 628c05f20fbSrjs chk->data->m_flags |= M_EOR; 629c05f20fbSrjs } else { 630c05f20fbSrjs /* Add the flag to the LAST mbuf in the chain */ 631c05f20fbSrjs m = chk->data; 632c05f20fbSrjs while (m->m_next != NULL) { 633c05f20fbSrjs m = m->m_next; 634c05f20fbSrjs } 635c05f20fbSrjs m->m_flags |= M_EOR; 636c05f20fbSrjs } 637c05f20fbSrjs } 638c05f20fbSrjs if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { 639c05f20fbSrjs struct sockaddr_in6 lsa6; 640c05f20fbSrjs 641c05f20fbSrjs control = sctp_build_ctl(stcb, chk); 642c05f20fbSrjs to = rtcache_getdst(&chk->whoTo->ro); 643c05f20fbSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) && 644c05f20fbSrjs to->sa_family == AF_INET) { 645c05f20fbSrjs const struct sockaddr_in *sin; 646c05f20fbSrjs 647c05f20fbSrjs sin = satocsin(to); 6487231b0cdSrtr in6_sin_2_v4mapsin6(sin, &sin6); 649c05f20fbSrjs to = (struct sockaddr *)&sin6; 650c05f20fbSrjs } 651c05f20fbSrjs /* check and strip embedded scope junk */ 652c05f20fbSrjs to = (const struct sockaddr *)sctp_recover_scope((const struct sockaddr_in6 *)to, 653c05f20fbSrjs &lsa6); 654c05f20fbSrjs if (((const struct sockaddr_in *)to)->sin_port == 0) { 655c05f20fbSrjs printf("Huh b, port is %d not net:%p %d?\n", 656c05f20fbSrjs ((const struct sockaddr_in *)to)->sin_port, 657c05f20fbSrjs chk->whoTo, 658c05f20fbSrjs (int)(ntohs(stcb->rport))); 659c05f20fbSrjs /*((struct sockaddr_in *)to)->sin_port = stcb->rport;*/ 660c05f20fbSrjs /* XXX */ 661c05f20fbSrjs } 662c05f20fbSrjs if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < 663c05f20fbSrjs (long)chk->send_size) { 664c05f20fbSrjs if (control) { 665c05f20fbSrjs sctp_m_freem(control); 666c05f20fbSrjs stcb->asoc.my_rwnd_control_len -= 667c05f20fbSrjs CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 668c05f20fbSrjs } 669c05f20fbSrjs sctp_sorwakeup(stcb->sctp_ep, 670c05f20fbSrjs stcb->sctp_socket); 671c05f20fbSrjs if (hold_locks == 0) { 672c05f20fbSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 673c05f20fbSrjs } 674c05f20fbSrjs return; 675c05f20fbSrjs } 676c05f20fbSrjs if (!sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv, 677c05f20fbSrjs to, chk->data, control, stcb->asoc.my_vtag, 678c05f20fbSrjs stcb->sctp_ep)) { 679c05f20fbSrjs /* Gak not enough room */ 680c05f20fbSrjs if (control) { 681c05f20fbSrjs sctp_m_freem(control); 682c05f20fbSrjs stcb->asoc.my_rwnd_control_len -= 683c05f20fbSrjs CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 684c05f20fbSrjs } 685c05f20fbSrjs sctp_sorwakeup(stcb->sctp_ep, 686c05f20fbSrjs stcb->sctp_socket); 687c05f20fbSrjs if (hold_locks == 0) { 688c05f20fbSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 689c05f20fbSrjs } 690c05f20fbSrjs return; 691c05f20fbSrjs } 692c05f20fbSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) { 693c05f20fbSrjs if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) { 694c05f20fbSrjs stcb->asoc.my_rwnd_control_len += 695c05f20fbSrjs sizeof(struct mbuf); 696c05f20fbSrjs } 697c05f20fbSrjs } else { 698c05f20fbSrjs stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf); 699c05f20fbSrjs } 700c05f20fbSrjs cntDel++; 701c05f20fbSrjs } else { 702c05f20fbSrjs if (sctp_sbspace(&stcb->sctp_socket->so_rcv) >= 703c05f20fbSrjs (long)chk->send_size) { 704c05f20fbSrjs sbappend(&stcb->sctp_socket->so_rcv, chk->data); 705c05f20fbSrjs cntDel++; 706c05f20fbSrjs } else { 707c05f20fbSrjs /* out of space in the sb */ 708c05f20fbSrjs sctp_sorwakeup(stcb->sctp_ep, 709c05f20fbSrjs stcb->sctp_socket); 710c05f20fbSrjs if (hold_locks == 0) { 711c05f20fbSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 712c05f20fbSrjs } 713c05f20fbSrjs return; 714c05f20fbSrjs } 715c05f20fbSrjs } 716c05f20fbSrjs /* pull it we did it */ 717c05f20fbSrjs TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next); 718c05f20fbSrjs if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { 719c05f20fbSrjs asoc->fragmented_delivery_inprogress = 0; 720c05f20fbSrjs if ((chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) == 0) { 721c05f20fbSrjs asoc->strmin[stream_no].last_sequence_delivered++; 722c05f20fbSrjs } 723c05f20fbSrjs } 724c05f20fbSrjs asoc->tsn_last_delivered = chk->rec.data.TSN_seq; 725c05f20fbSrjs asoc->size_on_reasm_queue -= chk->send_size; 726c05f20fbSrjs asoc->cnt_on_reasm_queue--; 727c05f20fbSrjs /* free up the chk */ 728c05f20fbSrjs sctp_free_remote_addr(chk->whoTo); 729c05f20fbSrjs chk->data = NULL; 730c05f20fbSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk); 731c05f20fbSrjs sctppcbinfo.ipi_count_chunk--; 732c05f20fbSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) { 733c05f20fbSrjs panic("Chunk count is negative"); 734c05f20fbSrjs } 735c05f20fbSrjs sctppcbinfo.ipi_gencnt_chunk++; 736c05f20fbSrjs if (asoc->fragmented_delivery_inprogress == 0) { 737c05f20fbSrjs /* 738c05f20fbSrjs * Now lets see if we can deliver the next one on the 739c05f20fbSrjs * stream 740c05f20fbSrjs */ 741c05f20fbSrjs /*u_int16_t nxt_todel;*/ 742c05f20fbSrjs struct sctp_stream_in *strm; 743c05f20fbSrjs 744c05f20fbSrjs strm = &asoc->strmin[stream_no]; 745c05f20fbSrjs nxt_todel = strm->last_sequence_delivered + 1; 746c05f20fbSrjs chk = TAILQ_FIRST(&strm->inqueue); 747c05f20fbSrjs if (chk && (nxt_todel == chk->rec.data.stream_seq)) { 748c05f20fbSrjs while (chk != NULL) { 749c05f20fbSrjs /* all delivered */ 750c05f20fbSrjs if (nxt_todel == 751c05f20fbSrjs chk->rec.data.stream_seq) { 752c05f20fbSrjs at = TAILQ_NEXT(chk, sctp_next); 753c05f20fbSrjs TAILQ_REMOVE(&strm->inqueue, 754c05f20fbSrjs chk, sctp_next); 755c05f20fbSrjs asoc->size_on_all_streams -= 756c05f20fbSrjs chk->send_size; 757c05f20fbSrjs asoc->cnt_on_all_streams--; 758c05f20fbSrjs strm->last_sequence_delivered++; 759c05f20fbSrjs /* 760c05f20fbSrjs * We ignore the return of 761c05f20fbSrjs * deliver_data here since we 762c05f20fbSrjs * always can hold the chunk on 763c05f20fbSrjs * the d-queue. And we have a 764c05f20fbSrjs * finite number that can be 765c05f20fbSrjs * delivered from the strq. 766c05f20fbSrjs */ 767c05f20fbSrjs sctp_deliver_data(stcb, asoc, chk, 1); 768c05f20fbSrjs chk = at; 769c05f20fbSrjs } else { 770c05f20fbSrjs break; 771c05f20fbSrjs } 772c05f20fbSrjs nxt_todel = 773c05f20fbSrjs strm->last_sequence_delivered + 1; 774c05f20fbSrjs } 775c05f20fbSrjs } 776c05f20fbSrjs if (!TAILQ_EMPTY(&asoc->delivery_queue)) { 777c05f20fbSrjs /* Here if deliver_data fails, we must break */ 778c05f20fbSrjs if (sctp_deliver_data(stcb, asoc, NULL, 1) == 0) 779c05f20fbSrjs break; 780c05f20fbSrjs } 781c05f20fbSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 782c05f20fbSrjs if (hold_locks == 0) { 783c05f20fbSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 784c05f20fbSrjs } 785c05f20fbSrjs return; 786c05f20fbSrjs } 787c05f20fbSrjs chk = TAILQ_FIRST(&asoc->reasmqueue); 788c05f20fbSrjs } while (chk); 789c05f20fbSrjs if (cntDel) { 790c05f20fbSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 791c05f20fbSrjs } 792c05f20fbSrjs if (hold_locks == 0) { 793c05f20fbSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 794c05f20fbSrjs } 795c05f20fbSrjs } 796c05f20fbSrjs 797c05f20fbSrjs /* 798c05f20fbSrjs * Queue the chunk either right into the socket buffer if it is the next one 799c05f20fbSrjs * to go OR put it in the correct place in the delivery queue. If we do 800c05f20fbSrjs * append to the so_buf, keep doing so until we are out of order. 801c05f20fbSrjs * One big question still remains, what to do when the socket buffer is FULL?? 802c05f20fbSrjs */ 803c05f20fbSrjs static void 804c05f20fbSrjs sctp_queue_data_to_stream(struct sctp_tcb *stcb, struct sctp_association *asoc, 805c05f20fbSrjs struct sctp_tmit_chunk *chk, int *abort_flag) 806c05f20fbSrjs { 807c05f20fbSrjs struct sctp_stream_in *strm; 808c05f20fbSrjs struct sctp_tmit_chunk *at; 809c05f20fbSrjs int queue_needed; 810c05f20fbSrjs u_int16_t nxt_todel; 811c05f20fbSrjs struct mbuf *oper; 812c05f20fbSrjs 813c05f20fbSrjs /*** FIX FIX FIX ??? 814c05f20fbSrjs * Need to add code to deal with 16 bit seq wrap 815c05f20fbSrjs * without a TSN wrap for ordered delivery (maybe). 816c05f20fbSrjs * FIX FIX FIX ??? 817c05f20fbSrjs */ 818c05f20fbSrjs queue_needed = 1; 819c05f20fbSrjs asoc->size_on_all_streams += chk->send_size; 820c05f20fbSrjs asoc->cnt_on_all_streams++; 821c05f20fbSrjs strm = &asoc->strmin[chk->rec.data.stream_number]; 822c05f20fbSrjs nxt_todel = strm->last_sequence_delivered + 1; 823c05f20fbSrjs #ifdef SCTP_STR_LOGGING 824c05f20fbSrjs sctp_log_strm_del(chk, NULL, SCTP_STR_LOG_FROM_INTO_STRD); 825c05f20fbSrjs #endif 826c05f20fbSrjs #ifdef SCTP_DEBUG 827c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 828c05f20fbSrjs printf("queue to stream called for ssn:%u lastdel:%u nxt:%u\n", 829c05f20fbSrjs (u_int)chk->rec.data.stream_seq, 830c05f20fbSrjs (u_int)strm->last_sequence_delivered, (u_int)nxt_todel); 831c05f20fbSrjs } 832c05f20fbSrjs #endif 833c05f20fbSrjs if (compare_with_wrap(strm->last_sequence_delivered, 834c05f20fbSrjs chk->rec.data.stream_seq, MAX_SEQ) || 835c05f20fbSrjs (strm->last_sequence_delivered == chk->rec.data.stream_seq)) { 836c05f20fbSrjs /* The incoming sseq is behind where we last delivered? */ 837c05f20fbSrjs #ifdef SCTP_DEBUG 838c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 839c05f20fbSrjs printf("Duplicate S-SEQ:%d delivered:%d from peer, Abort association\n", 840c05f20fbSrjs chk->rec.data.stream_seq, 841c05f20fbSrjs strm->last_sequence_delivered); 842c05f20fbSrjs } 843c05f20fbSrjs #endif 844c05f20fbSrjs /* 845c05f20fbSrjs * throw it in the stream so it gets cleaned up in 846c05f20fbSrjs * association destruction 847c05f20fbSrjs */ 848c05f20fbSrjs TAILQ_INSERT_HEAD(&strm->inqueue, chk, sctp_next); 849c05f20fbSrjs MGET(oper, M_DONTWAIT, MT_DATA); 850c05f20fbSrjs if (oper) { 851c05f20fbSrjs struct sctp_paramhdr *ph; 852c05f20fbSrjs u_int32_t *ippp; 853c05f20fbSrjs 854c05f20fbSrjs oper->m_len = sizeof(struct sctp_paramhdr) + 855c05f20fbSrjs sizeof(*ippp); 856c05f20fbSrjs ph = mtod(oper, struct sctp_paramhdr *); 857c05f20fbSrjs ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 858c05f20fbSrjs ph->param_length = htons(oper->m_len); 859c05f20fbSrjs ippp = (u_int32_t *)(ph + 1); 860c05f20fbSrjs *ippp = htonl(0x00000001); 861c05f20fbSrjs } 862c05f20fbSrjs sctp_abort_an_association(stcb->sctp_ep, stcb, 863c05f20fbSrjs SCTP_PEER_FAULTY, oper); 864c05f20fbSrjs 865c05f20fbSrjs *abort_flag = 1; 866c05f20fbSrjs return; 867c05f20fbSrjs 868c05f20fbSrjs } 869c05f20fbSrjs if (nxt_todel == chk->rec.data.stream_seq) { 870c05f20fbSrjs /* can be delivered right away */ 871c05f20fbSrjs #ifdef SCTP_DEBUG 872c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 873c05f20fbSrjs printf("It's NEXT!\n"); 874c05f20fbSrjs } 875c05f20fbSrjs #endif 876c05f20fbSrjs #ifdef SCTP_STR_LOGGING 877c05f20fbSrjs sctp_log_strm_del(chk, NULL, SCTP_STR_LOG_FROM_IMMED_DEL); 878c05f20fbSrjs #endif 879c05f20fbSrjs queue_needed = 0; 880c05f20fbSrjs asoc->size_on_all_streams -= chk->send_size; 881c05f20fbSrjs asoc->cnt_on_all_streams--; 882c05f20fbSrjs strm->last_sequence_delivered++; 883c05f20fbSrjs sctp_deliver_data(stcb, asoc, chk, 0); 884c05f20fbSrjs chk = TAILQ_FIRST(&strm->inqueue); 885c05f20fbSrjs while (chk != NULL) { 886c05f20fbSrjs /* all delivered */ 887c05f20fbSrjs nxt_todel = strm->last_sequence_delivered + 1; 888c05f20fbSrjs if (nxt_todel == chk->rec.data.stream_seq) { 889c05f20fbSrjs at = TAILQ_NEXT(chk, sctp_next); 890c05f20fbSrjs TAILQ_REMOVE(&strm->inqueue, chk, sctp_next); 891c05f20fbSrjs asoc->size_on_all_streams -= chk->send_size; 892c05f20fbSrjs asoc->cnt_on_all_streams--; 893c05f20fbSrjs strm->last_sequence_delivered++; 894c05f20fbSrjs /* 895c05f20fbSrjs * We ignore the return of deliver_data here 896c05f20fbSrjs * since we always can hold the chunk on the 897c05f20fbSrjs * d-queue. And we have a finite number that 898c05f20fbSrjs * can be delivered from the strq. 899c05f20fbSrjs */ 900c05f20fbSrjs #ifdef SCTP_STR_LOGGING 901c05f20fbSrjs sctp_log_strm_del(chk, NULL, 902c05f20fbSrjs SCTP_STR_LOG_FROM_IMMED_DEL); 903c05f20fbSrjs #endif 904c05f20fbSrjs sctp_deliver_data(stcb, asoc, chk, 0); 905c05f20fbSrjs chk = at; 906c05f20fbSrjs continue; 907c05f20fbSrjs } 908c05f20fbSrjs break; 909c05f20fbSrjs } 910c05f20fbSrjs } 911c05f20fbSrjs if (queue_needed) { 912c05f20fbSrjs /* 913c05f20fbSrjs * Ok, we did not deliver this guy, find 914c05f20fbSrjs * the correct place to put it on the queue. 915c05f20fbSrjs */ 916c05f20fbSrjs #ifdef SCTP_DEBUG 917c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 918c05f20fbSrjs printf("Queue Needed!\n"); 919c05f20fbSrjs } 920c05f20fbSrjs #endif 921c05f20fbSrjs if (TAILQ_EMPTY(&strm->inqueue)) { 922c05f20fbSrjs /* Empty queue */ 923c05f20fbSrjs #ifdef SCTP_STR_LOGGING 924c05f20fbSrjs sctp_log_strm_del(chk, NULL, SCTP_STR_LOG_FROM_INSERT_HD); 925c05f20fbSrjs #endif 926c05f20fbSrjs TAILQ_INSERT_HEAD(&strm->inqueue, chk, sctp_next); 927c05f20fbSrjs } else { 928c05f20fbSrjs TAILQ_FOREACH(at, &strm->inqueue, sctp_next) { 929c05f20fbSrjs if (compare_with_wrap(at->rec.data.stream_seq, 930c05f20fbSrjs chk->rec.data.stream_seq, MAX_SEQ)) { 931c05f20fbSrjs /* 932c05f20fbSrjs * one in queue is bigger than the new 933c05f20fbSrjs * one, insert before this one 934c05f20fbSrjs */ 935c05f20fbSrjs #ifdef SCTP_STR_LOGGING 936c05f20fbSrjs sctp_log_strm_del(chk, at, 937c05f20fbSrjs SCTP_STR_LOG_FROM_INSERT_MD); 938c05f20fbSrjs #endif 939c05f20fbSrjs TAILQ_INSERT_BEFORE(at, chk, sctp_next); 940c05f20fbSrjs break; 941c05f20fbSrjs } else if (at->rec.data.stream_seq == 942c05f20fbSrjs chk->rec.data.stream_seq) { 943c05f20fbSrjs /* 944c05f20fbSrjs * Gak, He sent me a duplicate str seq 945c05f20fbSrjs * number 946c05f20fbSrjs */ 947c05f20fbSrjs /* 948c05f20fbSrjs * foo bar, I guess I will just free 949c05f20fbSrjs * this new guy, should we abort too? 950c05f20fbSrjs * FIX ME MAYBE? Or it COULD be that 951c05f20fbSrjs * the SSN's have wrapped. Maybe I 952c05f20fbSrjs * should compare to TSN somehow... 953c05f20fbSrjs * sigh for now just blow away the 954c05f20fbSrjs * chunk! 955c05f20fbSrjs */ 956c05f20fbSrjs 957c05f20fbSrjs if (chk->data) 958c05f20fbSrjs sctp_m_freem(chk->data); 959c05f20fbSrjs chk->data = NULL; 960c05f20fbSrjs asoc->size_on_all_streams -= chk->send_size; 961c05f20fbSrjs asoc->cnt_on_all_streams--; 962c05f20fbSrjs sctp_pegs[SCTP_DUP_SSN_RCVD]++; 963c05f20fbSrjs sctp_free_remote_addr(chk->whoTo); 964c05f20fbSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk); 965c05f20fbSrjs sctppcbinfo.ipi_count_chunk--; 966c05f20fbSrjs if ((int)sctppcbinfo.ipi_count_chunk < 967c05f20fbSrjs 0) { 968c05f20fbSrjs panic("Chunk count is negative"); 969c05f20fbSrjs } 970c05f20fbSrjs sctppcbinfo.ipi_gencnt_chunk++; 971c05f20fbSrjs return; 972c05f20fbSrjs } else { 973c05f20fbSrjs if (TAILQ_NEXT(at, sctp_next) == NULL) { 974c05f20fbSrjs /* 975c05f20fbSrjs * We are at the end, insert it 976c05f20fbSrjs * after this one 977c05f20fbSrjs */ 978c05f20fbSrjs #ifdef SCTP_STR_LOGGING 979c05f20fbSrjs sctp_log_strm_del(chk, at, 980c05f20fbSrjs SCTP_STR_LOG_FROM_INSERT_TL); 981c05f20fbSrjs #endif 982c05f20fbSrjs TAILQ_INSERT_AFTER(&strm->inqueue, 983c05f20fbSrjs at, chk, sctp_next); 984c05f20fbSrjs break; 985c05f20fbSrjs } 986c05f20fbSrjs } 987c05f20fbSrjs } 988c05f20fbSrjs } 989c05f20fbSrjs } else { 990c05f20fbSrjs /* We delivered some chunks, wake them up */ 991c05f20fbSrjs 992c05f20fbSrjs #ifdef SCTP_DEBUG 993c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 994c05f20fbSrjs printf("Doing WAKEUP!\n"); 995c05f20fbSrjs } 996c05f20fbSrjs #endif 997c05f20fbSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 998c05f20fbSrjs } 999c05f20fbSrjs } 1000c05f20fbSrjs 1001c05f20fbSrjs /* 1002c05f20fbSrjs * Returns two things: You get the total size of the deliverable parts of the 1003c05f20fbSrjs * first fragmented message on the reassembly queue. And you get a 1 back if 1004c05f20fbSrjs * all of the message is ready or a 0 back if the message is still incomplete 1005c05f20fbSrjs */ 1006c05f20fbSrjs static int 1007c05f20fbSrjs sctp_is_all_msg_on_reasm(struct sctp_association *asoc, int *t_size) 1008c05f20fbSrjs { 1009c05f20fbSrjs struct sctp_tmit_chunk *chk; 1010c05f20fbSrjs u_int32_t tsn; 1011c05f20fbSrjs 1012c05f20fbSrjs *t_size = 0; 1013c05f20fbSrjs chk = TAILQ_FIRST(&asoc->reasmqueue); 1014c05f20fbSrjs if (chk == NULL) { 1015c05f20fbSrjs /* nothing on the queue */ 1016c05f20fbSrjs return (0); 1017c05f20fbSrjs } 1018c05f20fbSrjs if ((chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) == 0) { 1019c05f20fbSrjs /* Not a first on the queue */ 1020c05f20fbSrjs return (0); 1021c05f20fbSrjs } 1022c05f20fbSrjs tsn = chk->rec.data.TSN_seq; 1023c05f20fbSrjs while (chk) { 1024c05f20fbSrjs if (tsn != chk->rec.data.TSN_seq) { 1025c05f20fbSrjs return (0); 1026c05f20fbSrjs } 1027c05f20fbSrjs *t_size += chk->send_size; 1028c05f20fbSrjs if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { 1029c05f20fbSrjs return (1); 1030c05f20fbSrjs } 1031c05f20fbSrjs tsn++; 1032c05f20fbSrjs chk = TAILQ_NEXT(chk, sctp_next); 1033c05f20fbSrjs } 1034c05f20fbSrjs return (0); 1035c05f20fbSrjs } 1036c05f20fbSrjs 1037c05f20fbSrjs /* 1038c05f20fbSrjs * Dump onto the re-assembly queue, in its proper place. After dumping on 1039c05f20fbSrjs * the queue, see if anthing can be delivered. If so pull it off (or as much 1040c05f20fbSrjs * as we can. If we run out of space then we must dump what we can and set 1041c05f20fbSrjs * the appropriate flag to say we queued what we could. 1042c05f20fbSrjs */ 1043c05f20fbSrjs static void 1044c05f20fbSrjs sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, 1045c05f20fbSrjs struct sctp_tmit_chunk *chk, int *abort_flag) 1046c05f20fbSrjs { 1047c05f20fbSrjs struct mbuf *oper; 1048c05f20fbSrjs u_int16_t nxt_todel; 1049c05f20fbSrjs u_int32_t cum_ackp1, prev_tsn, post_tsn; 1050c05f20fbSrjs int tsize; 1051c05f20fbSrjs struct sctp_tmit_chunk *at, *prev, *next; 1052c05f20fbSrjs 1053c05f20fbSrjs prev = next = NULL; 1054c05f20fbSrjs cum_ackp1 = asoc->tsn_last_delivered + 1; 1055c05f20fbSrjs 1056c05f20fbSrjs if (TAILQ_EMPTY(&asoc->reasmqueue)) { 1057c05f20fbSrjs /* This is the first one on the queue */ 1058c05f20fbSrjs TAILQ_INSERT_HEAD(&asoc->reasmqueue, chk, sctp_next); 1059c05f20fbSrjs /* 1060c05f20fbSrjs * we do not check for delivery of anything when 1061c05f20fbSrjs * only one fragment is here 1062c05f20fbSrjs */ 1063c05f20fbSrjs asoc->size_on_reasm_queue = chk->send_size; 1064c05f20fbSrjs asoc->cnt_on_reasm_queue++; 1065c05f20fbSrjs if (chk->rec.data.TSN_seq == cum_ackp1) { 1066c05f20fbSrjs if (asoc->fragmented_delivery_inprogress == 0 && 1067c05f20fbSrjs (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) != 1068c05f20fbSrjs SCTP_DATA_FIRST_FRAG) { 1069c05f20fbSrjs /* 1070c05f20fbSrjs * An empty queue, no delivery inprogress, we 1071c05f20fbSrjs * hit the next one and it does NOT have a 1072c05f20fbSrjs * FIRST fragment mark. 1073c05f20fbSrjs */ 1074c05f20fbSrjs #ifdef SCTP_DEBUG 1075c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 1076c05f20fbSrjs printf("Gak, Evil plot, its not first, no fragmented delivery in progress\n"); 1077c05f20fbSrjs } 1078c05f20fbSrjs #endif 1079c05f20fbSrjs MGET(oper, M_DONTWAIT, MT_DATA); 1080c05f20fbSrjs if (oper) { 1081c05f20fbSrjs struct sctp_paramhdr *ph; 1082c05f20fbSrjs u_int32_t *ippp; 1083c05f20fbSrjs 1084c05f20fbSrjs oper->m_len = 1085c05f20fbSrjs sizeof(struct sctp_paramhdr) + 1086c05f20fbSrjs sizeof(*ippp); 1087c05f20fbSrjs ph = mtod(oper, struct sctp_paramhdr *); 1088c05f20fbSrjs ph->param_type = 1089c05f20fbSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 1090c05f20fbSrjs ph->param_length = htons(oper->m_len); 1091c05f20fbSrjs ippp = (u_int32_t *)(ph + 1); 1092c05f20fbSrjs *ippp = htonl(0x10000001); 1093c05f20fbSrjs } 1094c05f20fbSrjs sctp_abort_an_association(stcb->sctp_ep, stcb, 1095c05f20fbSrjs SCTP_PEER_FAULTY, oper); 1096c05f20fbSrjs *abort_flag = 1; 1097c05f20fbSrjs } else if (asoc->fragmented_delivery_inprogress && 1098c05f20fbSrjs (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) == SCTP_DATA_FIRST_FRAG) { 1099c05f20fbSrjs /* 1100c05f20fbSrjs * We are doing a partial delivery and the NEXT 1101c05f20fbSrjs * chunk MUST be either the LAST or MIDDLE 1102c05f20fbSrjs * fragment NOT a FIRST 1103c05f20fbSrjs */ 1104c05f20fbSrjs #ifdef SCTP_DEBUG 1105c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 1106c05f20fbSrjs printf("Gak, Evil plot, it IS a first and fragmented delivery in progress\n"); 1107c05f20fbSrjs } 1108c05f20fbSrjs #endif 1109c05f20fbSrjs MGET(oper, M_DONTWAIT, MT_DATA); 1110c05f20fbSrjs if (oper) { 1111c05f20fbSrjs struct sctp_paramhdr *ph; 1112c05f20fbSrjs u_int32_t *ippp; 1113c05f20fbSrjs 1114c05f20fbSrjs oper->m_len = 1115c05f20fbSrjs sizeof(struct sctp_paramhdr) + 1116c05f20fbSrjs sizeof(*ippp); 1117c05f20fbSrjs ph = mtod(oper, struct sctp_paramhdr *); 1118c05f20fbSrjs ph->param_type = 1119c05f20fbSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 1120c05f20fbSrjs ph->param_length = htons(oper->m_len); 1121c05f20fbSrjs ippp = (u_int32_t *)(ph + 1); 1122c05f20fbSrjs *ippp = htonl(0x10000002); 1123c05f20fbSrjs } 1124c05f20fbSrjs sctp_abort_an_association(stcb->sctp_ep, stcb, 1125c05f20fbSrjs SCTP_PEER_FAULTY, oper); 1126c05f20fbSrjs *abort_flag = 1; 1127c05f20fbSrjs } else if (asoc->fragmented_delivery_inprogress) { 1128c05f20fbSrjs /* Here we are ok with a MIDDLE or LAST piece */ 1129c05f20fbSrjs if (chk->rec.data.stream_number != 1130c05f20fbSrjs asoc->str_of_pdapi) { 1131c05f20fbSrjs /* Got to be the right STR No */ 1132c05f20fbSrjs #ifdef SCTP_DEBUG 1133c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 1134c05f20fbSrjs printf("Gak, Evil plot, it IS not same stream number %d vs %d\n", 1135c05f20fbSrjs chk->rec.data.stream_number, 1136c05f20fbSrjs asoc->str_of_pdapi); 1137c05f20fbSrjs } 1138c05f20fbSrjs #endif 1139c05f20fbSrjs MGET(oper, M_DONTWAIT, MT_DATA); 1140c05f20fbSrjs if (oper) { 1141c05f20fbSrjs struct sctp_paramhdr *ph; 1142c05f20fbSrjs u_int32_t *ippp; 1143c05f20fbSrjs oper->m_len = 1144c05f20fbSrjs sizeof(struct sctp_paramhdr) + 1145c05f20fbSrjs sizeof(*ippp); 1146c05f20fbSrjs ph = mtod(oper, 1147c05f20fbSrjs struct sctp_paramhdr *); 1148c05f20fbSrjs ph->param_type = 1149c05f20fbSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 1150c05f20fbSrjs ph->param_length = 1151c05f20fbSrjs htons(oper->m_len); 1152c05f20fbSrjs ippp = (u_int32_t *)(ph + 1); 1153c05f20fbSrjs *ippp = htonl(0x10000003); 1154c05f20fbSrjs } 1155c05f20fbSrjs sctp_abort_an_association(stcb->sctp_ep, 1156c05f20fbSrjs stcb, SCTP_PEER_FAULTY, oper); 1157c05f20fbSrjs *abort_flag = 1; 1158c05f20fbSrjs } else if ((asoc->fragment_flags & SCTP_DATA_UNORDERED) != 1159c05f20fbSrjs SCTP_DATA_UNORDERED && 1160c05f20fbSrjs chk->rec.data.stream_seq != 1161c05f20fbSrjs asoc->ssn_of_pdapi) { 1162c05f20fbSrjs /* Got to be the right STR Seq */ 1163c05f20fbSrjs #ifdef SCTP_DEBUG 1164c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 1165c05f20fbSrjs printf("Gak, Evil plot, it IS not same stream seq %d vs %d\n", 1166c05f20fbSrjs chk->rec.data.stream_seq, 1167c05f20fbSrjs asoc->ssn_of_pdapi); 1168c05f20fbSrjs } 1169c05f20fbSrjs #endif 1170c05f20fbSrjs MGET(oper, M_DONTWAIT, MT_DATA); 1171c05f20fbSrjs if (oper) { 1172c05f20fbSrjs struct sctp_paramhdr *ph; 1173c05f20fbSrjs u_int32_t *ippp; 1174c05f20fbSrjs oper->m_len = 1175c05f20fbSrjs sizeof(struct sctp_paramhdr) + 1176c05f20fbSrjs sizeof(*ippp); 1177c05f20fbSrjs ph = mtod(oper, 1178c05f20fbSrjs struct sctp_paramhdr *); 1179c05f20fbSrjs ph->param_type = 1180c05f20fbSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 1181c05f20fbSrjs ph->param_length = 1182c05f20fbSrjs htons(oper->m_len); 1183c05f20fbSrjs ippp = (u_int32_t *)(ph + 1); 1184c05f20fbSrjs *ippp = htonl(0x10000004); 1185c05f20fbSrjs } 1186c05f20fbSrjs sctp_abort_an_association(stcb->sctp_ep, 1187c05f20fbSrjs stcb, SCTP_PEER_FAULTY, oper); 1188c05f20fbSrjs *abort_flag = 1; 1189c05f20fbSrjs } 1190c05f20fbSrjs } 1191c05f20fbSrjs } 1192c05f20fbSrjs return; 1193c05f20fbSrjs } 1194c05f20fbSrjs /* Find its place */ 1195c05f20fbSrjs at = TAILQ_FIRST(&asoc->reasmqueue); 1196c05f20fbSrjs 1197c05f20fbSrjs /* Grab the top flags */ 1198c05f20fbSrjs TAILQ_FOREACH(at, &asoc->reasmqueue, sctp_next) { 1199c05f20fbSrjs if (compare_with_wrap(at->rec.data.TSN_seq, 1200c05f20fbSrjs chk->rec.data.TSN_seq, MAX_TSN)) { 1201c05f20fbSrjs /* 1202c05f20fbSrjs * one in queue is bigger than the new one, insert 1203c05f20fbSrjs * before this one 1204c05f20fbSrjs */ 1205c05f20fbSrjs /* A check */ 1206c05f20fbSrjs asoc->size_on_reasm_queue += chk->send_size; 1207c05f20fbSrjs asoc->cnt_on_reasm_queue++; 1208c05f20fbSrjs next = at; 1209c05f20fbSrjs TAILQ_INSERT_BEFORE(at, chk, sctp_next); 1210c05f20fbSrjs break; 1211c05f20fbSrjs } else if (at->rec.data.TSN_seq == chk->rec.data.TSN_seq) { 1212c05f20fbSrjs /* Gak, He sent me a duplicate str seq number */ 1213c05f20fbSrjs /* 1214c05f20fbSrjs * foo bar, I guess I will just free this new guy, 1215c05f20fbSrjs * should we abort too? FIX ME MAYBE? Or it COULD be 1216c05f20fbSrjs * that the SSN's have wrapped. Maybe I should compare 1217c05f20fbSrjs * to TSN somehow... sigh for now just blow away the 1218c05f20fbSrjs * chunk! 1219c05f20fbSrjs */ 1220c05f20fbSrjs if (chk->data) 1221c05f20fbSrjs sctp_m_freem(chk->data); 1222c05f20fbSrjs chk->data = NULL; 1223c05f20fbSrjs sctp_free_remote_addr(chk->whoTo); 1224c05f20fbSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk); 1225c05f20fbSrjs sctppcbinfo.ipi_count_chunk--; 1226c05f20fbSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) { 1227c05f20fbSrjs panic("Chunk count is negative"); 1228c05f20fbSrjs } 1229c05f20fbSrjs sctppcbinfo.ipi_gencnt_chunk++; 1230c05f20fbSrjs return; 1231c05f20fbSrjs } else { 1232c05f20fbSrjs prev = at; 1233c05f20fbSrjs if (TAILQ_NEXT(at, sctp_next) == NULL) { 1234c05f20fbSrjs /* 1235c05f20fbSrjs * We are at the end, insert it after this one 1236c05f20fbSrjs */ 1237c05f20fbSrjs /* check it first */ 1238c05f20fbSrjs asoc->size_on_reasm_queue += chk->send_size; 1239c05f20fbSrjs asoc->cnt_on_reasm_queue++; 1240c05f20fbSrjs TAILQ_INSERT_AFTER(&asoc->reasmqueue, at, chk, sctp_next); 1241c05f20fbSrjs break; 1242c05f20fbSrjs } 1243c05f20fbSrjs } 1244c05f20fbSrjs } 1245c05f20fbSrjs /* Now the audits */ 1246c05f20fbSrjs if (prev) { 1247c05f20fbSrjs prev_tsn = chk->rec.data.TSN_seq - 1; 1248c05f20fbSrjs if (prev_tsn == prev->rec.data.TSN_seq) { 1249c05f20fbSrjs /* 1250c05f20fbSrjs * Ok the one I am dropping onto the end 1251c05f20fbSrjs * is the NEXT. A bit of valdiation here. 1252c05f20fbSrjs */ 1253c05f20fbSrjs if ((prev->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) == 1254c05f20fbSrjs SCTP_DATA_FIRST_FRAG || 1255c05f20fbSrjs (prev->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) == 1256c05f20fbSrjs SCTP_DATA_MIDDLE_FRAG) { 1257c05f20fbSrjs /* 1258c05f20fbSrjs * Insert chk MUST be a MIDDLE or LAST fragment 1259c05f20fbSrjs */ 1260c05f20fbSrjs if ((chk->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) == 1261c05f20fbSrjs SCTP_DATA_FIRST_FRAG) { 1262c05f20fbSrjs #ifdef SCTP_DEBUG 1263c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 1264c05f20fbSrjs printf("Prev check - It can be a midlle or last but not a first\n"); 1265c05f20fbSrjs printf("Gak, Evil plot, it's a FIRST!\n"); 1266c05f20fbSrjs } 1267c05f20fbSrjs #endif 1268c05f20fbSrjs MGET(oper, M_DONTWAIT, MT_DATA); 1269c05f20fbSrjs if (oper) { 1270c05f20fbSrjs struct sctp_paramhdr *ph; 1271c05f20fbSrjs u_int32_t *ippp; 1272c05f20fbSrjs 1273c05f20fbSrjs oper->m_len = 1274c05f20fbSrjs sizeof(struct sctp_paramhdr) + 1275c05f20fbSrjs sizeof(*ippp); 1276c05f20fbSrjs ph = mtod(oper, 1277c05f20fbSrjs struct sctp_paramhdr *); 1278c05f20fbSrjs ph->param_type = 1279c05f20fbSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 1280c05f20fbSrjs ph->param_length = 1281c05f20fbSrjs htons(oper->m_len); 1282c05f20fbSrjs 1283c05f20fbSrjs ippp = (u_int32_t *)(ph + 1); 1284c05f20fbSrjs *ippp = htonl(0x10000005); 1285c05f20fbSrjs } 1286c05f20fbSrjs sctp_abort_an_association(stcb->sctp_ep, 1287c05f20fbSrjs stcb, SCTP_PEER_FAULTY, oper); 1288c05f20fbSrjs *abort_flag = 1; 1289c05f20fbSrjs return; 1290c05f20fbSrjs } 1291c05f20fbSrjs if (chk->rec.data.stream_number != 1292c05f20fbSrjs prev->rec.data.stream_number) { 1293c05f20fbSrjs /* 1294c05f20fbSrjs * Huh, need the correct STR here, they 1295c05f20fbSrjs * must be the same. 1296c05f20fbSrjs */ 1297c05f20fbSrjs #ifdef SCTP_DEBUG 1298c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 1299c05f20fbSrjs printf("Prev check - Gak, Evil plot, ssn:%d not the same as at:%d\n", 1300c05f20fbSrjs chk->rec.data.stream_number, 1301c05f20fbSrjs prev->rec.data.stream_number); 1302c05f20fbSrjs } 1303c05f20fbSrjs #endif 1304c05f20fbSrjs MGET(oper, M_DONTWAIT, MT_DATA); 1305c05f20fbSrjs if (oper) { 1306c05f20fbSrjs struct sctp_paramhdr *ph; 1307c05f20fbSrjs u_int32_t *ippp; 1308c05f20fbSrjs 1309c05f20fbSrjs oper->m_len = 1310c05f20fbSrjs sizeof(struct sctp_paramhdr) + 1311c05f20fbSrjs sizeof(*ippp); 1312c05f20fbSrjs ph = mtod(oper, 1313c05f20fbSrjs struct sctp_paramhdr *); 1314c05f20fbSrjs ph->param_type = 1315c05f20fbSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 1316c05f20fbSrjs ph->param_length = 1317c05f20fbSrjs htons(oper->m_len); 1318c05f20fbSrjs ippp = (u_int32_t *)(ph + 1); 1319c05f20fbSrjs *ippp = htonl(0x10000006); 1320c05f20fbSrjs } 1321c05f20fbSrjs 1322c05f20fbSrjs sctp_abort_an_association(stcb->sctp_ep, 1323c05f20fbSrjs stcb, SCTP_PEER_FAULTY, oper); 1324c05f20fbSrjs 1325c05f20fbSrjs *abort_flag = 1; 1326c05f20fbSrjs return; 1327c05f20fbSrjs } 1328c05f20fbSrjs if ((prev->rec.data.rcv_flags & SCTP_DATA_UNORDERED) == 0 && 1329c05f20fbSrjs chk->rec.data.stream_seq != 1330c05f20fbSrjs prev->rec.data.stream_seq) { 1331c05f20fbSrjs /* 1332c05f20fbSrjs * Huh, need the correct STR here, they 1333c05f20fbSrjs * must be the same. 1334c05f20fbSrjs */ 1335c05f20fbSrjs #ifdef SCTP_DEBUG 1336c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 1337c05f20fbSrjs printf("Prev check - Gak, Evil plot, sseq:%d not the same as at:%d\n", 1338c05f20fbSrjs chk->rec.data.stream_seq, 1339c05f20fbSrjs prev->rec.data.stream_seq); 1340c05f20fbSrjs } 1341c05f20fbSrjs #endif 1342c05f20fbSrjs MGET(oper, M_DONTWAIT, MT_DATA); 1343c05f20fbSrjs if (oper) { 1344c05f20fbSrjs struct sctp_paramhdr *ph; 1345c05f20fbSrjs u_int32_t *ippp; 1346c05f20fbSrjs 1347c05f20fbSrjs oper->m_len = 1348c05f20fbSrjs sizeof(struct sctp_paramhdr) + 1349c05f20fbSrjs sizeof(*ippp); 1350c05f20fbSrjs ph = mtod(oper, 1351c05f20fbSrjs struct sctp_paramhdr *); 1352c05f20fbSrjs ph->param_type = 1353c05f20fbSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 1354c05f20fbSrjs ph->param_length = 1355c05f20fbSrjs htons(oper->m_len); 1356c05f20fbSrjs ippp = (u_int32_t *)(ph + 1); 1357c05f20fbSrjs *ippp = htonl(0x10000007); 1358c05f20fbSrjs } 1359c05f20fbSrjs 1360c05f20fbSrjs sctp_abort_an_association(stcb->sctp_ep, 1361c05f20fbSrjs stcb, SCTP_PEER_FAULTY, oper); 1362c05f20fbSrjs 1363c05f20fbSrjs *abort_flag = 1; 1364c05f20fbSrjs return; 1365c05f20fbSrjs } 1366c05f20fbSrjs } else if ((prev->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) == 1367c05f20fbSrjs SCTP_DATA_LAST_FRAG) { 1368c05f20fbSrjs /* Insert chk MUST be a FIRST */ 1369c05f20fbSrjs if ((chk->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) != 1370c05f20fbSrjs SCTP_DATA_FIRST_FRAG) { 1371c05f20fbSrjs #ifdef SCTP_DEBUG 1372c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 1373c05f20fbSrjs printf("Prev check - Gak, evil plot, its not FIRST and it must be!\n"); 1374c05f20fbSrjs } 1375c05f20fbSrjs #endif 1376c05f20fbSrjs MGET(oper, M_DONTWAIT, MT_DATA); 1377c05f20fbSrjs if (oper) { 1378c05f20fbSrjs struct sctp_paramhdr *ph; 1379c05f20fbSrjs u_int32_t *ippp; 1380c05f20fbSrjs 1381c05f20fbSrjs oper->m_len = 1382c05f20fbSrjs sizeof(struct sctp_paramhdr) + 1383c05f20fbSrjs sizeof(*ippp); 1384c05f20fbSrjs ph = mtod(oper, 1385c05f20fbSrjs struct sctp_paramhdr *); 1386c05f20fbSrjs ph->param_type = 1387c05f20fbSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 1388c05f20fbSrjs ph->param_length = 1389c05f20fbSrjs htons(oper->m_len); 1390c05f20fbSrjs ippp = (u_int32_t *)(ph + 1); 1391c05f20fbSrjs *ippp = htonl(0x10000008); 1392c05f20fbSrjs } 1393c05f20fbSrjs 1394c05f20fbSrjs sctp_abort_an_association(stcb->sctp_ep, 1395c05f20fbSrjs stcb, SCTP_PEER_FAULTY, oper); 1396c05f20fbSrjs 1397c05f20fbSrjs *abort_flag = 1; 1398c05f20fbSrjs return; 1399c05f20fbSrjs } 1400c05f20fbSrjs } 1401c05f20fbSrjs } 1402c05f20fbSrjs } 1403c05f20fbSrjs 1404c05f20fbSrjs if (next) { 1405c05f20fbSrjs post_tsn = chk->rec.data.TSN_seq + 1; 1406c05f20fbSrjs if (post_tsn == next->rec.data.TSN_seq) { 1407c05f20fbSrjs /* 1408c05f20fbSrjs * Ok the one I am inserting ahead of 1409c05f20fbSrjs * is my NEXT one. A bit of valdiation here. 1410c05f20fbSrjs */ 1411c05f20fbSrjs if (next->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { 1412c05f20fbSrjs /* Insert chk MUST be a last fragment */ 1413c05f20fbSrjs if ((chk->rec.data.rcv_flags&SCTP_DATA_FRAG_MASK) 1414c05f20fbSrjs != SCTP_DATA_LAST_FRAG) { 1415c05f20fbSrjs #ifdef SCTP_DEBUG 1416c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 1417c05f20fbSrjs printf("Next chk - Next is FIRST, we must be LAST\n"); 1418c05f20fbSrjs printf("Gak, Evil plot, its not a last!\n"); 1419c05f20fbSrjs } 1420c05f20fbSrjs #endif 1421c05f20fbSrjs MGET(oper, M_DONTWAIT, MT_DATA); 1422c05f20fbSrjs if (oper) { 1423c05f20fbSrjs struct sctp_paramhdr *ph; 1424c05f20fbSrjs u_int32_t *ippp; 1425c05f20fbSrjs 1426c05f20fbSrjs oper->m_len = 1427c05f20fbSrjs sizeof(struct sctp_paramhdr) + 1428c05f20fbSrjs sizeof(*ippp); 1429c05f20fbSrjs ph = mtod(oper, 1430c05f20fbSrjs struct sctp_paramhdr *); 1431c05f20fbSrjs ph->param_type = 1432c05f20fbSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 1433c05f20fbSrjs ph->param_length = 1434c05f20fbSrjs htons(oper->m_len); 1435c05f20fbSrjs ippp = (u_int32_t *)(ph + 1); 1436c05f20fbSrjs *ippp = htonl(0x10000009); 1437c05f20fbSrjs } 1438c05f20fbSrjs 1439c05f20fbSrjs sctp_abort_an_association(stcb->sctp_ep, 1440c05f20fbSrjs stcb, SCTP_PEER_FAULTY, oper); 1441c05f20fbSrjs 1442c05f20fbSrjs *abort_flag = 1; 1443c05f20fbSrjs return; 1444c05f20fbSrjs } 1445c05f20fbSrjs } else if ((next->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) == 1446c05f20fbSrjs SCTP_DATA_MIDDLE_FRAG || 1447c05f20fbSrjs (next->rec.data.rcv_flags&SCTP_DATA_FRAG_MASK) == 1448c05f20fbSrjs SCTP_DATA_LAST_FRAG) { 1449c05f20fbSrjs /* Insert chk CAN be MIDDLE or FIRST NOT LAST */ 1450c05f20fbSrjs if ((chk->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) == 1451c05f20fbSrjs SCTP_DATA_LAST_FRAG) { 1452c05f20fbSrjs #ifdef SCTP_DEBUG 1453c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 1454c05f20fbSrjs printf("Next chk - Next is a MIDDLE/LAST\n"); 1455c05f20fbSrjs printf("Gak, Evil plot, new prev chunk is a LAST\n"); 1456c05f20fbSrjs } 1457c05f20fbSrjs #endif 1458c05f20fbSrjs MGET(oper, M_DONTWAIT, MT_DATA); 1459c05f20fbSrjs if (oper) { 1460c05f20fbSrjs struct sctp_paramhdr *ph; 1461c05f20fbSrjs u_int32_t *ippp; 1462c05f20fbSrjs 1463c05f20fbSrjs oper->m_len = 1464c05f20fbSrjs sizeof(struct sctp_paramhdr) + 1465c05f20fbSrjs sizeof(*ippp); 1466c05f20fbSrjs ph = mtod(oper, 1467c05f20fbSrjs struct sctp_paramhdr *); 1468c05f20fbSrjs ph->param_type = 1469c05f20fbSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 1470c05f20fbSrjs ph->param_length = 1471c05f20fbSrjs htons(oper->m_len); 1472c05f20fbSrjs ippp = (u_int32_t *)(ph + 1); 1473c05f20fbSrjs *ippp = htonl(0x1000000a); 1474c05f20fbSrjs } 1475c05f20fbSrjs sctp_abort_an_association(stcb->sctp_ep, 1476c05f20fbSrjs stcb, SCTP_PEER_FAULTY, oper); 1477c05f20fbSrjs 1478c05f20fbSrjs *abort_flag = 1; 1479c05f20fbSrjs return; 1480c05f20fbSrjs } 1481c05f20fbSrjs if (chk->rec.data.stream_number != 1482c05f20fbSrjs next->rec.data.stream_number) { 1483c05f20fbSrjs /* 1484c05f20fbSrjs * Huh, need the correct STR here, they 1485c05f20fbSrjs * must be the same. 1486c05f20fbSrjs */ 1487c05f20fbSrjs #ifdef SCTP_DEBUG 1488c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 1489c05f20fbSrjs printf("Next chk - Gak, Evil plot, ssn:%d not the same as at:%d\n", 1490c05f20fbSrjs chk->rec.data.stream_number, 1491c05f20fbSrjs next->rec.data.stream_number); 1492c05f20fbSrjs } 1493c05f20fbSrjs #endif 1494c05f20fbSrjs MGET(oper, M_DONTWAIT, MT_DATA); 1495c05f20fbSrjs if (oper) { 1496c05f20fbSrjs struct sctp_paramhdr *ph; 1497c05f20fbSrjs u_int32_t *ippp; 1498c05f20fbSrjs 1499c05f20fbSrjs oper->m_len = 1500c05f20fbSrjs sizeof(struct sctp_paramhdr) + 1501c05f20fbSrjs sizeof(*ippp); 1502c05f20fbSrjs ph = mtod(oper, 1503c05f20fbSrjs struct sctp_paramhdr *); 1504c05f20fbSrjs ph->param_type = 1505c05f20fbSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 1506c05f20fbSrjs ph->param_length = 1507c05f20fbSrjs htons(oper->m_len); 1508c05f20fbSrjs ippp = (u_int32_t *)(ph + 1); 1509c05f20fbSrjs *ippp = htonl(0x1000000b); 1510c05f20fbSrjs } 1511c05f20fbSrjs 1512c05f20fbSrjs sctp_abort_an_association(stcb->sctp_ep, 1513c05f20fbSrjs stcb, SCTP_PEER_FAULTY, oper); 1514c05f20fbSrjs 1515c05f20fbSrjs *abort_flag = 1; 1516c05f20fbSrjs return; 1517c05f20fbSrjs } 1518c05f20fbSrjs if ((next->rec.data.rcv_flags & SCTP_DATA_UNORDERED) == 0 && 1519c05f20fbSrjs chk->rec.data.stream_seq != 1520c05f20fbSrjs next->rec.data.stream_seq) { 1521c05f20fbSrjs /* 1522c05f20fbSrjs * Huh, need the correct STR here, they 1523c05f20fbSrjs * must be the same. 1524c05f20fbSrjs */ 1525c05f20fbSrjs #ifdef SCTP_DEBUG 1526c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 1527c05f20fbSrjs printf("Next chk - Gak, Evil plot, sseq:%d not the same as at:%d\n", 1528c05f20fbSrjs chk->rec.data.stream_seq, 1529c05f20fbSrjs next->rec.data.stream_seq); 1530c05f20fbSrjs } 1531c05f20fbSrjs #endif 1532c05f20fbSrjs MGET(oper, M_DONTWAIT, MT_DATA); 1533c05f20fbSrjs if (oper) { 1534c05f20fbSrjs struct sctp_paramhdr *ph; 1535c05f20fbSrjs u_int32_t *ippp; 1536c05f20fbSrjs 1537c05f20fbSrjs oper->m_len = 1538c05f20fbSrjs sizeof(struct sctp_paramhdr) + 1539c05f20fbSrjs sizeof(*ippp); 1540c05f20fbSrjs ph = mtod(oper, 1541c05f20fbSrjs struct sctp_paramhdr *); 1542c05f20fbSrjs ph->param_type = 1543c05f20fbSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 1544c05f20fbSrjs ph->param_length = 1545c05f20fbSrjs htons(oper->m_len); 1546c05f20fbSrjs ippp = (u_int32_t *)(ph + 1); 1547c05f20fbSrjs *ippp = htonl(0x1000000c); 1548c05f20fbSrjs } 1549c05f20fbSrjs 1550c05f20fbSrjs sctp_abort_an_association(stcb->sctp_ep, 1551c05f20fbSrjs stcb, SCTP_PEER_FAULTY, oper); 1552c05f20fbSrjs 1553c05f20fbSrjs *abort_flag = 1; 1554c05f20fbSrjs return; 1555c05f20fbSrjs 1556c05f20fbSrjs } 1557c05f20fbSrjs } 1558c05f20fbSrjs } 1559c05f20fbSrjs } 1560c05f20fbSrjs /* 1561c05f20fbSrjs * now that we have all in there place we must check a number of 1562c05f20fbSrjs * things to see if we can send data to the ULP. 1563c05f20fbSrjs */ 1564c05f20fbSrjs /* we need to do some delivery, if we can */ 1565c05f20fbSrjs chk = TAILQ_FIRST(&asoc->reasmqueue); 1566c05f20fbSrjs if (chk == NULL) { 1567c05f20fbSrjs /* Huh? */ 1568c05f20fbSrjs asoc->size_on_reasm_queue = 0; 1569c05f20fbSrjs asoc->cnt_on_reasm_queue = 0; 1570c05f20fbSrjs return; 1571c05f20fbSrjs } 1572c05f20fbSrjs if (asoc->fragmented_delivery_inprogress == 0) { 1573c05f20fbSrjs nxt_todel = 1574c05f20fbSrjs asoc->strmin[chk->rec.data.stream_number].last_sequence_delivered + 1; 1575c05f20fbSrjs if ((chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) && 1576c05f20fbSrjs (nxt_todel == chk->rec.data.stream_seq || 1577c05f20fbSrjs (chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED))) { 1578c05f20fbSrjs /* 1579c05f20fbSrjs * Yep the first one is here and its 1580c05f20fbSrjs * ok to deliver but should we? 1581c05f20fbSrjs */ 1582c05f20fbSrjs if (TAILQ_EMPTY(&asoc->delivery_queue) && 1583c05f20fbSrjs (sctp_is_all_msg_on_reasm(asoc, &tsize) || 1584c05f20fbSrjs (asoc->size_on_reasm_queue >= 1585c05f20fbSrjs (stcb->sctp_socket->so_rcv.sb_hiwat >> 2) && 1586c05f20fbSrjs tsize))) { 1587c05f20fbSrjs /* 1588c05f20fbSrjs * Yes, we setup to 1589c05f20fbSrjs * start reception, by backing down the TSN 1590c05f20fbSrjs * just in case we can't deliver. If we 1591c05f20fbSrjs */ 1592c05f20fbSrjs asoc->fragmented_delivery_inprogress = 1; 1593c05f20fbSrjs asoc->tsn_last_delivered = 1594c05f20fbSrjs chk->rec.data.TSN_seq - 1; 1595c05f20fbSrjs asoc->str_of_pdapi = 1596c05f20fbSrjs chk->rec.data.stream_number; 1597c05f20fbSrjs asoc->ssn_of_pdapi = chk->rec.data.stream_seq; 1598c05f20fbSrjs asoc->fragment_flags = chk->rec.data.rcv_flags; 1599c05f20fbSrjs sctp_service_reassembly(stcb, asoc, 0); 1600c05f20fbSrjs } 1601c05f20fbSrjs } 1602c05f20fbSrjs } else { 1603c05f20fbSrjs sctp_service_reassembly(stcb, asoc, 0); 1604c05f20fbSrjs } 1605c05f20fbSrjs } 1606c05f20fbSrjs 1607c05f20fbSrjs /* 1608c05f20fbSrjs * This is an unfortunate routine. It checks to make sure a evil guy is not 1609c05f20fbSrjs * stuffing us full of bad packet fragments. A broken peer could also do this 1610c05f20fbSrjs * but this is doubtful. It is to bad I must worry about evil crackers sigh 1611c05f20fbSrjs * :< more cycles. 1612c05f20fbSrjs */ 1613c05f20fbSrjs static int 1614c05f20fbSrjs sctp_does_chk_belong_to_reasm(struct sctp_association *asoc, 1615c05f20fbSrjs struct sctp_tmit_chunk *chk) 1616c05f20fbSrjs { 1617c05f20fbSrjs struct sctp_tmit_chunk *at; 1618c05f20fbSrjs u_int32_t tsn_est; 1619c05f20fbSrjs 1620c05f20fbSrjs TAILQ_FOREACH(at, &asoc->reasmqueue, sctp_next) { 1621c05f20fbSrjs if (compare_with_wrap(chk->rec.data.TSN_seq, 1622c05f20fbSrjs at->rec.data.TSN_seq, MAX_TSN)) { 1623c05f20fbSrjs /* is it one bigger? */ 1624c05f20fbSrjs tsn_est = at->rec.data.TSN_seq + 1; 1625c05f20fbSrjs if (tsn_est == chk->rec.data.TSN_seq) { 1626c05f20fbSrjs /* yep. It better be a last then*/ 1627c05f20fbSrjs if ((at->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) != 1628c05f20fbSrjs SCTP_DATA_LAST_FRAG) { 1629c05f20fbSrjs /* 1630c05f20fbSrjs * Ok this guy belongs next to a guy 1631c05f20fbSrjs * that is NOT last, it should be a 1632c05f20fbSrjs * middle/last, not a complete chunk. 1633c05f20fbSrjs */ 1634c05f20fbSrjs return (1); 1635c05f20fbSrjs } else { 1636c05f20fbSrjs /* 1637c05f20fbSrjs * This guy is ok since its a LAST and 1638c05f20fbSrjs * the new chunk is a fully self- 1639c05f20fbSrjs * contained one. 1640c05f20fbSrjs */ 1641c05f20fbSrjs return (0); 1642c05f20fbSrjs } 1643c05f20fbSrjs } 1644c05f20fbSrjs } else if (chk->rec.data.TSN_seq == at->rec.data.TSN_seq) { 1645c05f20fbSrjs /* Software error since I have a dup? */ 1646c05f20fbSrjs return (1); 1647c05f20fbSrjs } else { 1648c05f20fbSrjs /* 1649c05f20fbSrjs * Ok, 'at' is larger than new chunk but does it 1650c05f20fbSrjs * need to be right before it. 1651c05f20fbSrjs */ 1652c05f20fbSrjs tsn_est = chk->rec.data.TSN_seq + 1; 1653c05f20fbSrjs if (tsn_est == at->rec.data.TSN_seq) { 1654c05f20fbSrjs /* Yep, It better be a first */ 1655c05f20fbSrjs if ((at->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) != 1656c05f20fbSrjs SCTP_DATA_FIRST_FRAG) { 1657c05f20fbSrjs return (1); 1658c05f20fbSrjs } else { 1659c05f20fbSrjs return (0); 1660c05f20fbSrjs } 1661c05f20fbSrjs } 1662c05f20fbSrjs } 1663c05f20fbSrjs } 1664c05f20fbSrjs return (0); 1665c05f20fbSrjs } 1666c05f20fbSrjs 1667c05f20fbSrjs extern unsigned int sctp_max_chunks_on_queue; 1668c05f20fbSrjs static int 1669c05f20fbSrjs sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, 1670c05f20fbSrjs struct mbuf **m, int offset, struct sctp_data_chunk *ch, int chk_length, 1671c05f20fbSrjs struct sctp_nets *net, u_int32_t *high_tsn, int *abort_flag, 1672c05f20fbSrjs int *break_flag, int last_chunk) 1673c05f20fbSrjs { 1674c05f20fbSrjs /* Process a data chunk */ 1675c05f20fbSrjs /* struct sctp_tmit_chunk *chk;*/ 1676c05f20fbSrjs struct sctp_tmit_chunk *chk; 1677c05f20fbSrjs u_int32_t tsn, gap; 1678c05f20fbSrjs struct mbuf *dmbuf; 1679c05f20fbSrjs int the_len; 1680c05f20fbSrjs u_int16_t strmno, strmseq; 1681c05f20fbSrjs struct mbuf *oper; 1682c05f20fbSrjs 1683c05f20fbSrjs chk = NULL; 1684c05f20fbSrjs tsn = ntohl(ch->dp.tsn); 1685c05f20fbSrjs #ifdef SCTP_MAP_LOGGING 1686c05f20fbSrjs sctp_log_map(0, tsn, asoc->cumulative_tsn, SCTP_MAP_PREPARE_SLIDE); 1687c05f20fbSrjs #endif 1688c05f20fbSrjs if (compare_with_wrap(asoc->cumulative_tsn, tsn, MAX_TSN) || 1689c05f20fbSrjs asoc->cumulative_tsn == tsn) { 1690c05f20fbSrjs /* It is a duplicate */ 1691c05f20fbSrjs sctp_pegs[SCTP_DUPTSN_RECVD]++; 1692c05f20fbSrjs if (asoc->numduptsns < SCTP_MAX_DUP_TSNS) { 1693c05f20fbSrjs /* Record a dup for the next outbound sack */ 1694c05f20fbSrjs asoc->dup_tsns[asoc->numduptsns] = tsn; 1695c05f20fbSrjs asoc->numduptsns++; 1696c05f20fbSrjs } 1697c05f20fbSrjs return (0); 1698c05f20fbSrjs } 1699c05f20fbSrjs /* Calculate the number of TSN's between the base and this TSN */ 1700c05f20fbSrjs if (tsn >= asoc->mapping_array_base_tsn) { 1701c05f20fbSrjs gap = tsn - asoc->mapping_array_base_tsn; 1702c05f20fbSrjs } else { 1703c05f20fbSrjs gap = (MAX_TSN - asoc->mapping_array_base_tsn) + tsn + 1; 1704c05f20fbSrjs } 1705c05f20fbSrjs if (gap >= (SCTP_MAPPING_ARRAY << 3)) { 1706c05f20fbSrjs /* Can't hold the bit in the mapping at max array, toss it */ 1707c05f20fbSrjs return (0); 1708c05f20fbSrjs } 1709c05f20fbSrjs if (gap >= (uint32_t)(asoc->mapping_array_size << 3)) { 1710c05f20fbSrjs if (sctp_expand_mapping_array(asoc)) { 1711c05f20fbSrjs /* Can't expand, drop it */ 1712c05f20fbSrjs return (0); 1713c05f20fbSrjs } 1714c05f20fbSrjs } 1715c05f20fbSrjs if (compare_with_wrap(tsn, *high_tsn, MAX_TSN)) { 1716c05f20fbSrjs *high_tsn = tsn; 1717c05f20fbSrjs } 1718c05f20fbSrjs /* See if we have received this one already */ 1719c05f20fbSrjs if (SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap)) { 1720c05f20fbSrjs sctp_pegs[SCTP_DUPTSN_RECVD]++; 1721c05f20fbSrjs if (asoc->numduptsns < SCTP_MAX_DUP_TSNS) { 1722c05f20fbSrjs /* Record a dup for the next outbound sack */ 1723c05f20fbSrjs asoc->dup_tsns[asoc->numduptsns] = tsn; 1724c05f20fbSrjs asoc->numduptsns++; 1725c05f20fbSrjs } 1726c05f20fbSrjs if (!callout_pending(&asoc->dack_timer.timer)) { 1727c05f20fbSrjs /* 1728c05f20fbSrjs * By starting the timer we assure that we 1729c05f20fbSrjs * WILL sack at the end of the packet 1730c05f20fbSrjs * when sctp_sack_check gets called. 1731c05f20fbSrjs */ 1732c05f20fbSrjs sctp_timer_start(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, 1733c05f20fbSrjs stcb, NULL); 1734c05f20fbSrjs } 1735c05f20fbSrjs return (0); 1736c05f20fbSrjs } 1737c05f20fbSrjs /* 1738c05f20fbSrjs * Check to see about the GONE flag, duplicates would cause 1739c05f20fbSrjs * a sack to be sent up above 1740c05f20fbSrjs */ 1741c05f20fbSrjs if (stcb && (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 1742c05f20fbSrjs /* 1743c05f20fbSrjs * wait a minute, this guy is gone, there is no 1744c05f20fbSrjs * longer a receiver. Send peer an ABORT! 1745c05f20fbSrjs */ 1746c05f20fbSrjs struct mbuf *op_err; 1747c05f20fbSrjs op_err = sctp_generate_invmanparam(SCTP_CAUSE_OUT_OF_RESC); 1748c05f20fbSrjs sctp_abort_an_association(stcb->sctp_ep, stcb, 0, op_err); 1749c05f20fbSrjs *abort_flag = 1; 1750c05f20fbSrjs return (0); 1751c05f20fbSrjs } 1752c05f20fbSrjs /* 1753c05f20fbSrjs * Now before going further we see if there is room. If NOT then 1754c05f20fbSrjs * we MAY let one through only IF this TSN is the one we are 1755c05f20fbSrjs * waiting for on a partial delivery API. 1756c05f20fbSrjs */ 1757c05f20fbSrjs 1758c05f20fbSrjs /* now do the tests */ 1759c05f20fbSrjs if (((asoc->cnt_on_all_streams + 1760c05f20fbSrjs asoc->cnt_on_delivery_queue + 1761c05f20fbSrjs asoc->cnt_on_reasm_queue + 1762c05f20fbSrjs asoc->cnt_msg_on_sb) > sctp_max_chunks_on_queue) || 1763c05f20fbSrjs (((int)asoc->my_rwnd) <= 0)) { 1764c05f20fbSrjs /* 1765c05f20fbSrjs * When we have NO room in the rwnd we check 1766c05f20fbSrjs * to make sure the reader is doing its job... 1767c05f20fbSrjs */ 1768c05f20fbSrjs if (stcb->sctp_socket->so_rcv.sb_cc) { 1769c05f20fbSrjs /* some to read, wake-up */ 1770c05f20fbSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 1771c05f20fbSrjs } 1772c05f20fbSrjs /* now is it in the mapping array of what we have accepted? */ 1773c05f20fbSrjs if (compare_with_wrap(tsn, 1774c05f20fbSrjs asoc->highest_tsn_inside_map, MAX_TSN)) { 1775c05f20fbSrjs 1776c05f20fbSrjs /* Nope not in the valid range dump it */ 1777c05f20fbSrjs #ifdef SCTP_DEBUG 1778c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 1779c05f20fbSrjs printf("My rwnd overrun1:tsn:%lx rwnd %lu sbspace:%ld delq:%d!\n", 1780c05f20fbSrjs (u_long)tsn, (u_long)asoc->my_rwnd, 1781c05f20fbSrjs sctp_sbspace(&stcb->sctp_socket->so_rcv), 1782c05f20fbSrjs stcb->asoc.cnt_on_delivery_queue); 1783c05f20fbSrjs } 1784c05f20fbSrjs #endif 1785c05f20fbSrjs sctp_set_rwnd(stcb, asoc); 1786c05f20fbSrjs if ((asoc->cnt_on_all_streams + 1787c05f20fbSrjs asoc->cnt_on_delivery_queue + 1788c05f20fbSrjs asoc->cnt_on_reasm_queue + 1789c05f20fbSrjs asoc->cnt_msg_on_sb) > sctp_max_chunks_on_queue) { 1790c05f20fbSrjs sctp_pegs[SCTP_MSGC_DROP]++; 1791c05f20fbSrjs } else { 1792c05f20fbSrjs sctp_pegs[SCTP_RWND_DROPS]++; 1793c05f20fbSrjs } 1794c05f20fbSrjs *break_flag = 1; 1795c05f20fbSrjs return (0); 1796c05f20fbSrjs } 1797c05f20fbSrjs } 1798c05f20fbSrjs strmno = ntohs(ch->dp.stream_id); 1799c05f20fbSrjs if (strmno >= asoc->streamincnt) { 1800c05f20fbSrjs struct sctp_paramhdr *phdr; 1801c05f20fbSrjs struct mbuf *mb; 1802c05f20fbSrjs 1803c05f20fbSrjs MGETHDR(mb, M_DONTWAIT, MT_DATA); 1804c05f20fbSrjs if (mb != NULL) { 1805c05f20fbSrjs /* add some space up front so prepend will work well */ 1806c05f20fbSrjs mb->m_data += sizeof(struct sctp_chunkhdr); 1807c05f20fbSrjs phdr = mtod(mb, struct sctp_paramhdr *); 1808c05f20fbSrjs /* 1809c05f20fbSrjs * Error causes are just param's and this one has 1810c05f20fbSrjs * two back to back phdr, one with the error type 1811c05f20fbSrjs * and size, the other with the streamid and a rsvd 1812c05f20fbSrjs */ 1813c05f20fbSrjs mb->m_pkthdr.len = mb->m_len = 1814c05f20fbSrjs (sizeof(struct sctp_paramhdr) * 2); 1815c05f20fbSrjs phdr->param_type = htons(SCTP_CAUSE_INV_STRM); 1816c05f20fbSrjs phdr->param_length = 1817c05f20fbSrjs htons(sizeof(struct sctp_paramhdr) * 2); 1818c05f20fbSrjs phdr++; 1819c05f20fbSrjs /* We insert the stream in the type field */ 1820c05f20fbSrjs phdr->param_type = ch->dp.stream_id; 1821c05f20fbSrjs /* And set the length to 0 for the rsvd field */ 1822c05f20fbSrjs phdr->param_length = 0; 1823c05f20fbSrjs sctp_queue_op_err(stcb, mb); 1824c05f20fbSrjs } 1825c05f20fbSrjs sctp_pegs[SCTP_BAD_STRMNO]++; 1826c05f20fbSrjs return (0); 1827c05f20fbSrjs } 1828c05f20fbSrjs /* 1829c05f20fbSrjs * Before we continue lets validate that we are not 1830c05f20fbSrjs * being fooled by an evil attacker. We can only 1831c05f20fbSrjs * have 4k chunks based on our TSN spread allowed 1832c05f20fbSrjs * by the mapping array 512 * 8 bits, so there is 1833c05f20fbSrjs * no way our stream sequence numbers could have wrapped. 1834c05f20fbSrjs * We of course only validate the FIRST fragment so the 1835c05f20fbSrjs * bit must be set. 1836c05f20fbSrjs */ 1837c05f20fbSrjs strmseq = ntohs(ch->dp.stream_sequence); 1838c05f20fbSrjs if ((ch->ch.chunk_flags & SCTP_DATA_FIRST_FRAG) && 1839c05f20fbSrjs (ch->ch.chunk_flags & SCTP_DATA_UNORDERED) == 0 && 1840c05f20fbSrjs (compare_with_wrap(asoc->strmin[strmno].last_sequence_delivered, 1841c05f20fbSrjs strmseq, MAX_SEQ) || 1842c05f20fbSrjs asoc->strmin[strmno].last_sequence_delivered == strmseq)) { 1843c05f20fbSrjs /* The incoming sseq is behind where we last delivered? */ 1844c05f20fbSrjs #ifdef SCTP_DEBUG 1845c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 1846c05f20fbSrjs printf("EVIL/Broken-Dup S-SEQ:%d delivered:%d from peer, Abort!\n", 1847c05f20fbSrjs strmseq, 1848c05f20fbSrjs asoc->strmin[strmno].last_sequence_delivered); 1849c05f20fbSrjs } 1850c05f20fbSrjs #endif 1851c05f20fbSrjs /* 1852c05f20fbSrjs * throw it in the stream so it gets cleaned up in 1853c05f20fbSrjs * association destruction 1854c05f20fbSrjs */ 1855c05f20fbSrjs MGET(oper, M_DONTWAIT, MT_DATA); 1856c05f20fbSrjs if (oper) { 1857c05f20fbSrjs struct sctp_paramhdr *ph; 1858c05f20fbSrjs u_int32_t *ippp; 1859c05f20fbSrjs 1860c05f20fbSrjs oper->m_len = sizeof(struct sctp_paramhdr) + 1861c05f20fbSrjs sizeof(*ippp); 1862c05f20fbSrjs ph = mtod(oper, struct sctp_paramhdr *); 1863c05f20fbSrjs ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 1864c05f20fbSrjs ph->param_length = htons(oper->m_len); 1865c05f20fbSrjs ippp = (u_int32_t *)(ph + 1); 1866c05f20fbSrjs *ippp = htonl(0x20000001); 1867c05f20fbSrjs } 1868c05f20fbSrjs sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, 1869c05f20fbSrjs oper); 1870c05f20fbSrjs sctp_pegs[SCTP_BAD_SSN_WRAP]++; 1871c05f20fbSrjs *abort_flag = 1; 1872c05f20fbSrjs return (0); 1873c05f20fbSrjs } 1874c05f20fbSrjs 1875c05f20fbSrjs the_len = (chk_length-sizeof(struct sctp_data_chunk)); 1876c05f20fbSrjs if (last_chunk == 0) { 1877c05f20fbSrjs dmbuf = sctp_m_copym(*m, 1878c05f20fbSrjs (offset + sizeof(struct sctp_data_chunk)), 1879c05f20fbSrjs the_len, M_DONTWAIT); 1880c05f20fbSrjs } else { 1881c05f20fbSrjs /* We can steal the last chunk */ 1882c05f20fbSrjs dmbuf = *m; 1883c05f20fbSrjs /* lop off the top part */ 1884c05f20fbSrjs m_adj(dmbuf, (offset + sizeof(struct sctp_data_chunk))); 1885c05f20fbSrjs if (dmbuf->m_pkthdr.len > the_len) { 1886c05f20fbSrjs /* Trim the end round bytes off too */ 1887c05f20fbSrjs m_adj(dmbuf, -(dmbuf->m_pkthdr.len-the_len)); 1888c05f20fbSrjs } 1889c05f20fbSrjs sctp_pegs[SCTP_NO_COPY_IN]++; 1890c05f20fbSrjs } 1891c05f20fbSrjs if (dmbuf == NULL) { 1892c05f20fbSrjs sctp_pegs[SCTP_DROP_NOMEMORY]++; 1893c05f20fbSrjs return (0); 1894c05f20fbSrjs } 1895c05f20fbSrjs if ((ch->ch.chunk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG && 1896c05f20fbSrjs asoc->fragmented_delivery_inprogress == 0 && 1897c05f20fbSrjs TAILQ_EMPTY(&asoc->delivery_queue) && 1898c05f20fbSrjs ((ch->ch.chunk_flags & SCTP_DATA_UNORDERED) || 1899c05f20fbSrjs ((asoc->strmin[strmno].last_sequence_delivered + 1) == strmseq && 1900c05f20fbSrjs TAILQ_EMPTY(&asoc->strmin[strmno].inqueue))) && 1901c05f20fbSrjs ((long)(stcb->sctp_socket->so_rcv.sb_hiwat - 1902c05f20fbSrjs stcb->sctp_socket->so_rcv.sb_cc) >= (long)the_len)) { 1903c05f20fbSrjs /* Candidate for express delivery */ 1904c05f20fbSrjs /* 1905c05f20fbSrjs * Its not fragmented, 1906c05f20fbSrjs * No PD-API is up, 1907c05f20fbSrjs * Nothing in the delivery queue, 1908c05f20fbSrjs * Its un-ordered OR ordered and the next to deliver AND 1909c05f20fbSrjs * nothing else is stuck on the stream queue, 1910c05f20fbSrjs * And there is room for it in the socket buffer. 1911c05f20fbSrjs * Lets just stuff it up the buffer.... 1912c05f20fbSrjs */ 1913c05f20fbSrjs 1914c05f20fbSrjs struct mbuf *control, *mmm; 1915c05f20fbSrjs struct sockaddr_in6 sin6; 1916c05f20fbSrjs struct sockaddr_in6 lsa6; 1917c05f20fbSrjs const struct sockaddr *to; 1918c05f20fbSrjs 1919c05f20fbSrjs /* It would be nice to avoid this copy if we could :< */ 1920c05f20fbSrjs control = sctp_build_ctl_nchunk(stcb, tsn, 1921c05f20fbSrjs ch->dp.protocol_id, 0, strmno, strmseq, 1922c05f20fbSrjs ch->ch.chunk_flags); 1923c05f20fbSrjs /* XXX need to append PKTHDR to the socket buffer first */ 1924c05f20fbSrjs 1925c05f20fbSrjs if ((dmbuf->m_flags & M_PKTHDR) == 0) { 1926c05f20fbSrjs struct mbuf *tmp; 1927c05f20fbSrjs MGETHDR(tmp, M_DONTWAIT, MT_DATA); 1928c05f20fbSrjs if (tmp == NULL) { 1929c05f20fbSrjs 1930c05f20fbSrjs /* no room! */ 1931c05f20fbSrjs if (control) { 1932c05f20fbSrjs sctp_m_freem(control); 1933c05f20fbSrjs stcb->asoc.my_rwnd_control_len -= 1934c05f20fbSrjs CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 1935c05f20fbSrjs } 1936c05f20fbSrjs 1937c05f20fbSrjs goto failed_express_del; 1938c05f20fbSrjs } 1939c05f20fbSrjs tmp->m_pkthdr.len = the_len; 1940c05f20fbSrjs tmp->m_len = 0; 1941c05f20fbSrjs tmp->m_next = dmbuf; 1942c05f20fbSrjs dmbuf = tmp; 1943c05f20fbSrjs } 1944c05f20fbSrjs to = rtcache_getdst(&net->ro); 1945c05f20fbSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) && 1946c05f20fbSrjs to->sa_family == AF_INET) { 1947c05f20fbSrjs const struct sockaddr_in *sin; 1948c05f20fbSrjs 1949c05f20fbSrjs sin = satocsin(to); 19507231b0cdSrtr in6_sin_2_v4mapsin6(sin, &sin6); 1951c05f20fbSrjs to = (struct sockaddr *)&sin6; 1952c05f20fbSrjs } 1953c05f20fbSrjs 1954c05f20fbSrjs /* check and strip embedded scope junk */ 1955c05f20fbSrjs to = (const struct sockaddr *)sctp_recover_scope((const struct sockaddr_in6 *)to, 1956c05f20fbSrjs &lsa6); 1957c05f20fbSrjs if (((const struct sockaddr_in *)to)->sin_port == 0) { 1958c05f20fbSrjs printf("Huh c, port is %d not net:%p %d?\n", 1959c05f20fbSrjs ((const struct sockaddr_in *)to)->sin_port, 1960c05f20fbSrjs net, 1961c05f20fbSrjs (int)(ntohs(stcb->rport))); 1962c05f20fbSrjs /*((struct sockaddr_in *)to)->sin_port = stcb->rport;*/ 1963c05f20fbSrjs /* XXX */ 1964c05f20fbSrjs } 1965c05f20fbSrjs 1966c05f20fbSrjs mmm = dmbuf; 1967c05f20fbSrjs /* Mark the EOR */ 1968c05f20fbSrjs while (mmm->m_next != NULL) { 1969c05f20fbSrjs mmm = mmm->m_next; 1970c05f20fbSrjs } 1971c05f20fbSrjs mmm->m_flags |= M_EOR; 1972c05f20fbSrjs if (compare_with_wrap(tsn, asoc->highest_tsn_inside_map, MAX_TSN)) { 1973c05f20fbSrjs /* we have a new high score */ 1974c05f20fbSrjs asoc->highest_tsn_inside_map = tsn; 1975c05f20fbSrjs #ifdef SCTP_MAP_LOGGING 1976c05f20fbSrjs sctp_log_map(0, 1, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT); 1977c05f20fbSrjs #endif 1978c05f20fbSrjs } 1979c05f20fbSrjs SCTP_TCB_UNLOCK(stcb); 1980c05f20fbSrjs SCTP_INP_WLOCK(stcb->sctp_ep); 1981c05f20fbSrjs SCTP_TCB_LOCK(stcb); 1982c05f20fbSrjs if (!sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv, to, dmbuf, 1983c05f20fbSrjs control, stcb->asoc.my_vtag, stcb->sctp_ep)) { 1984c05f20fbSrjs if (control) { 1985c05f20fbSrjs sctp_m_freem(control); 1986c05f20fbSrjs stcb->asoc.my_rwnd_control_len -= 1987c05f20fbSrjs CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 1988c05f20fbSrjs } 1989c05f20fbSrjs sctp_m_freem(dmbuf); 1990c05f20fbSrjs goto failed_express_del; 1991c05f20fbSrjs } 1992c05f20fbSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) { 1993c05f20fbSrjs if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) { 1994c05f20fbSrjs stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf); 1995c05f20fbSrjs } 1996c05f20fbSrjs } else { 1997c05f20fbSrjs stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf); 1998c05f20fbSrjs } 1999c05f20fbSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 2000c05f20fbSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 2001c05f20fbSrjs if ((ch->ch.chunk_flags & SCTP_DATA_UNORDERED) == 0) { 2002c05f20fbSrjs 2003c05f20fbSrjs /* for ordered, bump what we delivered */ 2004c05f20fbSrjs asoc->strmin[strmno].last_sequence_delivered++; 2005c05f20fbSrjs } 2006c05f20fbSrjs sctp_pegs[SCTP_EXPRESS_ROUTE]++; 2007c05f20fbSrjs #ifdef SCTP_STR_LOGGING 2008c05f20fbSrjs sctp_log_strm_del_alt(tsn, strmseq, 2009c05f20fbSrjs SCTP_STR_LOG_FROM_EXPRS_DEL); 2010c05f20fbSrjs #endif 2011c05f20fbSrjs #ifdef SCTP_DEBUG 2012c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 2013c05f20fbSrjs printf("Express Delivery succeeds\n"); 2014c05f20fbSrjs } 2015c05f20fbSrjs #endif 2016c05f20fbSrjs goto finish_express_del; 2017c05f20fbSrjs } 2018c05f20fbSrjs 2019c05f20fbSrjs failed_express_del: 2020c05f20fbSrjs /* If we reach here this is a new chunk */ 2021c05f20fbSrjs chk = (struct sctp_tmit_chunk *)SCTP_ZONE_GET(sctppcbinfo.ipi_zone_chunk); 2022c05f20fbSrjs if (chk == NULL) { 2023c05f20fbSrjs /* No memory so we drop the chunk */ 2024c05f20fbSrjs sctp_pegs[SCTP_DROP_NOMEMORY]++; 2025c05f20fbSrjs if (last_chunk == 0) { 2026c05f20fbSrjs /* we copied it, free the copy */ 2027c05f20fbSrjs sctp_m_freem(dmbuf); 2028c05f20fbSrjs } 2029c05f20fbSrjs return (0); 2030c05f20fbSrjs } 2031c05f20fbSrjs sctppcbinfo.ipi_count_chunk++; 2032c05f20fbSrjs sctppcbinfo.ipi_gencnt_chunk++; 2033c05f20fbSrjs chk->rec.data.TSN_seq = tsn; 2034c05f20fbSrjs chk->rec.data.stream_seq = strmseq; 2035c05f20fbSrjs chk->rec.data.stream_number = strmno; 2036c05f20fbSrjs chk->rec.data.payloadtype = ch->dp.protocol_id; 2037c05f20fbSrjs chk->rec.data.context = 0; 2038c05f20fbSrjs chk->rec.data.doing_fast_retransmit = 0; 2039c05f20fbSrjs chk->rec.data.rcv_flags = ch->ch.chunk_flags; 2040c05f20fbSrjs chk->asoc = asoc; 2041c05f20fbSrjs chk->send_size = the_len; 2042c05f20fbSrjs chk->whoTo = net; 2043c05f20fbSrjs net->ref_count++; 2044c05f20fbSrjs chk->data = dmbuf; 2045c05f20fbSrjs 2046c05f20fbSrjs 2047c05f20fbSrjs /* Mark it as received */ 2048c05f20fbSrjs /* Now queue it where it belongs */ 2049c05f20fbSrjs if ((chk->rec.data.rcv_flags & SCTP_DATA_NOT_FRAG) == 2050c05f20fbSrjs SCTP_DATA_NOT_FRAG) { 2051c05f20fbSrjs /* First a sanity check */ 2052c05f20fbSrjs if (asoc->fragmented_delivery_inprogress) { 2053c05f20fbSrjs /* 2054c05f20fbSrjs * Ok, we have a fragmented delivery in progress 2055c05f20fbSrjs * if this chunk is next to deliver OR belongs in 2056c05f20fbSrjs * our view to the reassembly, the peer is evil 2057c05f20fbSrjs * or broken. 2058c05f20fbSrjs */ 2059c05f20fbSrjs u_int32_t estimate_tsn; 2060c05f20fbSrjs estimate_tsn = asoc->tsn_last_delivered + 1; 2061c05f20fbSrjs if (TAILQ_EMPTY(&asoc->reasmqueue) && 2062c05f20fbSrjs (estimate_tsn == chk->rec.data.TSN_seq)) { 2063c05f20fbSrjs /* Evil/Broke peer */ 2064c05f20fbSrjs MGET(oper, M_DONTWAIT, MT_DATA); 2065c05f20fbSrjs if (oper) { 2066c05f20fbSrjs struct sctp_paramhdr *ph; 2067c05f20fbSrjs u_int32_t *ippp; 2068c05f20fbSrjs 2069c05f20fbSrjs oper->m_len = 2070c05f20fbSrjs sizeof(struct sctp_paramhdr) + 2071c05f20fbSrjs sizeof(*ippp); 2072c05f20fbSrjs ph = mtod(oper, struct sctp_paramhdr *); 2073c05f20fbSrjs ph->param_type = 2074c05f20fbSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 2075c05f20fbSrjs ph->param_length = htons(oper->m_len); 2076c05f20fbSrjs ippp = (u_int32_t *)(ph + 1); 2077c05f20fbSrjs *ippp = htonl(0x20000002); 2078c05f20fbSrjs } 2079c05f20fbSrjs sctp_abort_an_association(stcb->sctp_ep, stcb, 2080c05f20fbSrjs SCTP_PEER_FAULTY, oper); 2081c05f20fbSrjs 2082c05f20fbSrjs *abort_flag = 1; 2083c05f20fbSrjs sctp_pegs[SCTP_DROP_FRAG]++; 2084c05f20fbSrjs return (0); 2085c05f20fbSrjs } else { 2086c05f20fbSrjs if (sctp_does_chk_belong_to_reasm(asoc, chk)) { 2087c05f20fbSrjs MGET(oper, M_DONTWAIT, MT_DATA); 2088c05f20fbSrjs if (oper) { 2089c05f20fbSrjs struct sctp_paramhdr *ph; 2090c05f20fbSrjs u_int32_t *ippp; 2091c05f20fbSrjs 2092c05f20fbSrjs oper->m_len = 2093c05f20fbSrjs sizeof(struct sctp_paramhdr) + 2094c05f20fbSrjs sizeof(*ippp); 2095c05f20fbSrjs ph = mtod(oper, 2096c05f20fbSrjs struct sctp_paramhdr *); 2097c05f20fbSrjs ph->param_type = 2098c05f20fbSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 2099c05f20fbSrjs ph->param_length = 2100c05f20fbSrjs htons(oper->m_len); 2101c05f20fbSrjs ippp = (u_int32_t *)(ph + 1); 2102c05f20fbSrjs *ippp = htonl(0x20000003); 2103c05f20fbSrjs } 2104c05f20fbSrjs sctp_abort_an_association(stcb->sctp_ep, 2105c05f20fbSrjs stcb, SCTP_PEER_FAULTY, oper); 2106c05f20fbSrjs 2107c05f20fbSrjs *abort_flag = 1; 2108c05f20fbSrjs sctp_pegs[SCTP_DROP_FRAG]++; 2109c05f20fbSrjs return (0); 2110c05f20fbSrjs } 2111c05f20fbSrjs } 2112c05f20fbSrjs } else { 2113c05f20fbSrjs if (!TAILQ_EMPTY(&asoc->reasmqueue)) { 2114c05f20fbSrjs /* 2115c05f20fbSrjs * Reassembly queue is NOT empty 2116c05f20fbSrjs * validate that this chk does not need to 2117c05f20fbSrjs * be in reasembly queue. If it does then 2118c05f20fbSrjs * our peer is broken or evil. 2119c05f20fbSrjs */ 2120c05f20fbSrjs if (sctp_does_chk_belong_to_reasm(asoc, chk)) { 2121c05f20fbSrjs MGET(oper, M_DONTWAIT, MT_DATA); 2122c05f20fbSrjs if (oper) { 2123c05f20fbSrjs struct sctp_paramhdr *ph; 2124c05f20fbSrjs u_int32_t *ippp; 2125c05f20fbSrjs 2126c05f20fbSrjs oper->m_len = 2127c05f20fbSrjs sizeof(struct sctp_paramhdr) + 2128c05f20fbSrjs sizeof(*ippp); 2129c05f20fbSrjs ph = mtod(oper, 2130c05f20fbSrjs struct sctp_paramhdr *); 2131c05f20fbSrjs ph->param_type = 2132c05f20fbSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 2133c05f20fbSrjs ph->param_length = 2134c05f20fbSrjs htons(oper->m_len); 2135c05f20fbSrjs ippp = (u_int32_t *)(ph + 1); 2136c05f20fbSrjs *ippp = htonl(0x20000004); 2137c05f20fbSrjs } 2138c05f20fbSrjs sctp_abort_an_association(stcb->sctp_ep, 2139c05f20fbSrjs stcb, SCTP_PEER_FAULTY, oper); 2140c05f20fbSrjs 2141c05f20fbSrjs *abort_flag = 1; 2142c05f20fbSrjs sctp_pegs[SCTP_DROP_FRAG]++; 2143c05f20fbSrjs return (0); 2144c05f20fbSrjs } 2145c05f20fbSrjs } 2146c05f20fbSrjs } 2147c05f20fbSrjs if (chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) { 2148c05f20fbSrjs /* queue directly into socket buffer */ 2149c05f20fbSrjs sctp_deliver_data(stcb, asoc, chk, 0); 2150c05f20fbSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 2151c05f20fbSrjs } else { 2152c05f20fbSrjs /* Special check for when streams are resetting. 2153c05f20fbSrjs * We could be more smart about this and check the 2154c05f20fbSrjs * actual stream to see if it is not being reset.. that 2155c05f20fbSrjs * way we would not create a HOLB when amongst streams 2156c05f20fbSrjs * being reset and those not being reset. 2157c05f20fbSrjs * 2158c05f20fbSrjs * We take complete messages that have a stream reset 2159c05f20fbSrjs * intervening (aka the TSN is after where our cum-ack needs 2160c05f20fbSrjs * to be) off and put them on a pending_reply_queue. The 2161c05f20fbSrjs * reassembly ones we do not have to worry about since 2162c05f20fbSrjs * they are all sorted and proceessed by TSN order. It 2163c05f20fbSrjs * is only the singletons I must worry about. 2164c05f20fbSrjs */ 2165c05f20fbSrjs if ((asoc->pending_reply) && 2166c05f20fbSrjs ((compare_with_wrap(tsn, ntohl(asoc->pending_reply->reset_at_tsn), MAX_TSN)) || 2167c05f20fbSrjs (tsn == ntohl(asoc->pending_reply->reset_at_tsn))) 2168c05f20fbSrjs ) { 2169c05f20fbSrjs /* yep its past where we need to reset... go ahead and 2170c05f20fbSrjs * queue it. 2171c05f20fbSrjs */ 2172c05f20fbSrjs TAILQ_INSERT_TAIL(&asoc->pending_reply_queue , chk, sctp_next); 2173c05f20fbSrjs } else { 2174c05f20fbSrjs sctp_queue_data_to_stream(stcb, asoc, chk, abort_flag); 2175c05f20fbSrjs } 2176c05f20fbSrjs } 2177c05f20fbSrjs } else { 2178c05f20fbSrjs /* Into the re-assembly queue */ 2179c05f20fbSrjs sctp_queue_data_for_reasm(stcb, asoc, chk, abort_flag); 2180c05f20fbSrjs if (*abort_flag) { 2181c05f20fbSrjs sctp_pegs[SCTP_DROP_FRAG]++; 2182c05f20fbSrjs return (0); 2183c05f20fbSrjs } 2184c05f20fbSrjs } 2185c05f20fbSrjs if (compare_with_wrap(tsn, asoc->highest_tsn_inside_map, MAX_TSN)) { 2186c05f20fbSrjs /* we have a new high score */ 2187c05f20fbSrjs asoc->highest_tsn_inside_map = tsn; 2188c05f20fbSrjs #ifdef SCTP_MAP_LOGGING 2189c05f20fbSrjs sctp_log_map(0, 2, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT); 2190c05f20fbSrjs #endif 2191c05f20fbSrjs } 2192c05f20fbSrjs finish_express_del: 2193c05f20fbSrjs if (last_chunk) { 2194c05f20fbSrjs *m = NULL; 2195c05f20fbSrjs } 2196c05f20fbSrjs sctp_pegs[SCTP_PEG_TSNS_RCVD]++; 2197c05f20fbSrjs /* Set it present please */ 2198c05f20fbSrjs #ifdef SCTP_STR_LOGGING 2199c05f20fbSrjs sctp_log_strm_del_alt(tsn, strmseq, SCTP_STR_LOG_FROM_MARK_TSN); 2200c05f20fbSrjs #endif 2201c05f20fbSrjs #ifdef SCTP_MAP_LOGGING 2202c05f20fbSrjs sctp_log_map(asoc->mapping_array_base_tsn, asoc->cumulative_tsn, 2203c05f20fbSrjs asoc->highest_tsn_inside_map, SCTP_MAP_PREPARE_SLIDE); 2204c05f20fbSrjs #endif 2205c05f20fbSrjs SCTP_SET_TSN_PRESENT(asoc->mapping_array, gap); 2206c05f20fbSrjs return (1); 2207c05f20fbSrjs } 2208c05f20fbSrjs 2209c05f20fbSrjs void 2210c05f20fbSrjs sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort_flag) 2211c05f20fbSrjs { 2212c05f20fbSrjs /* 2213c05f20fbSrjs * Now we also need to check the mapping array in a couple of ways. 2214c05f20fbSrjs * 1) Did we move the cum-ack point? 2215c05f20fbSrjs */ 2216c05f20fbSrjs struct sctp_association *asoc; 2217c05f20fbSrjs int i, at; 2218c05f20fbSrjs int m_size, all_ones; 2219c05f20fbSrjs int slide_from, slide_end, lgap, distance; 2220c05f20fbSrjs #ifdef SCTP_MAP_LOGGING 2221c05f20fbSrjs uint32_t old_cumack, old_base, old_highest; 2222c05f20fbSrjs unsigned char aux_array[64]; 2223c05f20fbSrjs #endif 2224c05f20fbSrjs 2225c05f20fbSrjs asoc = &stcb->asoc; 2226c05f20fbSrjs at = 0; 2227c05f20fbSrjs 2228c05f20fbSrjs #ifdef SCTP_MAP_LOGGING 2229c05f20fbSrjs old_cumack = asoc->cumulative_tsn; 2230c05f20fbSrjs old_base = asoc->mapping_array_base_tsn; 2231c05f20fbSrjs old_highest = asoc->highest_tsn_inside_map; 2232c05f20fbSrjs if (asoc->mapping_array_size < 64) 2233c05f20fbSrjs memcpy(aux_array, asoc->mapping_array, 2234c05f20fbSrjs asoc->mapping_array_size); 2235c05f20fbSrjs else 2236c05f20fbSrjs memcpy(aux_array, asoc->mapping_array, 64); 2237c05f20fbSrjs #endif 2238c05f20fbSrjs 2239c05f20fbSrjs /* 2240c05f20fbSrjs * We could probably improve this a small bit by calculating the 2241c05f20fbSrjs * offset of the current cum-ack as the starting point. 2242c05f20fbSrjs */ 2243c05f20fbSrjs all_ones = 1; 2244c05f20fbSrjs m_size = stcb->asoc.mapping_array_size << 3; 2245c05f20fbSrjs for (i = 0; i < m_size; i++) { 2246c05f20fbSrjs if (!SCTP_IS_TSN_PRESENT(asoc->mapping_array, i)) { 2247c05f20fbSrjs /* 2248c05f20fbSrjs * Ok we found the first place that we are 2249c05f20fbSrjs * missing a TSN. 2250c05f20fbSrjs */ 2251c05f20fbSrjs at = i; 2252c05f20fbSrjs all_ones = 0; 2253c05f20fbSrjs asoc->cumulative_tsn = asoc->mapping_array_base_tsn + 2254c05f20fbSrjs (i - 1); 2255c05f20fbSrjs break; 2256c05f20fbSrjs } 2257c05f20fbSrjs } 2258c05f20fbSrjs if (compare_with_wrap(asoc->cumulative_tsn, 2259c05f20fbSrjs asoc->highest_tsn_inside_map, 2260c05f20fbSrjs MAX_TSN)) { 2261c05f20fbSrjs panic("huh, cumack greater than high-tsn in map"); 2262c05f20fbSrjs } 2263c05f20fbSrjs if (all_ones || 2264c05f20fbSrjs (asoc->cumulative_tsn == asoc->highest_tsn_inside_map && at >= 8)) { 2265c05f20fbSrjs /* The complete array was completed by a single FR */ 2266c05f20fbSrjs /* higest becomes the cum-ack */ 2267c05f20fbSrjs int clr; 2268c05f20fbSrjs asoc->cumulative_tsn = asoc->highest_tsn_inside_map; 2269c05f20fbSrjs /* clear the array */ 2270c05f20fbSrjs if (all_ones) 2271c05f20fbSrjs clr = asoc->mapping_array_size; 2272c05f20fbSrjs else { 2273c05f20fbSrjs clr = (at >> 3) + 1; 2274c05f20fbSrjs /* 2275c05f20fbSrjs * this should be the allones case 2276c05f20fbSrjs * but just in case :> 2277c05f20fbSrjs */ 2278c05f20fbSrjs if (clr > asoc->mapping_array_size) 2279c05f20fbSrjs clr = asoc->mapping_array_size; 2280c05f20fbSrjs } 2281c05f20fbSrjs memset(asoc->mapping_array, 0, clr); 2282c05f20fbSrjs /* base becomes one ahead of the cum-ack */ 2283c05f20fbSrjs asoc->mapping_array_base_tsn = asoc->cumulative_tsn + 1; 2284c05f20fbSrjs #ifdef SCTP_MAP_LOGGING 2285c05f20fbSrjs sctp_log_map(old_base, old_cumack, old_highest, 2286c05f20fbSrjs SCTP_MAP_PREPARE_SLIDE); 2287c05f20fbSrjs sctp_log_map(asoc->mapping_array_base_tsn, asoc->cumulative_tsn, 2288c05f20fbSrjs asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_CLEARED); 2289c05f20fbSrjs #endif 2290c05f20fbSrjs } else if (at >= 8) { 2291c05f20fbSrjs /* we can slide the mapping array down */ 2292c05f20fbSrjs /* Calculate the new byte postion we can move down */ 2293c05f20fbSrjs slide_from = at >> 3; 2294c05f20fbSrjs /* now calculate the ceiling of the move using our highest TSN value */ 2295c05f20fbSrjs if (asoc->highest_tsn_inside_map >= asoc->mapping_array_base_tsn) { 2296c05f20fbSrjs lgap = asoc->highest_tsn_inside_map - 2297c05f20fbSrjs asoc->mapping_array_base_tsn; 2298c05f20fbSrjs } else { 2299c05f20fbSrjs lgap = (MAX_TSN - asoc->mapping_array_base_tsn) + 2300c05f20fbSrjs asoc->highest_tsn_inside_map + 1; 2301c05f20fbSrjs } 2302c05f20fbSrjs slide_end = lgap >> 3; 2303c05f20fbSrjs if (slide_end < slide_from) { 2304c05f20fbSrjs panic("impossible slide"); 2305c05f20fbSrjs } 2306c05f20fbSrjs distance = (slide_end-slide_from) + 1; 2307c05f20fbSrjs #ifdef SCTP_MAP_LOGGING 2308c05f20fbSrjs sctp_log_map(old_base, old_cumack, old_highest, 2309c05f20fbSrjs SCTP_MAP_PREPARE_SLIDE); 2310c05f20fbSrjs sctp_log_map((uint32_t)slide_from, (uint32_t)slide_end, 2311c05f20fbSrjs (uint32_t)lgap, SCTP_MAP_SLIDE_FROM); 2312c05f20fbSrjs #endif 2313c05f20fbSrjs if (distance + slide_from > asoc->mapping_array_size || 2314c05f20fbSrjs distance < 0) { 2315c05f20fbSrjs #ifdef SCTP_DEBUG 2316c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 2317c05f20fbSrjs printf("Ugh bad addition.. you can't hrumpp!\n"); 2318c05f20fbSrjs } 2319c05f20fbSrjs #endif 2320c05f20fbSrjs /* 2321c05f20fbSrjs * Here we do NOT slide forward the array so that 2322c05f20fbSrjs * hopefully when more data comes in to fill it up 2323c05f20fbSrjs * we will be able to slide it forward. Really 2324c05f20fbSrjs * I don't think this should happen :-0 2325c05f20fbSrjs */ 2326c05f20fbSrjs 2327c05f20fbSrjs #ifdef SCTP_MAP_LOGGING 2328c05f20fbSrjs sctp_log_map((uint32_t)distance, (uint32_t)slide_from, 2329c05f20fbSrjs (uint32_t)asoc->mapping_array_size, 2330c05f20fbSrjs SCTP_MAP_SLIDE_NONE); 2331c05f20fbSrjs #endif 2332c05f20fbSrjs } else { 2333c05f20fbSrjs int ii; 2334c05f20fbSrjs for (ii = 0; ii < distance; ii++) { 2335c05f20fbSrjs asoc->mapping_array[ii] = 2336c05f20fbSrjs asoc->mapping_array[slide_from + ii]; 2337c05f20fbSrjs } 2338c05f20fbSrjs for (ii = distance;ii <= slide_end; ii++) { 2339c05f20fbSrjs asoc->mapping_array[ii] = 0; 2340c05f20fbSrjs } 2341c05f20fbSrjs asoc->mapping_array_base_tsn += (slide_from << 3); 2342c05f20fbSrjs #ifdef SCTP_MAP_LOGGING 2343c05f20fbSrjs sctp_log_map(asoc->mapping_array_base_tsn, 2344c05f20fbSrjs asoc->cumulative_tsn, asoc->highest_tsn_inside_map, 2345c05f20fbSrjs SCTP_MAP_SLIDE_RESULT); 2346c05f20fbSrjs #endif 2347c05f20fbSrjs } 2348c05f20fbSrjs } 2349c05f20fbSrjs 2350c05f20fbSrjs /* check the special flag for stream resets */ 2351c05f20fbSrjs if ((asoc->pending_reply) && 2352c05f20fbSrjs ((compare_with_wrap((asoc->cumulative_tsn+1), ntohl(asoc->pending_reply->reset_at_tsn), MAX_TSN)) || 2353c05f20fbSrjs ((asoc->cumulative_tsn+1) == ntohl(asoc->pending_reply->reset_at_tsn))) 2354c05f20fbSrjs ) { 2355c05f20fbSrjs /* we have finished working through the backlogged TSN's now 2356c05f20fbSrjs * time to reset streams. 2357c05f20fbSrjs * 1: call reset function. 2358c05f20fbSrjs * 2: free pending_reply space 2359c05f20fbSrjs * 3: distribute any chunks in pending_reply_queue. 2360c05f20fbSrjs */ 2361c05f20fbSrjs struct sctp_tmit_chunk *chk; 2362c05f20fbSrjs sctp_handle_stream_reset_response(stcb, asoc->pending_reply); 2363c05f20fbSrjs free(asoc->pending_reply, M_PCB); 2364c05f20fbSrjs asoc->pending_reply = NULL; 2365c05f20fbSrjs chk = TAILQ_FIRST(&asoc->pending_reply_queue); 2366c05f20fbSrjs while (chk) { 2367c05f20fbSrjs TAILQ_REMOVE(&asoc->pending_reply_queue, chk, sctp_next); 2368c05f20fbSrjs sctp_queue_data_to_stream(stcb, asoc, chk, abort_flag); 2369c05f20fbSrjs if (*abort_flag) { 2370c05f20fbSrjs return; 2371c05f20fbSrjs } 2372c05f20fbSrjs chk = TAILQ_FIRST(&asoc->pending_reply_queue); 2373c05f20fbSrjs } 2374c05f20fbSrjs } 2375c05f20fbSrjs /* 2376c05f20fbSrjs * Now we need to see if we need to queue a sack or just start 2377c05f20fbSrjs * the timer (if allowed). 2378c05f20fbSrjs */ 2379c05f20fbSrjs if (ok_to_sack) { 2380c05f20fbSrjs if (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_SENT) { 2381c05f20fbSrjs /* 2382c05f20fbSrjs * Ok special case, in SHUTDOWN-SENT case. 2383c05f20fbSrjs * here we maker sure SACK timer is off and 2384c05f20fbSrjs * instead send a SHUTDOWN and a SACK 2385c05f20fbSrjs */ 2386c05f20fbSrjs if (callout_pending(&stcb->asoc.dack_timer.timer)) { 2387c05f20fbSrjs sctp_timer_stop(SCTP_TIMER_TYPE_RECV, 2388c05f20fbSrjs stcb->sctp_ep, stcb, NULL); 2389c05f20fbSrjs } 2390c05f20fbSrjs #ifdef SCTP_DEBUG 2391c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) { 2392c05f20fbSrjs printf("%s:%d sends a shutdown\n", 2393c05f20fbSrjs __FILE__, 2394c05f20fbSrjs __LINE__ 2395c05f20fbSrjs ); 2396c05f20fbSrjs } 2397c05f20fbSrjs #endif 2398c05f20fbSrjs sctp_send_shutdown(stcb, stcb->asoc.primary_destination); 2399c05f20fbSrjs sctp_send_sack(stcb); 2400c05f20fbSrjs } else { 2401c05f20fbSrjs int is_a_gap; 2402c05f20fbSrjs /* is there a gap now ? */ 2403c05f20fbSrjs is_a_gap = compare_with_wrap(stcb->asoc.highest_tsn_inside_map, 2404c05f20fbSrjs stcb->asoc.cumulative_tsn, MAX_TSN); 2405c05f20fbSrjs if ((stcb->asoc.first_ack_sent == 0) || /* First time we send a sack */ 2406c05f20fbSrjs ((was_a_gap) && (is_a_gap == 0)) || /* was a gap, but no longer is one */ 2407c05f20fbSrjs (stcb->asoc.numduptsns) || /* we have dup's */ 2408c05f20fbSrjs (is_a_gap) || /* is still a gap */ 2409c05f20fbSrjs (callout_pending(&stcb->asoc.dack_timer.timer)) /* timer was up . second packet */ 2410c05f20fbSrjs ) { 2411c05f20fbSrjs /* 2412c05f20fbSrjs * Ok we must build a SACK since the timer 2413c05f20fbSrjs * is pending, we got our first packet OR 2414c05f20fbSrjs * there are gaps or duplicates. 2415c05f20fbSrjs */ 2416c05f20fbSrjs stcb->asoc.first_ack_sent = 1; 2417c05f20fbSrjs sctp_send_sack(stcb); 2418c05f20fbSrjs /* The sending will stop the timer */ 2419c05f20fbSrjs } else { 2420c05f20fbSrjs sctp_timer_start(SCTP_TIMER_TYPE_RECV, 2421c05f20fbSrjs stcb->sctp_ep, stcb, NULL); 2422c05f20fbSrjs } 2423c05f20fbSrjs } 2424c05f20fbSrjs } 2425c05f20fbSrjs } 2426c05f20fbSrjs 2427c05f20fbSrjs void 2428c05f20fbSrjs sctp_service_queues(struct sctp_tcb *stcb, struct sctp_association *asoc, int hold_locks) 2429c05f20fbSrjs { 2430c05f20fbSrjs struct sctp_tmit_chunk *chk; 2431c05f20fbSrjs int tsize, cntDel; 2432c05f20fbSrjs u_int16_t nxt_todel; 2433c05f20fbSrjs 2434c05f20fbSrjs cntDel = 0; 2435c05f20fbSrjs if (asoc->fragmented_delivery_inprogress) { 2436c05f20fbSrjs sctp_service_reassembly(stcb, asoc, hold_locks); 2437c05f20fbSrjs } 2438c05f20fbSrjs /* Can we proceed further, i.e. the PD-API is complete */ 2439c05f20fbSrjs if (asoc->fragmented_delivery_inprogress) { 2440c05f20fbSrjs /* no */ 2441c05f20fbSrjs return; 2442c05f20fbSrjs } 2443c05f20fbSrjs 2444c05f20fbSrjs /* 2445c05f20fbSrjs * Yes, reassembly delivery no longer in progress see if we 2446c05f20fbSrjs * have some on the sb hold queue. 2447c05f20fbSrjs */ 2448c05f20fbSrjs do { 2449c05f20fbSrjs if (stcb->sctp_socket->so_rcv.sb_cc >= stcb->sctp_socket->so_rcv.sb_hiwat) { 2450c05f20fbSrjs if (cntDel == 0) 2451c05f20fbSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 2452c05f20fbSrjs break; 2453c05f20fbSrjs } 2454c05f20fbSrjs /* If deliver_data says no we must stop */ 2455c05f20fbSrjs if (sctp_deliver_data(stcb, asoc, (struct sctp_tmit_chunk *)NULL, hold_locks) == 0) 2456c05f20fbSrjs break; 2457c05f20fbSrjs cntDel++; 2458c05f20fbSrjs chk = TAILQ_FIRST(&asoc->delivery_queue); 2459c05f20fbSrjs } while (chk); 2460c05f20fbSrjs if (cntDel) { 2461c05f20fbSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 2462c05f20fbSrjs } 2463c05f20fbSrjs /* 2464c05f20fbSrjs * Now is there some other chunk I can deliver 2465c05f20fbSrjs * from the reassembly queue. 2466c05f20fbSrjs */ 2467c05f20fbSrjs chk = TAILQ_FIRST(&asoc->reasmqueue); 2468c05f20fbSrjs if (chk == NULL) { 2469c05f20fbSrjs asoc->size_on_reasm_queue = 0; 2470c05f20fbSrjs asoc->cnt_on_reasm_queue = 0; 2471c05f20fbSrjs return; 2472c05f20fbSrjs } 2473c05f20fbSrjs nxt_todel = asoc->strmin[chk->rec.data.stream_number].last_sequence_delivered + 1; 2474c05f20fbSrjs if ((chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) && 2475c05f20fbSrjs ((nxt_todel == chk->rec.data.stream_seq) || 2476c05f20fbSrjs (chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED))) { 2477c05f20fbSrjs /* 2478c05f20fbSrjs * Yep the first one is here. We setup to 2479c05f20fbSrjs * start reception, by backing down the TSN 2480c05f20fbSrjs * just in case we can't deliver. 2481c05f20fbSrjs */ 2482c05f20fbSrjs 2483c05f20fbSrjs /* 2484c05f20fbSrjs * Before we start though either all of the 2485c05f20fbSrjs * message should be here or 1/4 the socket buffer 2486c05f20fbSrjs * max or nothing on the delivery queue and something 2487c05f20fbSrjs * can be delivered. 2488c05f20fbSrjs */ 2489c05f20fbSrjs if (TAILQ_EMPTY(&asoc->delivery_queue) && 2490c05f20fbSrjs (sctp_is_all_msg_on_reasm(asoc, &tsize) || 2491c05f20fbSrjs (asoc->size_on_reasm_queue >= 2492c05f20fbSrjs (stcb->sctp_socket->so_rcv.sb_hiwat >> 2) && tsize))) { 2493c05f20fbSrjs asoc->fragmented_delivery_inprogress = 1; 2494c05f20fbSrjs asoc->tsn_last_delivered = chk->rec.data.TSN_seq-1; 2495c05f20fbSrjs asoc->str_of_pdapi = chk->rec.data.stream_number; 2496c05f20fbSrjs asoc->ssn_of_pdapi = chk->rec.data.stream_seq; 2497c05f20fbSrjs asoc->fragment_flags = chk->rec.data.rcv_flags; 2498c05f20fbSrjs sctp_service_reassembly(stcb, asoc, hold_locks); 2499c05f20fbSrjs } 2500c05f20fbSrjs } 2501c05f20fbSrjs } 2502c05f20fbSrjs 2503c05f20fbSrjs int 2504c05f20fbSrjs sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, 2505c05f20fbSrjs struct sctphdr *sh, struct sctp_inpcb *inp, struct sctp_tcb *stcb, 2506c05f20fbSrjs struct sctp_nets *net, u_int32_t *high_tsn) 2507c05f20fbSrjs { 2508c05f20fbSrjs struct sctp_data_chunk *ch, chunk_buf; 2509c05f20fbSrjs struct sctp_association *asoc; 2510c05f20fbSrjs int num_chunks = 0; /* number of control chunks processed */ 2511c05f20fbSrjs int chk_length, break_flag, last_chunk; 2512c05f20fbSrjs int abort_flag = 0, was_a_gap = 0; 2513c05f20fbSrjs struct mbuf *m; 2514c05f20fbSrjs 2515c05f20fbSrjs /* set the rwnd */ 2516c05f20fbSrjs sctp_set_rwnd(stcb, &stcb->asoc); 2517c05f20fbSrjs 2518c05f20fbSrjs m = *mm; 2519c05f20fbSrjs asoc = &stcb->asoc; 2520c05f20fbSrjs if (compare_with_wrap(stcb->asoc.highest_tsn_inside_map, 2521c05f20fbSrjs stcb->asoc.cumulative_tsn, MAX_TSN)) { 2522c05f20fbSrjs /* there was a gap before this data was processed */ 2523c05f20fbSrjs was_a_gap = 1; 2524c05f20fbSrjs } 2525c05f20fbSrjs /* 2526c05f20fbSrjs * setup where we got the last DATA packet from for 2527c05f20fbSrjs * any SACK that may need to go out. Don't bump 2528c05f20fbSrjs * the net. This is done ONLY when a chunk 2529c05f20fbSrjs * is assigned. 2530c05f20fbSrjs */ 2531c05f20fbSrjs asoc->last_data_chunk_from = net; 2532c05f20fbSrjs 2533c05f20fbSrjs /* 2534c05f20fbSrjs * Now before we proceed we must figure out if this 2535c05f20fbSrjs * is a wasted cluster... i.e. it is a small packet 2536c05f20fbSrjs * sent in and yet the driver underneath allocated a 2537c05f20fbSrjs * full cluster for it. If so we must copy it to a 2538c05f20fbSrjs * smaller mbuf and free up the cluster mbuf. This 2539c05f20fbSrjs * will help with cluster starvation. 2540c05f20fbSrjs */ 2541c05f20fbSrjs if (m->m_len < (long)MHLEN && m->m_next == NULL) { 2542c05f20fbSrjs /* we only handle mbufs that are singletons.. not chains */ 2543c05f20fbSrjs MGET(m, M_DONTWAIT, MT_DATA); 2544c05f20fbSrjs if (m) { 2545c05f20fbSrjs /* ok lets see if we can copy the data up */ 2546c05f20fbSrjs vaddr_t *from, *to; 2547c05f20fbSrjs 2548c05f20fbSrjs if ((*mm)->m_flags & M_PKTHDR) { 2549c05f20fbSrjs /* got to copy the header first */ 2550c05f20fbSrjs #ifdef __APPLE__ 2551c05f20fbSrjs M_COPY_PKTHDR(m, (*mm)); 2552c05f20fbSrjs #else 2553*bc2d92a5Smaxv m_move_pkthdr(m, (*mm)); 2554c05f20fbSrjs #endif 2555c05f20fbSrjs } 2556c05f20fbSrjs /* get the pointers and copy */ 2557c05f20fbSrjs to = mtod(m, vaddr_t *); 2558c05f20fbSrjs from = mtod((*mm), vaddr_t *); 2559c05f20fbSrjs memcpy(to, from, (*mm)->m_len); 2560c05f20fbSrjs /* copy the length and free up the old */ 2561c05f20fbSrjs m->m_len = (*mm)->m_len; 2562c05f20fbSrjs sctp_m_freem(*mm); 2563c05f20fbSrjs /* sucess, back copy */ 2564c05f20fbSrjs *mm = m; 2565c05f20fbSrjs } else { 2566c05f20fbSrjs /* We are in trouble in the mbuf world .. yikes */ 2567c05f20fbSrjs m = *mm; 2568c05f20fbSrjs } 2569c05f20fbSrjs } 2570c05f20fbSrjs /* get pointer to the first chunk header */ 2571c05f20fbSrjs ch = (struct sctp_data_chunk *)sctp_m_getptr(m, *offset, 2572c05f20fbSrjs sizeof(chunk_buf), (u_int8_t *)&chunk_buf); 2573c05f20fbSrjs if (ch == NULL) { 2574c05f20fbSrjs printf(" ... its short\n"); 2575c05f20fbSrjs return (1); 2576c05f20fbSrjs } 2577c05f20fbSrjs /* 2578c05f20fbSrjs * process all DATA chunks... 2579c05f20fbSrjs */ 2580c05f20fbSrjs 2581c05f20fbSrjs #ifdef SCTP_DEBUG 2582c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INPUT1) { 2583c05f20fbSrjs printf("In process data off:%d length:%d iphlen:%d ch->type:%d\n", 2584c05f20fbSrjs *offset, length, iphlen, (int)ch->ch.chunk_type); 2585c05f20fbSrjs } 2586c05f20fbSrjs #endif 2587c05f20fbSrjs 2588c05f20fbSrjs *high_tsn = asoc->cumulative_tsn; 2589c05f20fbSrjs break_flag = 0; 2590c05f20fbSrjs while (ch->ch.chunk_type == SCTP_DATA) { 2591c05f20fbSrjs /* validate chunk length */ 2592c05f20fbSrjs chk_length = ntohs(ch->ch.chunk_length); 2593c05f20fbSrjs if ((size_t)chk_length < sizeof(struct sctp_data_chunk) + 1 || 2594c05f20fbSrjs length - *offset < chk_length) { 2595c05f20fbSrjs /* 2596c05f20fbSrjs * Need to send an abort since we had a invalid 2597c05f20fbSrjs * data chunk. 2598c05f20fbSrjs */ 2599c05f20fbSrjs struct mbuf *op_err; 2600c05f20fbSrjs MGET(op_err, M_DONTWAIT, MT_DATA); 2601c05f20fbSrjs if (op_err) { 2602c05f20fbSrjs struct sctp_paramhdr *ph; 2603c05f20fbSrjs u_int32_t *ippp; 2604c05f20fbSrjs 2605c05f20fbSrjs op_err->m_len = sizeof(struct sctp_paramhdr) + 2606c05f20fbSrjs sizeof(*ippp); 2607c05f20fbSrjs ph = mtod(op_err, struct sctp_paramhdr *); 2608c05f20fbSrjs ph->param_type = 2609c05f20fbSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 2610c05f20fbSrjs ph->param_length = htons(op_err->m_len); 2611c05f20fbSrjs ippp = (u_int32_t *)(ph + 1); 2612c05f20fbSrjs *ippp = htonl(0x30000001); 2613c05f20fbSrjs } 2614c05f20fbSrjs sctp_abort_association(inp, stcb, m, iphlen, sh, 2615c05f20fbSrjs op_err); 2616c05f20fbSrjs return (2); 2617c05f20fbSrjs } 2618c05f20fbSrjs #ifdef SCTP_DEBUG 2619c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INPUT1) { 2620c05f20fbSrjs printf("A chunk of len:%d to process (tot:%d)\n", 2621c05f20fbSrjs chk_length, length - *offset); 2622c05f20fbSrjs } 2623c05f20fbSrjs #endif 2624c05f20fbSrjs 2625c05f20fbSrjs #ifdef SCTP_AUDITING_ENABLED 2626c05f20fbSrjs sctp_audit_log(0xB1, 0); 2627c05f20fbSrjs #endif 2628c05f20fbSrjs if (SCTP_SIZE32(chk_length) == *offset - length) { 2629c05f20fbSrjs last_chunk = 1; 2630c05f20fbSrjs } else { 2631c05f20fbSrjs last_chunk = 0; 2632c05f20fbSrjs } 2633c05f20fbSrjs if (sctp_process_a_data_chunk(stcb, asoc, mm, *offset, ch, 2634c05f20fbSrjs chk_length, net, high_tsn, &abort_flag, &break_flag, 2635c05f20fbSrjs last_chunk)) { 2636c05f20fbSrjs num_chunks++; 2637c05f20fbSrjs #ifdef SCTP_DEBUG 2638c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INPUT1) { 2639c05f20fbSrjs printf("Now incr num_chunks to %d\n", 2640c05f20fbSrjs num_chunks); 2641c05f20fbSrjs } 2642c05f20fbSrjs #endif 2643c05f20fbSrjs } 2644c05f20fbSrjs if (abort_flag) 2645c05f20fbSrjs return (2); 2646c05f20fbSrjs 2647c05f20fbSrjs if (break_flag) { 2648c05f20fbSrjs /* 2649c05f20fbSrjs * Set because of out of rwnd space and no drop rep 2650c05f20fbSrjs * space left. 2651c05f20fbSrjs */ 2652c05f20fbSrjs break; 2653c05f20fbSrjs } 2654c05f20fbSrjs 2655c05f20fbSrjs *offset += SCTP_SIZE32(chk_length); 2656c05f20fbSrjs if (*offset >= length) { 2657c05f20fbSrjs /* no more data left in the mbuf chain */ 2658c05f20fbSrjs break; 2659c05f20fbSrjs } 2660c05f20fbSrjs ch = (struct sctp_data_chunk *)sctp_m_getptr(m, *offset, 2661c05f20fbSrjs sizeof(chunk_buf), (u_int8_t *)&chunk_buf); 2662c05f20fbSrjs if (ch == NULL) { 2663c05f20fbSrjs *offset = length; 2664c05f20fbSrjs break; 2665c05f20fbSrjs } 2666c05f20fbSrjs } /* while */ 2667c05f20fbSrjs if (break_flag) { 2668c05f20fbSrjs /* 2669c05f20fbSrjs * we need to report rwnd overrun drops. 2670c05f20fbSrjs */ 2671c05f20fbSrjs sctp_send_packet_dropped(stcb, net, *mm, iphlen, 0); 2672c05f20fbSrjs } 2673c05f20fbSrjs if (num_chunks) { 2674c05f20fbSrjs /* 2675c05f20fbSrjs * Did we get data, if so update the time for 2676c05f20fbSrjs * auto-close and give peer credit for being 2677c05f20fbSrjs * alive. 2678c05f20fbSrjs */ 2679c05f20fbSrjs sctp_pegs[SCTP_DATA_DG_RECV]++; 2680c05f20fbSrjs stcb->asoc.overall_error_count = 0; 2681c05f20fbSrjs SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_last_rcvd); 2682c05f20fbSrjs } 2683c05f20fbSrjs /* now service all of the reassm queue and delivery queue */ 2684c05f20fbSrjs sctp_service_queues(stcb, asoc, 0); 2685c05f20fbSrjs if (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_SENT) { 2686c05f20fbSrjs /* 2687c05f20fbSrjs * Assure that we ack right away by making 2688c05f20fbSrjs * sure that a d-ack timer is running. So the 2689c05f20fbSrjs * sack_check will send a sack. 2690c05f20fbSrjs */ 2691c05f20fbSrjs sctp_timer_start(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, 2692c05f20fbSrjs net); 2693c05f20fbSrjs } 2694c05f20fbSrjs /* Start a sack timer or QUEUE a SACK for sending */ 2695c05f20fbSrjs sctp_sack_check(stcb, 1, was_a_gap, &abort_flag); 2696c05f20fbSrjs if (abort_flag) 2697c05f20fbSrjs return (2); 2698c05f20fbSrjs 2699c05f20fbSrjs return (0); 2700c05f20fbSrjs } 2701c05f20fbSrjs 2702c05f20fbSrjs static void 2703c05f20fbSrjs sctp_handle_segments(struct sctp_tcb *stcb, struct sctp_association *asoc, 2704c05f20fbSrjs struct sctp_sack_chunk *ch, u_long last_tsn, u_long *biggest_tsn_acked, 2705c05f20fbSrjs u_long *biggest_newly_acked_tsn, int num_seg, int *ecn_seg_sums) 2706c05f20fbSrjs { 2707c05f20fbSrjs /************************************************/ 2708c05f20fbSrjs /* process fragments and update sendqueue */ 2709c05f20fbSrjs /************************************************/ 2710c05f20fbSrjs struct sctp_sack *sack; 2711c05f20fbSrjs struct sctp_gap_ack_block *frag; 2712c05f20fbSrjs struct sctp_tmit_chunk *tp1; 2713c05f20fbSrjs int i; 2714c05f20fbSrjs unsigned int j; 2715c05f20fbSrjs #ifdef SCTP_FR_LOGGING 2716c05f20fbSrjs int num_frs=0; 2717c05f20fbSrjs #endif 2718c05f20fbSrjs uint16_t frag_strt, frag_end, primary_flag_set; 2719c05f20fbSrjs u_long last_frag_high; 2720c05f20fbSrjs 2721c05f20fbSrjs if (asoc->primary_destination->dest_state & SCTP_ADDR_SWITCH_PRIMARY) { 2722c05f20fbSrjs primary_flag_set = 1; 2723c05f20fbSrjs } else { 2724c05f20fbSrjs primary_flag_set = 0; 2725c05f20fbSrjs } 2726c05f20fbSrjs 2727c05f20fbSrjs sack = &ch->sack; 2728c05f20fbSrjs frag = (struct sctp_gap_ack_block *)((vaddr_t)sack + 2729c05f20fbSrjs sizeof(struct sctp_sack)); 2730c05f20fbSrjs tp1 = NULL; 2731c05f20fbSrjs last_frag_high = 0; 2732c05f20fbSrjs for (i = 0; i < num_seg; i++) { 2733c05f20fbSrjs frag_strt = ntohs(frag->start); 2734c05f20fbSrjs frag_end = ntohs(frag->end); 2735c05f20fbSrjs /* some sanity checks on the fargment offsets */ 2736c05f20fbSrjs if (frag_strt > frag_end) { 2737c05f20fbSrjs /* this one is malformed, skip */ 2738c05f20fbSrjs frag++; 2739c05f20fbSrjs continue; 2740c05f20fbSrjs } 2741c05f20fbSrjs if (compare_with_wrap((frag_end+last_tsn), *biggest_tsn_acked, 2742c05f20fbSrjs MAX_TSN)) 2743c05f20fbSrjs *biggest_tsn_acked = frag_end+last_tsn; 2744c05f20fbSrjs 2745c05f20fbSrjs /* mark acked dgs and find out the highestTSN being acked */ 2746c05f20fbSrjs if (tp1 == NULL) { 2747c05f20fbSrjs tp1 = TAILQ_FIRST(&asoc->sent_queue); 2748c05f20fbSrjs 2749c05f20fbSrjs /* save the locations of the last frags */ 2750c05f20fbSrjs last_frag_high = frag_end + last_tsn; 2751c05f20fbSrjs } else { 2752c05f20fbSrjs /* 2753c05f20fbSrjs * now lets see if we need to reset the queue 2754c05f20fbSrjs * due to a out-of-order SACK fragment 2755c05f20fbSrjs */ 2756c05f20fbSrjs if (compare_with_wrap(frag_strt+last_tsn, 2757c05f20fbSrjs last_frag_high, MAX_TSN)) { 2758c05f20fbSrjs /* 2759c05f20fbSrjs * if the new frag starts after the last TSN 2760c05f20fbSrjs * frag covered, we are ok 2761c05f20fbSrjs * and this one is beyond the last one 2762c05f20fbSrjs */ 2763c05f20fbSrjs ; 2764c05f20fbSrjs } else { 2765c05f20fbSrjs /* 2766c05f20fbSrjs * ok, they have reset us, so we need to reset 2767c05f20fbSrjs * the queue this will cause extra hunting but 2768c05f20fbSrjs * hey, they chose the performance 2769c05f20fbSrjs * hit when they failed to order there gaps.. 2770c05f20fbSrjs */ 2771c05f20fbSrjs tp1 = TAILQ_FIRST(&asoc->sent_queue); 2772c05f20fbSrjs } 2773c05f20fbSrjs last_frag_high = frag_end + last_tsn; 2774c05f20fbSrjs } 2775c05f20fbSrjs for (j = frag_strt + last_tsn; j <= frag_end + last_tsn; j++) { 2776c05f20fbSrjs while (tp1) { 2777c05f20fbSrjs #ifdef SCTP_FR_LOGGING 2778c05f20fbSrjs if (tp1->rec.data.doing_fast_retransmit) 2779c05f20fbSrjs num_frs++; 2780c05f20fbSrjs #endif 2781c05f20fbSrjs 2782c05f20fbSrjs if (tp1->rec.data.TSN_seq == j) { 2783c05f20fbSrjs if (tp1->sent != SCTP_DATAGRAM_UNSENT) { 2784c05f20fbSrjs /* must be held until cum-ack passes */ 2785c05f20fbSrjs /* ECN Nonce: Add the nonce value to the sender's nonce sum */ 2786c05f20fbSrjs if (tp1->sent < SCTP_DATAGRAM_ACKED) { 2787c05f20fbSrjs /* 2788c05f20fbSrjs * If it is less than 2789c05f20fbSrjs * ACKED, it is now 2790c05f20fbSrjs * no-longer in flight. 2791c05f20fbSrjs * Higher values may 2792c05f20fbSrjs * already be set via 2793c05f20fbSrjs * previous Gap Ack 2794c05f20fbSrjs * Blocks... 2795c05f20fbSrjs * i.e. ACKED or MARKED. 2796c05f20fbSrjs */ 2797c05f20fbSrjs if (compare_with_wrap(tp1->rec.data.TSN_seq, 2798c05f20fbSrjs *biggest_newly_acked_tsn, 2799c05f20fbSrjs MAX_TSN)) { 2800c05f20fbSrjs *biggest_newly_acked_tsn = 2801c05f20fbSrjs tp1->rec.data.TSN_seq; 2802c05f20fbSrjs } 2803c05f20fbSrjs sctp_flight_size_decrease(tp1); 2804c05f20fbSrjs 2805c05f20fbSrjs sctp_total_flight_decrease(stcb, tp1); 2806c05f20fbSrjs 2807c05f20fbSrjs if (tp1->snd_count < 2) { 2808c05f20fbSrjs /* True non-retransmited chunk */ 2809c05f20fbSrjs tp1->whoTo->net_ack2 += 2810c05f20fbSrjs tp1->send_size; 2811c05f20fbSrjs 2812c05f20fbSrjs /* update RTO too? */ 2813c05f20fbSrjs if (tp1->do_rtt) { 2814c05f20fbSrjs tp1->whoTo->RTO = 2815c05f20fbSrjs sctp_calculate_rto(stcb, 2816c05f20fbSrjs asoc, 2817c05f20fbSrjs tp1->whoTo, 2818c05f20fbSrjs &tp1->sent_rcv_time); 2819c05f20fbSrjs tp1->whoTo->rto_pending = 0; 2820c05f20fbSrjs tp1->do_rtt = 0; 2821c05f20fbSrjs } 2822c05f20fbSrjs } 2823c05f20fbSrjs } 2824c05f20fbSrjs if (tp1->sent <= SCTP_DATAGRAM_RESEND && 2825c05f20fbSrjs tp1->sent != SCTP_DATAGRAM_UNSENT && 2826c05f20fbSrjs compare_with_wrap(tp1->rec.data.TSN_seq, 2827c05f20fbSrjs asoc->this_sack_highest_gap, 2828c05f20fbSrjs MAX_TSN)) { 2829c05f20fbSrjs asoc->this_sack_highest_gap = 2830c05f20fbSrjs tp1->rec.data.TSN_seq; 2831c05f20fbSrjs if (primary_flag_set) { 2832c05f20fbSrjs tp1->whoTo->cacc_saw_newack = 1; 2833c05f20fbSrjs } 2834c05f20fbSrjs } 2835c05f20fbSrjs if (tp1->sent == SCTP_DATAGRAM_RESEND) { 2836c05f20fbSrjs #ifdef SCTP_DEBUG 2837c05f20fbSrjs if (sctp_debug_on & 2838c05f20fbSrjs SCTP_DEBUG_INDATA3) { 2839c05f20fbSrjs printf("Hmm. one that is in RESEND that is now ACKED\n"); 2840c05f20fbSrjs } 2841c05f20fbSrjs #endif 2842c05f20fbSrjs sctp_ucount_decr(asoc->sent_queue_retran_cnt); 2843c05f20fbSrjs #ifdef SCTP_AUDITING_ENABLED 2844c05f20fbSrjs sctp_audit_log(0xB2, 2845c05f20fbSrjs (asoc->sent_queue_retran_cnt & 0x000000ff)); 2846c05f20fbSrjs #endif 2847c05f20fbSrjs 2848c05f20fbSrjs } 2849c05f20fbSrjs (*ecn_seg_sums) += tp1->rec.data.ect_nonce; 2850c05f20fbSrjs (*ecn_seg_sums) &= SCTP_SACK_NONCE_SUM; 2851c05f20fbSrjs tp1->sent = SCTP_DATAGRAM_MARKED; 2852c05f20fbSrjs } 2853c05f20fbSrjs break; 2854c05f20fbSrjs } /* if (tp1->TSN_seq == j) */ 2855c05f20fbSrjs if (compare_with_wrap(tp1->rec.data.TSN_seq, j, 2856c05f20fbSrjs MAX_TSN)) 2857c05f20fbSrjs break; 2858c05f20fbSrjs tp1 = TAILQ_NEXT(tp1, sctp_next); 2859c05f20fbSrjs }/* end while (tp1) */ 2860c05f20fbSrjs } /* end for (j = fragStart */ 2861c05f20fbSrjs frag++; /* next one */ 2862c05f20fbSrjs } 2863c05f20fbSrjs #ifdef SCTP_FR_LOGGING 2864c05f20fbSrjs if (num_frs) 2865c05f20fbSrjs sctp_log_fr(*biggest_tsn_acked, *biggest_newly_acked_tsn, 2866c05f20fbSrjs last_tsn, SCTP_FR_LOG_BIGGEST_TSNS); 2867c05f20fbSrjs #endif 2868c05f20fbSrjs } 2869c05f20fbSrjs 2870c05f20fbSrjs static void 2871c05f20fbSrjs sctp_check_for_revoked(struct sctp_association *asoc, u_long cum_ack, 2872c05f20fbSrjs u_long biggest_tsn_acked) 2873c05f20fbSrjs { 2874c05f20fbSrjs struct sctp_tmit_chunk *tp1; 2875c05f20fbSrjs int tot_revoked=0; 2876c05f20fbSrjs 2877c05f20fbSrjs tp1 = TAILQ_FIRST(&asoc->sent_queue); 2878c05f20fbSrjs while (tp1) { 2879c05f20fbSrjs if (compare_with_wrap(tp1->rec.data.TSN_seq, cum_ack, 2880c05f20fbSrjs MAX_TSN)) { 2881c05f20fbSrjs /* 2882c05f20fbSrjs * ok this guy is either ACK or MARKED. If it is ACKED 2883c05f20fbSrjs * it has been previously acked but not this time i.e. 2884c05f20fbSrjs * revoked. If it is MARKED it was ACK'ed again. 2885c05f20fbSrjs */ 2886c05f20fbSrjs if (tp1->sent == SCTP_DATAGRAM_ACKED) { 2887c05f20fbSrjs /* it has been revoked */ 2888c05f20fbSrjs /* 2889c05f20fbSrjs * We do NOT add back to flight size here since 2890c05f20fbSrjs * it is really NOT in flight. Resend (when/if 2891c05f20fbSrjs * it occurs will add to flight size 2892c05f20fbSrjs */ 2893c05f20fbSrjs tp1->sent = SCTP_DATAGRAM_SENT; 2894c05f20fbSrjs tot_revoked++; 2895c05f20fbSrjs } else if (tp1->sent == SCTP_DATAGRAM_MARKED) { 2896c05f20fbSrjs /* it has been re-acked in this SACK */ 2897c05f20fbSrjs tp1->sent = SCTP_DATAGRAM_ACKED; 2898c05f20fbSrjs } 2899c05f20fbSrjs } 2900c05f20fbSrjs if (compare_with_wrap(tp1->rec.data.TSN_seq, biggest_tsn_acked, 2901c05f20fbSrjs MAX_TSN)) { 2902c05f20fbSrjs /* above the sack */ 2903c05f20fbSrjs break; 2904c05f20fbSrjs } 2905c05f20fbSrjs if (tp1->sent == SCTP_DATAGRAM_UNSENT) 2906c05f20fbSrjs break; 2907c05f20fbSrjs tp1 = TAILQ_NEXT(tp1, sctp_next); 2908c05f20fbSrjs } 2909c05f20fbSrjs if (tot_revoked > 0) { 2910c05f20fbSrjs /* Setup the ecn nonce re-sync point. We 2911c05f20fbSrjs * do this since once data is revoked 2912c05f20fbSrjs * we begin to retransmit things, which 2913c05f20fbSrjs * do NOT have the ECN bits set. This means 2914c05f20fbSrjs * we are now out of sync and must wait until 2915c05f20fbSrjs * we get back in sync with the peer to 2916c05f20fbSrjs * check ECN bits. 2917c05f20fbSrjs */ 2918c05f20fbSrjs tp1 = TAILQ_FIRST(&asoc->send_queue); 2919c05f20fbSrjs if (tp1 == NULL) { 2920c05f20fbSrjs asoc->nonce_resync_tsn = asoc->sending_seq; 2921c05f20fbSrjs } else { 2922c05f20fbSrjs asoc->nonce_resync_tsn = tp1->rec.data.TSN_seq; 2923c05f20fbSrjs } 2924c05f20fbSrjs asoc->nonce_wait_for_ecne = 0; 2925c05f20fbSrjs asoc->nonce_sum_check = 0; 2926c05f20fbSrjs } 2927c05f20fbSrjs 2928c05f20fbSrjs } 2929c05f20fbSrjs 2930c05f20fbSrjs extern int sctp_peer_chunk_oh; 2931c05f20fbSrjs 2932c05f20fbSrjs static void 2933c05f20fbSrjs sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, 2934c05f20fbSrjs u_long biggest_tsn_acked, int strike_enabled, 2935c05f20fbSrjs u_long biggest_tsn_newly_acked, int accum_moved) 2936c05f20fbSrjs { 2937c05f20fbSrjs struct sctp_tmit_chunk *tp1; 2938c05f20fbSrjs int strike_flag=0; 2939c05f20fbSrjs struct timeval now; 2940c05f20fbSrjs int tot_retrans=0; 2941c05f20fbSrjs u_int32_t sending_seq; 2942c05f20fbSrjs int primary_switch_active = 0; 2943c05f20fbSrjs int double_switch_active = 0; 2944c05f20fbSrjs 2945c05f20fbSrjs /* select the sending_seq, this is 2946c05f20fbSrjs * either the next thing ready to 2947c05f20fbSrjs * be sent but not transmitted, OR, 2948c05f20fbSrjs * the next seq we assign. 2949c05f20fbSrjs */ 2950c05f20fbSrjs tp1 = TAILQ_FIRST(&stcb->asoc.send_queue); 2951c05f20fbSrjs if (tp1 == NULL) { 2952c05f20fbSrjs sending_seq = asoc->sending_seq; 2953c05f20fbSrjs } else { 2954c05f20fbSrjs sending_seq = tp1->rec.data.TSN_seq; 2955c05f20fbSrjs } 2956c05f20fbSrjs 2957c05f20fbSrjs if (asoc->primary_destination->dest_state & SCTP_ADDR_SWITCH_PRIMARY) { 2958c05f20fbSrjs primary_switch_active = 1; 2959c05f20fbSrjs } 2960c05f20fbSrjs if (asoc->primary_destination->dest_state & SCTP_ADDR_DOUBLE_SWITCH) { 2961c05f20fbSrjs double_switch_active = 1; 2962c05f20fbSrjs } 2963c05f20fbSrjs if (stcb->asoc.peer_supports_prsctp ) { 2964c05f20fbSrjs SCTP_GETTIME_TIMEVAL(&now); 2965c05f20fbSrjs } 2966c05f20fbSrjs tp1 = TAILQ_FIRST(&asoc->sent_queue); 2967c05f20fbSrjs while (tp1) { 2968c05f20fbSrjs strike_flag=0; 2969c05f20fbSrjs if (compare_with_wrap(tp1->rec.data.TSN_seq, biggest_tsn_acked, 2970c05f20fbSrjs MAX_TSN) || 2971c05f20fbSrjs tp1->sent == SCTP_DATAGRAM_UNSENT) { 2972c05f20fbSrjs /* done */ 2973c05f20fbSrjs break; 2974c05f20fbSrjs } 2975c05f20fbSrjs if ((tp1->flags & (SCTP_PR_SCTP_ENABLED|SCTP_PR_SCTP_BUFFER)) == 2976c05f20fbSrjs SCTP_PR_SCTP_ENABLED && 2977c05f20fbSrjs tp1->sent < SCTP_DATAGRAM_ACKED) { 2978c05f20fbSrjs /* Is it expired? */ 2979c05f20fbSrjs #ifndef __FreeBSD__ 2980c05f20fbSrjs if (timercmp(&now, &tp1->rec.data.timetodrop, >)) 2981c05f20fbSrjs #else 2982c05f20fbSrjs if (timevalcmp(&now, &tp1->rec.data.timetodrop, >)) 2983c05f20fbSrjs #endif 2984c05f20fbSrjs { 2985c05f20fbSrjs /* Yes so drop it */ 2986c05f20fbSrjs if (tp1->data != NULL) { 2987c05f20fbSrjs sctp_release_pr_sctp_chunk(stcb, tp1, 2988c05f20fbSrjs (SCTP_RESPONSE_TO_USER_REQ|SCTP_NOTIFY_DATAGRAM_SENT), 2989c05f20fbSrjs &asoc->sent_queue); 2990c05f20fbSrjs } 2991c05f20fbSrjs tp1 = TAILQ_NEXT(tp1, sctp_next); 2992c05f20fbSrjs continue; 2993c05f20fbSrjs } 2994c05f20fbSrjs } 2995c05f20fbSrjs 2996c05f20fbSrjs if (compare_with_wrap(tp1->rec.data.TSN_seq, 2997c05f20fbSrjs asoc->this_sack_highest_gap, MAX_TSN)) { 2998c05f20fbSrjs /* we are beyond the tsn in the sack */ 2999c05f20fbSrjs break; 3000c05f20fbSrjs } 3001c05f20fbSrjs if (tp1->sent >= SCTP_DATAGRAM_RESEND) { 3002c05f20fbSrjs /* either a RESEND, ACKED, or MARKED */ 3003c05f20fbSrjs /* skip */ 3004c05f20fbSrjs tp1 = TAILQ_NEXT(tp1, sctp_next); 3005c05f20fbSrjs continue; 3006c05f20fbSrjs } 3007c05f20fbSrjs if (primary_switch_active && (strike_enabled == 0)) { 3008c05f20fbSrjs if (tp1->whoTo != asoc->primary_destination) { 3009c05f20fbSrjs /* 3010c05f20fbSrjs * We can only strike things on the primary if 3011c05f20fbSrjs * the strike_enabled flag is clear 3012c05f20fbSrjs */ 3013c05f20fbSrjs tp1 = TAILQ_NEXT(tp1, sctp_next); 3014c05f20fbSrjs continue; 3015c05f20fbSrjs } 3016c05f20fbSrjs } else if (primary_switch_active) { 3017c05f20fbSrjs if (tp1->whoTo->cacc_saw_newack == 0) { 3018c05f20fbSrjs /* 3019c05f20fbSrjs * Only one was received but it was NOT 3020c05f20fbSrjs * this one. 3021c05f20fbSrjs */ 3022c05f20fbSrjs tp1 = TAILQ_NEXT(tp1, sctp_next); 3023c05f20fbSrjs continue; 3024c05f20fbSrjs } 3025c05f20fbSrjs } 3026c05f20fbSrjs if (double_switch_active && 3027c05f20fbSrjs (compare_with_wrap(asoc->primary_destination->next_tsn_at_change, 3028c05f20fbSrjs tp1->rec.data.TSN_seq, MAX_TSN))) { 3029c05f20fbSrjs /* 3030c05f20fbSrjs * With a double switch we do NOT mark unless we 3031c05f20fbSrjs * are beyond the switch point. 3032c05f20fbSrjs */ 3033c05f20fbSrjs tp1 = TAILQ_NEXT(tp1, sctp_next); 3034c05f20fbSrjs continue; 3035c05f20fbSrjs } 3036c05f20fbSrjs /* 3037c05f20fbSrjs * Here we check to see if we were have already done a FR 3038c05f20fbSrjs * and if so we see if the biggest TSN we saw in the sack is 3039c05f20fbSrjs * smaller than the recovery point. If so we don't strike the 3040c05f20fbSrjs * tsn... otherwise we CAN strike the TSN. 3041c05f20fbSrjs */ 3042c05f20fbSrjs if (accum_moved && asoc->fast_retran_loss_recovery) { 3043c05f20fbSrjs /* 3044c05f20fbSrjs * Strike the TSN if in fast-recovery and 3045c05f20fbSrjs * cum-ack moved. 3046c05f20fbSrjs */ 3047c05f20fbSrjs tp1->sent++; 3048c05f20fbSrjs } else if (tp1->rec.data.doing_fast_retransmit) { 3049c05f20fbSrjs /* 3050c05f20fbSrjs * For those that have done a FR we must 3051c05f20fbSrjs * take special consideration if we strike. I.e 3052c05f20fbSrjs * the biggest_newly_acked must be higher 3053c05f20fbSrjs * than the sending_seq at the time we did 3054c05f20fbSrjs * the FR. 3055c05f20fbSrjs */ 3056c05f20fbSrjs #ifdef SCTP_FR_TO_ALTERNATE 3057c05f20fbSrjs /* 3058c05f20fbSrjs * If FR's go to new networks, then we 3059c05f20fbSrjs * must only do this for singly homed asoc's. However 3060c05f20fbSrjs * if the FR's go to the same network (Armando's work) 3061c05f20fbSrjs * then its ok to FR multiple times. 3062c05f20fbSrjs */ 3063c05f20fbSrjs if (asoc->numnets < 2) 3064c05f20fbSrjs #else 3065c05f20fbSrjs if (1) 3066c05f20fbSrjs #endif 3067c05f20fbSrjs { 3068c05f20fbSrjs if ((compare_with_wrap(biggest_tsn_newly_acked, 3069c05f20fbSrjs tp1->rec.data.fast_retran_tsn, MAX_TSN)) || 3070c05f20fbSrjs (biggest_tsn_newly_acked == 3071c05f20fbSrjs tp1->rec.data.fast_retran_tsn)) { 3072c05f20fbSrjs /* 3073c05f20fbSrjs * Strike the TSN, since this ack is 3074c05f20fbSrjs * beyond where things were when we did 3075c05f20fbSrjs * a FR. 3076c05f20fbSrjs */ 3077c05f20fbSrjs #ifdef SCTP_FR_LOGGING 3078c05f20fbSrjs sctp_log_fr(biggest_tsn_newly_acked, 3079c05f20fbSrjs tp1->rec.data.TSN_seq, 3080c05f20fbSrjs tp1->rec.data.fast_retran_tsn, 3081c05f20fbSrjs SCTP_FR_LOG_STRIKE_CHUNK); 3082c05f20fbSrjs #endif 3083c05f20fbSrjs tp1->sent++; 3084c05f20fbSrjs strike_flag=1; 3085c05f20fbSrjs } 3086c05f20fbSrjs } 3087c05f20fbSrjs } else if (compare_with_wrap(tp1->rec.data.TSN_seq, 3088c05f20fbSrjs biggest_tsn_newly_acked, MAX_TSN)) { 3089c05f20fbSrjs /* 3090c05f20fbSrjs * We don't strike these: 3091c05f20fbSrjs * This is the HTNA algorithm i.e. we don't strike 3092c05f20fbSrjs * If our TSN is larger than the Highest TSN Newly 3093c05f20fbSrjs * Acked. 3094c05f20fbSrjs */ 3095c05f20fbSrjs ; 3096c05f20fbSrjs } else { 3097c05f20fbSrjs /* Strike the TSN */ 3098c05f20fbSrjs tp1->sent++; 3099c05f20fbSrjs } 3100c05f20fbSrjs if (tp1->sent == SCTP_DATAGRAM_RESEND) { 3101c05f20fbSrjs /* Increment the count to resend */ 3102c05f20fbSrjs struct sctp_nets *alt; 3103c05f20fbSrjs 3104c05f20fbSrjs #ifdef SCTP_FR_LOGGING 3105c05f20fbSrjs sctp_log_fr(tp1->rec.data.TSN_seq, tp1->snd_count, 3106c05f20fbSrjs 0, SCTP_FR_MARKED); 3107c05f20fbSrjs #endif 3108c05f20fbSrjs if (strike_flag) { 3109c05f20fbSrjs /* This is a subsequent FR */ 3110c05f20fbSrjs sctp_pegs[SCTP_DUP_FR]++; 3111c05f20fbSrjs } 3112c05f20fbSrjs asoc->sent_queue_retran_cnt++; 3113c05f20fbSrjs #ifdef SCTP_FR_TO_ALTERNATE 3114c05f20fbSrjs /* Can we find an alternate? */ 3115c05f20fbSrjs alt = sctp_find_alternate_net(stcb, tp1->whoTo); 3116c05f20fbSrjs #else 3117c05f20fbSrjs /* 3118c05f20fbSrjs * default behavior is to NOT retransmit FR's 3119c05f20fbSrjs * to an alternate. Armando Caro's paper details 3120c05f20fbSrjs * why. 3121c05f20fbSrjs */ 3122c05f20fbSrjs alt = tp1->whoTo; 3123c05f20fbSrjs #endif 3124c05f20fbSrjs tp1->rec.data.doing_fast_retransmit = 1; 3125c05f20fbSrjs tot_retrans++; 3126c05f20fbSrjs /* mark the sending seq for possible subsequent FR's */ 3127c05f20fbSrjs if (TAILQ_EMPTY(&asoc->send_queue)) { 3128c05f20fbSrjs /* 3129c05f20fbSrjs * If the queue of send is empty then its the 3130c05f20fbSrjs * next sequence number that will be assigned so 3131c05f20fbSrjs * we subtract one from this to get the one we 3132c05f20fbSrjs * last sent. 3133c05f20fbSrjs */ 3134c05f20fbSrjs tp1->rec.data.fast_retran_tsn = sending_seq - 1; 3135c05f20fbSrjs } else { 3136c05f20fbSrjs /* 3137c05f20fbSrjs * If there are chunks on the send queue 3138c05f20fbSrjs * (unsent data that has made it from the 3139c05f20fbSrjs * stream queues but not out the door, we take 3140c05f20fbSrjs * the first one (which will have the lowest 3141c05f20fbSrjs * TSN) and subtract one to get the one we last 3142c05f20fbSrjs * sent. 3143c05f20fbSrjs */ 3144c05f20fbSrjs struct sctp_tmit_chunk *ttt; 3145c05f20fbSrjs ttt = TAILQ_FIRST(&asoc->send_queue); 3146c05f20fbSrjs tp1->rec.data.fast_retran_tsn = 3147c05f20fbSrjs ttt->rec.data.TSN_seq - 1; 3148c05f20fbSrjs } 3149c05f20fbSrjs if (tp1->do_rtt) { 3150c05f20fbSrjs /* 3151c05f20fbSrjs * this guy had a RTO calculation pending on it, 3152c05f20fbSrjs * cancel it 3153c05f20fbSrjs */ 3154c05f20fbSrjs tp1->whoTo->rto_pending = 0; 3155c05f20fbSrjs tp1->do_rtt = 0; 3156c05f20fbSrjs } 3157c05f20fbSrjs /* fix counts and things */ 3158c05f20fbSrjs 3159c05f20fbSrjs tp1->whoTo->net_ack++; 3160c05f20fbSrjs sctp_flight_size_decrease(tp1); 3161c05f20fbSrjs #ifdef SCTP_LOG_RWND 3162c05f20fbSrjs sctp_log_rwnd(SCTP_INCREASE_PEER_RWND, 3163c05f20fbSrjs asoc->peers_rwnd , tp1->send_size, sctp_peer_chunk_oh); 3164c05f20fbSrjs #endif 3165c05f20fbSrjs /* add back to the rwnd */ 3166c05f20fbSrjs asoc->peers_rwnd += (tp1->send_size + sctp_peer_chunk_oh); 3167c05f20fbSrjs 3168c05f20fbSrjs /* remove from the total flight */ 3169c05f20fbSrjs sctp_total_flight_decrease(stcb, tp1); 3170c05f20fbSrjs if (alt != tp1->whoTo) { 3171c05f20fbSrjs /* yes, there is an alternate. */ 3172c05f20fbSrjs sctp_free_remote_addr(tp1->whoTo); 3173c05f20fbSrjs tp1->whoTo = alt; 3174c05f20fbSrjs alt->ref_count++; 3175c05f20fbSrjs } 3176c05f20fbSrjs } 3177c05f20fbSrjs tp1 = TAILQ_NEXT(tp1, sctp_next); 3178c05f20fbSrjs } /* while (tp1) */ 3179c05f20fbSrjs 3180c05f20fbSrjs if (tot_retrans > 0) { 3181c05f20fbSrjs /* Setup the ecn nonce re-sync point. We 3182c05f20fbSrjs * do this since once we go to FR something 3183c05f20fbSrjs * we introduce a Karn's rule scenario and 3184c05f20fbSrjs * won't know the totals for the ECN bits. 3185c05f20fbSrjs */ 3186c05f20fbSrjs asoc->nonce_resync_tsn = sending_seq; 3187c05f20fbSrjs asoc->nonce_wait_for_ecne = 0; 3188c05f20fbSrjs asoc->nonce_sum_check = 0; 3189c05f20fbSrjs } 3190c05f20fbSrjs 3191c05f20fbSrjs } 3192c05f20fbSrjs 3193c05f20fbSrjs struct sctp_tmit_chunk * 3194c05f20fbSrjs sctp_try_advance_peer_ack_point(struct sctp_tcb *stcb, 3195c05f20fbSrjs struct sctp_association *asoc) 3196c05f20fbSrjs { 3197c05f20fbSrjs struct sctp_tmit_chunk *tp1, *tp2, *a_adv=NULL; 3198c05f20fbSrjs struct timeval now; 3199c05f20fbSrjs int now_filled=0; 3200c05f20fbSrjs 3201c05f20fbSrjs if (asoc->peer_supports_prsctp == 0) { 3202c05f20fbSrjs return (NULL); 3203c05f20fbSrjs } 3204c05f20fbSrjs tp1 = TAILQ_FIRST(&asoc->sent_queue); 3205c05f20fbSrjs while (tp1) { 3206c05f20fbSrjs if (tp1->sent != SCTP_FORWARD_TSN_SKIP && 3207c05f20fbSrjs tp1->sent != SCTP_DATAGRAM_RESEND) { 3208c05f20fbSrjs /* no chance to advance, out of here */ 3209c05f20fbSrjs break; 3210c05f20fbSrjs } 3211c05f20fbSrjs if ((tp1->flags & SCTP_PR_SCTP_ENABLED) == 0) { 3212c05f20fbSrjs /* 3213c05f20fbSrjs * We can't fwd-tsn past any that are reliable 3214c05f20fbSrjs * aka retransmitted until the asoc fails. 3215c05f20fbSrjs */ 3216c05f20fbSrjs break; 3217c05f20fbSrjs } 3218c05f20fbSrjs if (!now_filled) { 3219c05f20fbSrjs SCTP_GETTIME_TIMEVAL(&now); 3220c05f20fbSrjs now_filled = 1; 3221c05f20fbSrjs } 3222c05f20fbSrjs tp2 = TAILQ_NEXT(tp1, sctp_next); 3223c05f20fbSrjs /* 3224c05f20fbSrjs * now we got a chunk which is marked for another 3225c05f20fbSrjs * retransmission to a PR-stream but has run 3226c05f20fbSrjs * out its chances already maybe OR has been 3227c05f20fbSrjs * marked to skip now. Can we skip it if its a 3228c05f20fbSrjs * resend? 3229c05f20fbSrjs */ 3230c05f20fbSrjs if (tp1->sent == SCTP_DATAGRAM_RESEND && 3231c05f20fbSrjs (tp1->flags & SCTP_PR_SCTP_BUFFER) == 0) { 3232c05f20fbSrjs /* 3233c05f20fbSrjs * Now is this one marked for resend and its time 3234c05f20fbSrjs * is now up? 3235c05f20fbSrjs */ 3236c05f20fbSrjs #ifndef __FreeBSD__ 3237c05f20fbSrjs if (timercmp(&now, &tp1->rec.data.timetodrop, >)) 3238c05f20fbSrjs #else 3239c05f20fbSrjs if (timevalcmp(&now, &tp1->rec.data.timetodrop, >)) 3240c05f20fbSrjs #endif 3241c05f20fbSrjs { 3242c05f20fbSrjs /* Yes so drop it */ 3243c05f20fbSrjs if (tp1->data) { 3244c05f20fbSrjs sctp_release_pr_sctp_chunk(stcb, tp1, 3245c05f20fbSrjs (SCTP_RESPONSE_TO_USER_REQ|SCTP_NOTIFY_DATAGRAM_SENT), 3246c05f20fbSrjs &asoc->sent_queue); 3247c05f20fbSrjs } 3248c05f20fbSrjs } else { 3249c05f20fbSrjs /* 3250c05f20fbSrjs * No, we are done when hit one for resend whos 3251c05f20fbSrjs * time as not expired. 3252c05f20fbSrjs */ 3253c05f20fbSrjs break; 3254c05f20fbSrjs } 3255c05f20fbSrjs } 3256c05f20fbSrjs /* 3257c05f20fbSrjs * Ok now if this chunk is marked to drop it 3258c05f20fbSrjs * we can clean up the chunk, advance our peer ack point 3259c05f20fbSrjs * and we can check the next chunk. 3260c05f20fbSrjs */ 3261c05f20fbSrjs if (tp1->sent == SCTP_FORWARD_TSN_SKIP) { 3262c05f20fbSrjs /* advance PeerAckPoint goes forward */ 3263c05f20fbSrjs asoc->advanced_peer_ack_point = tp1->rec.data.TSN_seq; 3264c05f20fbSrjs a_adv = tp1; 3265c05f20fbSrjs /* 3266c05f20fbSrjs * we don't want to de-queue it here. Just wait for the 3267c05f20fbSrjs * next peer SACK to come with a new cumTSN and then 3268c05f20fbSrjs * the chunk will be droped in the normal fashion. 3269c05f20fbSrjs */ 3270c05f20fbSrjs if (tp1->data) { 3271c05f20fbSrjs sctp_free_bufspace(stcb, asoc, tp1); 3272c05f20fbSrjs #ifdef SCTP_DEBUG 3273c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_OUTPUT2) { 3274c05f20fbSrjs printf("--total out:%lu total_mbuf_out:%lu\n", 3275c05f20fbSrjs (u_long)asoc->total_output_queue_size, 3276c05f20fbSrjs (u_long)asoc->total_output_mbuf_queue_size); 3277c05f20fbSrjs } 3278c05f20fbSrjs #endif 3279c05f20fbSrjs /* 3280c05f20fbSrjs * Maybe there should be another notification 3281c05f20fbSrjs * type 3282c05f20fbSrjs */ 3283c05f20fbSrjs sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, 3284c05f20fbSrjs (SCTP_RESPONSE_TO_USER_REQ|SCTP_NOTIFY_DATAGRAM_SENT), 3285c05f20fbSrjs tp1); 3286c05f20fbSrjs sctp_m_freem(tp1->data); 3287c05f20fbSrjs tp1->data = NULL; 3288c05f20fbSrjs sctp_sowwakeup(stcb->sctp_ep, 3289c05f20fbSrjs stcb->sctp_socket); 3290c05f20fbSrjs } 3291c05f20fbSrjs } else { 3292c05f20fbSrjs /* If it is still in RESEND we can advance no further */ 3293c05f20fbSrjs break; 3294c05f20fbSrjs } 3295c05f20fbSrjs /* 3296c05f20fbSrjs * If we hit here we just dumped tp1, move to next 3297c05f20fbSrjs * tsn on sent queue. 3298c05f20fbSrjs */ 3299c05f20fbSrjs tp1 = tp2; 3300c05f20fbSrjs } 3301c05f20fbSrjs return (a_adv); 3302c05f20fbSrjs } 3303c05f20fbSrjs 3304c05f20fbSrjs #ifdef SCTP_HIGH_SPEED 3305c05f20fbSrjs struct sctp_hs_raise_drop { 3306c05f20fbSrjs int32_t cwnd; 3307c05f20fbSrjs int32_t increase; 3308c05f20fbSrjs int32_t drop_percent; 3309c05f20fbSrjs }; 3310c05f20fbSrjs 3311c05f20fbSrjs #define SCTP_HS_TABLE_SIZE 73 3312c05f20fbSrjs 3313c05f20fbSrjs struct sctp_hs_raise_drop sctp_cwnd_adjust[SCTP_HS_TABLE_SIZE] = { 3314c05f20fbSrjs {38,1,50}, /* 0 */ 3315c05f20fbSrjs {118,2,44}, /* 1 */ 3316c05f20fbSrjs {221,3,41}, /* 2 */ 3317c05f20fbSrjs {347,4,38}, /* 3 */ 3318c05f20fbSrjs {495,5,37}, /* 4 */ 3319c05f20fbSrjs {663,6,35}, /* 5 */ 3320c05f20fbSrjs {851,7,34}, /* 6 */ 3321c05f20fbSrjs {1058,8,33}, /* 7 */ 3322c05f20fbSrjs {1284,9,32}, /* 8 */ 3323c05f20fbSrjs {1529,10,31}, /* 9 */ 3324c05f20fbSrjs {1793,11,30}, /* 10 */ 3325c05f20fbSrjs {2076,12,29}, /* 11 */ 3326c05f20fbSrjs {2378,13,28}, /* 12 */ 3327c05f20fbSrjs {2699,14,28}, /* 13 */ 3328c05f20fbSrjs {3039,15,27}, /* 14 */ 3329c05f20fbSrjs {3399,16,27}, /* 15 */ 3330c05f20fbSrjs {3778,17,26}, /* 16 */ 3331c05f20fbSrjs {4177,18,26}, /* 17 */ 3332c05f20fbSrjs {4596,19,25}, /* 18 */ 3333c05f20fbSrjs {5036,20,25}, /* 19 */ 3334c05f20fbSrjs {5497,21,24}, /* 20 */ 3335c05f20fbSrjs {5979,22,24}, /* 21 */ 3336c05f20fbSrjs {6483,23,23}, /* 22 */ 3337c05f20fbSrjs {7009,24,23}, /* 23 */ 3338c05f20fbSrjs {7558,25,22}, /* 24 */ 3339c05f20fbSrjs {8130,26,22}, /* 25 */ 3340c05f20fbSrjs {8726,27,22}, /* 26 */ 3341c05f20fbSrjs {9346,28,21}, /* 27 */ 3342c05f20fbSrjs {9991,29,21}, /* 28 */ 3343c05f20fbSrjs {10661,30,21}, /* 29 */ 3344c05f20fbSrjs {11358,31,20}, /* 30 */ 3345c05f20fbSrjs {12082,32,20}, /* 31 */ 3346c05f20fbSrjs {12834,33,20}, /* 32 */ 3347c05f20fbSrjs {13614,34,19}, /* 33 */ 3348c05f20fbSrjs {14424,35,19}, /* 34 */ 3349c05f20fbSrjs {15265,36,19}, /* 35 */ 3350c05f20fbSrjs {16137,37,19}, /* 36 */ 3351c05f20fbSrjs {17042,38,18}, /* 37 */ 3352c05f20fbSrjs {17981,39,18}, /* 38 */ 3353c05f20fbSrjs {18955,40,18}, /* 39 */ 3354c05f20fbSrjs {19965,41,17}, /* 40 */ 3355c05f20fbSrjs {21013,42,17}, /* 41 */ 3356c05f20fbSrjs {22101,43,17}, /* 42 */ 3357c05f20fbSrjs {23230,44,17}, /* 43 */ 3358c05f20fbSrjs {24402,45,16}, /* 44 */ 3359c05f20fbSrjs {25618,46,16}, /* 45 */ 3360c05f20fbSrjs {26881,47,16}, /* 46 */ 3361c05f20fbSrjs {28193,48,16}, /* 47 */ 3362c05f20fbSrjs {29557,49,15}, /* 48 */ 3363c05f20fbSrjs {30975,50,15}, /* 49 */ 3364c05f20fbSrjs {32450,51,15}, /* 50 */ 3365c05f20fbSrjs {33986,52,15}, /* 51 */ 3366c05f20fbSrjs {35586,53,14}, /* 52 */ 3367c05f20fbSrjs {37253,54,14}, /* 53 */ 3368c05f20fbSrjs {38992,55,14}, /* 54 */ 3369c05f20fbSrjs {40808,56,14}, /* 55 */ 3370c05f20fbSrjs {42707,57,13}, /* 56 */ 3371c05f20fbSrjs {44694,58,13}, /* 57 */ 3372c05f20fbSrjs {46776,59,13}, /* 58 */ 3373c05f20fbSrjs {48961,60,13}, /* 59 */ 3374c05f20fbSrjs {51258,61,13}, /* 60 */ 3375c05f20fbSrjs {53677,62,12}, /* 61 */ 3376c05f20fbSrjs {56230,63,12}, /* 62 */ 3377c05f20fbSrjs {58932,64,12}, /* 63 */ 3378c05f20fbSrjs {61799,65,12}, /* 64 */ 3379c05f20fbSrjs {64851,66,11}, /* 65 */ 3380c05f20fbSrjs {68113,67,11}, /* 66 */ 3381c05f20fbSrjs {71617,68,11}, /* 67 */ 3382c05f20fbSrjs {75401,69,10}, /* 68 */ 3383c05f20fbSrjs {79517,70,10}, /* 69 */ 3384c05f20fbSrjs {84035,71,10}, /* 70 */ 3385c05f20fbSrjs {89053,72,10}, /* 71 */ 3386c05f20fbSrjs {94717,73,9} /* 72 */ 3387c05f20fbSrjs }; 3388c05f20fbSrjs 3389c05f20fbSrjs static void 3390c05f20fbSrjs sctp_hs_cwnd_increase(struct sctp_nets *net) 3391c05f20fbSrjs { 3392c05f20fbSrjs int cur_val, i, indx, incr; 3393c05f20fbSrjs 3394c05f20fbSrjs cur_val = net->cwnd >> 10; 3395c05f20fbSrjs indx = SCTP_HS_TABLE_SIZE - 1; 3396c05f20fbSrjs 3397c05f20fbSrjs if (cur_val < sctp_cwnd_adjust[0].cwnd) { 3398c05f20fbSrjs /* normal mode */ 3399c05f20fbSrjs if (net->net_ack > net->mtu) { 3400c05f20fbSrjs net->cwnd += net->mtu; 3401c05f20fbSrjs #ifdef SCTP_CWND_LOGGING 3402c05f20fbSrjs sctp_log_cwnd(net, net->mtu, SCTP_CWND_LOG_FROM_SS); 3403c05f20fbSrjs #endif 3404c05f20fbSrjs } else { 3405c05f20fbSrjs net->cwnd += net->net_ack; 3406c05f20fbSrjs #ifdef SCTP_CWND_LOGGING 3407c05f20fbSrjs sctp_log_cwnd(net, net->net_ack, SCTP_CWND_LOG_FROM_SS); 3408c05f20fbSrjs #endif 3409c05f20fbSrjs } 3410c05f20fbSrjs } else { 3411c05f20fbSrjs for (i=net->last_hs_used; i<SCTP_HS_TABLE_SIZE; i++) { 3412c05f20fbSrjs if (cur_val < sctp_cwnd_adjust[i].cwnd) { 3413c05f20fbSrjs indx = i; 3414c05f20fbSrjs break; 3415c05f20fbSrjs } 3416c05f20fbSrjs } 3417c05f20fbSrjs net->last_hs_used = indx; 3418c05f20fbSrjs incr = ((sctp_cwnd_adjust[indx].increase) << 10); 3419c05f20fbSrjs net->cwnd += incr; 3420c05f20fbSrjs #ifdef SCTP_CWND_LOGGING 3421c05f20fbSrjs sctp_log_cwnd(net, incr, SCTP_CWND_LOG_FROM_SS); 3422c05f20fbSrjs #endif 3423c05f20fbSrjs } 3424c05f20fbSrjs } 3425c05f20fbSrjs 3426c05f20fbSrjs static void 3427c05f20fbSrjs sctp_hs_cwnd_decrease(struct sctp_nets *net) 3428c05f20fbSrjs { 3429c05f20fbSrjs int cur_val, i, indx; 3430c05f20fbSrjs #ifdef SCTP_CWND_LOGGING 3431c05f20fbSrjs int old_cwnd = net->cwnd; 3432c05f20fbSrjs #endif 3433c05f20fbSrjs 3434c05f20fbSrjs cur_val = net->cwnd >> 10; 3435c05f20fbSrjs indx = net->last_hs_used; 3436c05f20fbSrjs if (cur_val < sctp_cwnd_adjust[0].cwnd) { 3437c05f20fbSrjs /* normal mode */ 3438c05f20fbSrjs net->ssthresh = net->cwnd / 2; 3439c05f20fbSrjs if (net->ssthresh < (net->mtu*2)) { 3440c05f20fbSrjs net->ssthresh = 2 * net->mtu; 3441c05f20fbSrjs } 3442c05f20fbSrjs net->cwnd = net->ssthresh; 3443c05f20fbSrjs #ifdef SCTP_CWND_LOGGING 3444c05f20fbSrjs sctp_log_cwnd(net, (net->cwnd-old_cwnd), SCTP_CWND_LOG_FROM_FR); 3445c05f20fbSrjs #endif 3446c05f20fbSrjs } else { 3447c05f20fbSrjs /* drop by the proper amount */ 3448c05f20fbSrjs net->ssthresh = net->cwnd - (int)((net->cwnd / 100) * 3449c05f20fbSrjs sctp_cwnd_adjust[net->last_hs_used].drop_percent); 3450c05f20fbSrjs net->cwnd = net->ssthresh; 3451c05f20fbSrjs /* now where are we */ 3452c05f20fbSrjs indx = net->last_hs_used; 3453c05f20fbSrjs cur_val = net->cwnd >> 10; 3454c05f20fbSrjs /* reset where we are in the table */ 3455c05f20fbSrjs if (cur_val < sctp_cwnd_adjust[0].cwnd) { 3456c05f20fbSrjs /* feel out of hs */ 3457c05f20fbSrjs net->last_hs_used = 0; 3458c05f20fbSrjs } else { 3459c05f20fbSrjs for (i = indx; i >= 1; i--) { 3460c05f20fbSrjs if (cur_val > sctp_cwnd_adjust[i - 1].cwnd) { 3461c05f20fbSrjs break; 3462c05f20fbSrjs } 3463c05f20fbSrjs } 3464c05f20fbSrjs net->last_hs_used = indx; 3465c05f20fbSrjs } 3466c05f20fbSrjs } 3467c05f20fbSrjs } 3468c05f20fbSrjs #endif 3469c05f20fbSrjs 3470c05f20fbSrjs void 3471c05f20fbSrjs sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb, 3472c05f20fbSrjs struct sctp_nets *net_from, int *abort_now) 3473c05f20fbSrjs { 3474c05f20fbSrjs struct sctp_association *asoc; 3475c05f20fbSrjs struct sctp_sack *sack; 3476c05f20fbSrjs struct sctp_tmit_chunk *tp1, *tp2; 3477c05f20fbSrjs u_long cum_ack, last_tsn, biggest_tsn_acked, biggest_tsn_newly_acked; 3478c05f20fbSrjs uint16_t num_seg; 3479c05f20fbSrjs unsigned int sack_length; 3480c05f20fbSrjs uint32_t send_s; 3481c05f20fbSrjs int some_on_streamwheel; 3482c05f20fbSrjs int strike_enabled = 0, cnt_of_cacc = 0; 3483c05f20fbSrjs int accum_moved = 0; 3484c05f20fbSrjs int marking_allowed = 1; 3485c05f20fbSrjs int will_exit_fast_recovery=0; 3486c05f20fbSrjs u_int32_t a_rwnd; 3487c05f20fbSrjs struct sctp_nets *net = NULL; 3488c05f20fbSrjs int nonce_sum_flag, ecn_seg_sums=0; 3489c05f20fbSrjs asoc = &stcb->asoc; 3490c05f20fbSrjs 3491c05f20fbSrjs /* 3492c05f20fbSrjs * Handle the incoming sack on data I have been sending. 3493c05f20fbSrjs */ 3494c05f20fbSrjs 3495c05f20fbSrjs /* 3496c05f20fbSrjs * we take any chance we can to service our queues since we 3497c05f20fbSrjs * cannot get awoken when the socket is read from :< 3498c05f20fbSrjs */ 3499c05f20fbSrjs asoc->overall_error_count = 0; 3500c05f20fbSrjs 3501c05f20fbSrjs if (asoc->sent_queue_retran_cnt) { 3502c05f20fbSrjs #ifdef SCTP_DEBUG 3503c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 3504c05f20fbSrjs printf("Handling SACK for asoc:%p retran:%d\n", 3505c05f20fbSrjs asoc, asoc->sent_queue_retran_cnt); 3506c05f20fbSrjs } 3507c05f20fbSrjs #endif 3508c05f20fbSrjs } 3509c05f20fbSrjs 3510c05f20fbSrjs sctp_service_queues(stcb, asoc, 0); 3511c05f20fbSrjs 3512c05f20fbSrjs /* 3513c05f20fbSrjs * Now perform the actual SACK handling: 3514c05f20fbSrjs * 1) Verify that it is not an old sack, if so discard. 3515c05f20fbSrjs * 2) If there is nothing left in the send queue (cum-ack is equal 3516c05f20fbSrjs * to last acked) then you have a duplicate too, update any rwnd 3517c05f20fbSrjs * change and verify no timers are running. then return. 3518c05f20fbSrjs * 3) Process any new consequtive data i.e. cum-ack moved 3519c05f20fbSrjs * process these first and note that it moved. 3520c05f20fbSrjs * 4) Process any sack blocks. 3521c05f20fbSrjs * 5) Drop any acked from the queue. 3522c05f20fbSrjs * 6) Check for any revoked blocks and mark. 3523c05f20fbSrjs * 7) Update the cwnd. 3524c05f20fbSrjs * 8) Nothing left, sync up flightsizes and things, stop all timers 3525c05f20fbSrjs * and also check for shutdown_pending state. If so then go ahead 3526c05f20fbSrjs * and send off the shutdown. If in shutdown recv, send off the 3527c05f20fbSrjs * shutdown-ack and start that timer, Ret. 3528c05f20fbSrjs * 9) Strike any non-acked things and do FR procedure if needed being 3529c05f20fbSrjs * sure to set the FR flag. 3530c05f20fbSrjs * 10) Do pr-sctp procedures. 3531c05f20fbSrjs * 11) Apply any FR penalties. 3532c05f20fbSrjs * 12) Assure we will SACK if in shutdown_recv state. 3533c05f20fbSrjs */ 3534c05f20fbSrjs 3535c05f20fbSrjs sack_length = ntohs(ch->ch.chunk_length); 3536c05f20fbSrjs if (sack_length < sizeof(struct sctp_sack_chunk)) { 3537c05f20fbSrjs #ifdef SCTP_DEBUG 3538c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 3539c05f20fbSrjs printf("Bad size on sack chunk .. to small\n"); 3540c05f20fbSrjs } 3541c05f20fbSrjs #endif 3542c05f20fbSrjs return; 3543c05f20fbSrjs } 3544c05f20fbSrjs /* ECN Nonce */ 3545c05f20fbSrjs nonce_sum_flag = ch->ch.chunk_flags & SCTP_SACK_NONCE_SUM; 3546c05f20fbSrjs sack = &ch->sack; 3547c05f20fbSrjs cum_ack = last_tsn = ntohl(sack->cum_tsn_ack); 3548c05f20fbSrjs num_seg = ntohs(sack->num_gap_ack_blks); 3549c05f20fbSrjs 3550c05f20fbSrjs /* reality check */ 3551c05f20fbSrjs if (TAILQ_EMPTY(&asoc->send_queue)) { 3552c05f20fbSrjs send_s = asoc->sending_seq; 3553c05f20fbSrjs } else { 3554c05f20fbSrjs tp1 = TAILQ_FIRST(&asoc->send_queue); 3555c05f20fbSrjs send_s = tp1->rec.data.TSN_seq; 3556c05f20fbSrjs } 3557c05f20fbSrjs 3558c05f20fbSrjs if (sctp_strict_sacks) { 3559c05f20fbSrjs if (cum_ack == send_s || 3560c05f20fbSrjs compare_with_wrap(cum_ack, send_s, MAX_TSN)) { 3561c05f20fbSrjs struct mbuf *oper; 3562c05f20fbSrjs /* 3563c05f20fbSrjs * no way, we have not even sent this TSN out yet. 3564c05f20fbSrjs * Peer is hopelessly messed up with us. 3565c05f20fbSrjs */ 3566c05f20fbSrjs hopeless_peer: 3567c05f20fbSrjs *abort_now = 1; 3568c05f20fbSrjs /* XXX */ 3569c05f20fbSrjs MGET(oper, M_DONTWAIT, MT_DATA); 3570c05f20fbSrjs if (oper) { 3571c05f20fbSrjs struct sctp_paramhdr *ph; 3572c05f20fbSrjs u_int32_t *ippp; 3573c05f20fbSrjs 3574c05f20fbSrjs oper->m_len = sizeof(struct sctp_paramhdr) + 3575c05f20fbSrjs sizeof(*ippp); 3576c05f20fbSrjs ph = mtod(oper, struct sctp_paramhdr *); 3577c05f20fbSrjs ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 3578c05f20fbSrjs ph->param_length = htons(oper->m_len); 3579c05f20fbSrjs ippp = (u_int32_t *)(ph + 1); 3580c05f20fbSrjs *ippp = htonl(0x30000002); 3581c05f20fbSrjs } 3582c05f20fbSrjs sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper); 3583c05f20fbSrjs return; 3584c05f20fbSrjs } 3585c05f20fbSrjs } 3586c05f20fbSrjs /* update the Rwnd of the peer */ 3587c05f20fbSrjs a_rwnd = (u_int32_t)ntohl(sack->a_rwnd); 3588c05f20fbSrjs if (asoc->sent_queue_retran_cnt) { 3589c05f20fbSrjs #ifdef SCTP_DEBUG 3590c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 3591c05f20fbSrjs printf("cum_ack:%lx num_seg:%u last_acked_seq:%x\n", 3592c05f20fbSrjs cum_ack, (u_int)num_seg, asoc->last_acked_seq); 3593c05f20fbSrjs } 3594c05f20fbSrjs #endif 3595c05f20fbSrjs } 3596c05f20fbSrjs if (compare_with_wrap(asoc->t3timeout_highest_marked, cum_ack, MAX_TSN)) { 3597c05f20fbSrjs /* we are not allowed to mark for FR */ 3598c05f20fbSrjs marking_allowed = 0; 3599c05f20fbSrjs } 3600c05f20fbSrjs /**********************/ 3601c05f20fbSrjs /* 1) check the range */ 3602c05f20fbSrjs /**********************/ 3603c05f20fbSrjs if (compare_with_wrap(asoc->last_acked_seq, last_tsn, MAX_TSN)) { 3604c05f20fbSrjs /* acking something behind */ 3605c05f20fbSrjs if (asoc->sent_queue_retran_cnt) { 3606c05f20fbSrjs #ifdef SCTP_DEBUG 3607c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 3608c05f20fbSrjs printf("The cum-ack is behind us\n"); 3609c05f20fbSrjs } 3610c05f20fbSrjs #endif 3611c05f20fbSrjs } 3612c05f20fbSrjs return; 3613c05f20fbSrjs } 3614c05f20fbSrjs 3615c05f20fbSrjs if (TAILQ_EMPTY(&asoc->sent_queue)) { 3616c05f20fbSrjs /* nothing left on sendqueue.. consider done */ 3617c05f20fbSrjs #ifdef SCTP_LOG_RWND 3618c05f20fbSrjs sctp_log_rwnd_set(SCTP_SET_PEER_RWND_VIA_SACK, 3619c05f20fbSrjs asoc->peers_rwnd, 0, 0, a_rwnd); 3620c05f20fbSrjs #endif 3621c05f20fbSrjs asoc->peers_rwnd = a_rwnd; 3622c05f20fbSrjs if (asoc->sent_queue_retran_cnt) { 3623c05f20fbSrjs #ifdef SCTP_DEBUG 3624c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 3625c05f20fbSrjs printf("Huh? retran set but none on queue\n"); 3626c05f20fbSrjs } 3627c05f20fbSrjs #endif 3628c05f20fbSrjs asoc->sent_queue_retran_cnt = 0; 3629c05f20fbSrjs } 3630c05f20fbSrjs if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) { 3631c05f20fbSrjs /* SWS sender side engages */ 3632c05f20fbSrjs asoc->peers_rwnd = 0; 3633c05f20fbSrjs } 3634c05f20fbSrjs /* stop any timers */ 3635c05f20fbSrjs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 3636c05f20fbSrjs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, 3637c05f20fbSrjs stcb, net); 3638c05f20fbSrjs net->partial_bytes_acked = 0; 3639c05f20fbSrjs net->flight_size = 0; 3640c05f20fbSrjs } 3641c05f20fbSrjs asoc->total_flight = 0; 3642c05f20fbSrjs asoc->total_flight_count = 0; 3643c05f20fbSrjs return; 3644c05f20fbSrjs } 3645c05f20fbSrjs /* 3646c05f20fbSrjs * We init netAckSz and netAckSz2 to 0. These are used to track 2 3647c05f20fbSrjs * things. The total byte count acked is tracked in netAckSz AND 3648c05f20fbSrjs * netAck2 is used to track the total bytes acked that are un- 3649c05f20fbSrjs * amibguious and were never retransmitted. We track these on a 3650c05f20fbSrjs * per destination address basis. 3651c05f20fbSrjs */ 3652c05f20fbSrjs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 3653c05f20fbSrjs net->prev_cwnd = net->cwnd; 3654c05f20fbSrjs net->net_ack = 0; 3655c05f20fbSrjs net->net_ack2 = 0; 3656c05f20fbSrjs } 3657c05f20fbSrjs /* process the new consecutive TSN first */ 3658c05f20fbSrjs tp1 = TAILQ_FIRST(&asoc->sent_queue); 3659c05f20fbSrjs while (tp1) { 3660c05f20fbSrjs if (compare_with_wrap(last_tsn, tp1->rec.data.TSN_seq, 3661c05f20fbSrjs MAX_TSN) || 3662c05f20fbSrjs last_tsn == tp1->rec.data.TSN_seq) { 3663c05f20fbSrjs if (tp1->sent != SCTP_DATAGRAM_UNSENT) { 3664c05f20fbSrjs /* ECN Nonce: Add the nonce to the sender's nonce sum */ 3665c05f20fbSrjs asoc->nonce_sum_expect_base += tp1->rec.data.ect_nonce; 3666c05f20fbSrjs accum_moved = 1; 3667c05f20fbSrjs if (tp1->sent < SCTP_DATAGRAM_ACKED) { 3668c05f20fbSrjs /* 3669c05f20fbSrjs * If it is less than ACKED, it is now 3670c05f20fbSrjs * no-longer in flight. Higher values 3671c05f20fbSrjs * may occur during marking 3672c05f20fbSrjs */ 3673c05f20fbSrjs if ((tp1->whoTo->dest_state & 3674c05f20fbSrjs SCTP_ADDR_UNCONFIRMED) && 3675c05f20fbSrjs (tp1->snd_count < 2) ) { 3676c05f20fbSrjs /* 3677c05f20fbSrjs * If there was no retran and 3678c05f20fbSrjs * the address is un-confirmed 3679c05f20fbSrjs * and we sent there and are 3680c05f20fbSrjs * now sacked.. its confirmed, 3681c05f20fbSrjs * mark it so. 3682c05f20fbSrjs */ 3683c05f20fbSrjs tp1->whoTo->dest_state &= 3684c05f20fbSrjs ~SCTP_ADDR_UNCONFIRMED; 3685c05f20fbSrjs } 3686c05f20fbSrjs sctp_flight_size_decrease(tp1); 3687c05f20fbSrjs sctp_total_flight_decrease(stcb, tp1); 3688c05f20fbSrjs tp1->whoTo->net_ack += tp1->send_size; 3689c05f20fbSrjs if (tp1->snd_count < 2) { 3690c05f20fbSrjs /* True non-retransmited chunk */ 3691c05f20fbSrjs tp1->whoTo->net_ack2 += 3692c05f20fbSrjs tp1->send_size; 3693c05f20fbSrjs /* update RTO too? */ 3694c05f20fbSrjs if (tp1->do_rtt) { 3695c05f20fbSrjs tp1->whoTo->RTO = 3696c05f20fbSrjs sctp_calculate_rto(stcb, 3697c05f20fbSrjs asoc, tp1->whoTo, 3698c05f20fbSrjs &tp1->sent_rcv_time); 3699c05f20fbSrjs tp1->whoTo->rto_pending = 0; 3700c05f20fbSrjs tp1->do_rtt = 0; 3701c05f20fbSrjs } 3702c05f20fbSrjs } 3703c05f20fbSrjs } 3704c05f20fbSrjs if (tp1->sent == SCTP_DATAGRAM_RESEND) { 3705c05f20fbSrjs #ifdef SCTP_DEBUG 3706c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA3) { 3707c05f20fbSrjs printf("Hmm. one that is in RESEND that is now ACKED\n"); 3708c05f20fbSrjs } 3709c05f20fbSrjs #endif 3710c05f20fbSrjs sctp_ucount_decr(asoc->sent_queue_retran_cnt); 3711c05f20fbSrjs #ifdef SCTP_AUDITING_ENABLED 3712c05f20fbSrjs sctp_audit_log(0xB3, 3713c05f20fbSrjs (asoc->sent_queue_retran_cnt & 0x000000ff)); 3714c05f20fbSrjs #endif 3715c05f20fbSrjs 3716c05f20fbSrjs } 3717c05f20fbSrjs tp1->sent = SCTP_DATAGRAM_ACKED; 3718c05f20fbSrjs } 3719c05f20fbSrjs } else { 3720c05f20fbSrjs break; 3721c05f20fbSrjs } 3722c05f20fbSrjs tp1 = TAILQ_NEXT(tp1, sctp_next); 3723c05f20fbSrjs } 3724c05f20fbSrjs /*******************************************/ 3725c05f20fbSrjs /* cancel ALL T3-send timer if accum moved */ 3726c05f20fbSrjs /*******************************************/ 3727c05f20fbSrjs if (accum_moved) { 3728c05f20fbSrjs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 3729c05f20fbSrjs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, 3730c05f20fbSrjs stcb, net); 3731c05f20fbSrjs } 3732c05f20fbSrjs } 3733c05f20fbSrjs biggest_tsn_newly_acked = biggest_tsn_acked = last_tsn; 3734c05f20fbSrjs /* always set this up to cum-ack */ 3735c05f20fbSrjs asoc->this_sack_highest_gap = last_tsn; 3736c05f20fbSrjs 3737a296faa8Schristos if (num_seg * sizeof(struct sctp_gap_ack_block) + sizeof(struct sctp_sack_chunk) > sack_length) { 3738c05f20fbSrjs /* skip corrupt segments */ 3739c05f20fbSrjs strike_enabled = 0; 3740c05f20fbSrjs goto skip_segments; 3741c05f20fbSrjs } 3742c05f20fbSrjs 3743c05f20fbSrjs if (num_seg > 0) { 3744c05f20fbSrjs if (asoc->primary_destination->dest_state & 3745c05f20fbSrjs SCTP_ADDR_SWITCH_PRIMARY) { 3746c05f20fbSrjs /* clear the nets CACC flags */ 3747c05f20fbSrjs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 3748c05f20fbSrjs net->cacc_saw_newack = 0; 3749c05f20fbSrjs } 3750c05f20fbSrjs } 3751c05f20fbSrjs /* 3752c05f20fbSrjs * thisSackHighestGap will increase while handling NEW segments 3753c05f20fbSrjs */ 3754c05f20fbSrjs 3755c05f20fbSrjs sctp_handle_segments(stcb, asoc, ch, last_tsn, 3756c05f20fbSrjs &biggest_tsn_acked, &biggest_tsn_newly_acked, 3757c05f20fbSrjs num_seg, &ecn_seg_sums); 3758c05f20fbSrjs 3759c05f20fbSrjs if (sctp_strict_sacks) { 3760c05f20fbSrjs /* validate the biggest_tsn_acked in the gap acks 3761c05f20fbSrjs * if strict adherence is wanted. 3762c05f20fbSrjs */ 3763c05f20fbSrjs if ((biggest_tsn_acked == send_s) || 3764c05f20fbSrjs (compare_with_wrap(biggest_tsn_acked, send_s, MAX_TSN))) { 3765c05f20fbSrjs /* 3766c05f20fbSrjs * peer is either confused or we are under 3767c05f20fbSrjs * attack. We must abort. 3768c05f20fbSrjs */ 3769c05f20fbSrjs goto hopeless_peer; 3770c05f20fbSrjs } 3771c05f20fbSrjs } 3772c05f20fbSrjs 3773c05f20fbSrjs if (asoc->primary_destination->dest_state & 3774c05f20fbSrjs SCTP_ADDR_SWITCH_PRIMARY) { 3775c05f20fbSrjs /* clear the nets CACC flags */ 3776c05f20fbSrjs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 3777c05f20fbSrjs if (net->cacc_saw_newack) { 3778c05f20fbSrjs cnt_of_cacc++; 3779c05f20fbSrjs } 3780c05f20fbSrjs } 3781c05f20fbSrjs } 3782c05f20fbSrjs 3783c05f20fbSrjs } 3784c05f20fbSrjs 3785c05f20fbSrjs if (cnt_of_cacc < 2) { 3786c05f20fbSrjs strike_enabled = 1; 3787c05f20fbSrjs } else { 3788c05f20fbSrjs strike_enabled = 0; 3789c05f20fbSrjs } 3790c05f20fbSrjs skip_segments: 3791c05f20fbSrjs /********************************************/ 3792c05f20fbSrjs /* drop the acked chunks from the sendqueue */ 3793c05f20fbSrjs /********************************************/ 3794c05f20fbSrjs asoc->last_acked_seq = cum_ack; 3795c05f20fbSrjs if (asoc->primary_destination->dest_state & SCTP_ADDR_SWITCH_PRIMARY) { 3796c05f20fbSrjs if ((cum_ack == asoc->primary_destination->next_tsn_at_change) || 3797c05f20fbSrjs (compare_with_wrap(cum_ack, 3798c05f20fbSrjs asoc->primary_destination->next_tsn_at_change, MAX_TSN))) { 3799c05f20fbSrjs struct sctp_nets *lnet; 3800c05f20fbSrjs /* Turn off the switch flag for ALL addresses */ 3801c05f20fbSrjs TAILQ_FOREACH(lnet, &asoc->nets, sctp_next) { 3802c05f20fbSrjs asoc->primary_destination->dest_state &= 3803c05f20fbSrjs ~(SCTP_ADDR_SWITCH_PRIMARY|SCTP_ADDR_DOUBLE_SWITCH); 3804c05f20fbSrjs } 3805c05f20fbSrjs } 3806c05f20fbSrjs } 3807c05f20fbSrjs /* Drag along the t3 timeout point so we don't have a problem at wrap */ 3808c05f20fbSrjs if (marking_allowed) { 3809c05f20fbSrjs asoc->t3timeout_highest_marked = cum_ack; 3810c05f20fbSrjs } 3811c05f20fbSrjs tp1 = TAILQ_FIRST(&asoc->sent_queue); 3812c05f20fbSrjs do { 3813c05f20fbSrjs if (compare_with_wrap(tp1->rec.data.TSN_seq, cum_ack, 3814c05f20fbSrjs MAX_TSN)) { 3815c05f20fbSrjs break; 3816c05f20fbSrjs } 3817c05f20fbSrjs if (tp1->sent == SCTP_DATAGRAM_UNSENT) { 3818c05f20fbSrjs /* no more sent on list */ 3819c05f20fbSrjs break; 3820c05f20fbSrjs } 3821c05f20fbSrjs tp2 = TAILQ_NEXT(tp1, sctp_next); 3822c05f20fbSrjs TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next); 3823c05f20fbSrjs if (tp1->data) { 3824c05f20fbSrjs sctp_free_bufspace(stcb, asoc, tp1); 3825c05f20fbSrjs #ifdef SCTP_DEBUG 3826c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_OUTPUT2) { 3827c05f20fbSrjs printf("--total out:%lu total_mbuf_out:%lu\n", 3828c05f20fbSrjs (u_long)asoc->total_output_queue_size, 3829c05f20fbSrjs (u_long)asoc->total_output_mbuf_queue_size); 3830c05f20fbSrjs } 3831c05f20fbSrjs #endif 3832c05f20fbSrjs 3833c05f20fbSrjs sctp_m_freem(tp1->data); 3834c05f20fbSrjs if (tp1->flags & SCTP_PR_SCTP_BUFFER) { 3835c05f20fbSrjs asoc->sent_queue_cnt_removeable--; 3836c05f20fbSrjs } 3837c05f20fbSrjs 3838c05f20fbSrjs } 3839c05f20fbSrjs tp1->data = NULL; 3840c05f20fbSrjs asoc->sent_queue_cnt--; 3841c05f20fbSrjs sctp_free_remote_addr(tp1->whoTo); 3842c05f20fbSrjs sctppcbinfo.ipi_count_chunk--; 3843c05f20fbSrjs asoc->chunks_on_out_queue--; 3844c05f20fbSrjs 3845c05f20fbSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) { 3846c05f20fbSrjs panic("Chunk count is going negative"); 3847c05f20fbSrjs } 3848c05f20fbSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, tp1); 3849c05f20fbSrjs sctppcbinfo.ipi_gencnt_chunk++; 3850c05f20fbSrjs sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket); 3851c05f20fbSrjs tp1 = tp2; 3852c05f20fbSrjs } while (tp1 != NULL); 3853c05f20fbSrjs 3854c05f20fbSrjs 3855c05f20fbSrjs if (asoc->fast_retran_loss_recovery && accum_moved) { 3856c05f20fbSrjs if (compare_with_wrap(asoc->last_acked_seq, 3857c05f20fbSrjs asoc->fast_recovery_tsn, MAX_TSN) || 3858c05f20fbSrjs asoc->last_acked_seq == asoc->fast_recovery_tsn) { 3859c05f20fbSrjs /* Setup so we will exit RFC2582 fast recovery */ 3860c05f20fbSrjs will_exit_fast_recovery = 1; 3861c05f20fbSrjs } 3862c05f20fbSrjs } 3863c05f20fbSrjs 3864c05f20fbSrjs /* Check for revoked fragments if we hand 3865c05f20fbSrjs * fragments in a previous segment. If we 3866c05f20fbSrjs * had no previous fragments we cannot have 3867c05f20fbSrjs * a revoke issue. 3868c05f20fbSrjs */ 3869c05f20fbSrjs if (asoc->saw_sack_with_frags) 3870c05f20fbSrjs sctp_check_for_revoked(asoc, cum_ack, biggest_tsn_acked); 3871c05f20fbSrjs 3872c05f20fbSrjs if (num_seg) 3873c05f20fbSrjs asoc->saw_sack_with_frags = 1; 3874c05f20fbSrjs else 3875c05f20fbSrjs asoc->saw_sack_with_frags = 0; 3876c05f20fbSrjs 3877c05f20fbSrjs /******************************/ 3878c05f20fbSrjs /* update cwnd */ 3879c05f20fbSrjs /******************************/ 3880c05f20fbSrjs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 3881c05f20fbSrjs /* if nothing was acked on this destination skip it */ 3882c05f20fbSrjs if (net->net_ack == 0) 3883c05f20fbSrjs continue; 3884c05f20fbSrjs 3885c05f20fbSrjs if (net->net_ack2 > 0) { 3886c05f20fbSrjs /* 3887c05f20fbSrjs * Karn's rule applies to clearing error count, 3888c05f20fbSrjs * this is optional. 3889c05f20fbSrjs */ 3890c05f20fbSrjs net->error_count = 0; 3891c05f20fbSrjs if ((net->dest_state&SCTP_ADDR_NOT_REACHABLE) == 3892c05f20fbSrjs SCTP_ADDR_NOT_REACHABLE) { 3893c05f20fbSrjs /* addr came good */ 3894c05f20fbSrjs net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE; 3895c05f20fbSrjs net->dest_state |= SCTP_ADDR_REACHABLE; 3896c05f20fbSrjs sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 3897c05f20fbSrjs SCTP_RECEIVED_SACK, (void *)net); 3898c05f20fbSrjs /* now was it the primary? if so restore */ 3899c05f20fbSrjs if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) { 3900c05f20fbSrjs sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net); 3901c05f20fbSrjs } 3902c05f20fbSrjs } 3903c05f20fbSrjs } 3904c05f20fbSrjs 3905c05f20fbSrjs if (asoc->fast_retran_loss_recovery && 3906c05f20fbSrjs will_exit_fast_recovery == 0) { 3907c05f20fbSrjs /* If we are in loss recovery we skip any cwnd update */ 3908c05f20fbSrjs sctp_pegs[SCTP_CWND_SKIP]++; 3909c05f20fbSrjs goto skip_cwnd_update; 3910c05f20fbSrjs } 3911c05f20fbSrjs if (accum_moved) { 3912c05f20fbSrjs /* If the cumulative ack moved we can proceed */ 3913c05f20fbSrjs if (net->cwnd <= net->ssthresh) { 3914c05f20fbSrjs /* We are in slow start */ 3915c05f20fbSrjs if (net->flight_size + net->net_ack >= 3916c05f20fbSrjs net->cwnd ) { 3917c05f20fbSrjs #ifdef SCTP_HIGH_SPEED 3918c05f20fbSrjs sctp_hs_cwnd_increase(net); 3919c05f20fbSrjs #else 3920c05f20fbSrjs if (net->net_ack > net->mtu) { 3921c05f20fbSrjs net->cwnd += net->mtu; 3922c05f20fbSrjs #ifdef SCTP_CWND_LOGGING 3923c05f20fbSrjs sctp_log_cwnd(net, net->mtu, 3924c05f20fbSrjs SCTP_CWND_LOG_FROM_SS); 3925c05f20fbSrjs #endif 3926c05f20fbSrjs 3927c05f20fbSrjs } else { 3928c05f20fbSrjs net->cwnd += net->net_ack; 3929c05f20fbSrjs #ifdef SCTP_CWND_LOGGING 3930c05f20fbSrjs sctp_log_cwnd(net, net->net_ack, 3931c05f20fbSrjs SCTP_CWND_LOG_FROM_SS); 3932c05f20fbSrjs #endif 3933c05f20fbSrjs 3934c05f20fbSrjs } 3935c05f20fbSrjs #endif 3936c05f20fbSrjs sctp_pegs[SCTP_CWND_SS]++; 3937c05f20fbSrjs } else { 3938c05f20fbSrjs unsigned int dif; 3939c05f20fbSrjs sctp_pegs[SCTP_CWND_NOUSE_SS]++; 3940c05f20fbSrjs dif = net->cwnd - (net->flight_size + 3941c05f20fbSrjs net->net_ack); 3942c05f20fbSrjs #ifdef SCTP_CWND_LOGGING 3943c05f20fbSrjs /* sctp_log_cwnd(net, net->net_ack, 3944c05f20fbSrjs SCTP_CWND_LOG_NOADV_SS);*/ 3945c05f20fbSrjs #endif 3946c05f20fbSrjs if (dif > sctp_pegs[SCTP_CWND_DIFF_SA]) { 3947c05f20fbSrjs sctp_pegs[SCTP_CWND_DIFF_SA] = 3948c05f20fbSrjs dif; 3949c05f20fbSrjs sctp_pegs[SCTP_OQS_AT_SS] = 3950c05f20fbSrjs asoc->total_output_queue_size; 3951c05f20fbSrjs sctp_pegs[SCTP_SQQ_AT_SS] = 3952c05f20fbSrjs asoc->sent_queue_cnt; 3953c05f20fbSrjs sctp_pegs[SCTP_SQC_AT_SS] = 3954c05f20fbSrjs asoc->send_queue_cnt; 3955c05f20fbSrjs } 3956c05f20fbSrjs } 3957c05f20fbSrjs } else { 3958c05f20fbSrjs /* We are in congestion avoidance */ 3959c05f20fbSrjs if (net->flight_size + net->net_ack >= 3960c05f20fbSrjs net->cwnd) { 3961c05f20fbSrjs /* 3962c05f20fbSrjs * add to pba only if we had a cwnd's 3963c05f20fbSrjs * worth (or so) in flight OR the 3964c05f20fbSrjs * burst limit was applied. 3965c05f20fbSrjs */ 3966c05f20fbSrjs net->partial_bytes_acked += 3967c05f20fbSrjs net->net_ack; 3968c05f20fbSrjs 3969c05f20fbSrjs /* 3970c05f20fbSrjs * Do we need to increase 3971c05f20fbSrjs * (if pba is > cwnd)? 3972c05f20fbSrjs */ 3973c05f20fbSrjs if (net->partial_bytes_acked >= 3974c05f20fbSrjs net->cwnd) { 3975c05f20fbSrjs if (net->cwnd < 3976c05f20fbSrjs net->partial_bytes_acked) { 3977c05f20fbSrjs net->partial_bytes_acked -= 3978c05f20fbSrjs net->cwnd; 3979c05f20fbSrjs } else { 3980c05f20fbSrjs net->partial_bytes_acked = 3981c05f20fbSrjs 0; 3982c05f20fbSrjs } 3983c05f20fbSrjs net->cwnd += net->mtu; 3984c05f20fbSrjs #ifdef SCTP_CWND_LOGGING 3985c05f20fbSrjs sctp_log_cwnd(net, net->mtu, 3986c05f20fbSrjs SCTP_CWND_LOG_FROM_CA); 3987c05f20fbSrjs #endif 3988c05f20fbSrjs sctp_pegs[SCTP_CWND_CA]++; 3989c05f20fbSrjs } 3990c05f20fbSrjs } else { 3991c05f20fbSrjs unsigned int dif; 3992c05f20fbSrjs sctp_pegs[SCTP_CWND_NOUSE_CA]++; 3993c05f20fbSrjs #ifdef SCTP_CWND_LOGGING 3994c05f20fbSrjs /* sctp_log_cwnd(net, net->net_ack, 3995c05f20fbSrjs SCTP_CWND_LOG_NOADV_CA); 3996c05f20fbSrjs */ 3997c05f20fbSrjs #endif 3998c05f20fbSrjs dif = net->cwnd - (net->flight_size + 3999c05f20fbSrjs net->net_ack); 4000c05f20fbSrjs if (dif > sctp_pegs[SCTP_CWND_DIFF_CA]) { 4001c05f20fbSrjs sctp_pegs[SCTP_CWND_DIFF_CA] = 4002c05f20fbSrjs dif; 4003c05f20fbSrjs sctp_pegs[SCTP_OQS_AT_CA] = 4004c05f20fbSrjs asoc->total_output_queue_size; 4005c05f20fbSrjs sctp_pegs[SCTP_SQQ_AT_CA] = 4006c05f20fbSrjs asoc->sent_queue_cnt; 4007c05f20fbSrjs sctp_pegs[SCTP_SQC_AT_CA] = 4008c05f20fbSrjs asoc->send_queue_cnt; 4009c05f20fbSrjs 4010c05f20fbSrjs } 4011c05f20fbSrjs 4012c05f20fbSrjs } 4013c05f20fbSrjs } 4014c05f20fbSrjs } else { 4015c05f20fbSrjs sctp_pegs[SCTP_CWND_NOCUM]++; 4016c05f20fbSrjs } 4017c05f20fbSrjs skip_cwnd_update: 4018c05f20fbSrjs /* 4019c05f20fbSrjs * NOW, according to Karn's rule do we need to restore the 4020c05f20fbSrjs * RTO timer back? Check our net_ack2. If not set then we 4021c05f20fbSrjs * have a ambiguity.. i.e. all data ack'd was sent to more 4022c05f20fbSrjs * than one place. 4023c05f20fbSrjs */ 4024c05f20fbSrjs 4025c05f20fbSrjs if (net->net_ack2) { 4026c05f20fbSrjs /* restore any doubled timers */ 4027c05f20fbSrjs net->RTO = ((net->lastsa >> 2) + net->lastsv) >> 1; 4028c05f20fbSrjs if (net->RTO < stcb->asoc.minrto) { 4029c05f20fbSrjs net->RTO = stcb->asoc.minrto; 4030c05f20fbSrjs } 4031c05f20fbSrjs if (net->RTO > stcb->asoc.maxrto) { 4032c05f20fbSrjs net->RTO = stcb->asoc.maxrto; 4033c05f20fbSrjs } 4034c05f20fbSrjs } 4035c05f20fbSrjs if (net->cwnd > sctp_pegs[SCTP_MAX_CWND]) { 4036c05f20fbSrjs sctp_pegs[SCTP_MAX_CWND] = net->cwnd; 4037c05f20fbSrjs } 4038c05f20fbSrjs } 4039c05f20fbSrjs /**********************************/ 4040c05f20fbSrjs /* Now what about shutdown issues */ 4041c05f20fbSrjs /**********************************/ 4042c05f20fbSrjs some_on_streamwheel = 0; 4043c05f20fbSrjs if (!TAILQ_EMPTY(&asoc->out_wheel)) { 4044c05f20fbSrjs /* Check to see if some data queued */ 4045c05f20fbSrjs struct sctp_stream_out *outs; 4046c05f20fbSrjs TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) { 4047c05f20fbSrjs if (!TAILQ_EMPTY(&outs->outqueue)) { 4048c05f20fbSrjs some_on_streamwheel = 1; 4049c05f20fbSrjs break; 4050c05f20fbSrjs } 4051c05f20fbSrjs } 4052c05f20fbSrjs } 4053c05f20fbSrjs if (TAILQ_EMPTY(&asoc->send_queue) && TAILQ_EMPTY(&asoc->sent_queue) && 4054c05f20fbSrjs some_on_streamwheel == 0) { 4055c05f20fbSrjs /* nothing left on sendqueue.. consider done */ 4056c05f20fbSrjs /* stop all timers */ 4057c05f20fbSrjs #ifdef SCTP_LOG_RWND 4058c05f20fbSrjs sctp_log_rwnd_set(SCTP_SET_PEER_RWND_VIA_SACK, 4059c05f20fbSrjs asoc->peers_rwnd, 0, 0, a_rwnd); 4060c05f20fbSrjs #endif 4061c05f20fbSrjs asoc->peers_rwnd = a_rwnd; 4062c05f20fbSrjs if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) { 4063c05f20fbSrjs /* SWS sender side engages */ 4064c05f20fbSrjs asoc->peers_rwnd = 0; 4065c05f20fbSrjs } 4066c05f20fbSrjs /* stop any timers */ 4067c05f20fbSrjs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 4068c05f20fbSrjs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, 4069c05f20fbSrjs stcb, net); 4070c05f20fbSrjs net->flight_size = 0; 4071c05f20fbSrjs net->partial_bytes_acked = 0; 4072c05f20fbSrjs } 4073c05f20fbSrjs asoc->total_flight = 0; 4074c05f20fbSrjs asoc->total_flight_count = 0; 4075c05f20fbSrjs /* clean up */ 4076c05f20fbSrjs if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) { 4077c05f20fbSrjs asoc->state = SCTP_STATE_SHUTDOWN_SENT; 4078c05f20fbSrjs #ifdef SCTP_DEBUG 4079c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) { 4080c05f20fbSrjs printf("%s:%d sends a shutdown\n", 4081c05f20fbSrjs __FILE__, 4082c05f20fbSrjs __LINE__ 4083c05f20fbSrjs ); 4084c05f20fbSrjs } 4085c05f20fbSrjs #endif 4086c05f20fbSrjs sctp_send_shutdown(stcb, 4087c05f20fbSrjs stcb->asoc.primary_destination); 4088c05f20fbSrjs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 4089c05f20fbSrjs stcb->sctp_ep, stcb, asoc->primary_destination); 4090c05f20fbSrjs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 4091c05f20fbSrjs stcb->sctp_ep, stcb, asoc->primary_destination); 4092c05f20fbSrjs } else if (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) { 4093c05f20fbSrjs asoc->state = SCTP_STATE_SHUTDOWN_ACK_SENT; 4094c05f20fbSrjs 4095c05f20fbSrjs sctp_send_shutdown_ack(stcb, 4096c05f20fbSrjs stcb->asoc.primary_destination); 4097c05f20fbSrjs 4098c05f20fbSrjs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, 4099c05f20fbSrjs stcb->sctp_ep, stcb, asoc->primary_destination); 4100c05f20fbSrjs } 4101c05f20fbSrjs return; 4102c05f20fbSrjs } 4103c05f20fbSrjs /* 4104c05f20fbSrjs * Now here we are going to recycle net_ack for a different 4105c05f20fbSrjs * use... HEADS UP. 4106c05f20fbSrjs */ 4107c05f20fbSrjs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 4108c05f20fbSrjs net->net_ack = 0; 4109c05f20fbSrjs } 4110c05f20fbSrjs if ((num_seg > 0) && marking_allowed) { 4111c05f20fbSrjs sctp_strike_gap_ack_chunks(stcb, asoc, biggest_tsn_acked, 4112c05f20fbSrjs strike_enabled, biggest_tsn_newly_acked, accum_moved); 4113c05f20fbSrjs } 4114c05f20fbSrjs 4115c05f20fbSrjs /*********************************************/ 4116c05f20fbSrjs /* Here we perform PR-SCTP procedures */ 4117c05f20fbSrjs /* (section 4.2) */ 4118c05f20fbSrjs /*********************************************/ 4119c05f20fbSrjs /* C1. update advancedPeerAckPoint */ 4120c05f20fbSrjs if (compare_with_wrap(cum_ack, asoc->advanced_peer_ack_point, MAX_TSN)) { 4121c05f20fbSrjs asoc->advanced_peer_ack_point = cum_ack; 4122c05f20fbSrjs } 4123c05f20fbSrjs /* C2. try to further move advancedPeerAckPoint ahead */ 4124c05f20fbSrjs if (asoc->peer_supports_prsctp) { 4125c05f20fbSrjs struct sctp_tmit_chunk *lchk; 4126c05f20fbSrjs lchk = sctp_try_advance_peer_ack_point(stcb, asoc); 4127c05f20fbSrjs /* C3. See if we need to send a Fwd-TSN */ 4128c05f20fbSrjs if (compare_with_wrap(asoc->advanced_peer_ack_point, cum_ack, 4129c05f20fbSrjs MAX_TSN)) { 4130c05f20fbSrjs /* 4131c05f20fbSrjs * ISSUE with ECN, see FWD-TSN processing for notes 4132c05f20fbSrjs * on issues that will occur when the ECN NONCE stuff 4133c05f20fbSrjs * is put into SCTP for cross checking. 4134c05f20fbSrjs */ 4135c05f20fbSrjs send_forward_tsn(stcb, asoc); 4136c05f20fbSrjs 4137c05f20fbSrjs /* ECN Nonce: Disable Nonce Sum check when FWD TSN is sent and store resync tsn*/ 4138c05f20fbSrjs asoc->nonce_sum_check = 0; 4139c05f20fbSrjs asoc->nonce_resync_tsn = asoc->advanced_peer_ack_point; 4140c05f20fbSrjs if (lchk) { 4141c05f20fbSrjs /* Assure a timer is up */ 4142c05f20fbSrjs sctp_timer_start(SCTP_TIMER_TYPE_SEND, 4143c05f20fbSrjs stcb->sctp_ep, stcb, lchk->whoTo); 4144c05f20fbSrjs } 4145c05f20fbSrjs } 4146c05f20fbSrjs } 4147c05f20fbSrjs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 4148c05f20fbSrjs if (asoc->fast_retran_loss_recovery == 0) { 4149c05f20fbSrjs /* out of a RFC2582 Fast recovery window? */ 4150c05f20fbSrjs if (net->net_ack > 0) { 4151c05f20fbSrjs /* 4152c05f20fbSrjs * per section 7.2.3, are there 4153c05f20fbSrjs * any destinations that had a fast 4154c05f20fbSrjs * retransmit to them. If so what we 4155c05f20fbSrjs * need to do is adjust ssthresh and 4156c05f20fbSrjs * cwnd. 4157c05f20fbSrjs */ 4158c05f20fbSrjs struct sctp_tmit_chunk *lchk; 4159c05f20fbSrjs #ifdef SCTP_HIGH_SPEED 4160c05f20fbSrjs sctp_hs_cwnd_decrease(net); 4161c05f20fbSrjs #else 4162c05f20fbSrjs #ifdef SCTP_CWND_LOGGING 4163c05f20fbSrjs int old_cwnd = net->cwnd; 4164c05f20fbSrjs #endif 4165c05f20fbSrjs net->ssthresh = net->cwnd / 2; 4166c05f20fbSrjs if (net->ssthresh < (net->mtu*2)) { 4167c05f20fbSrjs net->ssthresh = 2 * net->mtu; 4168c05f20fbSrjs } 4169c05f20fbSrjs net->cwnd = net->ssthresh; 4170c05f20fbSrjs #ifdef SCTP_CWND_LOGGING 4171c05f20fbSrjs sctp_log_cwnd(net, (net->cwnd-old_cwnd), 4172c05f20fbSrjs SCTP_CWND_LOG_FROM_FR); 4173c05f20fbSrjs #endif 4174c05f20fbSrjs #endif 4175c05f20fbSrjs 4176c05f20fbSrjs lchk = TAILQ_FIRST(&asoc->send_queue); 4177c05f20fbSrjs 4178c05f20fbSrjs net->partial_bytes_acked = 0; 4179c05f20fbSrjs /* Turn on fast recovery window */ 4180c05f20fbSrjs asoc->fast_retran_loss_recovery = 1; 4181c05f20fbSrjs if (lchk == NULL) { 4182c05f20fbSrjs /* Mark end of the window */ 4183c05f20fbSrjs asoc->fast_recovery_tsn = asoc->sending_seq - 1; 4184c05f20fbSrjs } else { 4185c05f20fbSrjs asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 4186c05f20fbSrjs } 4187c05f20fbSrjs 4188c05f20fbSrjs 4189c05f20fbSrjs /* Disable Nonce Sum Checking and store the resync tsn*/ 4190c05f20fbSrjs asoc->nonce_sum_check = 0; 4191c05f20fbSrjs asoc->nonce_resync_tsn = asoc->fast_recovery_tsn + 1; 4192c05f20fbSrjs 4193c05f20fbSrjs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 4194c05f20fbSrjs stcb->sctp_ep, stcb, net); 4195c05f20fbSrjs sctp_timer_start(SCTP_TIMER_TYPE_SEND, 4196c05f20fbSrjs stcb->sctp_ep, stcb, net); 4197c05f20fbSrjs } 4198c05f20fbSrjs } else if (net->net_ack > 0) { 4199c05f20fbSrjs /* 4200c05f20fbSrjs * Mark a peg that we WOULD have done a cwnd reduction 4201c05f20fbSrjs * but RFC2582 prevented this action. 4202c05f20fbSrjs */ 4203c05f20fbSrjs sctp_pegs[SCTP_FR_INAWINDOW]++; 4204c05f20fbSrjs } 4205c05f20fbSrjs } 4206c05f20fbSrjs 4207c05f20fbSrjs 4208c05f20fbSrjs /****************************************************************** 4209c05f20fbSrjs * Here we do the stuff with ECN Nonce checking. 4210c05f20fbSrjs * We basically check to see if the nonce sum flag was incorrect 4211c05f20fbSrjs * or if resynchronization needs to be done. Also if we catch a 4212c05f20fbSrjs * misbehaving receiver we give him the kick. 4213c05f20fbSrjs ******************************************************************/ 4214c05f20fbSrjs 4215c05f20fbSrjs if (asoc->ecn_nonce_allowed) { 4216c05f20fbSrjs if (asoc->nonce_sum_check) { 4217c05f20fbSrjs if (nonce_sum_flag != ((asoc->nonce_sum_expect_base + ecn_seg_sums) & SCTP_SACK_NONCE_SUM)) { 4218c05f20fbSrjs if (asoc->nonce_wait_for_ecne == 0) { 4219c05f20fbSrjs struct sctp_tmit_chunk *lchk; 4220c05f20fbSrjs lchk = TAILQ_FIRST(&asoc->send_queue); 4221c05f20fbSrjs asoc->nonce_wait_for_ecne = 1; 4222c05f20fbSrjs if (lchk) { 4223c05f20fbSrjs asoc->nonce_wait_tsn = lchk->rec.data.TSN_seq; 4224c05f20fbSrjs } else { 4225c05f20fbSrjs asoc->nonce_wait_tsn = asoc->sending_seq; 4226c05f20fbSrjs } 4227c05f20fbSrjs } else { 4228c05f20fbSrjs if (compare_with_wrap(asoc->last_acked_seq, asoc->nonce_wait_tsn, MAX_TSN) || 4229c05f20fbSrjs (asoc->last_acked_seq == asoc->nonce_wait_tsn)) { 4230c05f20fbSrjs /* Misbehaving peer. We need to react to this guy */ 4231c05f20fbSrjs printf("Mis-behaving peer detected\n"); 4232c05f20fbSrjs asoc->ecn_allowed = 0; 4233c05f20fbSrjs asoc->ecn_nonce_allowed = 0; 4234c05f20fbSrjs } 4235c05f20fbSrjs } 4236c05f20fbSrjs } 4237c05f20fbSrjs } else { 4238c05f20fbSrjs /* See if Resynchronization Possible */ 4239c05f20fbSrjs if (compare_with_wrap(asoc->last_acked_seq, asoc->nonce_resync_tsn, MAX_TSN)) { 4240c05f20fbSrjs asoc->nonce_sum_check = 1; 4241c05f20fbSrjs /* now we must calculate what the base 4242c05f20fbSrjs * is. We do this based on two things, we know 4243c05f20fbSrjs * the total's for all the segments gap-acked 4244c05f20fbSrjs * in the SACK, its stored in ecn_seg_sums. 4245c05f20fbSrjs * We also know the SACK's nonce sum, its 4246c05f20fbSrjs * in nonce_sum_flag. So we can build a truth 4247c05f20fbSrjs * table to back-calculate the new value of asoc->nonce_sum_expect_base: 4248c05f20fbSrjs * 4249c05f20fbSrjs * SACK-flag-Value Seg-Sums Base 4250c05f20fbSrjs * 0 0 0 4251c05f20fbSrjs * 1 0 1 4252c05f20fbSrjs * 0 1 1 4253c05f20fbSrjs * 1 1 0 4254c05f20fbSrjs */ 4255c05f20fbSrjs asoc->nonce_sum_expect_base = (ecn_seg_sums ^ nonce_sum_flag) & SCTP_SACK_NONCE_SUM; 4256c05f20fbSrjs } 4257c05f20fbSrjs } 4258c05f20fbSrjs } 4259c05f20fbSrjs /* Now are we exiting loss recovery ? */ 4260c05f20fbSrjs if (will_exit_fast_recovery) { 4261c05f20fbSrjs /* Ok, we must exit fast recovery */ 4262c05f20fbSrjs asoc->fast_retran_loss_recovery = 0; 4263c05f20fbSrjs } 4264c05f20fbSrjs if ((asoc->sat_t3_loss_recovery) && 4265c05f20fbSrjs ((compare_with_wrap(asoc->last_acked_seq, asoc->sat_t3_recovery_tsn, 4266c05f20fbSrjs MAX_TSN) || 4267c05f20fbSrjs (asoc->last_acked_seq == asoc->sat_t3_recovery_tsn)))) { 4268c05f20fbSrjs /* end satellite t3 loss recovery */ 4269c05f20fbSrjs asoc->sat_t3_loss_recovery = 0; 4270c05f20fbSrjs } 4271c05f20fbSrjs /* Adjust and set the new rwnd value */ 4272c05f20fbSrjs #ifdef SCTP_LOG_RWND 4273c05f20fbSrjs sctp_log_rwnd_set(SCTP_SET_PEER_RWND_VIA_SACK, 4274c05f20fbSrjs asoc->peers_rwnd, asoc->total_flight, (asoc->sent_queue_cnt * sctp_peer_chunk_oh), a_rwnd); 4275c05f20fbSrjs #endif 4276c05f20fbSrjs 4277c05f20fbSrjs asoc->peers_rwnd = sctp_sbspace_sub(a_rwnd, 4278c05f20fbSrjs (u_int32_t)(asoc->total_flight + (asoc->sent_queue_cnt * sctp_peer_chunk_oh))); 4279c05f20fbSrjs if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) { 4280c05f20fbSrjs /* SWS sender side engages */ 4281c05f20fbSrjs asoc->peers_rwnd = 0; 4282c05f20fbSrjs } 4283c05f20fbSrjs /* 4284c05f20fbSrjs * Now we must setup so we have a timer up for anyone with 4285c05f20fbSrjs * outstanding data. 4286c05f20fbSrjs */ 4287c05f20fbSrjs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 4288c05f20fbSrjs struct sctp_tmit_chunk *chk; 4289c05f20fbSrjs TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { 4290c05f20fbSrjs if (chk->whoTo == net && 4291c05f20fbSrjs (chk->sent < SCTP_DATAGRAM_ACKED || 4292c05f20fbSrjs chk->sent == SCTP_FORWARD_TSN_SKIP)) { 4293c05f20fbSrjs /* 4294c05f20fbSrjs * Not ack'ed and still outstanding to this 4295c05f20fbSrjs * destination or marked and must be 4296c05f20fbSrjs * sacked after fwd-tsn sent. 4297c05f20fbSrjs */ 4298c05f20fbSrjs sctp_timer_start(SCTP_TIMER_TYPE_SEND, 4299c05f20fbSrjs stcb->sctp_ep, stcb, net); 4300c05f20fbSrjs break; 4301c05f20fbSrjs } 4302c05f20fbSrjs } 4303c05f20fbSrjs } 4304c05f20fbSrjs } 4305c05f20fbSrjs 4306c05f20fbSrjs void 4307c05f20fbSrjs sctp_update_acked(struct sctp_tcb *stcb, struct sctp_shutdown_chunk *cp, 4308c05f20fbSrjs struct sctp_nets *netp, int *abort_flag) 4309c05f20fbSrjs { 4310c05f20fbSrjs /* Mutate a shutdown into a SACK */ 4311c05f20fbSrjs struct sctp_sack_chunk sack; 4312c05f20fbSrjs 4313c05f20fbSrjs /* Copy cum-ack */ 4314c05f20fbSrjs sack.sack.cum_tsn_ack = cp->cumulative_tsn_ack; 4315c05f20fbSrjs /* Arrange so a_rwnd does NOT change */ 4316c05f20fbSrjs sack.ch.chunk_type = SCTP_SELECTIVE_ACK; 4317c05f20fbSrjs sack.ch.chunk_flags = 0; 4318c05f20fbSrjs sack.ch.chunk_length = ntohs(sizeof(struct sctp_sack_chunk)); 4319c05f20fbSrjs sack.sack.a_rwnd = 4320c05f20fbSrjs htonl(stcb->asoc.peers_rwnd + stcb->asoc.total_flight); 4321c05f20fbSrjs /* 4322c05f20fbSrjs * no gaps in this one. This may cause a temporal view to reneging, 4323c05f20fbSrjs * but hopefully the second chunk is a true SACK in the packet and 4324c05f20fbSrjs * will correct this view. One will come soon after no matter what 4325c05f20fbSrjs * to fix this. 4326c05f20fbSrjs */ 4327c05f20fbSrjs sack.sack.num_gap_ack_blks = 0; 4328c05f20fbSrjs sack.sack.num_dup_tsns = 0; 4329c05f20fbSrjs /* Now call the SACK processor */ 4330c05f20fbSrjs sctp_handle_sack(&sack, stcb, netp, abort_flag); 4331c05f20fbSrjs } 4332c05f20fbSrjs 4333c05f20fbSrjs static void 4334c05f20fbSrjs sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb, 4335c05f20fbSrjs struct sctp_stream_in *strmin) 4336c05f20fbSrjs { 4337c05f20fbSrjs struct sctp_tmit_chunk *chk, *nchk; 4338c05f20fbSrjs struct sctp_association *asoc; 4339c05f20fbSrjs int tt; 4340c05f20fbSrjs 4341c05f20fbSrjs asoc = &stcb->asoc; 4342c05f20fbSrjs tt = strmin->last_sequence_delivered; 4343c05f20fbSrjs /* 4344c05f20fbSrjs * First deliver anything prior to and including the stream no that 4345c05f20fbSrjs * came in 4346c05f20fbSrjs */ 4347c05f20fbSrjs chk = TAILQ_FIRST(&strmin->inqueue); 4348c05f20fbSrjs while (chk) { 4349c05f20fbSrjs nchk = TAILQ_NEXT(chk, sctp_next); 4350c05f20fbSrjs if (compare_with_wrap(tt, chk->rec.data.stream_seq, MAX_SEQ) || 4351c05f20fbSrjs (tt == chk->rec.data.stream_seq)) { 4352c05f20fbSrjs /* this is deliverable now */ 4353c05f20fbSrjs TAILQ_REMOVE(&strmin->inqueue, chk, sctp_next); 4354c05f20fbSrjs /* subtract pending on streams */ 4355c05f20fbSrjs asoc->size_on_all_streams -= chk->send_size; 4356c05f20fbSrjs asoc->cnt_on_all_streams--; 4357c05f20fbSrjs /* deliver it to at least the delivery-q */ 4358c05f20fbSrjs sctp_deliver_data(stcb, &stcb->asoc, chk, 0); 4359c05f20fbSrjs } else { 4360c05f20fbSrjs /* no more delivery now. */ 4361c05f20fbSrjs break; 4362c05f20fbSrjs } 4363c05f20fbSrjs chk = nchk; 4364c05f20fbSrjs } 4365c05f20fbSrjs /* 4366c05f20fbSrjs * now we must deliver things in queue the normal way if any 4367c05f20fbSrjs * are now ready. 4368c05f20fbSrjs */ 4369c05f20fbSrjs tt = strmin->last_sequence_delivered + 1; 4370c05f20fbSrjs chk = TAILQ_FIRST(&strmin->inqueue); 4371c05f20fbSrjs while (chk) { 4372c05f20fbSrjs nchk = TAILQ_NEXT(chk, sctp_next); 4373c05f20fbSrjs if (tt == chk->rec.data.stream_seq) { 4374c05f20fbSrjs /* this is deliverable now */ 4375c05f20fbSrjs TAILQ_REMOVE(&strmin->inqueue, chk, sctp_next); 4376c05f20fbSrjs /* subtract pending on streams */ 4377c05f20fbSrjs asoc->size_on_all_streams -= chk->send_size; 4378c05f20fbSrjs asoc->cnt_on_all_streams--; 4379c05f20fbSrjs /* deliver it to at least the delivery-q */ 4380c05f20fbSrjs strmin->last_sequence_delivered = 4381c05f20fbSrjs chk->rec.data.stream_seq; 4382c05f20fbSrjs sctp_deliver_data(stcb, &stcb->asoc, chk, 0); 4383c05f20fbSrjs tt = strmin->last_sequence_delivered + 1; 4384c05f20fbSrjs } else { 4385c05f20fbSrjs break; 4386c05f20fbSrjs } 4387c05f20fbSrjs chk = nchk; 4388c05f20fbSrjs } 4389c05f20fbSrjs 4390c05f20fbSrjs } 4391c05f20fbSrjs 4392c05f20fbSrjs void 4393c05f20fbSrjs sctp_handle_forward_tsn(struct sctp_tcb *stcb, 4394c05f20fbSrjs struct sctp_forward_tsn_chunk *fwd, int *abort_flag) 4395c05f20fbSrjs { 4396c05f20fbSrjs /* 4397c05f20fbSrjs * ISSUES that MUST be fixed for ECN! When we are the 4398c05f20fbSrjs * sender of the forward TSN, when the SACK comes back 4399c05f20fbSrjs * that acknowledges the FWD-TSN we must reset the 4400c05f20fbSrjs * NONCE sum to match correctly. This will get quite 4401c05f20fbSrjs * tricky since we may have sent more data interveneing and 4402c05f20fbSrjs * must carefully account for what the SACK says on the 4403c05f20fbSrjs * nonce and any gaps that are reported. This work 4404c05f20fbSrjs * will NOT be done here, but I note it here since 4405c05f20fbSrjs * it is really related to PR-SCTP and FWD-TSN's 4406c05f20fbSrjs */ 4407c05f20fbSrjs 4408c05f20fbSrjs /* The pr-sctp fwd tsn */ 4409c05f20fbSrjs /* 4410c05f20fbSrjs * here we will perform all the data receiver side steps for 4411c05f20fbSrjs * processing FwdTSN, as required in by pr-sctp draft: 4412c05f20fbSrjs * 4413c05f20fbSrjs * Assume we get FwdTSN(x): 4414c05f20fbSrjs * 4415c05f20fbSrjs * 1) update local cumTSN to x 4416c05f20fbSrjs * 2) try to further advance cumTSN to x + others we have 4417c05f20fbSrjs * 3) examine and update re-ordering queue on pr-in-streams 4418c05f20fbSrjs * 4) clean up re-assembly queue 4419c05f20fbSrjs * 5) Send a sack to report where we are. 4420c05f20fbSrjs */ 4421c05f20fbSrjs struct sctp_strseq *stseq; 4422c05f20fbSrjs struct sctp_association *asoc; 4423c05f20fbSrjs u_int32_t new_cum_tsn, gap, back_out_htsn; 4424c05f20fbSrjs unsigned int i, cnt_gone, fwd_sz, cumack_set_flag, m_size; 4425c05f20fbSrjs struct sctp_stream_in *strm; 4426c05f20fbSrjs struct sctp_tmit_chunk *chk, *at; 4427c05f20fbSrjs 4428c05f20fbSrjs cumack_set_flag = 0; 4429c05f20fbSrjs asoc = &stcb->asoc; 4430c05f20fbSrjs cnt_gone = 0; 4431c05f20fbSrjs if ((fwd_sz = ntohs(fwd->ch.chunk_length)) < sizeof(struct sctp_forward_tsn_chunk)) { 4432c05f20fbSrjs #ifdef SCTP_DEBUG 4433c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 4434c05f20fbSrjs printf("Bad size too small/big fwd-tsn\n"); 4435c05f20fbSrjs } 4436c05f20fbSrjs #endif 4437c05f20fbSrjs return; 4438c05f20fbSrjs } 4439c05f20fbSrjs m_size = (stcb->asoc.mapping_array_size << 3); 4440c05f20fbSrjs /*************************************************************/ 4441c05f20fbSrjs /* 1. Here we update local cumTSN and shift the bitmap array */ 4442c05f20fbSrjs /*************************************************************/ 4443c05f20fbSrjs new_cum_tsn = ntohl(fwd->new_cumulative_tsn); 4444c05f20fbSrjs 4445c05f20fbSrjs if (compare_with_wrap(asoc->cumulative_tsn, new_cum_tsn, MAX_TSN) || 4446c05f20fbSrjs asoc->cumulative_tsn == new_cum_tsn) { 4447c05f20fbSrjs /* Already got there ... */ 4448c05f20fbSrjs return; 4449c05f20fbSrjs } 4450c05f20fbSrjs 4451c05f20fbSrjs back_out_htsn = asoc->highest_tsn_inside_map; 4452c05f20fbSrjs if (compare_with_wrap(new_cum_tsn, asoc->highest_tsn_inside_map, 4453c05f20fbSrjs MAX_TSN)) { 4454c05f20fbSrjs asoc->highest_tsn_inside_map = new_cum_tsn; 4455c05f20fbSrjs #ifdef SCTP_MAP_LOGGING 4456c05f20fbSrjs sctp_log_map(0, 0, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT); 4457c05f20fbSrjs #endif 4458c05f20fbSrjs } 4459c05f20fbSrjs /* 4460c05f20fbSrjs * now we know the new TSN is more advanced, let's find the 4461c05f20fbSrjs * actual gap 4462c05f20fbSrjs */ 4463c05f20fbSrjs if ((compare_with_wrap(new_cum_tsn, asoc->mapping_array_base_tsn, 4464c05f20fbSrjs MAX_TSN)) || 4465c05f20fbSrjs (new_cum_tsn == asoc->mapping_array_base_tsn)) { 4466c05f20fbSrjs gap = new_cum_tsn - asoc->mapping_array_base_tsn; 4467c05f20fbSrjs } else { 4468c05f20fbSrjs /* try to prevent underflow here */ 4469c05f20fbSrjs gap = new_cum_tsn + (MAX_TSN - asoc->mapping_array_base_tsn) + 1; 4470c05f20fbSrjs } 4471c05f20fbSrjs 4472c05f20fbSrjs if (gap >= m_size) { 4473c05f20fbSrjs asoc->highest_tsn_inside_map = back_out_htsn; 4474c05f20fbSrjs if ((long)gap > sctp_sbspace(&stcb->sctp_socket->so_rcv)) { 4475c05f20fbSrjs /* 4476c05f20fbSrjs * out of range (of single byte chunks in the rwnd I 4477c05f20fbSrjs * give out) 4478c05f20fbSrjs * too questionable. better to drop it silently 4479c05f20fbSrjs */ 4480c05f20fbSrjs return; 4481c05f20fbSrjs } 4482c05f20fbSrjs if (asoc->highest_tsn_inside_map > 4483c05f20fbSrjs asoc->mapping_array_base_tsn) { 4484c05f20fbSrjs gap = asoc->highest_tsn_inside_map - 4485c05f20fbSrjs asoc->mapping_array_base_tsn; 4486c05f20fbSrjs } else { 4487c05f20fbSrjs gap = asoc->highest_tsn_inside_map + 4488c05f20fbSrjs (MAX_TSN - asoc->mapping_array_base_tsn) + 1; 4489c05f20fbSrjs } 4490c05f20fbSrjs cumack_set_flag = 1; 4491c05f20fbSrjs } 4492c05f20fbSrjs for (i = 0; i <= gap; i++) { 4493c05f20fbSrjs SCTP_SET_TSN_PRESENT(asoc->mapping_array, i); 4494c05f20fbSrjs } 4495c05f20fbSrjs /* 4496c05f20fbSrjs * Now after marking all, slide thing forward but no 4497c05f20fbSrjs * sack please. 4498c05f20fbSrjs */ 4499c05f20fbSrjs sctp_sack_check(stcb, 0, 0, abort_flag); 4500c05f20fbSrjs if (*abort_flag) 4501c05f20fbSrjs return; 4502c05f20fbSrjs 4503c05f20fbSrjs if (cumack_set_flag) { 4504c05f20fbSrjs /* 4505c05f20fbSrjs * fwd-tsn went outside my gap array - not a 4506c05f20fbSrjs * common occurance. Do the same thing we 4507c05f20fbSrjs * do when a cookie-echo arrives. 4508c05f20fbSrjs */ 4509c05f20fbSrjs asoc->highest_tsn_inside_map = new_cum_tsn - 1; 4510c05f20fbSrjs asoc->mapping_array_base_tsn = new_cum_tsn; 4511c05f20fbSrjs asoc->cumulative_tsn = asoc->highest_tsn_inside_map; 4512c05f20fbSrjs #ifdef SCTP_MAP_LOGGING 4513c05f20fbSrjs sctp_log_map(0, 3, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT); 4514c05f20fbSrjs #endif 4515c05f20fbSrjs asoc->last_echo_tsn = asoc->highest_tsn_inside_map; 4516c05f20fbSrjs } 4517c05f20fbSrjs /*************************************************************/ 4518c05f20fbSrjs /* 2. Clear up re-assembly queue */ 4519c05f20fbSrjs /*************************************************************/ 4520c05f20fbSrjs 4521c05f20fbSrjs /* 4522c05f20fbSrjs * First service it if pd-api is up, just in case we can 4523c05f20fbSrjs * progress it forward 4524c05f20fbSrjs */ 4525c05f20fbSrjs if (asoc->fragmented_delivery_inprogress) { 4526c05f20fbSrjs sctp_service_reassembly(stcb, asoc, 0); 4527c05f20fbSrjs } 4528c05f20fbSrjs if (!TAILQ_EMPTY(&asoc->reasmqueue)) { 4529c05f20fbSrjs /* For each one on here see if we need to toss it */ 4530c05f20fbSrjs /* 4531c05f20fbSrjs * For now large messages held on the reasmqueue that are 4532c05f20fbSrjs * complete will be tossed too. We could in theory do more 4533c05f20fbSrjs * work to spin through and stop after dumping one msg 4534c05f20fbSrjs * aka seeing the start of a new msg at the head, and call 4535c05f20fbSrjs * the delivery function... to see if it can be delivered... 4536c05f20fbSrjs * But for now we just dump everything on the queue. 4537c05f20fbSrjs */ 4538c05f20fbSrjs chk = TAILQ_FIRST(&asoc->reasmqueue); 4539c05f20fbSrjs while (chk) { 4540c05f20fbSrjs at = TAILQ_NEXT(chk, sctp_next); 4541c05f20fbSrjs if (compare_with_wrap(asoc->cumulative_tsn, 4542c05f20fbSrjs chk->rec.data.TSN_seq, MAX_TSN) || 4543c05f20fbSrjs asoc->cumulative_tsn == chk->rec.data.TSN_seq) { 4544c05f20fbSrjs /* It needs to be tossed */ 4545c05f20fbSrjs TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next); 4546c05f20fbSrjs if (compare_with_wrap(chk->rec.data.TSN_seq, 4547c05f20fbSrjs asoc->tsn_last_delivered, MAX_TSN)) { 4548c05f20fbSrjs asoc->tsn_last_delivered = 4549c05f20fbSrjs chk->rec.data.TSN_seq; 4550c05f20fbSrjs asoc->str_of_pdapi = 4551c05f20fbSrjs chk->rec.data.stream_number; 4552c05f20fbSrjs asoc->ssn_of_pdapi = 4553c05f20fbSrjs chk->rec.data.stream_seq; 4554c05f20fbSrjs asoc->fragment_flags = 4555c05f20fbSrjs chk->rec.data.rcv_flags; 4556c05f20fbSrjs } 4557c05f20fbSrjs asoc->size_on_reasm_queue -= chk->send_size; 4558c05f20fbSrjs asoc->cnt_on_reasm_queue--; 4559c05f20fbSrjs cnt_gone++; 4560c05f20fbSrjs 4561c05f20fbSrjs /* Clear up any stream problem */ 4562c05f20fbSrjs if ((chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) != 4563c05f20fbSrjs SCTP_DATA_UNORDERED && 4564c05f20fbSrjs (compare_with_wrap(chk->rec.data.stream_seq, 4565c05f20fbSrjs asoc->strmin[chk->rec.data.stream_number].last_sequence_delivered, 4566c05f20fbSrjs MAX_SEQ))) { 4567c05f20fbSrjs /* 4568c05f20fbSrjs * We must dump forward this streams 4569c05f20fbSrjs * sequence number if the chunk is not 4570c05f20fbSrjs * unordered that is being skipped. 4571c05f20fbSrjs * There is a chance that if the peer 4572c05f20fbSrjs * does not include the last fragment 4573c05f20fbSrjs * in its FWD-TSN we WILL have a problem 4574c05f20fbSrjs * here since you would have a partial 4575c05f20fbSrjs * chunk in queue that may not be 4576c05f20fbSrjs * deliverable. 4577c05f20fbSrjs * Also if a Partial delivery API as 4578c05f20fbSrjs * started the user may get a partial 4579c05f20fbSrjs * chunk. The next read returning a new 4580c05f20fbSrjs * chunk... really ugly but I see no way 4581c05f20fbSrjs * around it! Maybe a notify?? 4582c05f20fbSrjs */ 4583c05f20fbSrjs asoc->strmin[chk->rec.data.stream_number].last_sequence_delivered = 4584c05f20fbSrjs chk->rec.data.stream_seq; 4585c05f20fbSrjs } 4586c05f20fbSrjs if (chk->data) { 4587c05f20fbSrjs sctp_m_freem(chk->data); 4588c05f20fbSrjs chk->data = NULL; 4589c05f20fbSrjs } 4590c05f20fbSrjs sctp_free_remote_addr(chk->whoTo); 4591c05f20fbSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk); 4592c05f20fbSrjs sctppcbinfo.ipi_count_chunk--; 4593c05f20fbSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) { 4594c05f20fbSrjs panic("Chunk count is negative"); 4595c05f20fbSrjs } 4596c05f20fbSrjs sctppcbinfo.ipi_gencnt_chunk++; 4597c05f20fbSrjs } else { 4598c05f20fbSrjs /* 4599c05f20fbSrjs * Ok we have gone beyond the end of the 4600c05f20fbSrjs * fwd-tsn's mark. Some checks... 4601c05f20fbSrjs */ 4602c05f20fbSrjs if ((asoc->fragmented_delivery_inprogress) && 4603c05f20fbSrjs (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG)) { 4604c05f20fbSrjs /* Special case PD-API is up and what we fwd-tsn' 4605c05f20fbSrjs * over includes one that had the LAST_FRAG. We 4606c05f20fbSrjs * no longer need to do the PD-API. 4607c05f20fbSrjs */ 4608c05f20fbSrjs asoc->fragmented_delivery_inprogress = 0; 4609c05f20fbSrjs sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION, 4610c05f20fbSrjs stcb, SCTP_PARTIAL_DELIVERY_ABORTED, (void *)NULL); 4611c05f20fbSrjs 4612c05f20fbSrjs } 4613c05f20fbSrjs break; 4614c05f20fbSrjs } 4615c05f20fbSrjs chk = at; 4616c05f20fbSrjs } 4617c05f20fbSrjs } 4618c05f20fbSrjs if (asoc->fragmented_delivery_inprogress) { 4619c05f20fbSrjs /* 4620c05f20fbSrjs * Ok we removed cnt_gone chunks in the PD-API queue that 4621c05f20fbSrjs * were being delivered. So now we must turn off the 4622c05f20fbSrjs * flag. 4623c05f20fbSrjs */ 4624c05f20fbSrjs sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION, 4625c05f20fbSrjs stcb, SCTP_PARTIAL_DELIVERY_ABORTED, (void *)NULL); 4626c05f20fbSrjs asoc->fragmented_delivery_inprogress = 0; 4627c05f20fbSrjs } 4628c05f20fbSrjs /*************************************************************/ 4629c05f20fbSrjs /* 3. Update the PR-stream re-ordering queues */ 4630c05f20fbSrjs /*************************************************************/ 4631c05f20fbSrjs stseq = (struct sctp_strseq *)((vaddr_t)fwd + sizeof(*fwd)); 4632c05f20fbSrjs fwd_sz -= sizeof(*fwd); 4633c05f20fbSrjs { 4634c05f20fbSrjs /* New method. */ 4635c05f20fbSrjs int num_str; 4636c05f20fbSrjs num_str = fwd_sz/sizeof(struct sctp_strseq); 4637c05f20fbSrjs #ifdef SCTP_DEBUG 4638c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 4639c05f20fbSrjs printf("Using NEW method, %d strseq's reported in FWD-TSN\n", 4640c05f20fbSrjs num_str); 4641c05f20fbSrjs } 4642c05f20fbSrjs #endif 4643c05f20fbSrjs for (i = 0; i < num_str; i++) { 4644c05f20fbSrjs u_int16_t st; 4645c05f20fbSrjs #if 0 4646c05f20fbSrjs unsigned char *xx; 4647c05f20fbSrjs /* Convert */ 4648c05f20fbSrjs xx = (unsigned char *)&stseq[i]; 4649c05f20fbSrjs #endif 4650c05f20fbSrjs st = ntohs(stseq[i].stream); 4651c05f20fbSrjs stseq[i].stream = st; 4652c05f20fbSrjs st = ntohs(stseq[i].sequence); 4653c05f20fbSrjs stseq[i].sequence = st; 4654c05f20fbSrjs /* now process */ 4655c05f20fbSrjs if (stseq[i].stream > asoc->streamincnt) { 4656c05f20fbSrjs #ifdef SCTP_DEBUG 4657c05f20fbSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 4658c05f20fbSrjs printf("Bogus stream number %d " 4659c05f20fbSrjs "streamincnt is %d\n", 4660c05f20fbSrjs stseq[i].stream, asoc->streamincnt); 4661c05f20fbSrjs } 4662c05f20fbSrjs #endif 4663c05f20fbSrjs /* 4664c05f20fbSrjs * It is arguable if we should continue. Since 4665c05f20fbSrjs * the peer sent bogus stream info we may be in 4666c05f20fbSrjs * deep trouble.. 4667c05f20fbSrjs * a return may be a better choice? 4668c05f20fbSrjs */ 4669c05f20fbSrjs continue; 4670c05f20fbSrjs } 4671c05f20fbSrjs strm = &asoc->strmin[stseq[i].stream]; 4672c05f20fbSrjs if (compare_with_wrap(stseq[i].sequence, 4673c05f20fbSrjs strm->last_sequence_delivered, MAX_SEQ)) { 4674c05f20fbSrjs /* Update the sequence number */ 4675c05f20fbSrjs strm->last_sequence_delivered = 4676c05f20fbSrjs stseq[i].sequence; 4677c05f20fbSrjs } 4678c05f20fbSrjs /* now kick the stream the new way */ 4679c05f20fbSrjs sctp_kick_prsctp_reorder_queue(stcb, strm); 4680c05f20fbSrjs } 4681c05f20fbSrjs } 4682c05f20fbSrjs } 4683