1*79604517Sandvar /* $NetBSD: sctp_indata.c,v 1.17 2024/12/04 21:18:34 andvar Exp $ */ 28c2654abSrjs /* $KAME: sctp_indata.c,v 1.36 2005/03/06 16:04:17 itojun Exp $ */ 38c2654abSrjs 48c2654abSrjs /* 58c2654abSrjs * Copyright (C) 2002, 2003, 2004 Cisco Systems Inc, 68c2654abSrjs * All rights reserved. 78c2654abSrjs * 88c2654abSrjs * Redistribution and use in source and binary forms, with or without 98c2654abSrjs * modification, are permitted provided that the following conditions 108c2654abSrjs * are met: 118c2654abSrjs * 1. Redistributions of source code must retain the above copyright 128c2654abSrjs * notice, this list of conditions and the following disclaimer. 138c2654abSrjs * 2. Redistributions in binary form must reproduce the above copyright 148c2654abSrjs * notice, this list of conditions and the following disclaimer in the 158c2654abSrjs * documentation and/or other materials provided with the distribution. 168c2654abSrjs * 3. Neither the name of the project nor the names of its contributors 178c2654abSrjs * may be used to endorse or promote products derived from this software 188c2654abSrjs * without specific prior written permission. 198c2654abSrjs * 208c2654abSrjs * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 218c2654abSrjs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 228c2654abSrjs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 238c2654abSrjs * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 248c2654abSrjs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 258c2654abSrjs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 268c2654abSrjs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 278c2654abSrjs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 288c2654abSrjs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 298c2654abSrjs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 308c2654abSrjs * SUCH DAMAGE. 318c2654abSrjs */ 328c2654abSrjs 338c2654abSrjs #include <sys/cdefs.h> 34*79604517Sandvar __KERNEL_RCSID(0, "$NetBSD: sctp_indata.c,v 1.17 2024/12/04 21:18:34 andvar Exp $"); 358c2654abSrjs 368c2654abSrjs #ifdef _KERNEL_OPT 378c2654abSrjs #include "opt_ipsec.h" 388c2654abSrjs #include "opt_inet.h" 398c2654abSrjs #include "opt_sctp.h" 408c2654abSrjs #endif /* _KERNEL_OPT */ 418c2654abSrjs 428c2654abSrjs #include <sys/param.h> 438c2654abSrjs #include <sys/systm.h> 448c2654abSrjs #include <sys/mbuf.h> 458c2654abSrjs #include <sys/malloc.h> 468c2654abSrjs #include <sys/socket.h> 478c2654abSrjs #include <sys/socketvar.h> 488c2654abSrjs #include <sys/sysctl.h> 498c2654abSrjs 508c2654abSrjs #include <net/if.h> 518c2654abSrjs #include <net/route.h> 528c2654abSrjs 538c2654abSrjs 548c2654abSrjs #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 558c2654abSrjs #include <sys/limits.h> 568c2654abSrjs #else 578c2654abSrjs #include <machine/limits.h> 588c2654abSrjs #endif 598c2654abSrjs #include <machine/cpu.h> 608c2654abSrjs 618c2654abSrjs #include <netinet/in.h> 628c2654abSrjs #include <netinet/in_systm.h> 638c2654abSrjs #include <netinet/ip.h> 648c2654abSrjs #ifdef INET6 658c2654abSrjs #include <netinet/ip6.h> 668c2654abSrjs #endif /* INET6 */ 678c2654abSrjs #include <netinet/in_pcb.h> 688c2654abSrjs #include <netinet/in_var.h> 698c2654abSrjs #include <netinet/ip_var.h> 708c2654abSrjs #ifdef INET6 718c2654abSrjs #include <netinet6/ip6_var.h> 728c2654abSrjs #endif /* INET6 */ 738c2654abSrjs #include <netinet/ip_icmp.h> 748c2654abSrjs #include <netinet/icmp_var.h> 758c2654abSrjs #include <netinet/sctp_var.h> 768c2654abSrjs #include <netinet/sctp_pcb.h> 778c2654abSrjs #include <netinet/sctp_header.h> 788c2654abSrjs #include <netinet/sctputil.h> 798c2654abSrjs #include <netinet/sctp_output.h> 808c2654abSrjs #include <netinet/sctp_input.h> 818c2654abSrjs #include <netinet/sctp_hashdriver.h> 828c2654abSrjs #include <netinet/sctp_indata.h> 838c2654abSrjs #include <netinet/sctp_uio.h> 848c2654abSrjs #include <netinet/sctp_timer.h> 858c2654abSrjs #ifdef IPSEC 86505ea976Srjs #include <netipsec/ipsec.h> 87505ea976Srjs #include <netipsec/key.h> 888c2654abSrjs #endif /*IPSEC*/ 898c2654abSrjs 908c2654abSrjs #ifdef SCTP_DEBUG 918c2654abSrjs extern u_int32_t sctp_debug_on; 928c2654abSrjs #endif 938c2654abSrjs 948c2654abSrjs /* 958c2654abSrjs * NOTES: On the outbound side of things I need to check the sack timer to 968c2654abSrjs * see if I should generate a sack into the chunk queue (if I have data to 978c2654abSrjs * send that is and will be sending it .. for bundling. 988c2654abSrjs * 998c2654abSrjs * The callback in sctp_usrreq.c will get called when the socket is read 1008c2654abSrjs * from. This will cause sctp_service_queues() to get called on the top 1018c2654abSrjs * entry in the list. 1028c2654abSrjs */ 1038c2654abSrjs 1048c2654abSrjs extern int sctp_strict_sacks; 1058c2654abSrjs 1068c2654abSrjs void 1078c2654abSrjs sctp_set_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc) 1088c2654abSrjs { 1098c2654abSrjs u_int32_t calc, calc_w_oh; 1108c2654abSrjs 1118c2654abSrjs #ifdef SCTP_DEBUG 1128c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA4) { 1138c2654abSrjs printf("cc:%lu hiwat:%lu lowat:%lu mbcnt:%lu mbmax:%lu\n", 1148c2654abSrjs (u_long)stcb->sctp_socket->so_rcv.sb_cc, 1158c2654abSrjs (u_long)stcb->sctp_socket->so_rcv.sb_hiwat, 1168c2654abSrjs (u_long)stcb->sctp_socket->so_rcv.sb_lowat, 1178c2654abSrjs (u_long)stcb->sctp_socket->so_rcv.sb_mbcnt, 1188c2654abSrjs (u_long)stcb->sctp_socket->so_rcv.sb_mbmax); 1198c2654abSrjs printf("Setting rwnd to: sb:%ld - (del:%d + reasm:%d str:%d)\n", 1208c2654abSrjs sctp_sbspace(&stcb->sctp_socket->so_rcv), 1218c2654abSrjs asoc->size_on_delivery_queue, 1228c2654abSrjs asoc->size_on_reasm_queue, 1238c2654abSrjs asoc->size_on_all_streams); 1248c2654abSrjs } 1258c2654abSrjs #endif 1268c2654abSrjs if (stcb->sctp_socket->so_rcv.sb_cc == 0 && 1278c2654abSrjs asoc->size_on_delivery_queue == 0 && 1288c2654abSrjs asoc->size_on_reasm_queue == 0 && 1298c2654abSrjs asoc->size_on_all_streams == 0) { 1308c2654abSrjs /* Full rwnd granted */ 131d1579b2dSriastradh asoc->my_rwnd = uimax(stcb->sctp_socket->so_rcv.sb_hiwat, 1328c2654abSrjs SCTP_MINIMAL_RWND); 1338c2654abSrjs return; 1348c2654abSrjs } 1358c2654abSrjs /* get actual space */ 1368c2654abSrjs calc = (u_int32_t)sctp_sbspace(&stcb->sctp_socket->so_rcv); 1378c2654abSrjs 1388c2654abSrjs /* take out what has NOT been put on socket queue and 1398c2654abSrjs * we yet hold for putting up. 1408c2654abSrjs */ 1418c2654abSrjs calc = sctp_sbspace_sub(calc, (u_int32_t)asoc->size_on_delivery_queue); 1428c2654abSrjs calc = sctp_sbspace_sub(calc, (u_int32_t)asoc->size_on_reasm_queue); 1438c2654abSrjs calc = sctp_sbspace_sub(calc, (u_int32_t)asoc->size_on_all_streams); 1448c2654abSrjs 1458c2654abSrjs /* what is the overhead of all these rwnd's */ 1468c2654abSrjs calc_w_oh = sctp_sbspace_sub(calc, stcb->asoc.my_rwnd_control_len); 1478c2654abSrjs 1488c2654abSrjs asoc->my_rwnd = calc; 1498c2654abSrjs if (calc_w_oh == 0) { 1508c2654abSrjs /* If our overhead is greater than the advertised 1518c2654abSrjs * rwnd, we clamp the rwnd to 1. This lets us 1528c2654abSrjs * still accept inbound segments, but hopefully will 1538c2654abSrjs * shut the sender down when he finally gets the message. 1548c2654abSrjs */ 1558c2654abSrjs asoc->my_rwnd = 1; 1568c2654abSrjs } else { 1578c2654abSrjs /* SWS threshold */ 1588c2654abSrjs if (asoc->my_rwnd && 1598c2654abSrjs (asoc->my_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_receiver)) { 1608c2654abSrjs /* SWS engaged, tell peer none left */ 1618c2654abSrjs asoc->my_rwnd = 1; 1628c2654abSrjs #ifdef SCTP_DEBUG 1638c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA4) { 1648c2654abSrjs printf(" - SWS zeros\n"); 1658c2654abSrjs } 1668c2654abSrjs } else { 1678c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA4) { 1688c2654abSrjs printf("\n"); 1698c2654abSrjs } 1708c2654abSrjs #endif 1718c2654abSrjs } 1728c2654abSrjs } 1738c2654abSrjs } 1748c2654abSrjs 1758c2654abSrjs /* 1768c2654abSrjs * Take a chk structure and build it into an mbuf. Hmm should we change things 1778c2654abSrjs * so that instead we store the data side in a chunk? 1788c2654abSrjs */ 1798c2654abSrjs static struct mbuf * 1808c2654abSrjs sctp_build_ctl_nchunk(struct sctp_tcb *stcb, uint32_t tsn, uint32_t ppid, 1818c2654abSrjs uint32_t context, uint16_t stream_no, uint16_t stream_seq, uint8_t flags) 1828c2654abSrjs { 1838c2654abSrjs struct sctp_sndrcvinfo *outinfo; 1848c2654abSrjs struct cmsghdr *cmh; 1858c2654abSrjs struct mbuf *ret; 1868c2654abSrjs 1878c2654abSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_RECVDATAIOEVNT) == 0) { 1888c2654abSrjs /* user does not want the sndrcv ctl */ 1898c2654abSrjs return (NULL); 1908c2654abSrjs } 1918c2654abSrjs 1928c2654abSrjs MGETHDR(ret, M_DONTWAIT, MT_CONTROL); 1938c2654abSrjs if (ret == NULL) { 1948c2654abSrjs /* No space */ 1958c2654abSrjs return (ret); 1968c2654abSrjs } 1978c2654abSrjs /* We need a CMSG header followed by the struct */ 1988c2654abSrjs cmh = mtod(ret, struct cmsghdr *); 1998c2654abSrjs outinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmh); 2008c2654abSrjs cmh->cmsg_level = IPPROTO_SCTP; 2018c2654abSrjs cmh->cmsg_type = SCTP_SNDRCV; 2028c2654abSrjs cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 2038c2654abSrjs outinfo->sinfo_stream = stream_no; 2048c2654abSrjs outinfo->sinfo_ssn = stream_seq; 2058c2654abSrjs if (flags & SCTP_DATA_UNORDERED) { 20620ba2d4fSrjs outinfo->sinfo_flags = SCTP_UNORDERED; 2078c2654abSrjs } else { 2088c2654abSrjs outinfo->sinfo_flags = 0; 2098c2654abSrjs } 2108c2654abSrjs outinfo->sinfo_ppid = ppid; 2118c2654abSrjs outinfo->sinfo_context = context; 2128c2654abSrjs outinfo->sinfo_assoc_id = sctp_get_associd(stcb); 2138c2654abSrjs outinfo->sinfo_tsn = tsn; 2148c2654abSrjs outinfo->sinfo_cumtsn = stcb->asoc.cumulative_tsn; 2158c2654abSrjs ret->m_len = cmh->cmsg_len; 2168c2654abSrjs ret->m_pkthdr.len = ret->m_len; 2178c2654abSrjs /* 2188c2654abSrjs * We track how many control len's have gone upon the sb 2198c2654abSrjs * and do not count these in the rwnd calculation. 2208c2654abSrjs */ 2218c2654abSrjs stcb->asoc.my_rwnd_control_len += 2228c2654abSrjs CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 2238c2654abSrjs 2248c2654abSrjs return (ret); 2258c2654abSrjs } 2268c2654abSrjs 2278c2654abSrjs /* 2288c2654abSrjs * Take a chk structure and build it into an mbuf. Should we change things 2298c2654abSrjs * so that instead we store the data side in a chunk? 2308c2654abSrjs */ 2318c2654abSrjs static 2328c2654abSrjs struct mbuf * 2338c2654abSrjs sctp_build_ctl(struct sctp_tcb *stcb, struct sctp_tmit_chunk *chk) 2348c2654abSrjs { 2358c2654abSrjs struct sctp_sndrcvinfo *outinfo; 2368c2654abSrjs struct cmsghdr *cmh; 2378c2654abSrjs struct mbuf *ret; 2388c2654abSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_RECVDATAIOEVNT) == 0) { 2398c2654abSrjs /* user does not want the sndrcv ctl */ 2408c2654abSrjs return (NULL); 2418c2654abSrjs } 2428c2654abSrjs MGET(ret, M_DONTWAIT, MT_CONTROL); 2438c2654abSrjs if (ret == NULL) { 2448c2654abSrjs /* No space */ 2458c2654abSrjs return (ret); 2468c2654abSrjs } 2478c2654abSrjs 2488c2654abSrjs /* We need a CMSG header followed by the struct */ 2498c2654abSrjs cmh = mtod(ret, struct cmsghdr *); 2508c2654abSrjs outinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmh); 2518c2654abSrjs cmh->cmsg_level = IPPROTO_SCTP; 2528c2654abSrjs cmh->cmsg_type = SCTP_SNDRCV; 2538c2654abSrjs cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 2548c2654abSrjs outinfo->sinfo_stream = chk->rec.data.stream_number; 2558c2654abSrjs outinfo->sinfo_ssn = chk->rec.data.stream_seq; 2568c2654abSrjs if (chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) { 25720ba2d4fSrjs outinfo->sinfo_flags = SCTP_UNORDERED; 2588c2654abSrjs } else { 2598c2654abSrjs outinfo->sinfo_flags = 0; 2608c2654abSrjs } 2618c2654abSrjs outinfo->sinfo_ppid = chk->rec.data.payloadtype; 2628c2654abSrjs outinfo->sinfo_context = chk->rec.data.context; 2638c2654abSrjs outinfo->sinfo_assoc_id = sctp_get_associd(stcb); 2648c2654abSrjs outinfo->sinfo_tsn = chk->rec.data.TSN_seq; 2658c2654abSrjs outinfo->sinfo_cumtsn = stcb->asoc.cumulative_tsn; 2668c2654abSrjs ret->m_len = cmh->cmsg_len; 2678c2654abSrjs stcb->asoc.my_rwnd_control_len += 2688c2654abSrjs CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 2698c2654abSrjs 2708c2654abSrjs return (ret); 2718c2654abSrjs } 2728c2654abSrjs 2738c2654abSrjs int 2748c2654abSrjs sctp_deliver_data(struct sctp_tcb *stcb, struct sctp_association *asoc, 2758c2654abSrjs struct sctp_tmit_chunk *chk, int hold_locks) 2768c2654abSrjs { 2778c2654abSrjs struct mbuf *control, *m; 2788c2654abSrjs int free_it; 2798c2654abSrjs struct sockaddr_in6 sin6; 2808c2654abSrjs const struct sockaddr *to; 2818c2654abSrjs 2828c2654abSrjs #ifdef SCTP_DEBUG 2838c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 2848c2654abSrjs printf("I am now in Deliver data! (%p)\n", chk); 2858c2654abSrjs } 2868c2654abSrjs #endif 2878c2654abSrjs /* get a write lock on the inp if not already */ 2888c2654abSrjs if (hold_locks == 0) { 2898c2654abSrjs SCTP_TCB_UNLOCK(stcb); 2908c2654abSrjs SCTP_INP_WLOCK(stcb->sctp_ep); 2918c2654abSrjs SCTP_TCB_LOCK(stcb); 2928c2654abSrjs } 2938c2654abSrjs free_it = 0; 2948c2654abSrjs /* We always add it to the queue */ 2958c2654abSrjs if (stcb && (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 2968c2654abSrjs /* socket above is long gone */ 2978c2654abSrjs #ifdef SCTP_DEBUG 2988c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 2998c2654abSrjs printf("gone is gone!\n"); 3008c2654abSrjs } 3018c2654abSrjs #endif 3028c2654abSrjs if (chk != NULL) { 3038c2654abSrjs sctp_m_freem(chk->data); 3048c2654abSrjs chk->data = NULL; 3058c2654abSrjs sctp_free_remote_addr(chk->whoTo); 3068c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk); 3078c2654abSrjs sctppcbinfo.ipi_count_chunk--; 3088c2654abSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) { 3098c2654abSrjs panic("Chunk count is negative"); 3108c2654abSrjs } 3118c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++; 3128c2654abSrjs } 3138c2654abSrjs TAILQ_FOREACH(chk, &asoc->delivery_queue, sctp_next) { 3148c2654abSrjs asoc->size_on_delivery_queue -= chk->send_size; 3158c2654abSrjs asoc->cnt_on_delivery_queue--; 3168c2654abSrjs /* 3178c2654abSrjs * Lose the data pointer, since its in the socket buffer 3188c2654abSrjs */ 3198c2654abSrjs sctp_m_freem(chk->data); 3208c2654abSrjs chk->data = NULL; 3218c2654abSrjs /* Now free the address and data */ 3228c2654abSrjs sctp_free_remote_addr(chk->whoTo); 3238c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk); 3248c2654abSrjs sctppcbinfo.ipi_count_chunk--; 3258c2654abSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) { 3268c2654abSrjs panic("Chunk count is negative"); 3278c2654abSrjs } 3288c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++; 3298c2654abSrjs } 3308c2654abSrjs if (hold_locks == 0) { 3318c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 3328c2654abSrjs } 3338c2654abSrjs return (0); 3348c2654abSrjs } 3358c2654abSrjs if (chk != NULL) { 3368c2654abSrjs TAILQ_INSERT_TAIL(&asoc->delivery_queue, chk, sctp_next); 3378c2654abSrjs asoc->size_on_delivery_queue += chk->send_size; 3388c2654abSrjs asoc->cnt_on_delivery_queue++; 3398c2654abSrjs } 3408c2654abSrjs if (asoc->fragmented_delivery_inprogress) { 3418c2654abSrjs /* 3428c2654abSrjs * oh oh, fragmented delivery in progress 3438c2654abSrjs * return out of here. 3448c2654abSrjs */ 3458c2654abSrjs #ifdef SCTP_DEBUG 3468c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 3478c2654abSrjs printf("Fragmented delivery in progress?\n"); 3488c2654abSrjs } 3498c2654abSrjs #endif 3508c2654abSrjs if (hold_locks == 0) { 3518c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 3528c2654abSrjs } 3538c2654abSrjs return (0); 3548c2654abSrjs } 3558c2654abSrjs /* Now grab the first one */ 3568c2654abSrjs chk = TAILQ_FIRST(&asoc->delivery_queue); 3578c2654abSrjs if (chk == NULL) { 3588c2654abSrjs /* Nothing in queue */ 3598c2654abSrjs #ifdef SCTP_DEBUG 3608c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 3618c2654abSrjs printf("Nothing in queue?\n"); 3628c2654abSrjs } 3638c2654abSrjs #endif 3648c2654abSrjs asoc->size_on_delivery_queue = 0; 3658c2654abSrjs asoc->cnt_on_delivery_queue = 0; 3668c2654abSrjs if (hold_locks == 0) { 3678c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 3688c2654abSrjs } 3698c2654abSrjs return (0); 3708c2654abSrjs } 3718c2654abSrjs 3728c2654abSrjs if (stcb->sctp_socket->so_rcv.sb_cc >= stcb->sctp_socket->so_rcv.sb_hiwat) { 3738c2654abSrjs /* Boy, there really is NO room */ 3748c2654abSrjs if (hold_locks == 0) { 3758c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 3768c2654abSrjs } 3778c2654abSrjs return (0); 3788c2654abSrjs } 3798c2654abSrjs #ifdef SCTP_DEBUG 3808c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 3818c2654abSrjs printf("Now to the delivery with chk(%p)!\n", chk); 3828c2654abSrjs } 3838c2654abSrjs #endif 3848c2654abSrjs /* XXX need to append PKTHDR to the socket buffer first */ 3858c2654abSrjs if ((chk->data->m_flags & M_PKTHDR) == 0) { 3868c2654abSrjs MGETHDR(m, M_DONTWAIT, MT_DATA); 3878c2654abSrjs if (m == NULL) { 3888c2654abSrjs /* no room! */ 3898c2654abSrjs if (hold_locks == 0) { 3908c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 3918c2654abSrjs } 3928c2654abSrjs return (0); 3938c2654abSrjs } 3948c2654abSrjs m->m_pkthdr.len = chk->send_size; 3958c2654abSrjs m->m_len = 0; 3968c2654abSrjs m->m_next = chk->data; 3978c2654abSrjs chk->data = m; 3988c2654abSrjs } 3998c2654abSrjs if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { 4008c2654abSrjs if (chk->data->m_next == NULL) { 4018c2654abSrjs /* hopefully we hit here most of the time */ 4028c2654abSrjs chk->data->m_flags |= M_EOR; 4038c2654abSrjs } else { 4048c2654abSrjs /* Add the flag to the LAST mbuf in the chain */ 4058c2654abSrjs m = chk->data; 4068c2654abSrjs while (m->m_next != NULL) { 4078c2654abSrjs m = m->m_next; 4088c2654abSrjs } 4098c2654abSrjs m->m_flags |= M_EOR; 4108c2654abSrjs } 4118c2654abSrjs } 4128c2654abSrjs 4138c2654abSrjs if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { 4148c2654abSrjs struct sockaddr_in6 lsa6; 4158c2654abSrjs 4168c2654abSrjs control = sctp_build_ctl(stcb, chk); 4178c2654abSrjs to = rtcache_getdst(&chk->whoTo->ro); 4188c2654abSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) && 4198c2654abSrjs to->sa_family == AF_INET) { 4208c2654abSrjs const struct sockaddr_in *sin; 4218c2654abSrjs 4228c2654abSrjs sin = (const struct sockaddr_in *)to; 4230a0528fdSrtr in6_sin_2_v4mapsin6(sin, &sin6); 4248c2654abSrjs to = (struct sockaddr *)&sin6; 4258c2654abSrjs } 4268c2654abSrjs /* check and strip embedded scope junk */ 4278c2654abSrjs to = (const struct sockaddr *)sctp_recover_scope((const struct sockaddr_in6 *)to, 4288c2654abSrjs &lsa6); 4298c2654abSrjs if (((const struct sockaddr_in *)to)->sin_port == 0) { 4308c2654abSrjs printf("Huh a, port is %d not net:%p %d?\n", 4318c2654abSrjs ((const struct sockaddr_in *)to)->sin_port, 4328c2654abSrjs chk->whoTo, 4338c2654abSrjs (int)(ntohs(stcb->rport))); 4348c2654abSrjs /*((struct sockaddr_in *)to)->sin_port = stcb->rport;*/ 4358c2654abSrjs /* XXX */ 4368c2654abSrjs } 4378c2654abSrjs if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < (long)chk->send_size) { 4388c2654abSrjs /* Gak not enough room */ 4398c2654abSrjs if (control) { 4408c2654abSrjs sctp_m_freem(control); 4418c2654abSrjs stcb->asoc.my_rwnd_control_len -= 4428c2654abSrjs CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 4438c2654abSrjs } 4448c2654abSrjs goto skip; 4458c2654abSrjs } 4468c2654abSrjs if (!sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv, 4478c2654abSrjs to, chk->data, control, stcb->asoc.my_vtag, 4488c2654abSrjs stcb->sctp_ep)) { 4498c2654abSrjs /* Gak not enough room */ 4508c2654abSrjs if (control) { 4518c2654abSrjs sctp_m_freem(control); 4528c2654abSrjs stcb->asoc.my_rwnd_control_len -= 4538c2654abSrjs CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 4548c2654abSrjs } 4558c2654abSrjs } else { 4568c2654abSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) { 4578c2654abSrjs if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) { 4588c2654abSrjs stcb->asoc.my_rwnd_control_len += 4598c2654abSrjs sizeof(struct mbuf); 4608c2654abSrjs } 4618c2654abSrjs } else { 4628c2654abSrjs stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf); 4638c2654abSrjs } 4648c2654abSrjs free_it = 1; 4658c2654abSrjs } 4668c2654abSrjs } else { 4678c2654abSrjs /* append to a already started message. */ 4688c2654abSrjs if (sctp_sbspace(&stcb->sctp_socket->so_rcv) >= 4698c2654abSrjs (long)chk->send_size) { 4708c2654abSrjs sbappend(&stcb->sctp_socket->so_rcv, chk->data); 4718c2654abSrjs free_it = 1; 4728c2654abSrjs } 4738c2654abSrjs } 4748c2654abSrjs skip: 4758c2654abSrjs if (hold_locks == 0) { 4768c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 4778c2654abSrjs } 4788c2654abSrjs /* free up the one we inserted */ 4798c2654abSrjs if (free_it) { 4808c2654abSrjs /* Pull it off the queue */ 4818c2654abSrjs #ifdef SCTP_DEBUG 4828c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 4838c2654abSrjs printf("Free_it true, doing tickle wakeup\n"); 4848c2654abSrjs } 4858c2654abSrjs #endif 4868c2654abSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 4878c2654abSrjs TAILQ_REMOVE(&asoc->delivery_queue, chk, sctp_next); 4888c2654abSrjs asoc->size_on_delivery_queue -= chk->send_size; 4898c2654abSrjs asoc->cnt_on_delivery_queue--; 4908c2654abSrjs /* Lose the data pointer, since its in the socket buffer */ 4918c2654abSrjs chk->data = NULL; 4928c2654abSrjs /* Now free the address and data */ 4938c2654abSrjs sctp_free_remote_addr(chk->whoTo); 4948c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk); 4958c2654abSrjs sctppcbinfo.ipi_count_chunk--; 4968c2654abSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) { 4978c2654abSrjs panic("Chunk count is negative"); 4988c2654abSrjs } 4998c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++; 5008c2654abSrjs } 5018c2654abSrjs return (free_it); 5028c2654abSrjs } 5038c2654abSrjs 5048c2654abSrjs /* 5058c2654abSrjs * We are delivering currently from the reassembly queue. We must continue to 5068c2654abSrjs * deliver until we either: 5078c2654abSrjs * 1) run out of space. 5088c2654abSrjs * 2) run out of sequential TSN's 5098c2654abSrjs * 3) hit the SCTP_DATA_LAST_FRAG flag. 5108c2654abSrjs */ 5118c2654abSrjs static void 5128c2654abSrjs sctp_service_reassembly(struct sctp_tcb *stcb, struct sctp_association *asoc, int hold_locks) 5138c2654abSrjs { 5148c2654abSrjs const struct sockaddr *to; 5158c2654abSrjs struct sockaddr_in6 sin6; 5168c2654abSrjs struct sctp_tmit_chunk *chk, *at; 5178c2654abSrjs struct mbuf *control, *m; 5188c2654abSrjs u_int16_t nxt_todel; 5198c2654abSrjs u_int16_t stream_no; 5208c2654abSrjs int cntDel; 5218c2654abSrjs cntDel = stream_no = 0; 5228c2654abSrjs if (hold_locks == 0) { 5238c2654abSrjs /* 5248c2654abSrjs * you always have the TCB lock, we need 5258c2654abSrjs * to have the inp write lock as well. 5268c2654abSrjs */ 5278c2654abSrjs SCTP_TCB_UNLOCK(stcb); 5288c2654abSrjs SCTP_INP_WLOCK(stcb->sctp_ep); 5298c2654abSrjs SCTP_TCB_LOCK(stcb); 5308c2654abSrjs } 5318c2654abSrjs if (stcb && (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 5328c2654abSrjs /* socket above is long gone */ 5338c2654abSrjs asoc->fragmented_delivery_inprogress = 0; 5348c2654abSrjs TAILQ_FOREACH(chk, &asoc->reasmqueue, sctp_next) { 5358c2654abSrjs asoc->size_on_delivery_queue -= chk->send_size; 5368c2654abSrjs asoc->cnt_on_delivery_queue--; 5378c2654abSrjs /* 5388c2654abSrjs * Lose the data pointer, since its in the socket buffer 5398c2654abSrjs */ 5408c2654abSrjs sctp_m_freem(chk->data); 5418c2654abSrjs chk->data = NULL; 5428c2654abSrjs /* Now free the address and data */ 5438c2654abSrjs sctp_free_remote_addr(chk->whoTo); 5448c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk); 5458c2654abSrjs sctppcbinfo.ipi_count_chunk--; 5468c2654abSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) { 5478c2654abSrjs panic("Chunk count is negative"); 5488c2654abSrjs } 5498c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++; 5508c2654abSrjs } 5518c2654abSrjs if (hold_locks == 0) { 5528c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 5538c2654abSrjs } 5548c2654abSrjs return; 5558c2654abSrjs } 5568c2654abSrjs do { 5578c2654abSrjs if (stcb->sctp_socket->so_rcv.sb_cc >= 5588c2654abSrjs stcb->sctp_socket->so_rcv.sb_hiwat) { 5598c2654abSrjs if (cntDel) { 5608c2654abSrjs sctp_sorwakeup(stcb->sctp_ep, 5618c2654abSrjs stcb->sctp_socket); 5628c2654abSrjs } 5638c2654abSrjs if (hold_locks == 0) { 5648c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 5658c2654abSrjs } 5668c2654abSrjs return; 5678c2654abSrjs } 5688c2654abSrjs chk = TAILQ_FIRST(&asoc->reasmqueue); 5698c2654abSrjs if (chk == NULL) { 5708c2654abSrjs if (cntDel) { 5718c2654abSrjs sctp_sorwakeup(stcb->sctp_ep, 5728c2654abSrjs stcb->sctp_socket); 5738c2654abSrjs } 5748c2654abSrjs if (hold_locks == 0) { 5758c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 5768c2654abSrjs } 5778c2654abSrjs return; 5788c2654abSrjs } 5798c2654abSrjs if (chk->rec.data.TSN_seq != (asoc->tsn_last_delivered + 1)) { 5808c2654abSrjs /* Can't deliver more :< */ 5818c2654abSrjs if (cntDel) { 5828c2654abSrjs sctp_sorwakeup(stcb->sctp_ep, 5838c2654abSrjs stcb->sctp_socket); 5848c2654abSrjs } 5858c2654abSrjs if (hold_locks == 0) { 5868c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 5878c2654abSrjs } 5888c2654abSrjs return; 5898c2654abSrjs } 5908c2654abSrjs stream_no = chk->rec.data.stream_number; 5918c2654abSrjs nxt_todel = asoc->strmin[stream_no].last_sequence_delivered + 1; 5928c2654abSrjs if (nxt_todel != chk->rec.data.stream_seq && 5938c2654abSrjs (chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) == 0) { 5948c2654abSrjs /* 5958c2654abSrjs * Not the next sequence to deliver in its stream OR 5968c2654abSrjs * unordered 5978c2654abSrjs */ 5988c2654abSrjs if (cntDel) { 5998c2654abSrjs sctp_sorwakeup(stcb->sctp_ep, 6008c2654abSrjs stcb->sctp_socket); 6018c2654abSrjs } 6028c2654abSrjs if (hold_locks == 0) { 6038c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 6048c2654abSrjs } 6058c2654abSrjs return; 6068c2654abSrjs } 6078c2654abSrjs 6088c2654abSrjs if ((chk->data->m_flags & M_PKTHDR) == 0) { 6098c2654abSrjs MGETHDR(m, M_DONTWAIT, MT_DATA); 6108c2654abSrjs if (m == NULL) { 6118c2654abSrjs /* no room! */ 6128c2654abSrjs if (hold_locks == 0) { 6138c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 6148c2654abSrjs } 6158c2654abSrjs return; 6168c2654abSrjs } 6178c2654abSrjs m->m_pkthdr.len = chk->send_size; 6188c2654abSrjs m->m_len = 0; 6198c2654abSrjs m->m_next = chk->data; 6208c2654abSrjs chk->data = m; 6218c2654abSrjs } 6228c2654abSrjs if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { 6238c2654abSrjs if (chk->data->m_next == NULL) { 6248c2654abSrjs /* hopefully we hit here most of the time */ 6258c2654abSrjs chk->data->m_flags |= M_EOR; 6268c2654abSrjs } else { 6278c2654abSrjs /* Add the flag to the LAST mbuf in the chain */ 6288c2654abSrjs m = chk->data; 6298c2654abSrjs while (m->m_next != NULL) { 6308c2654abSrjs m = m->m_next; 6318c2654abSrjs } 6328c2654abSrjs m->m_flags |= M_EOR; 6338c2654abSrjs } 6348c2654abSrjs } 6358c2654abSrjs if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { 6368c2654abSrjs struct sockaddr_in6 lsa6; 6378c2654abSrjs 6388c2654abSrjs control = sctp_build_ctl(stcb, chk); 6398c2654abSrjs to = rtcache_getdst(&chk->whoTo->ro); 6408c2654abSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) && 6418c2654abSrjs to->sa_family == AF_INET) { 6428c2654abSrjs const struct sockaddr_in *sin; 6438c2654abSrjs 6448c2654abSrjs sin = satocsin(to); 6450a0528fdSrtr in6_sin_2_v4mapsin6(sin, &sin6); 6468c2654abSrjs to = (struct sockaddr *)&sin6; 6478c2654abSrjs } 6488c2654abSrjs /* check and strip embedded scope junk */ 6498c2654abSrjs to = (const struct sockaddr *)sctp_recover_scope((const struct sockaddr_in6 *)to, 6508c2654abSrjs &lsa6); 6518c2654abSrjs if (((const struct sockaddr_in *)to)->sin_port == 0) { 6528c2654abSrjs printf("Huh b, port is %d not net:%p %d?\n", 6538c2654abSrjs ((const struct sockaddr_in *)to)->sin_port, 6548c2654abSrjs chk->whoTo, 6558c2654abSrjs (int)(ntohs(stcb->rport))); 6568c2654abSrjs /*((struct sockaddr_in *)to)->sin_port = stcb->rport;*/ 6578c2654abSrjs /* XXX */ 6588c2654abSrjs } 6598c2654abSrjs if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < 6608c2654abSrjs (long)chk->send_size) { 6618c2654abSrjs if (control) { 6628c2654abSrjs sctp_m_freem(control); 6638c2654abSrjs stcb->asoc.my_rwnd_control_len -= 6648c2654abSrjs CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 6658c2654abSrjs } 6668c2654abSrjs sctp_sorwakeup(stcb->sctp_ep, 6678c2654abSrjs stcb->sctp_socket); 6688c2654abSrjs if (hold_locks == 0) { 6698c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 6708c2654abSrjs } 6718c2654abSrjs return; 6728c2654abSrjs } 6738c2654abSrjs if (!sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv, 6748c2654abSrjs to, chk->data, control, stcb->asoc.my_vtag, 6758c2654abSrjs stcb->sctp_ep)) { 6768c2654abSrjs /* Gak not enough room */ 6778c2654abSrjs if (control) { 6788c2654abSrjs sctp_m_freem(control); 6798c2654abSrjs stcb->asoc.my_rwnd_control_len -= 6808c2654abSrjs CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 6818c2654abSrjs } 6828c2654abSrjs sctp_sorwakeup(stcb->sctp_ep, 6838c2654abSrjs stcb->sctp_socket); 6848c2654abSrjs if (hold_locks == 0) { 6858c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 6868c2654abSrjs } 6878c2654abSrjs return; 6888c2654abSrjs } 6898c2654abSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) { 6908c2654abSrjs if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) { 6918c2654abSrjs stcb->asoc.my_rwnd_control_len += 6928c2654abSrjs sizeof(struct mbuf); 6938c2654abSrjs } 6948c2654abSrjs } else { 6958c2654abSrjs stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf); 6968c2654abSrjs } 6978c2654abSrjs cntDel++; 6988c2654abSrjs } else { 6998c2654abSrjs if (sctp_sbspace(&stcb->sctp_socket->so_rcv) >= 7008c2654abSrjs (long)chk->send_size) { 7018c2654abSrjs sbappend(&stcb->sctp_socket->so_rcv, chk->data); 7028c2654abSrjs cntDel++; 7038c2654abSrjs } else { 7048c2654abSrjs /* out of space in the sb */ 7058c2654abSrjs sctp_sorwakeup(stcb->sctp_ep, 7068c2654abSrjs stcb->sctp_socket); 7078c2654abSrjs if (hold_locks == 0) { 7088c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 7098c2654abSrjs } 7108c2654abSrjs return; 7118c2654abSrjs } 7128c2654abSrjs } 7138c2654abSrjs /* pull it we did it */ 7148c2654abSrjs TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next); 7158c2654abSrjs if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { 7168c2654abSrjs asoc->fragmented_delivery_inprogress = 0; 7178c2654abSrjs if ((chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) == 0) { 7188c2654abSrjs asoc->strmin[stream_no].last_sequence_delivered++; 7198c2654abSrjs } 7208c2654abSrjs } 7218c2654abSrjs asoc->tsn_last_delivered = chk->rec.data.TSN_seq; 7228c2654abSrjs asoc->size_on_reasm_queue -= chk->send_size; 7238c2654abSrjs asoc->cnt_on_reasm_queue--; 7248c2654abSrjs /* free up the chk */ 7258c2654abSrjs sctp_free_remote_addr(chk->whoTo); 7268c2654abSrjs chk->data = NULL; 7278c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk); 7288c2654abSrjs sctppcbinfo.ipi_count_chunk--; 7298c2654abSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) { 7308c2654abSrjs panic("Chunk count is negative"); 7318c2654abSrjs } 7328c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++; 7338c2654abSrjs if (asoc->fragmented_delivery_inprogress == 0) { 7348c2654abSrjs /* 7358c2654abSrjs * Now lets see if we can deliver the next one on the 7368c2654abSrjs * stream 7378c2654abSrjs */ 7388c2654abSrjs /*u_int16_t nxt_todel;*/ 7398c2654abSrjs struct sctp_stream_in *strm; 7408c2654abSrjs 7418c2654abSrjs strm = &asoc->strmin[stream_no]; 7428c2654abSrjs nxt_todel = strm->last_sequence_delivered + 1; 7438c2654abSrjs chk = TAILQ_FIRST(&strm->inqueue); 7448c2654abSrjs if (chk && (nxt_todel == chk->rec.data.stream_seq)) { 7458c2654abSrjs while (chk != NULL) { 7468c2654abSrjs /* all delivered */ 7478c2654abSrjs if (nxt_todel == 7488c2654abSrjs chk->rec.data.stream_seq) { 7498c2654abSrjs at = TAILQ_NEXT(chk, sctp_next); 7508c2654abSrjs TAILQ_REMOVE(&strm->inqueue, 7518c2654abSrjs chk, sctp_next); 7528c2654abSrjs asoc->size_on_all_streams -= 7538c2654abSrjs chk->send_size; 7548c2654abSrjs asoc->cnt_on_all_streams--; 7558c2654abSrjs strm->last_sequence_delivered++; 7568c2654abSrjs /* 7578c2654abSrjs * We ignore the return of 7588c2654abSrjs * deliver_data here since we 7598c2654abSrjs * always can hold the chunk on 7608c2654abSrjs * the d-queue. And we have a 7618c2654abSrjs * finite number that can be 7628c2654abSrjs * delivered from the strq. 7638c2654abSrjs */ 7648c2654abSrjs sctp_deliver_data(stcb, asoc, chk, 1); 7658c2654abSrjs chk = at; 7668c2654abSrjs } else { 7678c2654abSrjs break; 7688c2654abSrjs } 7698c2654abSrjs nxt_todel = 7708c2654abSrjs strm->last_sequence_delivered + 1; 7718c2654abSrjs } 7728c2654abSrjs } 7738c2654abSrjs if (!TAILQ_EMPTY(&asoc->delivery_queue)) { 7748c2654abSrjs /* Here if deliver_data fails, we must break */ 7758c2654abSrjs if (sctp_deliver_data(stcb, asoc, NULL, 1) == 0) 7768c2654abSrjs break; 7778c2654abSrjs } 7788c2654abSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 7798c2654abSrjs if (hold_locks == 0) { 7808c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 7818c2654abSrjs } 7828c2654abSrjs return; 7838c2654abSrjs } 7848c2654abSrjs chk = TAILQ_FIRST(&asoc->reasmqueue); 7858c2654abSrjs } while (chk); 7868c2654abSrjs if (cntDel) { 7878c2654abSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 7888c2654abSrjs } 7898c2654abSrjs if (hold_locks == 0) { 7908c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 7918c2654abSrjs } 7928c2654abSrjs } 7938c2654abSrjs 7948c2654abSrjs /* 7958c2654abSrjs * Queue the chunk either right into the socket buffer if it is the next one 7968c2654abSrjs * to go OR put it in the correct place in the delivery queue. If we do 7978c2654abSrjs * append to the so_buf, keep doing so until we are out of order. 7988c2654abSrjs * One big question still remains, what to do when the socket buffer is FULL?? 7998c2654abSrjs */ 8008c2654abSrjs static void 8018c2654abSrjs sctp_queue_data_to_stream(struct sctp_tcb *stcb, struct sctp_association *asoc, 8028c2654abSrjs struct sctp_tmit_chunk *chk, int *abort_flag) 8038c2654abSrjs { 8048c2654abSrjs struct sctp_stream_in *strm; 8058c2654abSrjs struct sctp_tmit_chunk *at; 8068c2654abSrjs int queue_needed; 8078c2654abSrjs u_int16_t nxt_todel; 8088c2654abSrjs struct mbuf *oper; 8098c2654abSrjs 8108c2654abSrjs /*** FIX FIX FIX ??? 8118c2654abSrjs * Need to add code to deal with 16 bit seq wrap 8128c2654abSrjs * without a TSN wrap for ordered delivery (maybe). 8138c2654abSrjs * FIX FIX FIX ??? 8148c2654abSrjs */ 8158c2654abSrjs queue_needed = 1; 8168c2654abSrjs asoc->size_on_all_streams += chk->send_size; 8178c2654abSrjs asoc->cnt_on_all_streams++; 8188c2654abSrjs strm = &asoc->strmin[chk->rec.data.stream_number]; 8198c2654abSrjs nxt_todel = strm->last_sequence_delivered + 1; 8208c2654abSrjs #ifdef SCTP_STR_LOGGING 8218c2654abSrjs sctp_log_strm_del(chk, NULL, SCTP_STR_LOG_FROM_INTO_STRD); 8228c2654abSrjs #endif 8238c2654abSrjs #ifdef SCTP_DEBUG 8248c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 8258c2654abSrjs printf("queue to stream called for ssn:%u lastdel:%u nxt:%u\n", 8268c2654abSrjs (u_int)chk->rec.data.stream_seq, 8278c2654abSrjs (u_int)strm->last_sequence_delivered, (u_int)nxt_todel); 8288c2654abSrjs } 8298c2654abSrjs #endif 8308c2654abSrjs if (compare_with_wrap(strm->last_sequence_delivered, 8318c2654abSrjs chk->rec.data.stream_seq, MAX_SEQ) || 8328c2654abSrjs (strm->last_sequence_delivered == chk->rec.data.stream_seq)) { 8338c2654abSrjs /* The incoming sseq is behind where we last delivered? */ 8348c2654abSrjs #ifdef SCTP_DEBUG 8358c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 8368c2654abSrjs printf("Duplicate S-SEQ:%d delivered:%d from peer, Abort association\n", 8378c2654abSrjs chk->rec.data.stream_seq, 8388c2654abSrjs strm->last_sequence_delivered); 8398c2654abSrjs } 8408c2654abSrjs #endif 8418c2654abSrjs /* 8428c2654abSrjs * throw it in the stream so it gets cleaned up in 8438c2654abSrjs * association destruction 8448c2654abSrjs */ 8458c2654abSrjs TAILQ_INSERT_HEAD(&strm->inqueue, chk, sctp_next); 8468c2654abSrjs MGET(oper, M_DONTWAIT, MT_DATA); 8478c2654abSrjs if (oper) { 8488c2654abSrjs struct sctp_paramhdr *ph; 8498c2654abSrjs u_int32_t *ippp; 8508c2654abSrjs 8518c2654abSrjs oper->m_len = sizeof(struct sctp_paramhdr) + 8528c2654abSrjs sizeof(*ippp); 8538c2654abSrjs ph = mtod(oper, struct sctp_paramhdr *); 8548c2654abSrjs ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 8558c2654abSrjs ph->param_length = htons(oper->m_len); 8568c2654abSrjs ippp = (u_int32_t *)(ph + 1); 8578c2654abSrjs *ippp = htonl(0x00000001); 8588c2654abSrjs } 8598c2654abSrjs sctp_abort_an_association(stcb->sctp_ep, stcb, 8608c2654abSrjs SCTP_PEER_FAULTY, oper); 8618c2654abSrjs 8628c2654abSrjs *abort_flag = 1; 8638c2654abSrjs return; 8648c2654abSrjs 8658c2654abSrjs } 8668c2654abSrjs if (nxt_todel == chk->rec.data.stream_seq) { 8678c2654abSrjs /* can be delivered right away */ 8688c2654abSrjs #ifdef SCTP_DEBUG 8698c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 8708c2654abSrjs printf("It's NEXT!\n"); 8718c2654abSrjs } 8728c2654abSrjs #endif 8738c2654abSrjs #ifdef SCTP_STR_LOGGING 8748c2654abSrjs sctp_log_strm_del(chk, NULL, SCTP_STR_LOG_FROM_IMMED_DEL); 8758c2654abSrjs #endif 8768c2654abSrjs queue_needed = 0; 8778c2654abSrjs asoc->size_on_all_streams -= chk->send_size; 8788c2654abSrjs asoc->cnt_on_all_streams--; 8798c2654abSrjs strm->last_sequence_delivered++; 8808c2654abSrjs sctp_deliver_data(stcb, asoc, chk, 0); 8818c2654abSrjs chk = TAILQ_FIRST(&strm->inqueue); 8828c2654abSrjs while (chk != NULL) { 8838c2654abSrjs /* all delivered */ 8848c2654abSrjs nxt_todel = strm->last_sequence_delivered + 1; 8858c2654abSrjs if (nxt_todel == chk->rec.data.stream_seq) { 8868c2654abSrjs at = TAILQ_NEXT(chk, sctp_next); 8878c2654abSrjs TAILQ_REMOVE(&strm->inqueue, chk, sctp_next); 8888c2654abSrjs asoc->size_on_all_streams -= chk->send_size; 8898c2654abSrjs asoc->cnt_on_all_streams--; 8908c2654abSrjs strm->last_sequence_delivered++; 8918c2654abSrjs /* 8928c2654abSrjs * We ignore the return of deliver_data here 8938c2654abSrjs * since we always can hold the chunk on the 8948c2654abSrjs * d-queue. And we have a finite number that 8958c2654abSrjs * can be delivered from the strq. 8968c2654abSrjs */ 8978c2654abSrjs #ifdef SCTP_STR_LOGGING 8988c2654abSrjs sctp_log_strm_del(chk, NULL, 8998c2654abSrjs SCTP_STR_LOG_FROM_IMMED_DEL); 9008c2654abSrjs #endif 9018c2654abSrjs sctp_deliver_data(stcb, asoc, chk, 0); 9028c2654abSrjs chk = at; 9038c2654abSrjs continue; 9048c2654abSrjs } 9058c2654abSrjs break; 9068c2654abSrjs } 9078c2654abSrjs } 9088c2654abSrjs if (queue_needed) { 9098c2654abSrjs /* 9108c2654abSrjs * Ok, we did not deliver this guy, find 9118c2654abSrjs * the correct place to put it on the queue. 9128c2654abSrjs */ 9138c2654abSrjs #ifdef SCTP_DEBUG 9148c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 9158c2654abSrjs printf("Queue Needed!\n"); 9168c2654abSrjs } 9178c2654abSrjs #endif 9188c2654abSrjs if (TAILQ_EMPTY(&strm->inqueue)) { 9198c2654abSrjs /* Empty queue */ 9208c2654abSrjs #ifdef SCTP_STR_LOGGING 9218c2654abSrjs sctp_log_strm_del(chk, NULL, SCTP_STR_LOG_FROM_INSERT_HD); 9228c2654abSrjs #endif 9238c2654abSrjs TAILQ_INSERT_HEAD(&strm->inqueue, chk, sctp_next); 9248c2654abSrjs } else { 9258c2654abSrjs TAILQ_FOREACH(at, &strm->inqueue, sctp_next) { 9268c2654abSrjs if (compare_with_wrap(at->rec.data.stream_seq, 9278c2654abSrjs chk->rec.data.stream_seq, MAX_SEQ)) { 9288c2654abSrjs /* 9298c2654abSrjs * one in queue is bigger than the new 9308c2654abSrjs * one, insert before this one 9318c2654abSrjs */ 9328c2654abSrjs #ifdef SCTP_STR_LOGGING 9338c2654abSrjs sctp_log_strm_del(chk, at, 9348c2654abSrjs SCTP_STR_LOG_FROM_INSERT_MD); 9358c2654abSrjs #endif 9368c2654abSrjs TAILQ_INSERT_BEFORE(at, chk, sctp_next); 9378c2654abSrjs break; 9388c2654abSrjs } else if (at->rec.data.stream_seq == 9398c2654abSrjs chk->rec.data.stream_seq) { 9408c2654abSrjs /* 9418c2654abSrjs * Gak, He sent me a duplicate str seq 9428c2654abSrjs * number 9438c2654abSrjs */ 9448c2654abSrjs /* 9458c2654abSrjs * foo bar, I guess I will just free 9468c2654abSrjs * this new guy, should we abort too? 9478c2654abSrjs * FIX ME MAYBE? Or it COULD be that 9488c2654abSrjs * the SSN's have wrapped. Maybe I 9498c2654abSrjs * should compare to TSN somehow... 9508c2654abSrjs * sigh for now just blow away the 9518c2654abSrjs * chunk! 9528c2654abSrjs */ 9538c2654abSrjs 9548c2654abSrjs sctp_m_freem(chk->data); 9558c2654abSrjs chk->data = NULL; 9568c2654abSrjs asoc->size_on_all_streams -= chk->send_size; 9578c2654abSrjs asoc->cnt_on_all_streams--; 9588c2654abSrjs sctp_pegs[SCTP_DUP_SSN_RCVD]++; 9598c2654abSrjs sctp_free_remote_addr(chk->whoTo); 9608c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk); 9618c2654abSrjs sctppcbinfo.ipi_count_chunk--; 9628c2654abSrjs if ((int)sctppcbinfo.ipi_count_chunk < 9638c2654abSrjs 0) { 9648c2654abSrjs panic("Chunk count is negative"); 9658c2654abSrjs } 9668c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++; 9678c2654abSrjs return; 9688c2654abSrjs } else { 9698c2654abSrjs if (TAILQ_NEXT(at, sctp_next) == NULL) { 9708c2654abSrjs /* 9718c2654abSrjs * We are at the end, insert it 9728c2654abSrjs * after this one 9738c2654abSrjs */ 9748c2654abSrjs #ifdef SCTP_STR_LOGGING 9758c2654abSrjs sctp_log_strm_del(chk, at, 9768c2654abSrjs SCTP_STR_LOG_FROM_INSERT_TL); 9778c2654abSrjs #endif 9788c2654abSrjs TAILQ_INSERT_AFTER(&strm->inqueue, 9798c2654abSrjs at, chk, sctp_next); 9808c2654abSrjs break; 9818c2654abSrjs } 9828c2654abSrjs } 9838c2654abSrjs } 9848c2654abSrjs } 9858c2654abSrjs } else { 9868c2654abSrjs /* We delivered some chunks, wake them up */ 9878c2654abSrjs 9888c2654abSrjs #ifdef SCTP_DEBUG 9898c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 9908c2654abSrjs printf("Doing WAKEUP!\n"); 9918c2654abSrjs } 9928c2654abSrjs #endif 9938c2654abSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 9948c2654abSrjs } 9958c2654abSrjs } 9968c2654abSrjs 9978c2654abSrjs /* 9988c2654abSrjs * Returns two things: You get the total size of the deliverable parts of the 9998c2654abSrjs * first fragmented message on the reassembly queue. And you get a 1 back if 10008c2654abSrjs * all of the message is ready or a 0 back if the message is still incomplete 10018c2654abSrjs */ 10028c2654abSrjs static int 10038c2654abSrjs sctp_is_all_msg_on_reasm(struct sctp_association *asoc, int *t_size) 10048c2654abSrjs { 10058c2654abSrjs struct sctp_tmit_chunk *chk; 10068c2654abSrjs u_int32_t tsn; 10078c2654abSrjs 10088c2654abSrjs *t_size = 0; 10098c2654abSrjs chk = TAILQ_FIRST(&asoc->reasmqueue); 10108c2654abSrjs if (chk == NULL) { 10118c2654abSrjs /* nothing on the queue */ 10128c2654abSrjs return (0); 10138c2654abSrjs } 10148c2654abSrjs if ((chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) == 0) { 10158c2654abSrjs /* Not a first on the queue */ 10168c2654abSrjs return (0); 10178c2654abSrjs } 10188c2654abSrjs tsn = chk->rec.data.TSN_seq; 10198c2654abSrjs while (chk) { 10208c2654abSrjs if (tsn != chk->rec.data.TSN_seq) { 10218c2654abSrjs return (0); 10228c2654abSrjs } 10238c2654abSrjs *t_size += chk->send_size; 10248c2654abSrjs if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { 10258c2654abSrjs return (1); 10268c2654abSrjs } 10278c2654abSrjs tsn++; 10288c2654abSrjs chk = TAILQ_NEXT(chk, sctp_next); 10298c2654abSrjs } 10308c2654abSrjs return (0); 10318c2654abSrjs } 10328c2654abSrjs 10338c2654abSrjs /* 10348c2654abSrjs * Dump onto the re-assembly queue, in its proper place. After dumping on 1035fef573ecSandvar * the queue, see if anything can be delivered. If so pull it off (or as much 10368c2654abSrjs * as we can. If we run out of space then we must dump what we can and set 10378c2654abSrjs * the appropriate flag to say we queued what we could. 10388c2654abSrjs */ 10398c2654abSrjs static void 10408c2654abSrjs sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, 10418c2654abSrjs struct sctp_tmit_chunk *chk, int *abort_flag) 10428c2654abSrjs { 10438c2654abSrjs struct mbuf *oper; 10448c2654abSrjs u_int16_t nxt_todel; 10458c2654abSrjs u_int32_t cum_ackp1, prev_tsn, post_tsn; 10468c2654abSrjs int tsize; 10478c2654abSrjs struct sctp_tmit_chunk *at, *prev, *next; 10488c2654abSrjs 10498c2654abSrjs prev = next = NULL; 10508c2654abSrjs cum_ackp1 = asoc->tsn_last_delivered + 1; 10518c2654abSrjs 10528c2654abSrjs if (TAILQ_EMPTY(&asoc->reasmqueue)) { 10538c2654abSrjs /* This is the first one on the queue */ 10548c2654abSrjs TAILQ_INSERT_HEAD(&asoc->reasmqueue, chk, sctp_next); 10558c2654abSrjs /* 10568c2654abSrjs * we do not check for delivery of anything when 10578c2654abSrjs * only one fragment is here 10588c2654abSrjs */ 10598c2654abSrjs asoc->size_on_reasm_queue = chk->send_size; 10608c2654abSrjs asoc->cnt_on_reasm_queue++; 10618c2654abSrjs if (chk->rec.data.TSN_seq == cum_ackp1) { 10628c2654abSrjs if (asoc->fragmented_delivery_inprogress == 0 && 10638c2654abSrjs (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) != 10648c2654abSrjs SCTP_DATA_FIRST_FRAG) { 10658c2654abSrjs /* 10668c2654abSrjs * An empty queue, no delivery inprogress, we 10678c2654abSrjs * hit the next one and it does NOT have a 10688c2654abSrjs * FIRST fragment mark. 10698c2654abSrjs */ 10708c2654abSrjs #ifdef SCTP_DEBUG 10718c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 10728c2654abSrjs printf("Gak, Evil plot, its not first, no fragmented delivery in progress\n"); 10738c2654abSrjs } 10748c2654abSrjs #endif 10758c2654abSrjs MGET(oper, M_DONTWAIT, MT_DATA); 10768c2654abSrjs if (oper) { 10778c2654abSrjs struct sctp_paramhdr *ph; 10788c2654abSrjs u_int32_t *ippp; 10798c2654abSrjs 10808c2654abSrjs oper->m_len = 10818c2654abSrjs sizeof(struct sctp_paramhdr) + 10828c2654abSrjs sizeof(*ippp); 10838c2654abSrjs ph = mtod(oper, struct sctp_paramhdr *); 10848c2654abSrjs ph->param_type = 10858c2654abSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 10868c2654abSrjs ph->param_length = htons(oper->m_len); 10878c2654abSrjs ippp = (u_int32_t *)(ph + 1); 10888c2654abSrjs *ippp = htonl(0x10000001); 10898c2654abSrjs } 10908c2654abSrjs sctp_abort_an_association(stcb->sctp_ep, stcb, 10918c2654abSrjs SCTP_PEER_FAULTY, oper); 10928c2654abSrjs *abort_flag = 1; 10938c2654abSrjs } else if (asoc->fragmented_delivery_inprogress && 10948c2654abSrjs (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) == SCTP_DATA_FIRST_FRAG) { 10958c2654abSrjs /* 10968c2654abSrjs * We are doing a partial delivery and the NEXT 10978c2654abSrjs * chunk MUST be either the LAST or MIDDLE 10988c2654abSrjs * fragment NOT a FIRST 10998c2654abSrjs */ 11008c2654abSrjs #ifdef SCTP_DEBUG 11018c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 11028c2654abSrjs printf("Gak, Evil plot, it IS a first and fragmented delivery in progress\n"); 11038c2654abSrjs } 11048c2654abSrjs #endif 11058c2654abSrjs MGET(oper, M_DONTWAIT, MT_DATA); 11068c2654abSrjs if (oper) { 11078c2654abSrjs struct sctp_paramhdr *ph; 11088c2654abSrjs u_int32_t *ippp; 11098c2654abSrjs 11108c2654abSrjs oper->m_len = 11118c2654abSrjs sizeof(struct sctp_paramhdr) + 11128c2654abSrjs sizeof(*ippp); 11138c2654abSrjs ph = mtod(oper, struct sctp_paramhdr *); 11148c2654abSrjs ph->param_type = 11158c2654abSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 11168c2654abSrjs ph->param_length = htons(oper->m_len); 11178c2654abSrjs ippp = (u_int32_t *)(ph + 1); 11188c2654abSrjs *ippp = htonl(0x10000002); 11198c2654abSrjs } 11208c2654abSrjs sctp_abort_an_association(stcb->sctp_ep, stcb, 11218c2654abSrjs SCTP_PEER_FAULTY, oper); 11228c2654abSrjs *abort_flag = 1; 11238c2654abSrjs } else if (asoc->fragmented_delivery_inprogress) { 11248c2654abSrjs /* Here we are ok with a MIDDLE or LAST piece */ 11258c2654abSrjs if (chk->rec.data.stream_number != 11268c2654abSrjs asoc->str_of_pdapi) { 11278c2654abSrjs /* Got to be the right STR No */ 11288c2654abSrjs #ifdef SCTP_DEBUG 11298c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 11308c2654abSrjs printf("Gak, Evil plot, it IS not same stream number %d vs %d\n", 11318c2654abSrjs chk->rec.data.stream_number, 11328c2654abSrjs asoc->str_of_pdapi); 11338c2654abSrjs } 11348c2654abSrjs #endif 11358c2654abSrjs MGET(oper, M_DONTWAIT, MT_DATA); 11368c2654abSrjs if (oper) { 11378c2654abSrjs struct sctp_paramhdr *ph; 11388c2654abSrjs u_int32_t *ippp; 11398c2654abSrjs oper->m_len = 11408c2654abSrjs sizeof(struct sctp_paramhdr) + 11418c2654abSrjs sizeof(*ippp); 11428c2654abSrjs ph = mtod(oper, 11438c2654abSrjs struct sctp_paramhdr *); 11448c2654abSrjs ph->param_type = 11458c2654abSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 11468c2654abSrjs ph->param_length = 11478c2654abSrjs htons(oper->m_len); 11488c2654abSrjs ippp = (u_int32_t *)(ph + 1); 11498c2654abSrjs *ippp = htonl(0x10000003); 11508c2654abSrjs } 11518c2654abSrjs sctp_abort_an_association(stcb->sctp_ep, 11528c2654abSrjs stcb, SCTP_PEER_FAULTY, oper); 11538c2654abSrjs *abort_flag = 1; 11548c2654abSrjs } else if ((asoc->fragment_flags & SCTP_DATA_UNORDERED) != 11558c2654abSrjs SCTP_DATA_UNORDERED && 11568c2654abSrjs chk->rec.data.stream_seq != 11578c2654abSrjs asoc->ssn_of_pdapi) { 11588c2654abSrjs /* Got to be the right STR Seq */ 11598c2654abSrjs #ifdef SCTP_DEBUG 11608c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 11618c2654abSrjs printf("Gak, Evil plot, it IS not same stream seq %d vs %d\n", 11628c2654abSrjs chk->rec.data.stream_seq, 11638c2654abSrjs asoc->ssn_of_pdapi); 11648c2654abSrjs } 11658c2654abSrjs #endif 11668c2654abSrjs MGET(oper, M_DONTWAIT, MT_DATA); 11678c2654abSrjs if (oper) { 11688c2654abSrjs struct sctp_paramhdr *ph; 11698c2654abSrjs u_int32_t *ippp; 11708c2654abSrjs oper->m_len = 11718c2654abSrjs sizeof(struct sctp_paramhdr) + 11728c2654abSrjs sizeof(*ippp); 11738c2654abSrjs ph = mtod(oper, 11748c2654abSrjs struct sctp_paramhdr *); 11758c2654abSrjs ph->param_type = 11768c2654abSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 11778c2654abSrjs ph->param_length = 11788c2654abSrjs htons(oper->m_len); 11798c2654abSrjs ippp = (u_int32_t *)(ph + 1); 11808c2654abSrjs *ippp = htonl(0x10000004); 11818c2654abSrjs } 11828c2654abSrjs sctp_abort_an_association(stcb->sctp_ep, 11838c2654abSrjs stcb, SCTP_PEER_FAULTY, oper); 11848c2654abSrjs *abort_flag = 1; 11858c2654abSrjs } 11868c2654abSrjs } 11878c2654abSrjs } 11888c2654abSrjs return; 11898c2654abSrjs } 11908c2654abSrjs /* Find its place */ 11918c2654abSrjs at = TAILQ_FIRST(&asoc->reasmqueue); 11928c2654abSrjs 11938c2654abSrjs /* Grab the top flags */ 11948c2654abSrjs TAILQ_FOREACH(at, &asoc->reasmqueue, sctp_next) { 11958c2654abSrjs if (compare_with_wrap(at->rec.data.TSN_seq, 11968c2654abSrjs chk->rec.data.TSN_seq, MAX_TSN)) { 11978c2654abSrjs /* 11988c2654abSrjs * one in queue is bigger than the new one, insert 11998c2654abSrjs * before this one 12008c2654abSrjs */ 12018c2654abSrjs /* A check */ 12028c2654abSrjs asoc->size_on_reasm_queue += chk->send_size; 12038c2654abSrjs asoc->cnt_on_reasm_queue++; 12048c2654abSrjs next = at; 12058c2654abSrjs TAILQ_INSERT_BEFORE(at, chk, sctp_next); 12068c2654abSrjs break; 12078c2654abSrjs } else if (at->rec.data.TSN_seq == chk->rec.data.TSN_seq) { 12088c2654abSrjs /* Gak, He sent me a duplicate str seq number */ 12098c2654abSrjs /* 12108c2654abSrjs * foo bar, I guess I will just free this new guy, 12118c2654abSrjs * should we abort too? FIX ME MAYBE? Or it COULD be 12128c2654abSrjs * that the SSN's have wrapped. Maybe I should compare 12138c2654abSrjs * to TSN somehow... sigh for now just blow away the 12148c2654abSrjs * chunk! 12158c2654abSrjs */ 12168c2654abSrjs sctp_m_freem(chk->data); 12178c2654abSrjs chk->data = NULL; 12188c2654abSrjs sctp_free_remote_addr(chk->whoTo); 12198c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk); 12208c2654abSrjs sctppcbinfo.ipi_count_chunk--; 12218c2654abSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) { 12228c2654abSrjs panic("Chunk count is negative"); 12238c2654abSrjs } 12248c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++; 12258c2654abSrjs return; 12268c2654abSrjs } else { 12278c2654abSrjs prev = at; 12288c2654abSrjs if (TAILQ_NEXT(at, sctp_next) == NULL) { 12298c2654abSrjs /* 12308c2654abSrjs * We are at the end, insert it after this one 12318c2654abSrjs */ 12328c2654abSrjs /* check it first */ 12338c2654abSrjs asoc->size_on_reasm_queue += chk->send_size; 12348c2654abSrjs asoc->cnt_on_reasm_queue++; 12358c2654abSrjs TAILQ_INSERT_AFTER(&asoc->reasmqueue, at, chk, sctp_next); 12368c2654abSrjs break; 12378c2654abSrjs } 12388c2654abSrjs } 12398c2654abSrjs } 12408c2654abSrjs /* Now the audits */ 12418c2654abSrjs if (prev) { 12428c2654abSrjs prev_tsn = chk->rec.data.TSN_seq - 1; 12438c2654abSrjs if (prev_tsn == prev->rec.data.TSN_seq) { 12448c2654abSrjs /* 12458c2654abSrjs * Ok the one I am dropping onto the end 12468c2654abSrjs * is the NEXT. A bit of valdiation here. 12478c2654abSrjs */ 12488c2654abSrjs if ((prev->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) == 12498c2654abSrjs SCTP_DATA_FIRST_FRAG || 12508c2654abSrjs (prev->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) == 12518c2654abSrjs SCTP_DATA_MIDDLE_FRAG) { 12528c2654abSrjs /* 12538c2654abSrjs * Insert chk MUST be a MIDDLE or LAST fragment 12548c2654abSrjs */ 12558c2654abSrjs if ((chk->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) == 12568c2654abSrjs SCTP_DATA_FIRST_FRAG) { 12578c2654abSrjs #ifdef SCTP_DEBUG 12588c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 12598c2654abSrjs printf("Prev check - It can be a midlle or last but not a first\n"); 12608c2654abSrjs printf("Gak, Evil plot, it's a FIRST!\n"); 12618c2654abSrjs } 12628c2654abSrjs #endif 12638c2654abSrjs MGET(oper, M_DONTWAIT, MT_DATA); 12648c2654abSrjs if (oper) { 12658c2654abSrjs struct sctp_paramhdr *ph; 12668c2654abSrjs u_int32_t *ippp; 12678c2654abSrjs 12688c2654abSrjs oper->m_len = 12698c2654abSrjs sizeof(struct sctp_paramhdr) + 12708c2654abSrjs sizeof(*ippp); 12718c2654abSrjs ph = mtod(oper, 12728c2654abSrjs struct sctp_paramhdr *); 12738c2654abSrjs ph->param_type = 12748c2654abSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 12758c2654abSrjs ph->param_length = 12768c2654abSrjs htons(oper->m_len); 12778c2654abSrjs 12788c2654abSrjs ippp = (u_int32_t *)(ph + 1); 12798c2654abSrjs *ippp = htonl(0x10000005); 12808c2654abSrjs } 12818c2654abSrjs sctp_abort_an_association(stcb->sctp_ep, 12828c2654abSrjs stcb, SCTP_PEER_FAULTY, oper); 12838c2654abSrjs *abort_flag = 1; 12848c2654abSrjs return; 12858c2654abSrjs } 12868c2654abSrjs if (chk->rec.data.stream_number != 12878c2654abSrjs prev->rec.data.stream_number) { 12888c2654abSrjs /* 12898c2654abSrjs * Huh, need the correct STR here, they 12908c2654abSrjs * must be the same. 12918c2654abSrjs */ 12928c2654abSrjs #ifdef SCTP_DEBUG 12938c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 12948c2654abSrjs printf("Prev check - Gak, Evil plot, ssn:%d not the same as at:%d\n", 12958c2654abSrjs chk->rec.data.stream_number, 12968c2654abSrjs prev->rec.data.stream_number); 12978c2654abSrjs } 12988c2654abSrjs #endif 12998c2654abSrjs MGET(oper, M_DONTWAIT, MT_DATA); 13008c2654abSrjs if (oper) { 13018c2654abSrjs struct sctp_paramhdr *ph; 13028c2654abSrjs u_int32_t *ippp; 13038c2654abSrjs 13048c2654abSrjs oper->m_len = 13058c2654abSrjs sizeof(struct sctp_paramhdr) + 13068c2654abSrjs sizeof(*ippp); 13078c2654abSrjs ph = mtod(oper, 13088c2654abSrjs struct sctp_paramhdr *); 13098c2654abSrjs ph->param_type = 13108c2654abSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 13118c2654abSrjs ph->param_length = 13128c2654abSrjs htons(oper->m_len); 13138c2654abSrjs ippp = (u_int32_t *)(ph + 1); 13148c2654abSrjs *ippp = htonl(0x10000006); 13158c2654abSrjs } 13168c2654abSrjs 13178c2654abSrjs sctp_abort_an_association(stcb->sctp_ep, 13188c2654abSrjs stcb, SCTP_PEER_FAULTY, oper); 13198c2654abSrjs 13208c2654abSrjs *abort_flag = 1; 13218c2654abSrjs return; 13228c2654abSrjs } 13238c2654abSrjs if ((prev->rec.data.rcv_flags & SCTP_DATA_UNORDERED) == 0 && 13248c2654abSrjs chk->rec.data.stream_seq != 13258c2654abSrjs prev->rec.data.stream_seq) { 13268c2654abSrjs /* 13278c2654abSrjs * Huh, need the correct STR here, they 13288c2654abSrjs * must be the same. 13298c2654abSrjs */ 13308c2654abSrjs #ifdef SCTP_DEBUG 13318c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 13328c2654abSrjs printf("Prev check - Gak, Evil plot, sseq:%d not the same as at:%d\n", 13338c2654abSrjs chk->rec.data.stream_seq, 13348c2654abSrjs prev->rec.data.stream_seq); 13358c2654abSrjs } 13368c2654abSrjs #endif 13378c2654abSrjs MGET(oper, M_DONTWAIT, MT_DATA); 13388c2654abSrjs if (oper) { 13398c2654abSrjs struct sctp_paramhdr *ph; 13408c2654abSrjs u_int32_t *ippp; 13418c2654abSrjs 13428c2654abSrjs oper->m_len = 13438c2654abSrjs sizeof(struct sctp_paramhdr) + 13448c2654abSrjs sizeof(*ippp); 13458c2654abSrjs ph = mtod(oper, 13468c2654abSrjs struct sctp_paramhdr *); 13478c2654abSrjs ph->param_type = 13488c2654abSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 13498c2654abSrjs ph->param_length = 13508c2654abSrjs htons(oper->m_len); 13518c2654abSrjs ippp = (u_int32_t *)(ph + 1); 13528c2654abSrjs *ippp = htonl(0x10000007); 13538c2654abSrjs } 13548c2654abSrjs 13558c2654abSrjs sctp_abort_an_association(stcb->sctp_ep, 13568c2654abSrjs stcb, SCTP_PEER_FAULTY, oper); 13578c2654abSrjs 13588c2654abSrjs *abort_flag = 1; 13598c2654abSrjs return; 13608c2654abSrjs } 13618c2654abSrjs } else if ((prev->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) == 13628c2654abSrjs SCTP_DATA_LAST_FRAG) { 13638c2654abSrjs /* Insert chk MUST be a FIRST */ 13648c2654abSrjs if ((chk->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) != 13658c2654abSrjs SCTP_DATA_FIRST_FRAG) { 13668c2654abSrjs #ifdef SCTP_DEBUG 13678c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 13688c2654abSrjs printf("Prev check - Gak, evil plot, its not FIRST and it must be!\n"); 13698c2654abSrjs } 13708c2654abSrjs #endif 13718c2654abSrjs MGET(oper, M_DONTWAIT, MT_DATA); 13728c2654abSrjs if (oper) { 13738c2654abSrjs struct sctp_paramhdr *ph; 13748c2654abSrjs u_int32_t *ippp; 13758c2654abSrjs 13768c2654abSrjs oper->m_len = 13778c2654abSrjs sizeof(struct sctp_paramhdr) + 13788c2654abSrjs sizeof(*ippp); 13798c2654abSrjs ph = mtod(oper, 13808c2654abSrjs struct sctp_paramhdr *); 13818c2654abSrjs ph->param_type = 13828c2654abSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 13838c2654abSrjs ph->param_length = 13848c2654abSrjs htons(oper->m_len); 13858c2654abSrjs ippp = (u_int32_t *)(ph + 1); 13868c2654abSrjs *ippp = htonl(0x10000008); 13878c2654abSrjs } 13888c2654abSrjs 13898c2654abSrjs sctp_abort_an_association(stcb->sctp_ep, 13908c2654abSrjs stcb, SCTP_PEER_FAULTY, oper); 13918c2654abSrjs 13928c2654abSrjs *abort_flag = 1; 13938c2654abSrjs return; 13948c2654abSrjs } 13958c2654abSrjs } 13968c2654abSrjs } 13978c2654abSrjs } 13988c2654abSrjs 13998c2654abSrjs if (next) { 14008c2654abSrjs post_tsn = chk->rec.data.TSN_seq + 1; 14018c2654abSrjs if (post_tsn == next->rec.data.TSN_seq) { 14028c2654abSrjs /* 14038c2654abSrjs * Ok the one I am inserting ahead of 14048c2654abSrjs * is my NEXT one. A bit of valdiation here. 14058c2654abSrjs */ 14068c2654abSrjs if (next->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { 14078c2654abSrjs /* Insert chk MUST be a last fragment */ 14088c2654abSrjs if ((chk->rec.data.rcv_flags&SCTP_DATA_FRAG_MASK) 14098c2654abSrjs != SCTP_DATA_LAST_FRAG) { 14108c2654abSrjs #ifdef SCTP_DEBUG 14118c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 14128c2654abSrjs printf("Next chk - Next is FIRST, we must be LAST\n"); 14138c2654abSrjs printf("Gak, Evil plot, its not a last!\n"); 14148c2654abSrjs } 14158c2654abSrjs #endif 14168c2654abSrjs MGET(oper, M_DONTWAIT, MT_DATA); 14178c2654abSrjs if (oper) { 14188c2654abSrjs struct sctp_paramhdr *ph; 14198c2654abSrjs u_int32_t *ippp; 14208c2654abSrjs 14218c2654abSrjs oper->m_len = 14228c2654abSrjs sizeof(struct sctp_paramhdr) + 14238c2654abSrjs sizeof(*ippp); 14248c2654abSrjs ph = mtod(oper, 14258c2654abSrjs struct sctp_paramhdr *); 14268c2654abSrjs ph->param_type = 14278c2654abSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 14288c2654abSrjs ph->param_length = 14298c2654abSrjs htons(oper->m_len); 14308c2654abSrjs ippp = (u_int32_t *)(ph + 1); 14318c2654abSrjs *ippp = htonl(0x10000009); 14328c2654abSrjs } 14338c2654abSrjs 14348c2654abSrjs sctp_abort_an_association(stcb->sctp_ep, 14358c2654abSrjs stcb, SCTP_PEER_FAULTY, oper); 14368c2654abSrjs 14378c2654abSrjs *abort_flag = 1; 14388c2654abSrjs return; 14398c2654abSrjs } 14408c2654abSrjs } else if ((next->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) == 14418c2654abSrjs SCTP_DATA_MIDDLE_FRAG || 14428c2654abSrjs (next->rec.data.rcv_flags&SCTP_DATA_FRAG_MASK) == 14438c2654abSrjs SCTP_DATA_LAST_FRAG) { 14448c2654abSrjs /* Insert chk CAN be MIDDLE or FIRST NOT LAST */ 14458c2654abSrjs if ((chk->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) == 14468c2654abSrjs SCTP_DATA_LAST_FRAG) { 14478c2654abSrjs #ifdef SCTP_DEBUG 14488c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 14498c2654abSrjs printf("Next chk - Next is a MIDDLE/LAST\n"); 14508c2654abSrjs printf("Gak, Evil plot, new prev chunk is a LAST\n"); 14518c2654abSrjs } 14528c2654abSrjs #endif 14538c2654abSrjs MGET(oper, M_DONTWAIT, MT_DATA); 14548c2654abSrjs if (oper) { 14558c2654abSrjs struct sctp_paramhdr *ph; 14568c2654abSrjs u_int32_t *ippp; 14578c2654abSrjs 14588c2654abSrjs oper->m_len = 14598c2654abSrjs sizeof(struct sctp_paramhdr) + 14608c2654abSrjs sizeof(*ippp); 14618c2654abSrjs ph = mtod(oper, 14628c2654abSrjs struct sctp_paramhdr *); 14638c2654abSrjs ph->param_type = 14648c2654abSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 14658c2654abSrjs ph->param_length = 14668c2654abSrjs htons(oper->m_len); 14678c2654abSrjs ippp = (u_int32_t *)(ph + 1); 14688c2654abSrjs *ippp = htonl(0x1000000a); 14698c2654abSrjs } 14708c2654abSrjs sctp_abort_an_association(stcb->sctp_ep, 14718c2654abSrjs stcb, SCTP_PEER_FAULTY, oper); 14728c2654abSrjs 14738c2654abSrjs *abort_flag = 1; 14748c2654abSrjs return; 14758c2654abSrjs } 14768c2654abSrjs if (chk->rec.data.stream_number != 14778c2654abSrjs next->rec.data.stream_number) { 14788c2654abSrjs /* 14798c2654abSrjs * Huh, need the correct STR here, they 14808c2654abSrjs * must be the same. 14818c2654abSrjs */ 14828c2654abSrjs #ifdef SCTP_DEBUG 14838c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 14848c2654abSrjs printf("Next chk - Gak, Evil plot, ssn:%d not the same as at:%d\n", 14858c2654abSrjs chk->rec.data.stream_number, 14868c2654abSrjs next->rec.data.stream_number); 14878c2654abSrjs } 14888c2654abSrjs #endif 14898c2654abSrjs MGET(oper, M_DONTWAIT, MT_DATA); 14908c2654abSrjs if (oper) { 14918c2654abSrjs struct sctp_paramhdr *ph; 14928c2654abSrjs u_int32_t *ippp; 14938c2654abSrjs 14948c2654abSrjs oper->m_len = 14958c2654abSrjs sizeof(struct sctp_paramhdr) + 14968c2654abSrjs sizeof(*ippp); 14978c2654abSrjs ph = mtod(oper, 14988c2654abSrjs struct sctp_paramhdr *); 14998c2654abSrjs ph->param_type = 15008c2654abSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 15018c2654abSrjs ph->param_length = 15028c2654abSrjs htons(oper->m_len); 15038c2654abSrjs ippp = (u_int32_t *)(ph + 1); 15048c2654abSrjs *ippp = htonl(0x1000000b); 15058c2654abSrjs } 15068c2654abSrjs 15078c2654abSrjs sctp_abort_an_association(stcb->sctp_ep, 15088c2654abSrjs stcb, SCTP_PEER_FAULTY, oper); 15098c2654abSrjs 15108c2654abSrjs *abort_flag = 1; 15118c2654abSrjs return; 15128c2654abSrjs } 15138c2654abSrjs if ((next->rec.data.rcv_flags & SCTP_DATA_UNORDERED) == 0 && 15148c2654abSrjs chk->rec.data.stream_seq != 15158c2654abSrjs next->rec.data.stream_seq) { 15168c2654abSrjs /* 15178c2654abSrjs * Huh, need the correct STR here, they 15188c2654abSrjs * must be the same. 15198c2654abSrjs */ 15208c2654abSrjs #ifdef SCTP_DEBUG 15218c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 15228c2654abSrjs printf("Next chk - Gak, Evil plot, sseq:%d not the same as at:%d\n", 15238c2654abSrjs chk->rec.data.stream_seq, 15248c2654abSrjs next->rec.data.stream_seq); 15258c2654abSrjs } 15268c2654abSrjs #endif 15278c2654abSrjs MGET(oper, M_DONTWAIT, MT_DATA); 15288c2654abSrjs if (oper) { 15298c2654abSrjs struct sctp_paramhdr *ph; 15308c2654abSrjs u_int32_t *ippp; 15318c2654abSrjs 15328c2654abSrjs oper->m_len = 15338c2654abSrjs sizeof(struct sctp_paramhdr) + 15348c2654abSrjs sizeof(*ippp); 15358c2654abSrjs ph = mtod(oper, 15368c2654abSrjs struct sctp_paramhdr *); 15378c2654abSrjs ph->param_type = 15388c2654abSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 15398c2654abSrjs ph->param_length = 15408c2654abSrjs htons(oper->m_len); 15418c2654abSrjs ippp = (u_int32_t *)(ph + 1); 15428c2654abSrjs *ippp = htonl(0x1000000c); 15438c2654abSrjs } 15448c2654abSrjs 15458c2654abSrjs sctp_abort_an_association(stcb->sctp_ep, 15468c2654abSrjs stcb, SCTP_PEER_FAULTY, oper); 15478c2654abSrjs 15488c2654abSrjs *abort_flag = 1; 15498c2654abSrjs return; 15508c2654abSrjs 15518c2654abSrjs } 15528c2654abSrjs } 15538c2654abSrjs } 15548c2654abSrjs } 15558c2654abSrjs /* 15568c2654abSrjs * now that we have all in there place we must check a number of 15578c2654abSrjs * things to see if we can send data to the ULP. 15588c2654abSrjs */ 15598c2654abSrjs /* we need to do some delivery, if we can */ 15608c2654abSrjs chk = TAILQ_FIRST(&asoc->reasmqueue); 15618c2654abSrjs if (chk == NULL) { 15628c2654abSrjs /* Huh? */ 15638c2654abSrjs asoc->size_on_reasm_queue = 0; 15648c2654abSrjs asoc->cnt_on_reasm_queue = 0; 15658c2654abSrjs return; 15668c2654abSrjs } 15678c2654abSrjs if (asoc->fragmented_delivery_inprogress == 0) { 15688c2654abSrjs nxt_todel = 15698c2654abSrjs asoc->strmin[chk->rec.data.stream_number].last_sequence_delivered + 1; 15708c2654abSrjs if ((chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) && 15718c2654abSrjs (nxt_todel == chk->rec.data.stream_seq || 15728c2654abSrjs (chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED))) { 15738c2654abSrjs /* 15748c2654abSrjs * Yep the first one is here and its 15758c2654abSrjs * ok to deliver but should we? 15768c2654abSrjs */ 15778c2654abSrjs if (TAILQ_EMPTY(&asoc->delivery_queue) && 15788c2654abSrjs (sctp_is_all_msg_on_reasm(asoc, &tsize) || 15798c2654abSrjs (asoc->size_on_reasm_queue >= 15808c2654abSrjs (stcb->sctp_socket->so_rcv.sb_hiwat >> 2) && 15818c2654abSrjs tsize))) { 15828c2654abSrjs /* 15838c2654abSrjs * Yes, we setup to 15848c2654abSrjs * start reception, by backing down the TSN 15858c2654abSrjs * just in case we can't deliver. If we 15868c2654abSrjs */ 15878c2654abSrjs asoc->fragmented_delivery_inprogress = 1; 15888c2654abSrjs asoc->tsn_last_delivered = 15898c2654abSrjs chk->rec.data.TSN_seq - 1; 15908c2654abSrjs asoc->str_of_pdapi = 15918c2654abSrjs chk->rec.data.stream_number; 15928c2654abSrjs asoc->ssn_of_pdapi = chk->rec.data.stream_seq; 15938c2654abSrjs asoc->fragment_flags = chk->rec.data.rcv_flags; 15948c2654abSrjs sctp_service_reassembly(stcb, asoc, 0); 15958c2654abSrjs } 15968c2654abSrjs } 15978c2654abSrjs } else { 15988c2654abSrjs sctp_service_reassembly(stcb, asoc, 0); 15998c2654abSrjs } 16008c2654abSrjs } 16018c2654abSrjs 16028c2654abSrjs /* 16038c2654abSrjs * This is an unfortunate routine. It checks to make sure a evil guy is not 16048c2654abSrjs * stuffing us full of bad packet fragments. A broken peer could also do this 16058c2654abSrjs * but this is doubtful. It is to bad I must worry about evil crackers sigh 16068c2654abSrjs * :< more cycles. 16078c2654abSrjs */ 16088c2654abSrjs static int 16098c2654abSrjs sctp_does_chk_belong_to_reasm(struct sctp_association *asoc, 16108c2654abSrjs struct sctp_tmit_chunk *chk) 16118c2654abSrjs { 16128c2654abSrjs struct sctp_tmit_chunk *at; 16138c2654abSrjs u_int32_t tsn_est; 16148c2654abSrjs 16158c2654abSrjs TAILQ_FOREACH(at, &asoc->reasmqueue, sctp_next) { 16168c2654abSrjs if (compare_with_wrap(chk->rec.data.TSN_seq, 16178c2654abSrjs at->rec.data.TSN_seq, MAX_TSN)) { 16188c2654abSrjs /* is it one bigger? */ 16198c2654abSrjs tsn_est = at->rec.data.TSN_seq + 1; 16208c2654abSrjs if (tsn_est == chk->rec.data.TSN_seq) { 16218c2654abSrjs /* yep. It better be a last then*/ 16228c2654abSrjs if ((at->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) != 16238c2654abSrjs SCTP_DATA_LAST_FRAG) { 16248c2654abSrjs /* 16258c2654abSrjs * Ok this guy belongs next to a guy 16268c2654abSrjs * that is NOT last, it should be a 16278c2654abSrjs * middle/last, not a complete chunk. 16288c2654abSrjs */ 16298c2654abSrjs return (1); 16308c2654abSrjs } else { 16318c2654abSrjs /* 16328c2654abSrjs * This guy is ok since its a LAST and 16338c2654abSrjs * the new chunk is a fully self- 16348c2654abSrjs * contained one. 16358c2654abSrjs */ 16368c2654abSrjs return (0); 16378c2654abSrjs } 16388c2654abSrjs } 16398c2654abSrjs } else if (chk->rec.data.TSN_seq == at->rec.data.TSN_seq) { 16408c2654abSrjs /* Software error since I have a dup? */ 16418c2654abSrjs return (1); 16428c2654abSrjs } else { 16438c2654abSrjs /* 16448c2654abSrjs * Ok, 'at' is larger than new chunk but does it 16458c2654abSrjs * need to be right before it. 16468c2654abSrjs */ 16478c2654abSrjs tsn_est = chk->rec.data.TSN_seq + 1; 16488c2654abSrjs if (tsn_est == at->rec.data.TSN_seq) { 16498c2654abSrjs /* Yep, It better be a first */ 16508c2654abSrjs if ((at->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) != 16518c2654abSrjs SCTP_DATA_FIRST_FRAG) { 16528c2654abSrjs return (1); 16538c2654abSrjs } else { 16548c2654abSrjs return (0); 16558c2654abSrjs } 16568c2654abSrjs } 16578c2654abSrjs } 16588c2654abSrjs } 16598c2654abSrjs return (0); 16608c2654abSrjs } 16618c2654abSrjs 16628c2654abSrjs extern unsigned int sctp_max_chunks_on_queue; 16638c2654abSrjs static int 16648c2654abSrjs sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, 16658c2654abSrjs struct mbuf **m, int offset, struct sctp_data_chunk *ch, int chk_length, 16668c2654abSrjs struct sctp_nets *net, u_int32_t *high_tsn, int *abort_flag, 16678c2654abSrjs int *break_flag, int last_chunk) 16688c2654abSrjs { 16698c2654abSrjs /* Process a data chunk */ 16708c2654abSrjs /* struct sctp_tmit_chunk *chk;*/ 16718c2654abSrjs struct sctp_tmit_chunk *chk; 16728c2654abSrjs u_int32_t tsn, gap; 16738c2654abSrjs struct mbuf *dmbuf; 16748c2654abSrjs int the_len; 16758c2654abSrjs u_int16_t strmno, strmseq; 16768c2654abSrjs struct mbuf *oper; 16778c2654abSrjs 16788c2654abSrjs chk = NULL; 16798c2654abSrjs tsn = ntohl(ch->dp.tsn); 16808c2654abSrjs #ifdef SCTP_MAP_LOGGING 16818c2654abSrjs sctp_log_map(0, tsn, asoc->cumulative_tsn, SCTP_MAP_PREPARE_SLIDE); 16828c2654abSrjs #endif 16838c2654abSrjs if (compare_with_wrap(asoc->cumulative_tsn, tsn, MAX_TSN) || 16848c2654abSrjs asoc->cumulative_tsn == tsn) { 16858c2654abSrjs /* It is a duplicate */ 16868c2654abSrjs sctp_pegs[SCTP_DUPTSN_RECVD]++; 16878c2654abSrjs if (asoc->numduptsns < SCTP_MAX_DUP_TSNS) { 16888c2654abSrjs /* Record a dup for the next outbound sack */ 16898c2654abSrjs asoc->dup_tsns[asoc->numduptsns] = tsn; 16908c2654abSrjs asoc->numduptsns++; 16918c2654abSrjs } 16928c2654abSrjs return (0); 16938c2654abSrjs } 16948c2654abSrjs /* Calculate the number of TSN's between the base and this TSN */ 16958c2654abSrjs if (tsn >= asoc->mapping_array_base_tsn) { 16968c2654abSrjs gap = tsn - asoc->mapping_array_base_tsn; 16978c2654abSrjs } else { 16988c2654abSrjs gap = (MAX_TSN - asoc->mapping_array_base_tsn) + tsn + 1; 16998c2654abSrjs } 17008c2654abSrjs if (gap >= (SCTP_MAPPING_ARRAY << 3)) { 17018c2654abSrjs /* Can't hold the bit in the mapping at max array, toss it */ 17028c2654abSrjs return (0); 17038c2654abSrjs } 17048c2654abSrjs if (gap >= (uint32_t)(asoc->mapping_array_size << 3)) { 17058c2654abSrjs if (sctp_expand_mapping_array(asoc)) { 17068c2654abSrjs /* Can't expand, drop it */ 17078c2654abSrjs return (0); 17088c2654abSrjs } 17098c2654abSrjs } 17108c2654abSrjs if (compare_with_wrap(tsn, *high_tsn, MAX_TSN)) { 17118c2654abSrjs *high_tsn = tsn; 17128c2654abSrjs } 17138c2654abSrjs /* See if we have received this one already */ 17148c2654abSrjs if (SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap)) { 17158c2654abSrjs sctp_pegs[SCTP_DUPTSN_RECVD]++; 17168c2654abSrjs if (asoc->numduptsns < SCTP_MAX_DUP_TSNS) { 17178c2654abSrjs /* Record a dup for the next outbound sack */ 17188c2654abSrjs asoc->dup_tsns[asoc->numduptsns] = tsn; 17198c2654abSrjs asoc->numduptsns++; 17208c2654abSrjs } 17218c2654abSrjs if (!callout_pending(&asoc->dack_timer.timer)) { 17228c2654abSrjs /* 17238c2654abSrjs * By starting the timer we assure that we 17248c2654abSrjs * WILL sack at the end of the packet 17258c2654abSrjs * when sctp_sack_check gets called. 17268c2654abSrjs */ 17278c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, 17288c2654abSrjs stcb, NULL); 17298c2654abSrjs } 17308c2654abSrjs return (0); 17318c2654abSrjs } 17328c2654abSrjs /* 17338c2654abSrjs * Check to see about the GONE flag, duplicates would cause 17348c2654abSrjs * a sack to be sent up above 17358c2654abSrjs */ 17368c2654abSrjs if (stcb && (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 17378c2654abSrjs /* 17388c2654abSrjs * wait a minute, this guy is gone, there is no 17398c2654abSrjs * longer a receiver. Send peer an ABORT! 17408c2654abSrjs */ 17418c2654abSrjs struct mbuf *op_err; 17428c2654abSrjs op_err = sctp_generate_invmanparam(SCTP_CAUSE_OUT_OF_RESC); 17438c2654abSrjs sctp_abort_an_association(stcb->sctp_ep, stcb, 0, op_err); 17448c2654abSrjs *abort_flag = 1; 17458c2654abSrjs return (0); 17468c2654abSrjs } 17478c2654abSrjs /* 17488c2654abSrjs * Now before going further we see if there is room. If NOT then 17498c2654abSrjs * we MAY let one through only IF this TSN is the one we are 17508c2654abSrjs * waiting for on a partial delivery API. 17518c2654abSrjs */ 17528c2654abSrjs 17538c2654abSrjs /* now do the tests */ 17548c2654abSrjs if (((asoc->cnt_on_all_streams + 17558c2654abSrjs asoc->cnt_on_delivery_queue + 17568c2654abSrjs asoc->cnt_on_reasm_queue + 17578c2654abSrjs asoc->cnt_msg_on_sb) > sctp_max_chunks_on_queue) || 17588c2654abSrjs (((int)asoc->my_rwnd) <= 0)) { 17598c2654abSrjs /* 17608c2654abSrjs * When we have NO room in the rwnd we check 17618c2654abSrjs * to make sure the reader is doing its job... 17628c2654abSrjs */ 17638c2654abSrjs if (stcb->sctp_socket->so_rcv.sb_cc) { 17648c2654abSrjs /* some to read, wake-up */ 17658c2654abSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 17668c2654abSrjs } 17678c2654abSrjs /* now is it in the mapping array of what we have accepted? */ 17688c2654abSrjs if (compare_with_wrap(tsn, 17698c2654abSrjs asoc->highest_tsn_inside_map, MAX_TSN)) { 17708c2654abSrjs 17718c2654abSrjs /* Nope not in the valid range dump it */ 17728c2654abSrjs #ifdef SCTP_DEBUG 17738c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 17748c2654abSrjs printf("My rwnd overrun1:tsn:%lx rwnd %lu sbspace:%ld delq:%d!\n", 17758c2654abSrjs (u_long)tsn, (u_long)asoc->my_rwnd, 17768c2654abSrjs sctp_sbspace(&stcb->sctp_socket->so_rcv), 17778c2654abSrjs stcb->asoc.cnt_on_delivery_queue); 17788c2654abSrjs } 17798c2654abSrjs #endif 17808c2654abSrjs sctp_set_rwnd(stcb, asoc); 17818c2654abSrjs if ((asoc->cnt_on_all_streams + 17828c2654abSrjs asoc->cnt_on_delivery_queue + 17838c2654abSrjs asoc->cnt_on_reasm_queue + 17848c2654abSrjs asoc->cnt_msg_on_sb) > sctp_max_chunks_on_queue) { 17858c2654abSrjs sctp_pegs[SCTP_MSGC_DROP]++; 17868c2654abSrjs } else { 17878c2654abSrjs sctp_pegs[SCTP_RWND_DROPS]++; 17888c2654abSrjs } 17898c2654abSrjs *break_flag = 1; 17908c2654abSrjs return (0); 17918c2654abSrjs } 17928c2654abSrjs } 17938c2654abSrjs strmno = ntohs(ch->dp.stream_id); 17948c2654abSrjs if (strmno >= asoc->streamincnt) { 17958c2654abSrjs struct sctp_paramhdr *phdr; 17968c2654abSrjs struct mbuf *mb; 17978c2654abSrjs 17988c2654abSrjs MGETHDR(mb, M_DONTWAIT, MT_DATA); 17998c2654abSrjs if (mb != NULL) { 18008c2654abSrjs /* add some space up front so prepend will work well */ 18018c2654abSrjs mb->m_data += sizeof(struct sctp_chunkhdr); 18028c2654abSrjs phdr = mtod(mb, struct sctp_paramhdr *); 18038c2654abSrjs /* 18048c2654abSrjs * Error causes are just param's and this one has 18058c2654abSrjs * two back to back phdr, one with the error type 18068c2654abSrjs * and size, the other with the streamid and a rsvd 18078c2654abSrjs */ 18088c2654abSrjs mb->m_pkthdr.len = mb->m_len = 18098c2654abSrjs (sizeof(struct sctp_paramhdr) * 2); 18108c2654abSrjs phdr->param_type = htons(SCTP_CAUSE_INV_STRM); 18118c2654abSrjs phdr->param_length = 18128c2654abSrjs htons(sizeof(struct sctp_paramhdr) * 2); 18138c2654abSrjs phdr++; 18148c2654abSrjs /* We insert the stream in the type field */ 18158c2654abSrjs phdr->param_type = ch->dp.stream_id; 18168c2654abSrjs /* And set the length to 0 for the rsvd field */ 18178c2654abSrjs phdr->param_length = 0; 18188c2654abSrjs sctp_queue_op_err(stcb, mb); 18198c2654abSrjs } 18208c2654abSrjs sctp_pegs[SCTP_BAD_STRMNO]++; 18218c2654abSrjs return (0); 18228c2654abSrjs } 18238c2654abSrjs /* 18248c2654abSrjs * Before we continue lets validate that we are not 18258c2654abSrjs * being fooled by an evil attacker. We can only 18268c2654abSrjs * have 4k chunks based on our TSN spread allowed 18278c2654abSrjs * by the mapping array 512 * 8 bits, so there is 18288c2654abSrjs * no way our stream sequence numbers could have wrapped. 18298c2654abSrjs * We of course only validate the FIRST fragment so the 18308c2654abSrjs * bit must be set. 18318c2654abSrjs */ 18328c2654abSrjs strmseq = ntohs(ch->dp.stream_sequence); 18338c2654abSrjs if ((ch->ch.chunk_flags & SCTP_DATA_FIRST_FRAG) && 18348c2654abSrjs (ch->ch.chunk_flags & SCTP_DATA_UNORDERED) == 0 && 18358c2654abSrjs (compare_with_wrap(asoc->strmin[strmno].last_sequence_delivered, 18368c2654abSrjs strmseq, MAX_SEQ) || 18378c2654abSrjs asoc->strmin[strmno].last_sequence_delivered == strmseq)) { 18388c2654abSrjs /* The incoming sseq is behind where we last delivered? */ 18398c2654abSrjs #ifdef SCTP_DEBUG 18408c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 18418c2654abSrjs printf("EVIL/Broken-Dup S-SEQ:%d delivered:%d from peer, Abort!\n", 18428c2654abSrjs strmseq, 18438c2654abSrjs asoc->strmin[strmno].last_sequence_delivered); 18448c2654abSrjs } 18458c2654abSrjs #endif 18468c2654abSrjs /* 18478c2654abSrjs * throw it in the stream so it gets cleaned up in 18488c2654abSrjs * association destruction 18498c2654abSrjs */ 18508c2654abSrjs MGET(oper, M_DONTWAIT, MT_DATA); 18518c2654abSrjs if (oper) { 18528c2654abSrjs struct sctp_paramhdr *ph; 18538c2654abSrjs u_int32_t *ippp; 18548c2654abSrjs 18558c2654abSrjs oper->m_len = sizeof(struct sctp_paramhdr) + 18568c2654abSrjs sizeof(*ippp); 18578c2654abSrjs ph = mtod(oper, struct sctp_paramhdr *); 18588c2654abSrjs ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 18598c2654abSrjs ph->param_length = htons(oper->m_len); 18608c2654abSrjs ippp = (u_int32_t *)(ph + 1); 18618c2654abSrjs *ippp = htonl(0x20000001); 18628c2654abSrjs } 18638c2654abSrjs sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, 18648c2654abSrjs oper); 18658c2654abSrjs sctp_pegs[SCTP_BAD_SSN_WRAP]++; 18668c2654abSrjs *abort_flag = 1; 18678c2654abSrjs return (0); 18688c2654abSrjs } 18698c2654abSrjs 18708c2654abSrjs the_len = (chk_length-sizeof(struct sctp_data_chunk)); 18718c2654abSrjs if (last_chunk == 0) { 18728c2654abSrjs dmbuf = sctp_m_copym(*m, 18738c2654abSrjs (offset + sizeof(struct sctp_data_chunk)), 18748c2654abSrjs the_len, M_DONTWAIT); 18758c2654abSrjs } else { 18768c2654abSrjs /* We can steal the last chunk */ 18778c2654abSrjs dmbuf = *m; 18788c2654abSrjs /* lop off the top part */ 18798c2654abSrjs m_adj(dmbuf, (offset + sizeof(struct sctp_data_chunk))); 18808c2654abSrjs if (dmbuf->m_pkthdr.len > the_len) { 18818c2654abSrjs /* Trim the end round bytes off too */ 18828c2654abSrjs m_adj(dmbuf, -(dmbuf->m_pkthdr.len-the_len)); 18838c2654abSrjs } 18848c2654abSrjs sctp_pegs[SCTP_NO_COPY_IN]++; 18858c2654abSrjs } 18868c2654abSrjs if (dmbuf == NULL) { 18878c2654abSrjs sctp_pegs[SCTP_DROP_NOMEMORY]++; 18888c2654abSrjs return (0); 18898c2654abSrjs } 18908c2654abSrjs if ((ch->ch.chunk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG && 18918c2654abSrjs asoc->fragmented_delivery_inprogress == 0 && 18928c2654abSrjs TAILQ_EMPTY(&asoc->delivery_queue) && 18938c2654abSrjs ((ch->ch.chunk_flags & SCTP_DATA_UNORDERED) || 18948c2654abSrjs ((asoc->strmin[strmno].last_sequence_delivered + 1) == strmseq && 18958c2654abSrjs TAILQ_EMPTY(&asoc->strmin[strmno].inqueue))) && 18968c2654abSrjs ((long)(stcb->sctp_socket->so_rcv.sb_hiwat - 18978c2654abSrjs stcb->sctp_socket->so_rcv.sb_cc) >= (long)the_len)) { 18988c2654abSrjs /* Candidate for express delivery */ 18998c2654abSrjs /* 19008c2654abSrjs * Its not fragmented, 19018c2654abSrjs * No PD-API is up, 19028c2654abSrjs * Nothing in the delivery queue, 19038c2654abSrjs * Its un-ordered OR ordered and the next to deliver AND 19048c2654abSrjs * nothing else is stuck on the stream queue, 19058c2654abSrjs * And there is room for it in the socket buffer. 19068c2654abSrjs * Lets just stuff it up the buffer.... 19078c2654abSrjs */ 19088c2654abSrjs 19098c2654abSrjs struct mbuf *control, *mmm; 19108c2654abSrjs struct sockaddr_in6 sin6; 19118c2654abSrjs struct sockaddr_in6 lsa6; 19128c2654abSrjs const struct sockaddr *to; 19138c2654abSrjs 19148c2654abSrjs /* It would be nice to avoid this copy if we could :< */ 19158c2654abSrjs control = sctp_build_ctl_nchunk(stcb, tsn, 19168c2654abSrjs ch->dp.protocol_id, 0, strmno, strmseq, 19178c2654abSrjs ch->ch.chunk_flags); 19188c2654abSrjs /* XXX need to append PKTHDR to the socket buffer first */ 19198c2654abSrjs 19208c2654abSrjs if ((dmbuf->m_flags & M_PKTHDR) == 0) { 19218c2654abSrjs struct mbuf *tmp; 19228c2654abSrjs MGETHDR(tmp, M_DONTWAIT, MT_DATA); 19238c2654abSrjs if (tmp == NULL) { 19248c2654abSrjs 19258c2654abSrjs /* no room! */ 19268c2654abSrjs if (control) { 19278c2654abSrjs sctp_m_freem(control); 19288c2654abSrjs stcb->asoc.my_rwnd_control_len -= 19298c2654abSrjs CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 19308c2654abSrjs } 19318c2654abSrjs 19328c2654abSrjs goto failed_express_del; 19338c2654abSrjs } 19348c2654abSrjs tmp->m_pkthdr.len = the_len; 19358c2654abSrjs tmp->m_len = 0; 19368c2654abSrjs tmp->m_next = dmbuf; 19378c2654abSrjs dmbuf = tmp; 19388c2654abSrjs } 19398c2654abSrjs to = rtcache_getdst(&net->ro); 19408c2654abSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) && 19418c2654abSrjs to->sa_family == AF_INET) { 19428c2654abSrjs const struct sockaddr_in *sin; 19438c2654abSrjs 19448c2654abSrjs sin = satocsin(to); 19450a0528fdSrtr in6_sin_2_v4mapsin6(sin, &sin6); 19468c2654abSrjs to = (struct sockaddr *)&sin6; 19478c2654abSrjs } 19488c2654abSrjs 19498c2654abSrjs /* check and strip embedded scope junk */ 19508c2654abSrjs to = (const struct sockaddr *)sctp_recover_scope((const struct sockaddr_in6 *)to, 19518c2654abSrjs &lsa6); 19528c2654abSrjs if (((const struct sockaddr_in *)to)->sin_port == 0) { 19538c2654abSrjs printf("Huh c, port is %d not net:%p %d?\n", 19548c2654abSrjs ((const struct sockaddr_in *)to)->sin_port, 19558c2654abSrjs net, 19568c2654abSrjs (int)(ntohs(stcb->rport))); 19578c2654abSrjs /*((struct sockaddr_in *)to)->sin_port = stcb->rport;*/ 19588c2654abSrjs /* XXX */ 19598c2654abSrjs } 19608c2654abSrjs 19618c2654abSrjs mmm = dmbuf; 19628c2654abSrjs /* Mark the EOR */ 19638c2654abSrjs while (mmm->m_next != NULL) { 19648c2654abSrjs mmm = mmm->m_next; 19658c2654abSrjs } 19668c2654abSrjs mmm->m_flags |= M_EOR; 19678c2654abSrjs if (compare_with_wrap(tsn, asoc->highest_tsn_inside_map, MAX_TSN)) { 19688c2654abSrjs /* we have a new high score */ 19698c2654abSrjs asoc->highest_tsn_inside_map = tsn; 19708c2654abSrjs #ifdef SCTP_MAP_LOGGING 19718c2654abSrjs sctp_log_map(0, 1, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT); 19728c2654abSrjs #endif 19738c2654abSrjs } 19748c2654abSrjs SCTP_TCB_UNLOCK(stcb); 19758c2654abSrjs SCTP_INP_WLOCK(stcb->sctp_ep); 19768c2654abSrjs SCTP_TCB_LOCK(stcb); 19778c2654abSrjs if (!sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv, to, dmbuf, 19788c2654abSrjs control, stcb->asoc.my_vtag, stcb->sctp_ep)) { 19798c2654abSrjs if (control) { 19808c2654abSrjs sctp_m_freem(control); 19818c2654abSrjs stcb->asoc.my_rwnd_control_len -= 19828c2654abSrjs CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 19838c2654abSrjs } 19848c2654abSrjs sctp_m_freem(dmbuf); 19858c2654abSrjs goto failed_express_del; 19868c2654abSrjs } 19878c2654abSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) { 19888c2654abSrjs if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) { 19898c2654abSrjs stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf); 19908c2654abSrjs } 19918c2654abSrjs } else { 19928c2654abSrjs stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf); 19938c2654abSrjs } 19948c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep); 19958c2654abSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 19968c2654abSrjs if ((ch->ch.chunk_flags & SCTP_DATA_UNORDERED) == 0) { 19978c2654abSrjs 19988c2654abSrjs /* for ordered, bump what we delivered */ 19998c2654abSrjs asoc->strmin[strmno].last_sequence_delivered++; 20008c2654abSrjs } 20018c2654abSrjs sctp_pegs[SCTP_EXPRESS_ROUTE]++; 20028c2654abSrjs #ifdef SCTP_STR_LOGGING 20038c2654abSrjs sctp_log_strm_del_alt(tsn, strmseq, 20048c2654abSrjs SCTP_STR_LOG_FROM_EXPRS_DEL); 20058c2654abSrjs #endif 20068c2654abSrjs #ifdef SCTP_DEBUG 20078c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 20088c2654abSrjs printf("Express Delivery succeeds\n"); 20098c2654abSrjs } 20108c2654abSrjs #endif 20118c2654abSrjs goto finish_express_del; 20128c2654abSrjs } 20138c2654abSrjs 20148c2654abSrjs failed_express_del: 20158c2654abSrjs /* If we reach here this is a new chunk */ 20168c2654abSrjs chk = (struct sctp_tmit_chunk *)SCTP_ZONE_GET(sctppcbinfo.ipi_zone_chunk); 20178c2654abSrjs if (chk == NULL) { 20188c2654abSrjs /* No memory so we drop the chunk */ 20198c2654abSrjs sctp_pegs[SCTP_DROP_NOMEMORY]++; 20208c2654abSrjs if (last_chunk == 0) { 20218c2654abSrjs /* we copied it, free the copy */ 20228c2654abSrjs sctp_m_freem(dmbuf); 20238c2654abSrjs } 20248c2654abSrjs return (0); 20258c2654abSrjs } 20268c2654abSrjs sctppcbinfo.ipi_count_chunk++; 20278c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++; 20288c2654abSrjs chk->rec.data.TSN_seq = tsn; 20298c2654abSrjs chk->rec.data.stream_seq = strmseq; 20308c2654abSrjs chk->rec.data.stream_number = strmno; 20318c2654abSrjs chk->rec.data.payloadtype = ch->dp.protocol_id; 20328c2654abSrjs chk->rec.data.context = 0; 20338c2654abSrjs chk->rec.data.doing_fast_retransmit = 0; 20348c2654abSrjs chk->rec.data.rcv_flags = ch->ch.chunk_flags; 20358c2654abSrjs chk->asoc = asoc; 20368c2654abSrjs chk->send_size = the_len; 20378c2654abSrjs chk->whoTo = net; 20388c2654abSrjs net->ref_count++; 20398c2654abSrjs chk->data = dmbuf; 20408c2654abSrjs 20418c2654abSrjs 20428c2654abSrjs /* Mark it as received */ 20438c2654abSrjs /* Now queue it where it belongs */ 20448c2654abSrjs if ((chk->rec.data.rcv_flags & SCTP_DATA_NOT_FRAG) == 20458c2654abSrjs SCTP_DATA_NOT_FRAG) { 20468c2654abSrjs /* First a sanity check */ 20478c2654abSrjs if (asoc->fragmented_delivery_inprogress) { 20488c2654abSrjs /* 20498c2654abSrjs * Ok, we have a fragmented delivery in progress 20508c2654abSrjs * if this chunk is next to deliver OR belongs in 20518c2654abSrjs * our view to the reassembly, the peer is evil 20528c2654abSrjs * or broken. 20538c2654abSrjs */ 20548c2654abSrjs u_int32_t estimate_tsn; 20558c2654abSrjs estimate_tsn = asoc->tsn_last_delivered + 1; 20568c2654abSrjs if (TAILQ_EMPTY(&asoc->reasmqueue) && 20578c2654abSrjs (estimate_tsn == chk->rec.data.TSN_seq)) { 20588c2654abSrjs /* Evil/Broke peer */ 20598c2654abSrjs MGET(oper, M_DONTWAIT, MT_DATA); 20608c2654abSrjs if (oper) { 20618c2654abSrjs struct sctp_paramhdr *ph; 20628c2654abSrjs u_int32_t *ippp; 20638c2654abSrjs 20648c2654abSrjs oper->m_len = 20658c2654abSrjs sizeof(struct sctp_paramhdr) + 20668c2654abSrjs sizeof(*ippp); 20678c2654abSrjs ph = mtod(oper, struct sctp_paramhdr *); 20688c2654abSrjs ph->param_type = 20698c2654abSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 20708c2654abSrjs ph->param_length = htons(oper->m_len); 20718c2654abSrjs ippp = (u_int32_t *)(ph + 1); 20728c2654abSrjs *ippp = htonl(0x20000002); 20738c2654abSrjs } 20748c2654abSrjs sctp_abort_an_association(stcb->sctp_ep, stcb, 20758c2654abSrjs SCTP_PEER_FAULTY, oper); 20768c2654abSrjs 20778c2654abSrjs *abort_flag = 1; 20788c2654abSrjs sctp_pegs[SCTP_DROP_FRAG]++; 20798c2654abSrjs return (0); 20808c2654abSrjs } else { 20818c2654abSrjs if (sctp_does_chk_belong_to_reasm(asoc, chk)) { 20828c2654abSrjs MGET(oper, M_DONTWAIT, MT_DATA); 20838c2654abSrjs if (oper) { 20848c2654abSrjs struct sctp_paramhdr *ph; 20858c2654abSrjs u_int32_t *ippp; 20868c2654abSrjs 20878c2654abSrjs oper->m_len = 20888c2654abSrjs sizeof(struct sctp_paramhdr) + 20898c2654abSrjs sizeof(*ippp); 20908c2654abSrjs ph = mtod(oper, 20918c2654abSrjs struct sctp_paramhdr *); 20928c2654abSrjs ph->param_type = 20938c2654abSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 20948c2654abSrjs ph->param_length = 20958c2654abSrjs htons(oper->m_len); 20968c2654abSrjs ippp = (u_int32_t *)(ph + 1); 20978c2654abSrjs *ippp = htonl(0x20000003); 20988c2654abSrjs } 20998c2654abSrjs sctp_abort_an_association(stcb->sctp_ep, 21008c2654abSrjs stcb, SCTP_PEER_FAULTY, oper); 21018c2654abSrjs 21028c2654abSrjs *abort_flag = 1; 21038c2654abSrjs sctp_pegs[SCTP_DROP_FRAG]++; 21048c2654abSrjs return (0); 21058c2654abSrjs } 21068c2654abSrjs } 21078c2654abSrjs } else { 21088c2654abSrjs if (!TAILQ_EMPTY(&asoc->reasmqueue)) { 21098c2654abSrjs /* 21108c2654abSrjs * Reassembly queue is NOT empty 21118c2654abSrjs * validate that this chk does not need to 21128c2654abSrjs * be in reasembly queue. If it does then 21138c2654abSrjs * our peer is broken or evil. 21148c2654abSrjs */ 21158c2654abSrjs if (sctp_does_chk_belong_to_reasm(asoc, chk)) { 21168c2654abSrjs MGET(oper, M_DONTWAIT, MT_DATA); 21178c2654abSrjs if (oper) { 21188c2654abSrjs struct sctp_paramhdr *ph; 21198c2654abSrjs u_int32_t *ippp; 21208c2654abSrjs 21218c2654abSrjs oper->m_len = 21228c2654abSrjs sizeof(struct sctp_paramhdr) + 21238c2654abSrjs sizeof(*ippp); 21248c2654abSrjs ph = mtod(oper, 21258c2654abSrjs struct sctp_paramhdr *); 21268c2654abSrjs ph->param_type = 21278c2654abSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 21288c2654abSrjs ph->param_length = 21298c2654abSrjs htons(oper->m_len); 21308c2654abSrjs ippp = (u_int32_t *)(ph + 1); 21318c2654abSrjs *ippp = htonl(0x20000004); 21328c2654abSrjs } 21338c2654abSrjs sctp_abort_an_association(stcb->sctp_ep, 21348c2654abSrjs stcb, SCTP_PEER_FAULTY, oper); 21358c2654abSrjs 21368c2654abSrjs *abort_flag = 1; 21378c2654abSrjs sctp_pegs[SCTP_DROP_FRAG]++; 21388c2654abSrjs return (0); 21398c2654abSrjs } 21408c2654abSrjs } 21418c2654abSrjs } 21428c2654abSrjs if (chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) { 21438c2654abSrjs /* queue directly into socket buffer */ 21448c2654abSrjs sctp_deliver_data(stcb, asoc, chk, 0); 21458c2654abSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 21468c2654abSrjs } else { 21478c2654abSrjs /* Special check for when streams are resetting. 21488c2654abSrjs * We could be more smart about this and check the 21498c2654abSrjs * actual stream to see if it is not being reset.. that 21508c2654abSrjs * way we would not create a HOLB when amongst streams 21518c2654abSrjs * being reset and those not being reset. 21528c2654abSrjs * 21538c2654abSrjs * We take complete messages that have a stream reset 21548c2654abSrjs * intervening (aka the TSN is after where our cum-ack needs 21558c2654abSrjs * to be) off and put them on a pending_reply_queue. The 21568c2654abSrjs * reassembly ones we do not have to worry about since 2157e31f1e95Sandvar * they are all sorted and processed by TSN order. It 21588c2654abSrjs * is only the singletons I must worry about. 21598c2654abSrjs */ 21608c2654abSrjs if ((asoc->pending_reply) && 21618c2654abSrjs ((compare_with_wrap(tsn, ntohl(asoc->pending_reply->reset_at_tsn), MAX_TSN)) || 21628c2654abSrjs (tsn == ntohl(asoc->pending_reply->reset_at_tsn))) 21638c2654abSrjs ) { 21648c2654abSrjs /* yep its past where we need to reset... go ahead and 21658c2654abSrjs * queue it. 21668c2654abSrjs */ 21678c2654abSrjs TAILQ_INSERT_TAIL(&asoc->pending_reply_queue , chk, sctp_next); 21688c2654abSrjs } else { 21698c2654abSrjs sctp_queue_data_to_stream(stcb, asoc, chk, abort_flag); 21708c2654abSrjs } 21718c2654abSrjs } 21728c2654abSrjs } else { 21738c2654abSrjs /* Into the re-assembly queue */ 21748c2654abSrjs sctp_queue_data_for_reasm(stcb, asoc, chk, abort_flag); 21758c2654abSrjs if (*abort_flag) { 21768c2654abSrjs sctp_pegs[SCTP_DROP_FRAG]++; 21778c2654abSrjs return (0); 21788c2654abSrjs } 21798c2654abSrjs } 21808c2654abSrjs if (compare_with_wrap(tsn, asoc->highest_tsn_inside_map, MAX_TSN)) { 21818c2654abSrjs /* we have a new high score */ 21828c2654abSrjs asoc->highest_tsn_inside_map = tsn; 21838c2654abSrjs #ifdef SCTP_MAP_LOGGING 21848c2654abSrjs sctp_log_map(0, 2, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT); 21858c2654abSrjs #endif 21868c2654abSrjs } 21878c2654abSrjs finish_express_del: 21888c2654abSrjs if (last_chunk) { 21898c2654abSrjs *m = NULL; 21908c2654abSrjs } 21918c2654abSrjs sctp_pegs[SCTP_PEG_TSNS_RCVD]++; 21928c2654abSrjs /* Set it present please */ 21938c2654abSrjs #ifdef SCTP_STR_LOGGING 21948c2654abSrjs sctp_log_strm_del_alt(tsn, strmseq, SCTP_STR_LOG_FROM_MARK_TSN); 21958c2654abSrjs #endif 21968c2654abSrjs #ifdef SCTP_MAP_LOGGING 21978c2654abSrjs sctp_log_map(asoc->mapping_array_base_tsn, asoc->cumulative_tsn, 21988c2654abSrjs asoc->highest_tsn_inside_map, SCTP_MAP_PREPARE_SLIDE); 21998c2654abSrjs #endif 22008c2654abSrjs SCTP_SET_TSN_PRESENT(asoc->mapping_array, gap); 22018c2654abSrjs return (1); 22028c2654abSrjs } 22038c2654abSrjs 22048c2654abSrjs void 22058c2654abSrjs sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort_flag) 22068c2654abSrjs { 22078c2654abSrjs /* 22088c2654abSrjs * Now we also need to check the mapping array in a couple of ways. 22098c2654abSrjs * 1) Did we move the cum-ack point? 22108c2654abSrjs */ 22118c2654abSrjs struct sctp_association *asoc; 22128c2654abSrjs int i, at; 22138c2654abSrjs int m_size, all_ones; 22148c2654abSrjs int slide_from, slide_end, lgap, distance; 22158c2654abSrjs #ifdef SCTP_MAP_LOGGING 22168c2654abSrjs uint32_t old_cumack, old_base, old_highest; 22178c2654abSrjs unsigned char aux_array[64]; 22188c2654abSrjs #endif 22198c2654abSrjs 22208c2654abSrjs asoc = &stcb->asoc; 22218c2654abSrjs at = 0; 22228c2654abSrjs 22238c2654abSrjs #ifdef SCTP_MAP_LOGGING 22248c2654abSrjs old_cumack = asoc->cumulative_tsn; 22258c2654abSrjs old_base = asoc->mapping_array_base_tsn; 22268c2654abSrjs old_highest = asoc->highest_tsn_inside_map; 22278c2654abSrjs if (asoc->mapping_array_size < 64) 22288c2654abSrjs memcpy(aux_array, asoc->mapping_array, 22298c2654abSrjs asoc->mapping_array_size); 22308c2654abSrjs else 22318c2654abSrjs memcpy(aux_array, asoc->mapping_array, 64); 22328c2654abSrjs #endif 22338c2654abSrjs 22348c2654abSrjs /* 22358c2654abSrjs * We could probably improve this a small bit by calculating the 22368c2654abSrjs * offset of the current cum-ack as the starting point. 22378c2654abSrjs */ 22388c2654abSrjs all_ones = 1; 22398c2654abSrjs m_size = stcb->asoc.mapping_array_size << 3; 22408c2654abSrjs for (i = 0; i < m_size; i++) { 22418c2654abSrjs if (!SCTP_IS_TSN_PRESENT(asoc->mapping_array, i)) { 22428c2654abSrjs /* 22438c2654abSrjs * Ok we found the first place that we are 22448c2654abSrjs * missing a TSN. 22458c2654abSrjs */ 22468c2654abSrjs at = i; 22478c2654abSrjs all_ones = 0; 22488c2654abSrjs asoc->cumulative_tsn = asoc->mapping_array_base_tsn + 22498c2654abSrjs (i - 1); 22508c2654abSrjs break; 22518c2654abSrjs } 22528c2654abSrjs } 22538c2654abSrjs if (compare_with_wrap(asoc->cumulative_tsn, 22548c2654abSrjs asoc->highest_tsn_inside_map, 22558c2654abSrjs MAX_TSN)) { 22568c2654abSrjs panic("huh, cumack greater than high-tsn in map"); 22578c2654abSrjs } 22588c2654abSrjs if (all_ones || 22598c2654abSrjs (asoc->cumulative_tsn == asoc->highest_tsn_inside_map && at >= 8)) { 22608c2654abSrjs /* The complete array was completed by a single FR */ 2261114b0226Sandvar /* highest becomes the cum-ack */ 22628c2654abSrjs int clr; 22638c2654abSrjs asoc->cumulative_tsn = asoc->highest_tsn_inside_map; 22648c2654abSrjs /* clear the array */ 22658c2654abSrjs if (all_ones) 22668c2654abSrjs clr = asoc->mapping_array_size; 22678c2654abSrjs else { 22688c2654abSrjs clr = (at >> 3) + 1; 22698c2654abSrjs /* 22708c2654abSrjs * this should be the allones case 22718c2654abSrjs * but just in case :> 22728c2654abSrjs */ 22738c2654abSrjs if (clr > asoc->mapping_array_size) 22748c2654abSrjs clr = asoc->mapping_array_size; 22758c2654abSrjs } 22768c2654abSrjs memset(asoc->mapping_array, 0, clr); 22778c2654abSrjs /* base becomes one ahead of the cum-ack */ 22788c2654abSrjs asoc->mapping_array_base_tsn = asoc->cumulative_tsn + 1; 22798c2654abSrjs #ifdef SCTP_MAP_LOGGING 22808c2654abSrjs sctp_log_map(old_base, old_cumack, old_highest, 22818c2654abSrjs SCTP_MAP_PREPARE_SLIDE); 22828c2654abSrjs sctp_log_map(asoc->mapping_array_base_tsn, asoc->cumulative_tsn, 22838c2654abSrjs asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_CLEARED); 22848c2654abSrjs #endif 22858c2654abSrjs } else if (at >= 8) { 22868c2654abSrjs /* we can slide the mapping array down */ 2287146d03e6Sandvar /* Calculate the new byte position we can move down */ 22888c2654abSrjs slide_from = at >> 3; 22898c2654abSrjs /* now calculate the ceiling of the move using our highest TSN value */ 22908c2654abSrjs if (asoc->highest_tsn_inside_map >= asoc->mapping_array_base_tsn) { 22918c2654abSrjs lgap = asoc->highest_tsn_inside_map - 22928c2654abSrjs asoc->mapping_array_base_tsn; 22938c2654abSrjs } else { 22948c2654abSrjs lgap = (MAX_TSN - asoc->mapping_array_base_tsn) + 22958c2654abSrjs asoc->highest_tsn_inside_map + 1; 22968c2654abSrjs } 22978c2654abSrjs slide_end = lgap >> 3; 22988c2654abSrjs if (slide_end < slide_from) { 22998c2654abSrjs panic("impossible slide"); 23008c2654abSrjs } 23018c2654abSrjs distance = (slide_end-slide_from) + 1; 23028c2654abSrjs #ifdef SCTP_MAP_LOGGING 23038c2654abSrjs sctp_log_map(old_base, old_cumack, old_highest, 23048c2654abSrjs SCTP_MAP_PREPARE_SLIDE); 23058c2654abSrjs sctp_log_map((uint32_t)slide_from, (uint32_t)slide_end, 23068c2654abSrjs (uint32_t)lgap, SCTP_MAP_SLIDE_FROM); 23078c2654abSrjs #endif 23088c2654abSrjs if (distance + slide_from > asoc->mapping_array_size || 23098c2654abSrjs distance < 0) { 23108c2654abSrjs #ifdef SCTP_DEBUG 23118c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 23128c2654abSrjs printf("Ugh bad addition.. you can't hrumpp!\n"); 23138c2654abSrjs } 23148c2654abSrjs #endif 23158c2654abSrjs /* 23168c2654abSrjs * Here we do NOT slide forward the array so that 23178c2654abSrjs * hopefully when more data comes in to fill it up 23188c2654abSrjs * we will be able to slide it forward. Really 23198c2654abSrjs * I don't think this should happen :-0 23208c2654abSrjs */ 23218c2654abSrjs 23228c2654abSrjs #ifdef SCTP_MAP_LOGGING 23238c2654abSrjs sctp_log_map((uint32_t)distance, (uint32_t)slide_from, 23248c2654abSrjs (uint32_t)asoc->mapping_array_size, 23258c2654abSrjs SCTP_MAP_SLIDE_NONE); 23268c2654abSrjs #endif 23278c2654abSrjs } else { 23288c2654abSrjs int ii; 23298c2654abSrjs for (ii = 0; ii < distance; ii++) { 23308c2654abSrjs asoc->mapping_array[ii] = 23318c2654abSrjs asoc->mapping_array[slide_from + ii]; 23328c2654abSrjs } 23338c2654abSrjs for (ii = distance;ii <= slide_end; ii++) { 23348c2654abSrjs asoc->mapping_array[ii] = 0; 23358c2654abSrjs } 23368c2654abSrjs asoc->mapping_array_base_tsn += (slide_from << 3); 23378c2654abSrjs #ifdef SCTP_MAP_LOGGING 23388c2654abSrjs sctp_log_map(asoc->mapping_array_base_tsn, 23398c2654abSrjs asoc->cumulative_tsn, asoc->highest_tsn_inside_map, 23408c2654abSrjs SCTP_MAP_SLIDE_RESULT); 23418c2654abSrjs #endif 23428c2654abSrjs } 23438c2654abSrjs } 23448c2654abSrjs 23458c2654abSrjs /* check the special flag for stream resets */ 23468c2654abSrjs if ((asoc->pending_reply) && 23478c2654abSrjs ((compare_with_wrap((asoc->cumulative_tsn+1), ntohl(asoc->pending_reply->reset_at_tsn), MAX_TSN)) || 23488c2654abSrjs ((asoc->cumulative_tsn+1) == ntohl(asoc->pending_reply->reset_at_tsn))) 23498c2654abSrjs ) { 23508c2654abSrjs /* we have finished working through the backlogged TSN's now 23518c2654abSrjs * time to reset streams. 23528c2654abSrjs * 1: call reset function. 23538c2654abSrjs * 2: free pending_reply space 23548c2654abSrjs * 3: distribute any chunks in pending_reply_queue. 23558c2654abSrjs */ 23568c2654abSrjs struct sctp_tmit_chunk *chk; 23578c2654abSrjs sctp_handle_stream_reset_response(stcb, asoc->pending_reply); 23588c2654abSrjs free(asoc->pending_reply, M_PCB); 23598c2654abSrjs asoc->pending_reply = NULL; 23608c2654abSrjs chk = TAILQ_FIRST(&asoc->pending_reply_queue); 23618c2654abSrjs while (chk) { 23628c2654abSrjs TAILQ_REMOVE(&asoc->pending_reply_queue, chk, sctp_next); 23638c2654abSrjs sctp_queue_data_to_stream(stcb, asoc, chk, abort_flag); 23648c2654abSrjs if (*abort_flag) { 23658c2654abSrjs return; 23668c2654abSrjs } 23678c2654abSrjs chk = TAILQ_FIRST(&asoc->pending_reply_queue); 23688c2654abSrjs } 23698c2654abSrjs } 23708c2654abSrjs /* 23718c2654abSrjs * Now we need to see if we need to queue a sack or just start 23728c2654abSrjs * the timer (if allowed). 23738c2654abSrjs */ 23748c2654abSrjs if (ok_to_sack) { 23758c2654abSrjs if (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_SENT) { 23768c2654abSrjs /* 23778c2654abSrjs * Ok special case, in SHUTDOWN-SENT case. 23788c2654abSrjs * here we maker sure SACK timer is off and 23798c2654abSrjs * instead send a SHUTDOWN and a SACK 23808c2654abSrjs */ 23818c2654abSrjs if (callout_pending(&stcb->asoc.dack_timer.timer)) { 23828c2654abSrjs sctp_timer_stop(SCTP_TIMER_TYPE_RECV, 23838c2654abSrjs stcb->sctp_ep, stcb, NULL); 23848c2654abSrjs } 23858c2654abSrjs #ifdef SCTP_DEBUG 23868c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) { 23878c2654abSrjs printf("%s:%d sends a shutdown\n", 23888c2654abSrjs __FILE__, 23898c2654abSrjs __LINE__ 23908c2654abSrjs ); 23918c2654abSrjs } 23928c2654abSrjs #endif 23938c2654abSrjs sctp_send_shutdown(stcb, stcb->asoc.primary_destination); 23948c2654abSrjs sctp_send_sack(stcb); 23958c2654abSrjs } else { 23968c2654abSrjs int is_a_gap; 23978c2654abSrjs /* is there a gap now ? */ 23988c2654abSrjs is_a_gap = compare_with_wrap(stcb->asoc.highest_tsn_inside_map, 23998c2654abSrjs stcb->asoc.cumulative_tsn, MAX_TSN); 24008c2654abSrjs if ((stcb->asoc.first_ack_sent == 0) || /* First time we send a sack */ 24018c2654abSrjs ((was_a_gap) && (is_a_gap == 0)) || /* was a gap, but no longer is one */ 24028c2654abSrjs (stcb->asoc.numduptsns) || /* we have dup's */ 24038c2654abSrjs (is_a_gap) || /* is still a gap */ 24048c2654abSrjs (callout_pending(&stcb->asoc.dack_timer.timer)) /* timer was up . second packet */ 24058c2654abSrjs ) { 24068c2654abSrjs /* 24078c2654abSrjs * Ok we must build a SACK since the timer 24088c2654abSrjs * is pending, we got our first packet OR 24098c2654abSrjs * there are gaps or duplicates. 24108c2654abSrjs */ 24118c2654abSrjs stcb->asoc.first_ack_sent = 1; 24128c2654abSrjs sctp_send_sack(stcb); 24138c2654abSrjs /* The sending will stop the timer */ 24148c2654abSrjs } else { 24158c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_RECV, 24168c2654abSrjs stcb->sctp_ep, stcb, NULL); 24178c2654abSrjs } 24188c2654abSrjs } 24198c2654abSrjs } 24208c2654abSrjs } 24218c2654abSrjs 24228c2654abSrjs void 24238c2654abSrjs sctp_service_queues(struct sctp_tcb *stcb, struct sctp_association *asoc, int hold_locks) 24248c2654abSrjs { 24258c2654abSrjs struct sctp_tmit_chunk *chk; 24268c2654abSrjs int tsize, cntDel; 24278c2654abSrjs u_int16_t nxt_todel; 24288c2654abSrjs 24298c2654abSrjs cntDel = 0; 24308c2654abSrjs if (asoc->fragmented_delivery_inprogress) { 24318c2654abSrjs sctp_service_reassembly(stcb, asoc, hold_locks); 24328c2654abSrjs } 24338c2654abSrjs /* Can we proceed further, i.e. the PD-API is complete */ 24348c2654abSrjs if (asoc->fragmented_delivery_inprogress) { 24358c2654abSrjs /* no */ 24368c2654abSrjs return; 24378c2654abSrjs } 24388c2654abSrjs 24398c2654abSrjs /* 24408c2654abSrjs * Yes, reassembly delivery no longer in progress see if we 24418c2654abSrjs * have some on the sb hold queue. 24428c2654abSrjs */ 24438c2654abSrjs do { 24448c2654abSrjs if (stcb->sctp_socket->so_rcv.sb_cc >= stcb->sctp_socket->so_rcv.sb_hiwat) { 24458c2654abSrjs if (cntDel == 0) 24468c2654abSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 24478c2654abSrjs break; 24488c2654abSrjs } 24498c2654abSrjs /* If deliver_data says no we must stop */ 24508c2654abSrjs if (sctp_deliver_data(stcb, asoc, (struct sctp_tmit_chunk *)NULL, hold_locks) == 0) 24518c2654abSrjs break; 24528c2654abSrjs cntDel++; 24538c2654abSrjs chk = TAILQ_FIRST(&asoc->delivery_queue); 24548c2654abSrjs } while (chk); 24558c2654abSrjs if (cntDel) { 24568c2654abSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 24578c2654abSrjs } 24588c2654abSrjs /* 24598c2654abSrjs * Now is there some other chunk I can deliver 24608c2654abSrjs * from the reassembly queue. 24618c2654abSrjs */ 24628c2654abSrjs chk = TAILQ_FIRST(&asoc->reasmqueue); 24638c2654abSrjs if (chk == NULL) { 24648c2654abSrjs asoc->size_on_reasm_queue = 0; 24658c2654abSrjs asoc->cnt_on_reasm_queue = 0; 24668c2654abSrjs return; 24678c2654abSrjs } 24688c2654abSrjs nxt_todel = asoc->strmin[chk->rec.data.stream_number].last_sequence_delivered + 1; 24698c2654abSrjs if ((chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) && 24708c2654abSrjs ((nxt_todel == chk->rec.data.stream_seq) || 24718c2654abSrjs (chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED))) { 24728c2654abSrjs /* 24738c2654abSrjs * Yep the first one is here. We setup to 24748c2654abSrjs * start reception, by backing down the TSN 24758c2654abSrjs * just in case we can't deliver. 24768c2654abSrjs */ 24778c2654abSrjs 24788c2654abSrjs /* 24798c2654abSrjs * Before we start though either all of the 24808c2654abSrjs * message should be here or 1/4 the socket buffer 24818c2654abSrjs * max or nothing on the delivery queue and something 24828c2654abSrjs * can be delivered. 24838c2654abSrjs */ 24848c2654abSrjs if (TAILQ_EMPTY(&asoc->delivery_queue) && 24858c2654abSrjs (sctp_is_all_msg_on_reasm(asoc, &tsize) || 24868c2654abSrjs (asoc->size_on_reasm_queue >= 24878c2654abSrjs (stcb->sctp_socket->so_rcv.sb_hiwat >> 2) && tsize))) { 24888c2654abSrjs asoc->fragmented_delivery_inprogress = 1; 24898c2654abSrjs asoc->tsn_last_delivered = chk->rec.data.TSN_seq-1; 24908c2654abSrjs asoc->str_of_pdapi = chk->rec.data.stream_number; 24918c2654abSrjs asoc->ssn_of_pdapi = chk->rec.data.stream_seq; 24928c2654abSrjs asoc->fragment_flags = chk->rec.data.rcv_flags; 24938c2654abSrjs sctp_service_reassembly(stcb, asoc, hold_locks); 24948c2654abSrjs } 24958c2654abSrjs } 24968c2654abSrjs } 24978c2654abSrjs 24988c2654abSrjs int 24998c2654abSrjs sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, 25008c2654abSrjs struct sctphdr *sh, struct sctp_inpcb *inp, struct sctp_tcb *stcb, 25018c2654abSrjs struct sctp_nets *net, u_int32_t *high_tsn) 25028c2654abSrjs { 25038c2654abSrjs struct sctp_data_chunk *ch, chunk_buf; 25048c2654abSrjs struct sctp_association *asoc; 25058c2654abSrjs int num_chunks = 0; /* number of control chunks processed */ 25068c2654abSrjs int chk_length, break_flag, last_chunk; 25078c2654abSrjs int abort_flag = 0, was_a_gap = 0; 25088c2654abSrjs struct mbuf *m; 25098c2654abSrjs 25108c2654abSrjs /* set the rwnd */ 25118c2654abSrjs sctp_set_rwnd(stcb, &stcb->asoc); 25128c2654abSrjs 25138c2654abSrjs m = *mm; 25148c2654abSrjs asoc = &stcb->asoc; 25158c2654abSrjs if (compare_with_wrap(stcb->asoc.highest_tsn_inside_map, 25168c2654abSrjs stcb->asoc.cumulative_tsn, MAX_TSN)) { 25178c2654abSrjs /* there was a gap before this data was processed */ 25188c2654abSrjs was_a_gap = 1; 25198c2654abSrjs } 25208c2654abSrjs /* 25218c2654abSrjs * setup where we got the last DATA packet from for 25228c2654abSrjs * any SACK that may need to go out. Don't bump 25238c2654abSrjs * the net. This is done ONLY when a chunk 25248c2654abSrjs * is assigned. 25258c2654abSrjs */ 25268c2654abSrjs asoc->last_data_chunk_from = net; 25278c2654abSrjs 25288c2654abSrjs /* 25298c2654abSrjs * Now before we proceed we must figure out if this 25308c2654abSrjs * is a wasted cluster... i.e. it is a small packet 25318c2654abSrjs * sent in and yet the driver underneath allocated a 25328c2654abSrjs * full cluster for it. If so we must copy it to a 25338c2654abSrjs * smaller mbuf and free up the cluster mbuf. This 25348c2654abSrjs * will help with cluster starvation. 25358c2654abSrjs */ 25368c2654abSrjs if (m->m_len < (long)MHLEN && m->m_next == NULL) { 25378c2654abSrjs /* we only handle mbufs that are singletons.. not chains */ 25388c2654abSrjs MGET(m, M_DONTWAIT, MT_DATA); 25398c2654abSrjs if (m) { 25408c2654abSrjs /* ok lets see if we can copy the data up */ 25418c2654abSrjs vaddr_t *from, *to; 25428c2654abSrjs 25438c2654abSrjs if ((*mm)->m_flags & M_PKTHDR) { 25448c2654abSrjs /* got to copy the header first */ 25458c2654abSrjs #ifdef __APPLE__ 25468c2654abSrjs M_COPY_PKTHDR(m, (*mm)); 25478c2654abSrjs #else 2548b1305a6dSmaxv m_move_pkthdr(m, (*mm)); 25498c2654abSrjs #endif 25508c2654abSrjs } 25518c2654abSrjs /* get the pointers and copy */ 25528c2654abSrjs to = mtod(m, vaddr_t *); 25538c2654abSrjs from = mtod((*mm), vaddr_t *); 25548c2654abSrjs memcpy(to, from, (*mm)->m_len); 25558c2654abSrjs /* copy the length and free up the old */ 25568c2654abSrjs m->m_len = (*mm)->m_len; 25578c2654abSrjs sctp_m_freem(*mm); 25588c2654abSrjs /* sucess, back copy */ 25598c2654abSrjs *mm = m; 25608c2654abSrjs } else { 25618c2654abSrjs /* We are in trouble in the mbuf world .. yikes */ 25628c2654abSrjs m = *mm; 25638c2654abSrjs } 25648c2654abSrjs } 25658c2654abSrjs /* get pointer to the first chunk header */ 25668c2654abSrjs ch = (struct sctp_data_chunk *)sctp_m_getptr(m, *offset, 25678c2654abSrjs sizeof(chunk_buf), (u_int8_t *)&chunk_buf); 25688c2654abSrjs if (ch == NULL) { 25698c2654abSrjs printf(" ... its short\n"); 25708c2654abSrjs return (1); 25718c2654abSrjs } 25728c2654abSrjs /* 25738c2654abSrjs * process all DATA chunks... 25748c2654abSrjs */ 25758c2654abSrjs 25768c2654abSrjs #ifdef SCTP_DEBUG 25778c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INPUT1) { 25788c2654abSrjs printf("In process data off:%d length:%d iphlen:%d ch->type:%d\n", 25798c2654abSrjs *offset, length, iphlen, (int)ch->ch.chunk_type); 25808c2654abSrjs } 25818c2654abSrjs #endif 25828c2654abSrjs 25838c2654abSrjs *high_tsn = asoc->cumulative_tsn; 25848c2654abSrjs break_flag = 0; 25858c2654abSrjs while (ch->ch.chunk_type == SCTP_DATA) { 25868c2654abSrjs /* validate chunk length */ 25878c2654abSrjs chk_length = ntohs(ch->ch.chunk_length); 25888c2654abSrjs if ((size_t)chk_length < sizeof(struct sctp_data_chunk) + 1 || 25898c2654abSrjs length - *offset < chk_length) { 25908c2654abSrjs /* 25918c2654abSrjs * Need to send an abort since we had a invalid 25928c2654abSrjs * data chunk. 25938c2654abSrjs */ 25948c2654abSrjs struct mbuf *op_err; 25958c2654abSrjs MGET(op_err, M_DONTWAIT, MT_DATA); 25968c2654abSrjs if (op_err) { 25978c2654abSrjs struct sctp_paramhdr *ph; 25988c2654abSrjs u_int32_t *ippp; 25998c2654abSrjs 26008c2654abSrjs op_err->m_len = sizeof(struct sctp_paramhdr) + 26018c2654abSrjs sizeof(*ippp); 26028c2654abSrjs ph = mtod(op_err, struct sctp_paramhdr *); 26038c2654abSrjs ph->param_type = 26048c2654abSrjs htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 26058c2654abSrjs ph->param_length = htons(op_err->m_len); 26068c2654abSrjs ippp = (u_int32_t *)(ph + 1); 26078c2654abSrjs *ippp = htonl(0x30000001); 26088c2654abSrjs } 26098c2654abSrjs sctp_abort_association(inp, stcb, m, iphlen, sh, 26108c2654abSrjs op_err); 26118c2654abSrjs return (2); 26128c2654abSrjs } 26138c2654abSrjs #ifdef SCTP_DEBUG 26148c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INPUT1) { 26158c2654abSrjs printf("A chunk of len:%d to process (tot:%d)\n", 26168c2654abSrjs chk_length, length - *offset); 26178c2654abSrjs } 26188c2654abSrjs #endif 26198c2654abSrjs 26208c2654abSrjs #ifdef SCTP_AUDITING_ENABLED 26218c2654abSrjs sctp_audit_log(0xB1, 0); 26228c2654abSrjs #endif 26238c2654abSrjs if (SCTP_SIZE32(chk_length) == *offset - length) { 26248c2654abSrjs last_chunk = 1; 26258c2654abSrjs } else { 26268c2654abSrjs last_chunk = 0; 26278c2654abSrjs } 26288c2654abSrjs if (sctp_process_a_data_chunk(stcb, asoc, mm, *offset, ch, 26298c2654abSrjs chk_length, net, high_tsn, &abort_flag, &break_flag, 26308c2654abSrjs last_chunk)) { 26318c2654abSrjs num_chunks++; 26328c2654abSrjs #ifdef SCTP_DEBUG 26338c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INPUT1) { 26348c2654abSrjs printf("Now incr num_chunks to %d\n", 26358c2654abSrjs num_chunks); 26368c2654abSrjs } 26378c2654abSrjs #endif 26388c2654abSrjs } 26398c2654abSrjs if (abort_flag) 26408c2654abSrjs return (2); 26418c2654abSrjs 26428c2654abSrjs if (break_flag) { 26438c2654abSrjs /* 26448c2654abSrjs * Set because of out of rwnd space and no drop rep 26458c2654abSrjs * space left. 26468c2654abSrjs */ 26478c2654abSrjs break; 26488c2654abSrjs } 26498c2654abSrjs 26508c2654abSrjs *offset += SCTP_SIZE32(chk_length); 26518c2654abSrjs if (*offset >= length) { 26528c2654abSrjs /* no more data left in the mbuf chain */ 26538c2654abSrjs break; 26548c2654abSrjs } 26558c2654abSrjs ch = (struct sctp_data_chunk *)sctp_m_getptr(m, *offset, 26568c2654abSrjs sizeof(chunk_buf), (u_int8_t *)&chunk_buf); 26578c2654abSrjs if (ch == NULL) { 26588c2654abSrjs *offset = length; 26598c2654abSrjs break; 26608c2654abSrjs } 26618c2654abSrjs } /* while */ 26628c2654abSrjs if (break_flag) { 26638c2654abSrjs /* 26648c2654abSrjs * we need to report rwnd overrun drops. 26658c2654abSrjs */ 26668c2654abSrjs sctp_send_packet_dropped(stcb, net, *mm, iphlen, 0); 26678c2654abSrjs } 26688c2654abSrjs if (num_chunks) { 26698c2654abSrjs /* 26708c2654abSrjs * Did we get data, if so update the time for 26718c2654abSrjs * auto-close and give peer credit for being 26728c2654abSrjs * alive. 26738c2654abSrjs */ 26748c2654abSrjs sctp_pegs[SCTP_DATA_DG_RECV]++; 26758c2654abSrjs stcb->asoc.overall_error_count = 0; 26768c2654abSrjs SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_last_rcvd); 26778c2654abSrjs } 26788c2654abSrjs /* now service all of the reassm queue and delivery queue */ 26798c2654abSrjs sctp_service_queues(stcb, asoc, 0); 26808c2654abSrjs if (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_SENT) { 26818c2654abSrjs /* 26828c2654abSrjs * Assure that we ack right away by making 26838c2654abSrjs * sure that a d-ack timer is running. So the 26848c2654abSrjs * sack_check will send a sack. 26858c2654abSrjs */ 26868c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, 26878c2654abSrjs net); 26888c2654abSrjs } 26898c2654abSrjs /* Start a sack timer or QUEUE a SACK for sending */ 26908c2654abSrjs sctp_sack_check(stcb, 1, was_a_gap, &abort_flag); 26918c2654abSrjs if (abort_flag) 26928c2654abSrjs return (2); 26938c2654abSrjs 26948c2654abSrjs return (0); 26958c2654abSrjs } 26968c2654abSrjs 26978c2654abSrjs static void 26988c2654abSrjs sctp_handle_segments(struct sctp_tcb *stcb, struct sctp_association *asoc, 26998c2654abSrjs struct sctp_sack_chunk *ch, u_long last_tsn, u_long *biggest_tsn_acked, 27008c2654abSrjs u_long *biggest_newly_acked_tsn, int num_seg, int *ecn_seg_sums) 27018c2654abSrjs { 27028c2654abSrjs /************************************************/ 27038c2654abSrjs /* process fragments and update sendqueue */ 27048c2654abSrjs /************************************************/ 27058c2654abSrjs struct sctp_sack *sack; 27068c2654abSrjs struct sctp_gap_ack_block *frag; 27078c2654abSrjs struct sctp_tmit_chunk *tp1; 27088c2654abSrjs int i; 27098c2654abSrjs unsigned int j; 27108c2654abSrjs #ifdef SCTP_FR_LOGGING 27118c2654abSrjs int num_frs=0; 27128c2654abSrjs #endif 27138c2654abSrjs uint16_t frag_strt, frag_end, primary_flag_set; 27148c2654abSrjs u_long last_frag_high; 27158c2654abSrjs 27168c2654abSrjs if (asoc->primary_destination->dest_state & SCTP_ADDR_SWITCH_PRIMARY) { 27178c2654abSrjs primary_flag_set = 1; 27188c2654abSrjs } else { 27198c2654abSrjs primary_flag_set = 0; 27208c2654abSrjs } 27218c2654abSrjs 27228c2654abSrjs sack = &ch->sack; 27238c2654abSrjs frag = (struct sctp_gap_ack_block *)((vaddr_t)sack + 27248c2654abSrjs sizeof(struct sctp_sack)); 27258c2654abSrjs tp1 = NULL; 27268c2654abSrjs last_frag_high = 0; 27278c2654abSrjs for (i = 0; i < num_seg; i++) { 27288c2654abSrjs frag_strt = ntohs(frag->start); 27298c2654abSrjs frag_end = ntohs(frag->end); 2730915340d5Sandvar /* some sanity checks on the fragment offsets */ 27318c2654abSrjs if (frag_strt > frag_end) { 27328c2654abSrjs /* this one is malformed, skip */ 27338c2654abSrjs frag++; 27348c2654abSrjs continue; 27358c2654abSrjs } 27368c2654abSrjs if (compare_with_wrap((frag_end+last_tsn), *biggest_tsn_acked, 27378c2654abSrjs MAX_TSN)) 27388c2654abSrjs *biggest_tsn_acked = frag_end+last_tsn; 27398c2654abSrjs 27408c2654abSrjs /* mark acked dgs and find out the highestTSN being acked */ 27418c2654abSrjs if (tp1 == NULL) { 27428c2654abSrjs tp1 = TAILQ_FIRST(&asoc->sent_queue); 27438c2654abSrjs 27448c2654abSrjs /* save the locations of the last frags */ 27458c2654abSrjs last_frag_high = frag_end + last_tsn; 27468c2654abSrjs } else { 27478c2654abSrjs /* 27488c2654abSrjs * now lets see if we need to reset the queue 27498c2654abSrjs * due to a out-of-order SACK fragment 27508c2654abSrjs */ 27518c2654abSrjs if (compare_with_wrap(frag_strt+last_tsn, 27528c2654abSrjs last_frag_high, MAX_TSN)) { 27538c2654abSrjs /* 27548c2654abSrjs * if the new frag starts after the last TSN 27558c2654abSrjs * frag covered, we are ok 27568c2654abSrjs * and this one is beyond the last one 27578c2654abSrjs */ 27588c2654abSrjs ; 27598c2654abSrjs } else { 27608c2654abSrjs /* 27618c2654abSrjs * ok, they have reset us, so we need to reset 27628c2654abSrjs * the queue this will cause extra hunting but 27638c2654abSrjs * hey, they chose the performance 27648c2654abSrjs * hit when they failed to order there gaps.. 27658c2654abSrjs */ 27668c2654abSrjs tp1 = TAILQ_FIRST(&asoc->sent_queue); 27678c2654abSrjs } 27688c2654abSrjs last_frag_high = frag_end + last_tsn; 27698c2654abSrjs } 27708c2654abSrjs for (j = frag_strt + last_tsn; j <= frag_end + last_tsn; j++) { 27718c2654abSrjs while (tp1) { 27728c2654abSrjs #ifdef SCTP_FR_LOGGING 27738c2654abSrjs if (tp1->rec.data.doing_fast_retransmit) 27748c2654abSrjs num_frs++; 27758c2654abSrjs #endif 27768c2654abSrjs 27778c2654abSrjs if (tp1->rec.data.TSN_seq == j) { 27788c2654abSrjs if (tp1->sent != SCTP_DATAGRAM_UNSENT) { 27798c2654abSrjs /* must be held until cum-ack passes */ 27808c2654abSrjs /* ECN Nonce: Add the nonce value to the sender's nonce sum */ 27818c2654abSrjs if (tp1->sent < SCTP_DATAGRAM_ACKED) { 27828c2654abSrjs /* 27838c2654abSrjs * If it is less than 27848c2654abSrjs * ACKED, it is now 27858c2654abSrjs * no-longer in flight. 27868c2654abSrjs * Higher values may 27878c2654abSrjs * already be set via 27888c2654abSrjs * previous Gap Ack 27898c2654abSrjs * Blocks... 27908c2654abSrjs * i.e. ACKED or MARKED. 27918c2654abSrjs */ 27928c2654abSrjs if (compare_with_wrap(tp1->rec.data.TSN_seq, 27938c2654abSrjs *biggest_newly_acked_tsn, 27948c2654abSrjs MAX_TSN)) { 27958c2654abSrjs *biggest_newly_acked_tsn = 27968c2654abSrjs tp1->rec.data.TSN_seq; 27978c2654abSrjs } 27988c2654abSrjs sctp_flight_size_decrease(tp1); 27998c2654abSrjs 28008c2654abSrjs sctp_total_flight_decrease(stcb, tp1); 28018c2654abSrjs 28028c2654abSrjs if (tp1->snd_count < 2) { 2803*79604517Sandvar /* True non-retransmitted chunk */ 28048c2654abSrjs tp1->whoTo->net_ack2 += 28058c2654abSrjs tp1->send_size; 28068c2654abSrjs 28078c2654abSrjs /* update RTO too? */ 28088c2654abSrjs if (tp1->do_rtt) { 28098c2654abSrjs tp1->whoTo->RTO = 28108c2654abSrjs sctp_calculate_rto(stcb, 28118c2654abSrjs asoc, 28128c2654abSrjs tp1->whoTo, 28138c2654abSrjs &tp1->sent_rcv_time); 28148c2654abSrjs tp1->whoTo->rto_pending = 0; 28158c2654abSrjs tp1->do_rtt = 0; 28168c2654abSrjs } 28178c2654abSrjs } 28188c2654abSrjs } 28198c2654abSrjs if (tp1->sent <= SCTP_DATAGRAM_RESEND && 28208c2654abSrjs tp1->sent != SCTP_DATAGRAM_UNSENT && 28218c2654abSrjs compare_with_wrap(tp1->rec.data.TSN_seq, 28228c2654abSrjs asoc->this_sack_highest_gap, 28238c2654abSrjs MAX_TSN)) { 28248c2654abSrjs asoc->this_sack_highest_gap = 28258c2654abSrjs tp1->rec.data.TSN_seq; 28268c2654abSrjs if (primary_flag_set) { 28278c2654abSrjs tp1->whoTo->cacc_saw_newack = 1; 28288c2654abSrjs } 28298c2654abSrjs } 28308c2654abSrjs if (tp1->sent == SCTP_DATAGRAM_RESEND) { 28318c2654abSrjs #ifdef SCTP_DEBUG 28328c2654abSrjs if (sctp_debug_on & 28338c2654abSrjs SCTP_DEBUG_INDATA3) { 28348c2654abSrjs printf("Hmm. one that is in RESEND that is now ACKED\n"); 28358c2654abSrjs } 28368c2654abSrjs #endif 28378c2654abSrjs sctp_ucount_decr(asoc->sent_queue_retran_cnt); 28388c2654abSrjs #ifdef SCTP_AUDITING_ENABLED 28398c2654abSrjs sctp_audit_log(0xB2, 28408c2654abSrjs (asoc->sent_queue_retran_cnt & 0x000000ff)); 28418c2654abSrjs #endif 28428c2654abSrjs 28438c2654abSrjs } 28448c2654abSrjs (*ecn_seg_sums) += tp1->rec.data.ect_nonce; 28458c2654abSrjs (*ecn_seg_sums) &= SCTP_SACK_NONCE_SUM; 28468c2654abSrjs tp1->sent = SCTP_DATAGRAM_MARKED; 28478c2654abSrjs } 28488c2654abSrjs break; 28498c2654abSrjs } /* if (tp1->TSN_seq == j) */ 28508c2654abSrjs if (compare_with_wrap(tp1->rec.data.TSN_seq, j, 28518c2654abSrjs MAX_TSN)) 28528c2654abSrjs break; 28538c2654abSrjs tp1 = TAILQ_NEXT(tp1, sctp_next); 28548c2654abSrjs }/* end while (tp1) */ 28558c2654abSrjs } /* end for (j = fragStart */ 28568c2654abSrjs frag++; /* next one */ 28578c2654abSrjs } 28588c2654abSrjs #ifdef SCTP_FR_LOGGING 28598c2654abSrjs if (num_frs) 28608c2654abSrjs sctp_log_fr(*biggest_tsn_acked, *biggest_newly_acked_tsn, 28618c2654abSrjs last_tsn, SCTP_FR_LOG_BIGGEST_TSNS); 28628c2654abSrjs #endif 28638c2654abSrjs } 28648c2654abSrjs 28658c2654abSrjs static void 28668c2654abSrjs sctp_check_for_revoked(struct sctp_association *asoc, u_long cum_ack, 28678c2654abSrjs u_long biggest_tsn_acked) 28688c2654abSrjs { 28698c2654abSrjs struct sctp_tmit_chunk *tp1; 28708c2654abSrjs int tot_revoked=0; 28718c2654abSrjs 28728c2654abSrjs tp1 = TAILQ_FIRST(&asoc->sent_queue); 28738c2654abSrjs while (tp1) { 28748c2654abSrjs if (compare_with_wrap(tp1->rec.data.TSN_seq, cum_ack, 28758c2654abSrjs MAX_TSN)) { 28768c2654abSrjs /* 28778c2654abSrjs * ok this guy is either ACK or MARKED. If it is ACKED 28788c2654abSrjs * it has been previously acked but not this time i.e. 28798c2654abSrjs * revoked. If it is MARKED it was ACK'ed again. 28808c2654abSrjs */ 28818c2654abSrjs if (tp1->sent == SCTP_DATAGRAM_ACKED) { 28828c2654abSrjs /* it has been revoked */ 28838c2654abSrjs /* 28848c2654abSrjs * We do NOT add back to flight size here since 28858c2654abSrjs * it is really NOT in flight. Resend (when/if 28868c2654abSrjs * it occurs will add to flight size 28878c2654abSrjs */ 28888c2654abSrjs tp1->sent = SCTP_DATAGRAM_SENT; 28898c2654abSrjs tot_revoked++; 28908c2654abSrjs } else if (tp1->sent == SCTP_DATAGRAM_MARKED) { 28918c2654abSrjs /* it has been re-acked in this SACK */ 28928c2654abSrjs tp1->sent = SCTP_DATAGRAM_ACKED; 28938c2654abSrjs } 28948c2654abSrjs } 28958c2654abSrjs if (compare_with_wrap(tp1->rec.data.TSN_seq, biggest_tsn_acked, 28968c2654abSrjs MAX_TSN)) { 28978c2654abSrjs /* above the sack */ 28988c2654abSrjs break; 28998c2654abSrjs } 29008c2654abSrjs if (tp1->sent == SCTP_DATAGRAM_UNSENT) 29018c2654abSrjs break; 29028c2654abSrjs tp1 = TAILQ_NEXT(tp1, sctp_next); 29038c2654abSrjs } 29048c2654abSrjs if (tot_revoked > 0) { 29058c2654abSrjs /* Setup the ecn nonce re-sync point. We 29068c2654abSrjs * do this since once data is revoked 29078c2654abSrjs * we begin to retransmit things, which 29088c2654abSrjs * do NOT have the ECN bits set. This means 29098c2654abSrjs * we are now out of sync and must wait until 29108c2654abSrjs * we get back in sync with the peer to 29118c2654abSrjs * check ECN bits. 29128c2654abSrjs */ 29138c2654abSrjs tp1 = TAILQ_FIRST(&asoc->send_queue); 29148c2654abSrjs if (tp1 == NULL) { 29158c2654abSrjs asoc->nonce_resync_tsn = asoc->sending_seq; 29168c2654abSrjs } else { 29178c2654abSrjs asoc->nonce_resync_tsn = tp1->rec.data.TSN_seq; 29188c2654abSrjs } 29198c2654abSrjs asoc->nonce_wait_for_ecne = 0; 29208c2654abSrjs asoc->nonce_sum_check = 0; 29218c2654abSrjs } 29228c2654abSrjs 29238c2654abSrjs } 29248c2654abSrjs 29258c2654abSrjs extern int sctp_peer_chunk_oh; 29268c2654abSrjs 29278c2654abSrjs static void 29288c2654abSrjs sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, 29298c2654abSrjs u_long biggest_tsn_acked, int strike_enabled, 29308c2654abSrjs u_long biggest_tsn_newly_acked, int accum_moved) 29318c2654abSrjs { 29328c2654abSrjs struct sctp_tmit_chunk *tp1; 29338c2654abSrjs int strike_flag=0; 29348c2654abSrjs struct timeval now; 29358c2654abSrjs int tot_retrans=0; 29368c2654abSrjs u_int32_t sending_seq; 29378c2654abSrjs int primary_switch_active = 0; 29388c2654abSrjs int double_switch_active = 0; 29398c2654abSrjs 29408c2654abSrjs /* select the sending_seq, this is 29418c2654abSrjs * either the next thing ready to 29428c2654abSrjs * be sent but not transmitted, OR, 29438c2654abSrjs * the next seq we assign. 29448c2654abSrjs */ 29458c2654abSrjs tp1 = TAILQ_FIRST(&stcb->asoc.send_queue); 29468c2654abSrjs if (tp1 == NULL) { 29478c2654abSrjs sending_seq = asoc->sending_seq; 29488c2654abSrjs } else { 29498c2654abSrjs sending_seq = tp1->rec.data.TSN_seq; 29508c2654abSrjs } 29518c2654abSrjs 29528c2654abSrjs if (asoc->primary_destination->dest_state & SCTP_ADDR_SWITCH_PRIMARY) { 29538c2654abSrjs primary_switch_active = 1; 29548c2654abSrjs } 29558c2654abSrjs if (asoc->primary_destination->dest_state & SCTP_ADDR_DOUBLE_SWITCH) { 29568c2654abSrjs double_switch_active = 1; 29578c2654abSrjs } 29588c2654abSrjs if (stcb->asoc.peer_supports_prsctp ) { 29598c2654abSrjs SCTP_GETTIME_TIMEVAL(&now); 29608c2654abSrjs } 29618c2654abSrjs tp1 = TAILQ_FIRST(&asoc->sent_queue); 29628c2654abSrjs while (tp1) { 29638c2654abSrjs strike_flag=0; 29648c2654abSrjs if (compare_with_wrap(tp1->rec.data.TSN_seq, biggest_tsn_acked, 29658c2654abSrjs MAX_TSN) || 29668c2654abSrjs tp1->sent == SCTP_DATAGRAM_UNSENT) { 29678c2654abSrjs /* done */ 29688c2654abSrjs break; 29698c2654abSrjs } 29708c2654abSrjs if ((tp1->flags & (SCTP_PR_SCTP_ENABLED|SCTP_PR_SCTP_BUFFER)) == 29718c2654abSrjs SCTP_PR_SCTP_ENABLED && 29728c2654abSrjs tp1->sent < SCTP_DATAGRAM_ACKED) { 29738c2654abSrjs /* Is it expired? */ 29748c2654abSrjs #ifndef __FreeBSD__ 29758c2654abSrjs if (timercmp(&now, &tp1->rec.data.timetodrop, >)) 29768c2654abSrjs #else 29778c2654abSrjs if (timevalcmp(&now, &tp1->rec.data.timetodrop, >)) 29788c2654abSrjs #endif 29798c2654abSrjs { 29808c2654abSrjs /* Yes so drop it */ 29818c2654abSrjs if (tp1->data != NULL) { 29828c2654abSrjs sctp_release_pr_sctp_chunk(stcb, tp1, 29838c2654abSrjs (SCTP_RESPONSE_TO_USER_REQ|SCTP_NOTIFY_DATAGRAM_SENT), 29848c2654abSrjs &asoc->sent_queue); 29858c2654abSrjs } 29868c2654abSrjs tp1 = TAILQ_NEXT(tp1, sctp_next); 29878c2654abSrjs continue; 29888c2654abSrjs } 29898c2654abSrjs } 29908c2654abSrjs 29918c2654abSrjs if (compare_with_wrap(tp1->rec.data.TSN_seq, 29928c2654abSrjs asoc->this_sack_highest_gap, MAX_TSN)) { 29938c2654abSrjs /* we are beyond the tsn in the sack */ 29948c2654abSrjs break; 29958c2654abSrjs } 29968c2654abSrjs if (tp1->sent >= SCTP_DATAGRAM_RESEND) { 29978c2654abSrjs /* either a RESEND, ACKED, or MARKED */ 29988c2654abSrjs /* skip */ 29998c2654abSrjs tp1 = TAILQ_NEXT(tp1, sctp_next); 30008c2654abSrjs continue; 30018c2654abSrjs } 30028c2654abSrjs if (primary_switch_active && (strike_enabled == 0)) { 30038c2654abSrjs if (tp1->whoTo != asoc->primary_destination) { 30048c2654abSrjs /* 30058c2654abSrjs * We can only strike things on the primary if 30068c2654abSrjs * the strike_enabled flag is clear 30078c2654abSrjs */ 30088c2654abSrjs tp1 = TAILQ_NEXT(tp1, sctp_next); 30098c2654abSrjs continue; 30108c2654abSrjs } 30118c2654abSrjs } else if (primary_switch_active) { 30128c2654abSrjs if (tp1->whoTo->cacc_saw_newack == 0) { 30138c2654abSrjs /* 30148c2654abSrjs * Only one was received but it was NOT 30158c2654abSrjs * this one. 30168c2654abSrjs */ 30178c2654abSrjs tp1 = TAILQ_NEXT(tp1, sctp_next); 30188c2654abSrjs continue; 30198c2654abSrjs } 30208c2654abSrjs } 30218c2654abSrjs if (double_switch_active && 30228c2654abSrjs (compare_with_wrap(asoc->primary_destination->next_tsn_at_change, 30238c2654abSrjs tp1->rec.data.TSN_seq, MAX_TSN))) { 30248c2654abSrjs /* 30258c2654abSrjs * With a double switch we do NOT mark unless we 30268c2654abSrjs * are beyond the switch point. 30278c2654abSrjs */ 30288c2654abSrjs tp1 = TAILQ_NEXT(tp1, sctp_next); 30298c2654abSrjs continue; 30308c2654abSrjs } 30318c2654abSrjs /* 30328c2654abSrjs * Here we check to see if we were have already done a FR 30338c2654abSrjs * and if so we see if the biggest TSN we saw in the sack is 30348c2654abSrjs * smaller than the recovery point. If so we don't strike the 30358c2654abSrjs * tsn... otherwise we CAN strike the TSN. 30368c2654abSrjs */ 30378c2654abSrjs if (accum_moved && asoc->fast_retran_loss_recovery) { 30388c2654abSrjs /* 30398c2654abSrjs * Strike the TSN if in fast-recovery and 30408c2654abSrjs * cum-ack moved. 30418c2654abSrjs */ 30428c2654abSrjs tp1->sent++; 30438c2654abSrjs } else if (tp1->rec.data.doing_fast_retransmit) { 30448c2654abSrjs /* 30458c2654abSrjs * For those that have done a FR we must 30468c2654abSrjs * take special consideration if we strike. I.e 30478c2654abSrjs * the biggest_newly_acked must be higher 30488c2654abSrjs * than the sending_seq at the time we did 30498c2654abSrjs * the FR. 30508c2654abSrjs */ 30518c2654abSrjs #ifdef SCTP_FR_TO_ALTERNATE 30528c2654abSrjs /* 30538c2654abSrjs * If FR's go to new networks, then we 30548c2654abSrjs * must only do this for singly homed asoc's. However 30558c2654abSrjs * if the FR's go to the same network (Armando's work) 30568c2654abSrjs * then its ok to FR multiple times. 30578c2654abSrjs */ 30588c2654abSrjs if (asoc->numnets < 2) 30598c2654abSrjs #else 30608c2654abSrjs if (1) 30618c2654abSrjs #endif 30628c2654abSrjs { 30638c2654abSrjs if ((compare_with_wrap(biggest_tsn_newly_acked, 30648c2654abSrjs tp1->rec.data.fast_retran_tsn, MAX_TSN)) || 30658c2654abSrjs (biggest_tsn_newly_acked == 30668c2654abSrjs tp1->rec.data.fast_retran_tsn)) { 30678c2654abSrjs /* 30688c2654abSrjs * Strike the TSN, since this ack is 30698c2654abSrjs * beyond where things were when we did 30708c2654abSrjs * a FR. 30718c2654abSrjs */ 30728c2654abSrjs #ifdef SCTP_FR_LOGGING 30738c2654abSrjs sctp_log_fr(biggest_tsn_newly_acked, 30748c2654abSrjs tp1->rec.data.TSN_seq, 30758c2654abSrjs tp1->rec.data.fast_retran_tsn, 30768c2654abSrjs SCTP_FR_LOG_STRIKE_CHUNK); 30778c2654abSrjs #endif 30788c2654abSrjs tp1->sent++; 30798c2654abSrjs strike_flag=1; 30808c2654abSrjs } 30818c2654abSrjs } 30828c2654abSrjs } else if (compare_with_wrap(tp1->rec.data.TSN_seq, 30838c2654abSrjs biggest_tsn_newly_acked, MAX_TSN)) { 30848c2654abSrjs /* 30858c2654abSrjs * We don't strike these: 30868c2654abSrjs * This is the HTNA algorithm i.e. we don't strike 30878c2654abSrjs * If our TSN is larger than the Highest TSN Newly 30888c2654abSrjs * Acked. 30898c2654abSrjs */ 30908c2654abSrjs ; 30918c2654abSrjs } else { 30928c2654abSrjs /* Strike the TSN */ 30938c2654abSrjs tp1->sent++; 30948c2654abSrjs } 30958c2654abSrjs if (tp1->sent == SCTP_DATAGRAM_RESEND) { 30968c2654abSrjs /* Increment the count to resend */ 30978c2654abSrjs struct sctp_nets *alt; 30988c2654abSrjs 30998c2654abSrjs #ifdef SCTP_FR_LOGGING 31008c2654abSrjs sctp_log_fr(tp1->rec.data.TSN_seq, tp1->snd_count, 31018c2654abSrjs 0, SCTP_FR_MARKED); 31028c2654abSrjs #endif 31038c2654abSrjs if (strike_flag) { 31048c2654abSrjs /* This is a subsequent FR */ 31058c2654abSrjs sctp_pegs[SCTP_DUP_FR]++; 31068c2654abSrjs } 31078c2654abSrjs asoc->sent_queue_retran_cnt++; 31088c2654abSrjs #ifdef SCTP_FR_TO_ALTERNATE 31098c2654abSrjs /* Can we find an alternate? */ 31108c2654abSrjs alt = sctp_find_alternate_net(stcb, tp1->whoTo); 31118c2654abSrjs #else 31128c2654abSrjs /* 31138c2654abSrjs * default behavior is to NOT retransmit FR's 31148c2654abSrjs * to an alternate. Armando Caro's paper details 31158c2654abSrjs * why. 31168c2654abSrjs */ 31178c2654abSrjs alt = tp1->whoTo; 31188c2654abSrjs #endif 31198c2654abSrjs tp1->rec.data.doing_fast_retransmit = 1; 31208c2654abSrjs tot_retrans++; 31218c2654abSrjs /* mark the sending seq for possible subsequent FR's */ 31228c2654abSrjs if (TAILQ_EMPTY(&asoc->send_queue)) { 31238c2654abSrjs /* 31248c2654abSrjs * If the queue of send is empty then its the 31258c2654abSrjs * next sequence number that will be assigned so 31268c2654abSrjs * we subtract one from this to get the one we 31278c2654abSrjs * last sent. 31288c2654abSrjs */ 31298c2654abSrjs tp1->rec.data.fast_retran_tsn = sending_seq - 1; 31308c2654abSrjs } else { 31318c2654abSrjs /* 31328c2654abSrjs * If there are chunks on the send queue 31338c2654abSrjs * (unsent data that has made it from the 31348c2654abSrjs * stream queues but not out the door, we take 31358c2654abSrjs * the first one (which will have the lowest 31368c2654abSrjs * TSN) and subtract one to get the one we last 31378c2654abSrjs * sent. 31388c2654abSrjs */ 31398c2654abSrjs struct sctp_tmit_chunk *ttt; 31408c2654abSrjs ttt = TAILQ_FIRST(&asoc->send_queue); 31418c2654abSrjs tp1->rec.data.fast_retran_tsn = 31428c2654abSrjs ttt->rec.data.TSN_seq - 1; 31438c2654abSrjs } 31448c2654abSrjs if (tp1->do_rtt) { 31458c2654abSrjs /* 31468c2654abSrjs * this guy had a RTO calculation pending on it, 31478c2654abSrjs * cancel it 31488c2654abSrjs */ 31498c2654abSrjs tp1->whoTo->rto_pending = 0; 31508c2654abSrjs tp1->do_rtt = 0; 31518c2654abSrjs } 31528c2654abSrjs /* fix counts and things */ 31538c2654abSrjs 31548c2654abSrjs tp1->whoTo->net_ack++; 31558c2654abSrjs sctp_flight_size_decrease(tp1); 31568c2654abSrjs #ifdef SCTP_LOG_RWND 31578c2654abSrjs sctp_log_rwnd(SCTP_INCREASE_PEER_RWND, 31588c2654abSrjs asoc->peers_rwnd , tp1->send_size, sctp_peer_chunk_oh); 31598c2654abSrjs #endif 31608c2654abSrjs /* add back to the rwnd */ 31618c2654abSrjs asoc->peers_rwnd += (tp1->send_size + sctp_peer_chunk_oh); 31628c2654abSrjs 31638c2654abSrjs /* remove from the total flight */ 31648c2654abSrjs sctp_total_flight_decrease(stcb, tp1); 31658c2654abSrjs if (alt != tp1->whoTo) { 31668c2654abSrjs /* yes, there is an alternate. */ 31678c2654abSrjs sctp_free_remote_addr(tp1->whoTo); 31688c2654abSrjs tp1->whoTo = alt; 31698c2654abSrjs alt->ref_count++; 31708c2654abSrjs } 31718c2654abSrjs } 31728c2654abSrjs tp1 = TAILQ_NEXT(tp1, sctp_next); 31738c2654abSrjs } /* while (tp1) */ 31748c2654abSrjs 31758c2654abSrjs if (tot_retrans > 0) { 31768c2654abSrjs /* Setup the ecn nonce re-sync point. We 31778c2654abSrjs * do this since once we go to FR something 31788c2654abSrjs * we introduce a Karn's rule scenario and 31798c2654abSrjs * won't know the totals for the ECN bits. 31808c2654abSrjs */ 31818c2654abSrjs asoc->nonce_resync_tsn = sending_seq; 31828c2654abSrjs asoc->nonce_wait_for_ecne = 0; 31838c2654abSrjs asoc->nonce_sum_check = 0; 31848c2654abSrjs } 31858c2654abSrjs 31868c2654abSrjs } 31878c2654abSrjs 31888c2654abSrjs struct sctp_tmit_chunk * 31898c2654abSrjs sctp_try_advance_peer_ack_point(struct sctp_tcb *stcb, 31908c2654abSrjs struct sctp_association *asoc) 31918c2654abSrjs { 31928c2654abSrjs struct sctp_tmit_chunk *tp1, *tp2, *a_adv=NULL; 31938c2654abSrjs struct timeval now; 31948c2654abSrjs int now_filled=0; 31958c2654abSrjs 31968c2654abSrjs if (asoc->peer_supports_prsctp == 0) { 31978c2654abSrjs return (NULL); 31988c2654abSrjs } 31998c2654abSrjs tp1 = TAILQ_FIRST(&asoc->sent_queue); 32008c2654abSrjs while (tp1) { 32018c2654abSrjs if (tp1->sent != SCTP_FORWARD_TSN_SKIP && 32028c2654abSrjs tp1->sent != SCTP_DATAGRAM_RESEND) { 32038c2654abSrjs /* no chance to advance, out of here */ 32048c2654abSrjs break; 32058c2654abSrjs } 32068c2654abSrjs if ((tp1->flags & SCTP_PR_SCTP_ENABLED) == 0) { 32078c2654abSrjs /* 32088c2654abSrjs * We can't fwd-tsn past any that are reliable 32098c2654abSrjs * aka retransmitted until the asoc fails. 32108c2654abSrjs */ 32118c2654abSrjs break; 32128c2654abSrjs } 32138c2654abSrjs if (!now_filled) { 32148c2654abSrjs SCTP_GETTIME_TIMEVAL(&now); 32158c2654abSrjs now_filled = 1; 32168c2654abSrjs } 32178c2654abSrjs tp2 = TAILQ_NEXT(tp1, sctp_next); 32188c2654abSrjs /* 32198c2654abSrjs * now we got a chunk which is marked for another 32208c2654abSrjs * retransmission to a PR-stream but has run 32218c2654abSrjs * out its chances already maybe OR has been 32228c2654abSrjs * marked to skip now. Can we skip it if its a 32238c2654abSrjs * resend? 32248c2654abSrjs */ 32258c2654abSrjs if (tp1->sent == SCTP_DATAGRAM_RESEND && 32268c2654abSrjs (tp1->flags & SCTP_PR_SCTP_BUFFER) == 0) { 32278c2654abSrjs /* 32288c2654abSrjs * Now is this one marked for resend and its time 32298c2654abSrjs * is now up? 32308c2654abSrjs */ 32318c2654abSrjs #ifndef __FreeBSD__ 32328c2654abSrjs if (timercmp(&now, &tp1->rec.data.timetodrop, >)) 32338c2654abSrjs #else 32348c2654abSrjs if (timevalcmp(&now, &tp1->rec.data.timetodrop, >)) 32358c2654abSrjs #endif 32368c2654abSrjs { 32378c2654abSrjs /* Yes so drop it */ 32388c2654abSrjs if (tp1->data) { 32398c2654abSrjs sctp_release_pr_sctp_chunk(stcb, tp1, 32408c2654abSrjs (SCTP_RESPONSE_TO_USER_REQ|SCTP_NOTIFY_DATAGRAM_SENT), 32418c2654abSrjs &asoc->sent_queue); 32428c2654abSrjs } 32438c2654abSrjs } else { 32448c2654abSrjs /* 32458c2654abSrjs * No, we are done when hit one for resend whos 32468c2654abSrjs * time as not expired. 32478c2654abSrjs */ 32488c2654abSrjs break; 32498c2654abSrjs } 32508c2654abSrjs } 32518c2654abSrjs /* 32528c2654abSrjs * Ok now if this chunk is marked to drop it 32538c2654abSrjs * we can clean up the chunk, advance our peer ack point 32548c2654abSrjs * and we can check the next chunk. 32558c2654abSrjs */ 32568c2654abSrjs if (tp1->sent == SCTP_FORWARD_TSN_SKIP) { 32578c2654abSrjs /* advance PeerAckPoint goes forward */ 32588c2654abSrjs asoc->advanced_peer_ack_point = tp1->rec.data.TSN_seq; 32598c2654abSrjs a_adv = tp1; 32608c2654abSrjs /* 32618c2654abSrjs * we don't want to de-queue it here. Just wait for the 32628c2654abSrjs * next peer SACK to come with a new cumTSN and then 3263cdc507f0Sandvar * the chunk will be dropped in the normal fashion. 32648c2654abSrjs */ 32658c2654abSrjs if (tp1->data) { 32668c2654abSrjs sctp_free_bufspace(stcb, asoc, tp1); 32678c2654abSrjs #ifdef SCTP_DEBUG 32688c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_OUTPUT2) { 32698c2654abSrjs printf("--total out:%lu total_mbuf_out:%lu\n", 32708c2654abSrjs (u_long)asoc->total_output_queue_size, 32718c2654abSrjs (u_long)asoc->total_output_mbuf_queue_size); 32728c2654abSrjs } 32738c2654abSrjs #endif 32748c2654abSrjs /* 32758c2654abSrjs * Maybe there should be another notification 32768c2654abSrjs * type 32778c2654abSrjs */ 32788c2654abSrjs sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, 32798c2654abSrjs (SCTP_RESPONSE_TO_USER_REQ|SCTP_NOTIFY_DATAGRAM_SENT), 32808c2654abSrjs tp1); 32818c2654abSrjs sctp_m_freem(tp1->data); 32828c2654abSrjs tp1->data = NULL; 32838c2654abSrjs sctp_sowwakeup(stcb->sctp_ep, 32848c2654abSrjs stcb->sctp_socket); 32858c2654abSrjs } 32868c2654abSrjs } else { 32878c2654abSrjs /* If it is still in RESEND we can advance no further */ 32888c2654abSrjs break; 32898c2654abSrjs } 32908c2654abSrjs /* 32918c2654abSrjs * If we hit here we just dumped tp1, move to next 32928c2654abSrjs * tsn on sent queue. 32938c2654abSrjs */ 32948c2654abSrjs tp1 = tp2; 32958c2654abSrjs } 32968c2654abSrjs return (a_adv); 32978c2654abSrjs } 32988c2654abSrjs 32998c2654abSrjs #ifdef SCTP_HIGH_SPEED 33008c2654abSrjs struct sctp_hs_raise_drop { 33018c2654abSrjs int32_t cwnd; 33028c2654abSrjs int32_t increase; 33038c2654abSrjs int32_t drop_percent; 33048c2654abSrjs }; 33058c2654abSrjs 33068c2654abSrjs #define SCTP_HS_TABLE_SIZE 73 33078c2654abSrjs 33088c2654abSrjs struct sctp_hs_raise_drop sctp_cwnd_adjust[SCTP_HS_TABLE_SIZE] = { 33098c2654abSrjs {38,1,50}, /* 0 */ 33108c2654abSrjs {118,2,44}, /* 1 */ 33118c2654abSrjs {221,3,41}, /* 2 */ 33128c2654abSrjs {347,4,38}, /* 3 */ 33138c2654abSrjs {495,5,37}, /* 4 */ 33148c2654abSrjs {663,6,35}, /* 5 */ 33158c2654abSrjs {851,7,34}, /* 6 */ 33168c2654abSrjs {1058,8,33}, /* 7 */ 33178c2654abSrjs {1284,9,32}, /* 8 */ 33188c2654abSrjs {1529,10,31}, /* 9 */ 33198c2654abSrjs {1793,11,30}, /* 10 */ 33208c2654abSrjs {2076,12,29}, /* 11 */ 33218c2654abSrjs {2378,13,28}, /* 12 */ 33228c2654abSrjs {2699,14,28}, /* 13 */ 33238c2654abSrjs {3039,15,27}, /* 14 */ 33248c2654abSrjs {3399,16,27}, /* 15 */ 33258c2654abSrjs {3778,17,26}, /* 16 */ 33268c2654abSrjs {4177,18,26}, /* 17 */ 33278c2654abSrjs {4596,19,25}, /* 18 */ 33288c2654abSrjs {5036,20,25}, /* 19 */ 33298c2654abSrjs {5497,21,24}, /* 20 */ 33308c2654abSrjs {5979,22,24}, /* 21 */ 33318c2654abSrjs {6483,23,23}, /* 22 */ 33328c2654abSrjs {7009,24,23}, /* 23 */ 33338c2654abSrjs {7558,25,22}, /* 24 */ 33348c2654abSrjs {8130,26,22}, /* 25 */ 33358c2654abSrjs {8726,27,22}, /* 26 */ 33368c2654abSrjs {9346,28,21}, /* 27 */ 33378c2654abSrjs {9991,29,21}, /* 28 */ 33388c2654abSrjs {10661,30,21}, /* 29 */ 33398c2654abSrjs {11358,31,20}, /* 30 */ 33408c2654abSrjs {12082,32,20}, /* 31 */ 33418c2654abSrjs {12834,33,20}, /* 32 */ 33428c2654abSrjs {13614,34,19}, /* 33 */ 33438c2654abSrjs {14424,35,19}, /* 34 */ 33448c2654abSrjs {15265,36,19}, /* 35 */ 33458c2654abSrjs {16137,37,19}, /* 36 */ 33468c2654abSrjs {17042,38,18}, /* 37 */ 33478c2654abSrjs {17981,39,18}, /* 38 */ 33488c2654abSrjs {18955,40,18}, /* 39 */ 33498c2654abSrjs {19965,41,17}, /* 40 */ 33508c2654abSrjs {21013,42,17}, /* 41 */ 33518c2654abSrjs {22101,43,17}, /* 42 */ 33528c2654abSrjs {23230,44,17}, /* 43 */ 33538c2654abSrjs {24402,45,16}, /* 44 */ 33548c2654abSrjs {25618,46,16}, /* 45 */ 33558c2654abSrjs {26881,47,16}, /* 46 */ 33568c2654abSrjs {28193,48,16}, /* 47 */ 33578c2654abSrjs {29557,49,15}, /* 48 */ 33588c2654abSrjs {30975,50,15}, /* 49 */ 33598c2654abSrjs {32450,51,15}, /* 50 */ 33608c2654abSrjs {33986,52,15}, /* 51 */ 33618c2654abSrjs {35586,53,14}, /* 52 */ 33628c2654abSrjs {37253,54,14}, /* 53 */ 33638c2654abSrjs {38992,55,14}, /* 54 */ 33648c2654abSrjs {40808,56,14}, /* 55 */ 33658c2654abSrjs {42707,57,13}, /* 56 */ 33668c2654abSrjs {44694,58,13}, /* 57 */ 33678c2654abSrjs {46776,59,13}, /* 58 */ 33688c2654abSrjs {48961,60,13}, /* 59 */ 33698c2654abSrjs {51258,61,13}, /* 60 */ 33708c2654abSrjs {53677,62,12}, /* 61 */ 33718c2654abSrjs {56230,63,12}, /* 62 */ 33728c2654abSrjs {58932,64,12}, /* 63 */ 33738c2654abSrjs {61799,65,12}, /* 64 */ 33748c2654abSrjs {64851,66,11}, /* 65 */ 33758c2654abSrjs {68113,67,11}, /* 66 */ 33768c2654abSrjs {71617,68,11}, /* 67 */ 33778c2654abSrjs {75401,69,10}, /* 68 */ 33788c2654abSrjs {79517,70,10}, /* 69 */ 33798c2654abSrjs {84035,71,10}, /* 70 */ 33808c2654abSrjs {89053,72,10}, /* 71 */ 33818c2654abSrjs {94717,73,9} /* 72 */ 33828c2654abSrjs }; 33838c2654abSrjs 33848c2654abSrjs static void 33858c2654abSrjs sctp_hs_cwnd_increase(struct sctp_nets *net) 33868c2654abSrjs { 33878c2654abSrjs int cur_val, i, indx, incr; 33888c2654abSrjs 33898c2654abSrjs cur_val = net->cwnd >> 10; 33908c2654abSrjs indx = SCTP_HS_TABLE_SIZE - 1; 33918c2654abSrjs 33928c2654abSrjs if (cur_val < sctp_cwnd_adjust[0].cwnd) { 33938c2654abSrjs /* normal mode */ 33948c2654abSrjs if (net->net_ack > net->mtu) { 33958c2654abSrjs net->cwnd += net->mtu; 33968c2654abSrjs #ifdef SCTP_CWND_LOGGING 33978c2654abSrjs sctp_log_cwnd(net, net->mtu, SCTP_CWND_LOG_FROM_SS); 33988c2654abSrjs #endif 33998c2654abSrjs } else { 34008c2654abSrjs net->cwnd += net->net_ack; 34018c2654abSrjs #ifdef SCTP_CWND_LOGGING 34028c2654abSrjs sctp_log_cwnd(net, net->net_ack, SCTP_CWND_LOG_FROM_SS); 34038c2654abSrjs #endif 34048c2654abSrjs } 34058c2654abSrjs } else { 34068c2654abSrjs for (i=net->last_hs_used; i<SCTP_HS_TABLE_SIZE; i++) { 34078c2654abSrjs if (cur_val < sctp_cwnd_adjust[i].cwnd) { 34088c2654abSrjs indx = i; 34098c2654abSrjs break; 34108c2654abSrjs } 34118c2654abSrjs } 34128c2654abSrjs net->last_hs_used = indx; 34138c2654abSrjs incr = ((sctp_cwnd_adjust[indx].increase) << 10); 34148c2654abSrjs net->cwnd += incr; 34158c2654abSrjs #ifdef SCTP_CWND_LOGGING 34168c2654abSrjs sctp_log_cwnd(net, incr, SCTP_CWND_LOG_FROM_SS); 34178c2654abSrjs #endif 34188c2654abSrjs } 34198c2654abSrjs } 34208c2654abSrjs 34218c2654abSrjs static void 34228c2654abSrjs sctp_hs_cwnd_decrease(struct sctp_nets *net) 34238c2654abSrjs { 34248c2654abSrjs int cur_val, i, indx; 34258c2654abSrjs #ifdef SCTP_CWND_LOGGING 34268c2654abSrjs int old_cwnd = net->cwnd; 34278c2654abSrjs #endif 34288c2654abSrjs 34298c2654abSrjs cur_val = net->cwnd >> 10; 34308c2654abSrjs indx = net->last_hs_used; 34318c2654abSrjs if (cur_val < sctp_cwnd_adjust[0].cwnd) { 34328c2654abSrjs /* normal mode */ 34338c2654abSrjs net->ssthresh = net->cwnd / 2; 34348c2654abSrjs if (net->ssthresh < (net->mtu*2)) { 34358c2654abSrjs net->ssthresh = 2 * net->mtu; 34368c2654abSrjs } 34378c2654abSrjs net->cwnd = net->ssthresh; 34388c2654abSrjs #ifdef SCTP_CWND_LOGGING 34398c2654abSrjs sctp_log_cwnd(net, (net->cwnd-old_cwnd), SCTP_CWND_LOG_FROM_FR); 34408c2654abSrjs #endif 34418c2654abSrjs } else { 34428c2654abSrjs /* drop by the proper amount */ 34438c2654abSrjs net->ssthresh = net->cwnd - (int)((net->cwnd / 100) * 34448c2654abSrjs sctp_cwnd_adjust[net->last_hs_used].drop_percent); 34458c2654abSrjs net->cwnd = net->ssthresh; 34468c2654abSrjs /* now where are we */ 34478c2654abSrjs indx = net->last_hs_used; 34488c2654abSrjs cur_val = net->cwnd >> 10; 34498c2654abSrjs /* reset where we are in the table */ 34508c2654abSrjs if (cur_val < sctp_cwnd_adjust[0].cwnd) { 34518c2654abSrjs /* feel out of hs */ 34528c2654abSrjs net->last_hs_used = 0; 34538c2654abSrjs } else { 34548c2654abSrjs for (i = indx; i >= 1; i--) { 34558c2654abSrjs if (cur_val > sctp_cwnd_adjust[i - 1].cwnd) { 34568c2654abSrjs break; 34578c2654abSrjs } 34588c2654abSrjs } 34598c2654abSrjs net->last_hs_used = indx; 34608c2654abSrjs } 34618c2654abSrjs } 34628c2654abSrjs } 34638c2654abSrjs #endif 34648c2654abSrjs 34658c2654abSrjs void 34668c2654abSrjs sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb, 34678c2654abSrjs struct sctp_nets *net_from, int *abort_now) 34688c2654abSrjs { 34698c2654abSrjs struct sctp_association *asoc; 34708c2654abSrjs struct sctp_sack *sack; 34718c2654abSrjs struct sctp_tmit_chunk *tp1, *tp2; 34728c2654abSrjs u_long cum_ack, last_tsn, biggest_tsn_acked, biggest_tsn_newly_acked; 34738c2654abSrjs uint16_t num_seg; 34748c2654abSrjs unsigned int sack_length; 34758c2654abSrjs uint32_t send_s; 34768c2654abSrjs int some_on_streamwheel; 34778c2654abSrjs int strike_enabled = 0, cnt_of_cacc = 0; 34788c2654abSrjs int accum_moved = 0; 34798c2654abSrjs int marking_allowed = 1; 34808c2654abSrjs int will_exit_fast_recovery=0; 34818c2654abSrjs u_int32_t a_rwnd; 34828c2654abSrjs struct sctp_nets *net = NULL; 34838c2654abSrjs int nonce_sum_flag, ecn_seg_sums=0; 34848c2654abSrjs asoc = &stcb->asoc; 34858c2654abSrjs 34868c2654abSrjs /* 34878c2654abSrjs * Handle the incoming sack on data I have been sending. 34888c2654abSrjs */ 34898c2654abSrjs 34908c2654abSrjs /* 34918c2654abSrjs * we take any chance we can to service our queues since we 34928c2654abSrjs * cannot get awoken when the socket is read from :< 34938c2654abSrjs */ 34948c2654abSrjs asoc->overall_error_count = 0; 34958c2654abSrjs 34968c2654abSrjs if (asoc->sent_queue_retran_cnt) { 34978c2654abSrjs #ifdef SCTP_DEBUG 34988c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 34998c2654abSrjs printf("Handling SACK for asoc:%p retran:%d\n", 35008c2654abSrjs asoc, asoc->sent_queue_retran_cnt); 35018c2654abSrjs } 35028c2654abSrjs #endif 35038c2654abSrjs } 35048c2654abSrjs 35058c2654abSrjs sctp_service_queues(stcb, asoc, 0); 35068c2654abSrjs 35078c2654abSrjs /* 35088c2654abSrjs * Now perform the actual SACK handling: 35098c2654abSrjs * 1) Verify that it is not an old sack, if so discard. 35108c2654abSrjs * 2) If there is nothing left in the send queue (cum-ack is equal 35118c2654abSrjs * to last acked) then you have a duplicate too, update any rwnd 35128c2654abSrjs * change and verify no timers are running. then return. 35138c2654abSrjs * 3) Process any new consequtive data i.e. cum-ack moved 35148c2654abSrjs * process these first and note that it moved. 35158c2654abSrjs * 4) Process any sack blocks. 35168c2654abSrjs * 5) Drop any acked from the queue. 35178c2654abSrjs * 6) Check for any revoked blocks and mark. 35188c2654abSrjs * 7) Update the cwnd. 35198c2654abSrjs * 8) Nothing left, sync up flightsizes and things, stop all timers 35208c2654abSrjs * and also check for shutdown_pending state. If so then go ahead 35218c2654abSrjs * and send off the shutdown. If in shutdown recv, send off the 35228c2654abSrjs * shutdown-ack and start that timer, Ret. 35238c2654abSrjs * 9) Strike any non-acked things and do FR procedure if needed being 35248c2654abSrjs * sure to set the FR flag. 35258c2654abSrjs * 10) Do pr-sctp procedures. 35268c2654abSrjs * 11) Apply any FR penalties. 35278c2654abSrjs * 12) Assure we will SACK if in shutdown_recv state. 35288c2654abSrjs */ 35298c2654abSrjs 35308c2654abSrjs sack_length = ntohs(ch->ch.chunk_length); 35318c2654abSrjs if (sack_length < sizeof(struct sctp_sack_chunk)) { 35328c2654abSrjs #ifdef SCTP_DEBUG 35338c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 35348c2654abSrjs printf("Bad size on sack chunk .. to small\n"); 35358c2654abSrjs } 35368c2654abSrjs #endif 35378c2654abSrjs return; 35388c2654abSrjs } 35398c2654abSrjs /* ECN Nonce */ 35408c2654abSrjs nonce_sum_flag = ch->ch.chunk_flags & SCTP_SACK_NONCE_SUM; 35418c2654abSrjs sack = &ch->sack; 35428c2654abSrjs cum_ack = last_tsn = ntohl(sack->cum_tsn_ack); 35438c2654abSrjs num_seg = ntohs(sack->num_gap_ack_blks); 35448c2654abSrjs 35458c2654abSrjs /* reality check */ 35468c2654abSrjs if (TAILQ_EMPTY(&asoc->send_queue)) { 35478c2654abSrjs send_s = asoc->sending_seq; 35488c2654abSrjs } else { 35498c2654abSrjs tp1 = TAILQ_FIRST(&asoc->send_queue); 35508c2654abSrjs send_s = tp1->rec.data.TSN_seq; 35518c2654abSrjs } 35528c2654abSrjs 35538c2654abSrjs if (sctp_strict_sacks) { 35548c2654abSrjs if (cum_ack == send_s || 35558c2654abSrjs compare_with_wrap(cum_ack, send_s, MAX_TSN)) { 35568c2654abSrjs struct mbuf *oper; 35578c2654abSrjs /* 35588c2654abSrjs * no way, we have not even sent this TSN out yet. 35598c2654abSrjs * Peer is hopelessly messed up with us. 35608c2654abSrjs */ 35618c2654abSrjs hopeless_peer: 35628c2654abSrjs *abort_now = 1; 35638c2654abSrjs /* XXX */ 35648c2654abSrjs MGET(oper, M_DONTWAIT, MT_DATA); 35658c2654abSrjs if (oper) { 35668c2654abSrjs struct sctp_paramhdr *ph; 35678c2654abSrjs u_int32_t *ippp; 35688c2654abSrjs 35698c2654abSrjs oper->m_len = sizeof(struct sctp_paramhdr) + 35708c2654abSrjs sizeof(*ippp); 35718c2654abSrjs ph = mtod(oper, struct sctp_paramhdr *); 35728c2654abSrjs ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 35738c2654abSrjs ph->param_length = htons(oper->m_len); 35748c2654abSrjs ippp = (u_int32_t *)(ph + 1); 35758c2654abSrjs *ippp = htonl(0x30000002); 35768c2654abSrjs } 35778c2654abSrjs sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper); 35788c2654abSrjs return; 35798c2654abSrjs } 35808c2654abSrjs } 35818c2654abSrjs /* update the Rwnd of the peer */ 35828c2654abSrjs a_rwnd = (u_int32_t)ntohl(sack->a_rwnd); 35838c2654abSrjs if (asoc->sent_queue_retran_cnt) { 35848c2654abSrjs #ifdef SCTP_DEBUG 35858c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 35868c2654abSrjs printf("cum_ack:%lx num_seg:%u last_acked_seq:%x\n", 35878c2654abSrjs cum_ack, (u_int)num_seg, asoc->last_acked_seq); 35888c2654abSrjs } 35898c2654abSrjs #endif 35908c2654abSrjs } 35918c2654abSrjs if (compare_with_wrap(asoc->t3timeout_highest_marked, cum_ack, MAX_TSN)) { 35928c2654abSrjs /* we are not allowed to mark for FR */ 35938c2654abSrjs marking_allowed = 0; 35948c2654abSrjs } 35958c2654abSrjs /**********************/ 35968c2654abSrjs /* 1) check the range */ 35978c2654abSrjs /**********************/ 35988c2654abSrjs if (compare_with_wrap(asoc->last_acked_seq, last_tsn, MAX_TSN)) { 35998c2654abSrjs /* acking something behind */ 36008c2654abSrjs if (asoc->sent_queue_retran_cnt) { 36018c2654abSrjs #ifdef SCTP_DEBUG 36028c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 36038c2654abSrjs printf("The cum-ack is behind us\n"); 36048c2654abSrjs } 36058c2654abSrjs #endif 36068c2654abSrjs } 36078c2654abSrjs return; 36088c2654abSrjs } 36098c2654abSrjs 36108c2654abSrjs if (TAILQ_EMPTY(&asoc->sent_queue)) { 36118c2654abSrjs /* nothing left on sendqueue.. consider done */ 36128c2654abSrjs #ifdef SCTP_LOG_RWND 36138c2654abSrjs sctp_log_rwnd_set(SCTP_SET_PEER_RWND_VIA_SACK, 36148c2654abSrjs asoc->peers_rwnd, 0, 0, a_rwnd); 36158c2654abSrjs #endif 36168c2654abSrjs asoc->peers_rwnd = a_rwnd; 36178c2654abSrjs if (asoc->sent_queue_retran_cnt) { 36188c2654abSrjs #ifdef SCTP_DEBUG 36198c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 36208c2654abSrjs printf("Huh? retran set but none on queue\n"); 36218c2654abSrjs } 36228c2654abSrjs #endif 36238c2654abSrjs asoc->sent_queue_retran_cnt = 0; 36248c2654abSrjs } 36258c2654abSrjs if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) { 36268c2654abSrjs /* SWS sender side engages */ 36278c2654abSrjs asoc->peers_rwnd = 0; 36288c2654abSrjs } 36298c2654abSrjs /* stop any timers */ 36308c2654abSrjs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 36318c2654abSrjs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, 36328c2654abSrjs stcb, net); 36338c2654abSrjs net->partial_bytes_acked = 0; 36348c2654abSrjs net->flight_size = 0; 36358c2654abSrjs } 36368c2654abSrjs asoc->total_flight = 0; 36378c2654abSrjs asoc->total_flight_count = 0; 36388c2654abSrjs return; 36398c2654abSrjs } 36408c2654abSrjs /* 36418c2654abSrjs * We init netAckSz and netAckSz2 to 0. These are used to track 2 36428c2654abSrjs * things. The total byte count acked is tracked in netAckSz AND 36438c2654abSrjs * netAck2 is used to track the total bytes acked that are un- 36448c2654abSrjs * amibguious and were never retransmitted. We track these on a 36458c2654abSrjs * per destination address basis. 36468c2654abSrjs */ 36478c2654abSrjs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 36488c2654abSrjs net->prev_cwnd = net->cwnd; 36498c2654abSrjs net->net_ack = 0; 36508c2654abSrjs net->net_ack2 = 0; 36518c2654abSrjs } 36528c2654abSrjs /* process the new consecutive TSN first */ 36538c2654abSrjs tp1 = TAILQ_FIRST(&asoc->sent_queue); 36548c2654abSrjs while (tp1) { 36558c2654abSrjs if (compare_with_wrap(last_tsn, tp1->rec.data.TSN_seq, 36568c2654abSrjs MAX_TSN) || 36578c2654abSrjs last_tsn == tp1->rec.data.TSN_seq) { 36588c2654abSrjs if (tp1->sent != SCTP_DATAGRAM_UNSENT) { 36598c2654abSrjs /* ECN Nonce: Add the nonce to the sender's nonce sum */ 36608c2654abSrjs asoc->nonce_sum_expect_base += tp1->rec.data.ect_nonce; 36618c2654abSrjs accum_moved = 1; 36628c2654abSrjs if (tp1->sent < SCTP_DATAGRAM_ACKED) { 36638c2654abSrjs /* 36648c2654abSrjs * If it is less than ACKED, it is now 36658c2654abSrjs * no-longer in flight. Higher values 36668c2654abSrjs * may occur during marking 36678c2654abSrjs */ 36688c2654abSrjs if ((tp1->whoTo->dest_state & 36698c2654abSrjs SCTP_ADDR_UNCONFIRMED) && 36708c2654abSrjs (tp1->snd_count < 2) ) { 36718c2654abSrjs /* 36728c2654abSrjs * If there was no retran and 36738c2654abSrjs * the address is un-confirmed 36748c2654abSrjs * and we sent there and are 36758c2654abSrjs * now sacked.. its confirmed, 36768c2654abSrjs * mark it so. 36778c2654abSrjs */ 36788c2654abSrjs tp1->whoTo->dest_state &= 36798c2654abSrjs ~SCTP_ADDR_UNCONFIRMED; 36808c2654abSrjs } 36818c2654abSrjs sctp_flight_size_decrease(tp1); 36828c2654abSrjs sctp_total_flight_decrease(stcb, tp1); 36838c2654abSrjs tp1->whoTo->net_ack += tp1->send_size; 36848c2654abSrjs if (tp1->snd_count < 2) { 3685*79604517Sandvar /* True non-retransmitted chunk */ 36868c2654abSrjs tp1->whoTo->net_ack2 += 36878c2654abSrjs tp1->send_size; 36888c2654abSrjs /* update RTO too? */ 36898c2654abSrjs if (tp1->do_rtt) { 36908c2654abSrjs tp1->whoTo->RTO = 36918c2654abSrjs sctp_calculate_rto(stcb, 36928c2654abSrjs asoc, tp1->whoTo, 36938c2654abSrjs &tp1->sent_rcv_time); 36948c2654abSrjs tp1->whoTo->rto_pending = 0; 36958c2654abSrjs tp1->do_rtt = 0; 36968c2654abSrjs } 36978c2654abSrjs } 36988c2654abSrjs } 36998c2654abSrjs if (tp1->sent == SCTP_DATAGRAM_RESEND) { 37008c2654abSrjs #ifdef SCTP_DEBUG 37018c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA3) { 37028c2654abSrjs printf("Hmm. one that is in RESEND that is now ACKED\n"); 37038c2654abSrjs } 37048c2654abSrjs #endif 37058c2654abSrjs sctp_ucount_decr(asoc->sent_queue_retran_cnt); 37068c2654abSrjs #ifdef SCTP_AUDITING_ENABLED 37078c2654abSrjs sctp_audit_log(0xB3, 37088c2654abSrjs (asoc->sent_queue_retran_cnt & 0x000000ff)); 37098c2654abSrjs #endif 37108c2654abSrjs 37118c2654abSrjs } 37128c2654abSrjs tp1->sent = SCTP_DATAGRAM_ACKED; 37138c2654abSrjs } 37148c2654abSrjs } else { 37158c2654abSrjs break; 37168c2654abSrjs } 37178c2654abSrjs tp1 = TAILQ_NEXT(tp1, sctp_next); 37188c2654abSrjs } 37198c2654abSrjs /*******************************************/ 37208c2654abSrjs /* cancel ALL T3-send timer if accum moved */ 37218c2654abSrjs /*******************************************/ 37228c2654abSrjs if (accum_moved) { 37238c2654abSrjs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 37248c2654abSrjs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, 37258c2654abSrjs stcb, net); 37268c2654abSrjs } 37278c2654abSrjs } 37288c2654abSrjs biggest_tsn_newly_acked = biggest_tsn_acked = last_tsn; 37298c2654abSrjs /* always set this up to cum-ack */ 37308c2654abSrjs asoc->this_sack_highest_gap = last_tsn; 37318c2654abSrjs 3732f2d1d0f2Schristos if (num_seg * sizeof(struct sctp_gap_ack_block) + sizeof(struct sctp_sack_chunk) > sack_length) { 37338c2654abSrjs /* skip corrupt segments */ 37348c2654abSrjs strike_enabled = 0; 37358c2654abSrjs goto skip_segments; 37368c2654abSrjs } 37378c2654abSrjs 37388c2654abSrjs if (num_seg > 0) { 37398c2654abSrjs if (asoc->primary_destination->dest_state & 37408c2654abSrjs SCTP_ADDR_SWITCH_PRIMARY) { 37418c2654abSrjs /* clear the nets CACC flags */ 37428c2654abSrjs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 37438c2654abSrjs net->cacc_saw_newack = 0; 37448c2654abSrjs } 37458c2654abSrjs } 37468c2654abSrjs /* 37478c2654abSrjs * thisSackHighestGap will increase while handling NEW segments 37488c2654abSrjs */ 37498c2654abSrjs 37508c2654abSrjs sctp_handle_segments(stcb, asoc, ch, last_tsn, 37518c2654abSrjs &biggest_tsn_acked, &biggest_tsn_newly_acked, 37528c2654abSrjs num_seg, &ecn_seg_sums); 37538c2654abSrjs 37548c2654abSrjs if (sctp_strict_sacks) { 37558c2654abSrjs /* validate the biggest_tsn_acked in the gap acks 37568c2654abSrjs * if strict adherence is wanted. 37578c2654abSrjs */ 37588c2654abSrjs if ((biggest_tsn_acked == send_s) || 37598c2654abSrjs (compare_with_wrap(biggest_tsn_acked, send_s, MAX_TSN))) { 37608c2654abSrjs /* 37618c2654abSrjs * peer is either confused or we are under 37628c2654abSrjs * attack. We must abort. 37638c2654abSrjs */ 37648c2654abSrjs goto hopeless_peer; 37658c2654abSrjs } 37668c2654abSrjs } 37678c2654abSrjs 37688c2654abSrjs if (asoc->primary_destination->dest_state & 37698c2654abSrjs SCTP_ADDR_SWITCH_PRIMARY) { 37708c2654abSrjs /* clear the nets CACC flags */ 37718c2654abSrjs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 37728c2654abSrjs if (net->cacc_saw_newack) { 37738c2654abSrjs cnt_of_cacc++; 37748c2654abSrjs } 37758c2654abSrjs } 37768c2654abSrjs } 37778c2654abSrjs 37788c2654abSrjs } 37798c2654abSrjs 37808c2654abSrjs if (cnt_of_cacc < 2) { 37818c2654abSrjs strike_enabled = 1; 37828c2654abSrjs } else { 37838c2654abSrjs strike_enabled = 0; 37848c2654abSrjs } 37858c2654abSrjs skip_segments: 37868c2654abSrjs /********************************************/ 37878c2654abSrjs /* drop the acked chunks from the sendqueue */ 37888c2654abSrjs /********************************************/ 37898c2654abSrjs asoc->last_acked_seq = cum_ack; 37908c2654abSrjs if (asoc->primary_destination->dest_state & SCTP_ADDR_SWITCH_PRIMARY) { 37918c2654abSrjs if ((cum_ack == asoc->primary_destination->next_tsn_at_change) || 37928c2654abSrjs (compare_with_wrap(cum_ack, 37938c2654abSrjs asoc->primary_destination->next_tsn_at_change, MAX_TSN))) { 37948c2654abSrjs struct sctp_nets *lnet; 37958c2654abSrjs /* Turn off the switch flag for ALL addresses */ 37968c2654abSrjs TAILQ_FOREACH(lnet, &asoc->nets, sctp_next) { 37978c2654abSrjs asoc->primary_destination->dest_state &= 37988c2654abSrjs ~(SCTP_ADDR_SWITCH_PRIMARY|SCTP_ADDR_DOUBLE_SWITCH); 37998c2654abSrjs } 38008c2654abSrjs } 38018c2654abSrjs } 38028c2654abSrjs /* Drag along the t3 timeout point so we don't have a problem at wrap */ 38038c2654abSrjs if (marking_allowed) { 38048c2654abSrjs asoc->t3timeout_highest_marked = cum_ack; 38058c2654abSrjs } 38068c2654abSrjs tp1 = TAILQ_FIRST(&asoc->sent_queue); 38078c2654abSrjs do { 38088c2654abSrjs if (compare_with_wrap(tp1->rec.data.TSN_seq, cum_ack, 38098c2654abSrjs MAX_TSN)) { 38108c2654abSrjs break; 38118c2654abSrjs } 38128c2654abSrjs if (tp1->sent == SCTP_DATAGRAM_UNSENT) { 38138c2654abSrjs /* no more sent on list */ 38148c2654abSrjs break; 38158c2654abSrjs } 38168c2654abSrjs tp2 = TAILQ_NEXT(tp1, sctp_next); 38178c2654abSrjs TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next); 38188c2654abSrjs if (tp1->data) { 38198c2654abSrjs sctp_free_bufspace(stcb, asoc, tp1); 38208c2654abSrjs #ifdef SCTP_DEBUG 38218c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_OUTPUT2) { 38228c2654abSrjs printf("--total out:%lu total_mbuf_out:%lu\n", 38238c2654abSrjs (u_long)asoc->total_output_queue_size, 38248c2654abSrjs (u_long)asoc->total_output_mbuf_queue_size); 38258c2654abSrjs } 38268c2654abSrjs #endif 38278c2654abSrjs 38288c2654abSrjs sctp_m_freem(tp1->data); 38298c2654abSrjs if (tp1->flags & SCTP_PR_SCTP_BUFFER) { 38308c2654abSrjs asoc->sent_queue_cnt_removeable--; 38318c2654abSrjs } 38328c2654abSrjs 38338c2654abSrjs } 38348c2654abSrjs tp1->data = NULL; 38358c2654abSrjs asoc->sent_queue_cnt--; 38368c2654abSrjs sctp_free_remote_addr(tp1->whoTo); 38378c2654abSrjs sctppcbinfo.ipi_count_chunk--; 38388c2654abSrjs asoc->chunks_on_out_queue--; 38398c2654abSrjs 38408c2654abSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) { 38418c2654abSrjs panic("Chunk count is going negative"); 38428c2654abSrjs } 38438c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, tp1); 38448c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++; 38458c2654abSrjs sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket); 38468c2654abSrjs tp1 = tp2; 38478c2654abSrjs } while (tp1 != NULL); 38488c2654abSrjs 38498c2654abSrjs 38508c2654abSrjs if (asoc->fast_retran_loss_recovery && accum_moved) { 38518c2654abSrjs if (compare_with_wrap(asoc->last_acked_seq, 38528c2654abSrjs asoc->fast_recovery_tsn, MAX_TSN) || 38538c2654abSrjs asoc->last_acked_seq == asoc->fast_recovery_tsn) { 38548c2654abSrjs /* Setup so we will exit RFC2582 fast recovery */ 38558c2654abSrjs will_exit_fast_recovery = 1; 38568c2654abSrjs } 38578c2654abSrjs } 38588c2654abSrjs 38598c2654abSrjs /* Check for revoked fragments if we hand 38608c2654abSrjs * fragments in a previous segment. If we 38618c2654abSrjs * had no previous fragments we cannot have 38628c2654abSrjs * a revoke issue. 38638c2654abSrjs */ 38648c2654abSrjs if (asoc->saw_sack_with_frags) 38658c2654abSrjs sctp_check_for_revoked(asoc, cum_ack, biggest_tsn_acked); 38668c2654abSrjs 38678c2654abSrjs if (num_seg) 38688c2654abSrjs asoc->saw_sack_with_frags = 1; 38698c2654abSrjs else 38708c2654abSrjs asoc->saw_sack_with_frags = 0; 38718c2654abSrjs 38728c2654abSrjs /******************************/ 38738c2654abSrjs /* update cwnd */ 38748c2654abSrjs /******************************/ 38758c2654abSrjs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 38768c2654abSrjs /* if nothing was acked on this destination skip it */ 38778c2654abSrjs if (net->net_ack == 0) 38788c2654abSrjs continue; 38798c2654abSrjs 38808c2654abSrjs if (net->net_ack2 > 0) { 38818c2654abSrjs /* 38828c2654abSrjs * Karn's rule applies to clearing error count, 38838c2654abSrjs * this is optional. 38848c2654abSrjs */ 38858c2654abSrjs net->error_count = 0; 38868c2654abSrjs if ((net->dest_state&SCTP_ADDR_NOT_REACHABLE) == 38878c2654abSrjs SCTP_ADDR_NOT_REACHABLE) { 38888c2654abSrjs /* addr came good */ 38898c2654abSrjs net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE; 38908c2654abSrjs net->dest_state |= SCTP_ADDR_REACHABLE; 38918c2654abSrjs sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 38928c2654abSrjs SCTP_RECEIVED_SACK, (void *)net); 38938c2654abSrjs /* now was it the primary? if so restore */ 38948c2654abSrjs if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) { 38958c2654abSrjs sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net); 38968c2654abSrjs } 38978c2654abSrjs } 38988c2654abSrjs } 38998c2654abSrjs 39008c2654abSrjs if (asoc->fast_retran_loss_recovery && 39018c2654abSrjs will_exit_fast_recovery == 0) { 39028c2654abSrjs /* If we are in loss recovery we skip any cwnd update */ 39038c2654abSrjs sctp_pegs[SCTP_CWND_SKIP]++; 39048c2654abSrjs goto skip_cwnd_update; 39058c2654abSrjs } 39068c2654abSrjs if (accum_moved) { 39078c2654abSrjs /* If the cumulative ack moved we can proceed */ 39088c2654abSrjs if (net->cwnd <= net->ssthresh) { 39098c2654abSrjs /* We are in slow start */ 39108c2654abSrjs if (net->flight_size + net->net_ack >= 39118c2654abSrjs net->cwnd ) { 39128c2654abSrjs #ifdef SCTP_HIGH_SPEED 39138c2654abSrjs sctp_hs_cwnd_increase(net); 39148c2654abSrjs #else 39158c2654abSrjs if (net->net_ack > net->mtu) { 39168c2654abSrjs net->cwnd += net->mtu; 39178c2654abSrjs #ifdef SCTP_CWND_LOGGING 39188c2654abSrjs sctp_log_cwnd(net, net->mtu, 39198c2654abSrjs SCTP_CWND_LOG_FROM_SS); 39208c2654abSrjs #endif 39218c2654abSrjs 39228c2654abSrjs } else { 39238c2654abSrjs net->cwnd += net->net_ack; 39248c2654abSrjs #ifdef SCTP_CWND_LOGGING 39258c2654abSrjs sctp_log_cwnd(net, net->net_ack, 39268c2654abSrjs SCTP_CWND_LOG_FROM_SS); 39278c2654abSrjs #endif 39288c2654abSrjs 39298c2654abSrjs } 39308c2654abSrjs #endif 39318c2654abSrjs sctp_pegs[SCTP_CWND_SS]++; 39328c2654abSrjs } else { 39338c2654abSrjs unsigned int dif; 39348c2654abSrjs sctp_pegs[SCTP_CWND_NOUSE_SS]++; 39358c2654abSrjs dif = net->cwnd - (net->flight_size + 39368c2654abSrjs net->net_ack); 39378c2654abSrjs #ifdef SCTP_CWND_LOGGING 39388c2654abSrjs /* sctp_log_cwnd(net, net->net_ack, 39398c2654abSrjs SCTP_CWND_LOG_NOADV_SS);*/ 39408c2654abSrjs #endif 39418c2654abSrjs if (dif > sctp_pegs[SCTP_CWND_DIFF_SA]) { 39428c2654abSrjs sctp_pegs[SCTP_CWND_DIFF_SA] = 39438c2654abSrjs dif; 39448c2654abSrjs sctp_pegs[SCTP_OQS_AT_SS] = 39458c2654abSrjs asoc->total_output_queue_size; 39468c2654abSrjs sctp_pegs[SCTP_SQQ_AT_SS] = 39478c2654abSrjs asoc->sent_queue_cnt; 39488c2654abSrjs sctp_pegs[SCTP_SQC_AT_SS] = 39498c2654abSrjs asoc->send_queue_cnt; 39508c2654abSrjs } 39518c2654abSrjs } 39528c2654abSrjs } else { 39538c2654abSrjs /* We are in congestion avoidance */ 39548c2654abSrjs if (net->flight_size + net->net_ack >= 39558c2654abSrjs net->cwnd) { 39568c2654abSrjs /* 39578c2654abSrjs * add to pba only if we had a cwnd's 39588c2654abSrjs * worth (or so) in flight OR the 39598c2654abSrjs * burst limit was applied. 39608c2654abSrjs */ 39618c2654abSrjs net->partial_bytes_acked += 39628c2654abSrjs net->net_ack; 39638c2654abSrjs 39648c2654abSrjs /* 39658c2654abSrjs * Do we need to increase 39668c2654abSrjs * (if pba is > cwnd)? 39678c2654abSrjs */ 39688c2654abSrjs if (net->partial_bytes_acked >= 39698c2654abSrjs net->cwnd) { 39708c2654abSrjs if (net->cwnd < 39718c2654abSrjs net->partial_bytes_acked) { 39728c2654abSrjs net->partial_bytes_acked -= 39738c2654abSrjs net->cwnd; 39748c2654abSrjs } else { 39758c2654abSrjs net->partial_bytes_acked = 39768c2654abSrjs 0; 39778c2654abSrjs } 39788c2654abSrjs net->cwnd += net->mtu; 39798c2654abSrjs #ifdef SCTP_CWND_LOGGING 39808c2654abSrjs sctp_log_cwnd(net, net->mtu, 39818c2654abSrjs SCTP_CWND_LOG_FROM_CA); 39828c2654abSrjs #endif 39838c2654abSrjs sctp_pegs[SCTP_CWND_CA]++; 39848c2654abSrjs } 39858c2654abSrjs } else { 39868c2654abSrjs unsigned int dif; 39878c2654abSrjs sctp_pegs[SCTP_CWND_NOUSE_CA]++; 39888c2654abSrjs #ifdef SCTP_CWND_LOGGING 39898c2654abSrjs /* sctp_log_cwnd(net, net->net_ack, 39908c2654abSrjs SCTP_CWND_LOG_NOADV_CA); 39918c2654abSrjs */ 39928c2654abSrjs #endif 39938c2654abSrjs dif = net->cwnd - (net->flight_size + 39948c2654abSrjs net->net_ack); 39958c2654abSrjs if (dif > sctp_pegs[SCTP_CWND_DIFF_CA]) { 39968c2654abSrjs sctp_pegs[SCTP_CWND_DIFF_CA] = 39978c2654abSrjs dif; 39988c2654abSrjs sctp_pegs[SCTP_OQS_AT_CA] = 39998c2654abSrjs asoc->total_output_queue_size; 40008c2654abSrjs sctp_pegs[SCTP_SQQ_AT_CA] = 40018c2654abSrjs asoc->sent_queue_cnt; 40028c2654abSrjs sctp_pegs[SCTP_SQC_AT_CA] = 40038c2654abSrjs asoc->send_queue_cnt; 40048c2654abSrjs 40058c2654abSrjs } 40068c2654abSrjs 40078c2654abSrjs } 40088c2654abSrjs } 40098c2654abSrjs } else { 40108c2654abSrjs sctp_pegs[SCTP_CWND_NOCUM]++; 40118c2654abSrjs } 40128c2654abSrjs skip_cwnd_update: 40138c2654abSrjs /* 40148c2654abSrjs * NOW, according to Karn's rule do we need to restore the 40158c2654abSrjs * RTO timer back? Check our net_ack2. If not set then we 40168c2654abSrjs * have a ambiguity.. i.e. all data ack'd was sent to more 40178c2654abSrjs * than one place. 40188c2654abSrjs */ 40198c2654abSrjs 40208c2654abSrjs if (net->net_ack2) { 40218c2654abSrjs /* restore any doubled timers */ 40228c2654abSrjs net->RTO = ((net->lastsa >> 2) + net->lastsv) >> 1; 40238c2654abSrjs if (net->RTO < stcb->asoc.minrto) { 40248c2654abSrjs net->RTO = stcb->asoc.minrto; 40258c2654abSrjs } 40268c2654abSrjs if (net->RTO > stcb->asoc.maxrto) { 40278c2654abSrjs net->RTO = stcb->asoc.maxrto; 40288c2654abSrjs } 40298c2654abSrjs } 40308c2654abSrjs if (net->cwnd > sctp_pegs[SCTP_MAX_CWND]) { 40318c2654abSrjs sctp_pegs[SCTP_MAX_CWND] = net->cwnd; 40328c2654abSrjs } 40338c2654abSrjs } 40348c2654abSrjs /**********************************/ 40358c2654abSrjs /* Now what about shutdown issues */ 40368c2654abSrjs /**********************************/ 40378c2654abSrjs some_on_streamwheel = 0; 40388c2654abSrjs if (!TAILQ_EMPTY(&asoc->out_wheel)) { 40398c2654abSrjs /* Check to see if some data queued */ 40408c2654abSrjs struct sctp_stream_out *outs; 40418c2654abSrjs TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) { 40428c2654abSrjs if (!TAILQ_EMPTY(&outs->outqueue)) { 40438c2654abSrjs some_on_streamwheel = 1; 40448c2654abSrjs break; 40458c2654abSrjs } 40468c2654abSrjs } 40478c2654abSrjs } 40488c2654abSrjs if (TAILQ_EMPTY(&asoc->send_queue) && TAILQ_EMPTY(&asoc->sent_queue) && 40498c2654abSrjs some_on_streamwheel == 0) { 40508c2654abSrjs /* nothing left on sendqueue.. consider done */ 40518c2654abSrjs /* stop all timers */ 40528c2654abSrjs #ifdef SCTP_LOG_RWND 40538c2654abSrjs sctp_log_rwnd_set(SCTP_SET_PEER_RWND_VIA_SACK, 40548c2654abSrjs asoc->peers_rwnd, 0, 0, a_rwnd); 40558c2654abSrjs #endif 40568c2654abSrjs asoc->peers_rwnd = a_rwnd; 40578c2654abSrjs if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) { 40588c2654abSrjs /* SWS sender side engages */ 40598c2654abSrjs asoc->peers_rwnd = 0; 40608c2654abSrjs } 40618c2654abSrjs /* stop any timers */ 40628c2654abSrjs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 40638c2654abSrjs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, 40648c2654abSrjs stcb, net); 40658c2654abSrjs net->flight_size = 0; 40668c2654abSrjs net->partial_bytes_acked = 0; 40678c2654abSrjs } 40688c2654abSrjs asoc->total_flight = 0; 40698c2654abSrjs asoc->total_flight_count = 0; 40708c2654abSrjs /* clean up */ 40718c2654abSrjs if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) { 40728c2654abSrjs asoc->state = SCTP_STATE_SHUTDOWN_SENT; 40738c2654abSrjs #ifdef SCTP_DEBUG 40748c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) { 40758c2654abSrjs printf("%s:%d sends a shutdown\n", 40768c2654abSrjs __FILE__, 40778c2654abSrjs __LINE__ 40788c2654abSrjs ); 40798c2654abSrjs } 40808c2654abSrjs #endif 40818c2654abSrjs sctp_send_shutdown(stcb, 40828c2654abSrjs stcb->asoc.primary_destination); 40838c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 40848c2654abSrjs stcb->sctp_ep, stcb, asoc->primary_destination); 40858c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 40868c2654abSrjs stcb->sctp_ep, stcb, asoc->primary_destination); 40878c2654abSrjs } else if (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) { 40888c2654abSrjs asoc->state = SCTP_STATE_SHUTDOWN_ACK_SENT; 40898c2654abSrjs 40908c2654abSrjs sctp_send_shutdown_ack(stcb, 40918c2654abSrjs stcb->asoc.primary_destination); 40928c2654abSrjs 40938c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, 40948c2654abSrjs stcb->sctp_ep, stcb, asoc->primary_destination); 40958c2654abSrjs } 40968c2654abSrjs return; 40978c2654abSrjs } 40988c2654abSrjs /* 40998c2654abSrjs * Now here we are going to recycle net_ack for a different 41008c2654abSrjs * use... HEADS UP. 41018c2654abSrjs */ 41028c2654abSrjs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 41038c2654abSrjs net->net_ack = 0; 41048c2654abSrjs } 41058c2654abSrjs if ((num_seg > 0) && marking_allowed) { 41068c2654abSrjs sctp_strike_gap_ack_chunks(stcb, asoc, biggest_tsn_acked, 41078c2654abSrjs strike_enabled, biggest_tsn_newly_acked, accum_moved); 41088c2654abSrjs } 41098c2654abSrjs 41108c2654abSrjs /*********************************************/ 41118c2654abSrjs /* Here we perform PR-SCTP procedures */ 41128c2654abSrjs /* (section 4.2) */ 41138c2654abSrjs /*********************************************/ 41148c2654abSrjs /* C1. update advancedPeerAckPoint */ 41158c2654abSrjs if (compare_with_wrap(cum_ack, asoc->advanced_peer_ack_point, MAX_TSN)) { 41168c2654abSrjs asoc->advanced_peer_ack_point = cum_ack; 41178c2654abSrjs } 41188c2654abSrjs /* C2. try to further move advancedPeerAckPoint ahead */ 41198c2654abSrjs if (asoc->peer_supports_prsctp) { 41208c2654abSrjs struct sctp_tmit_chunk *lchk; 41218c2654abSrjs lchk = sctp_try_advance_peer_ack_point(stcb, asoc); 41228c2654abSrjs /* C3. See if we need to send a Fwd-TSN */ 41238c2654abSrjs if (compare_with_wrap(asoc->advanced_peer_ack_point, cum_ack, 41248c2654abSrjs MAX_TSN)) { 41258c2654abSrjs /* 41268c2654abSrjs * ISSUE with ECN, see FWD-TSN processing for notes 41278c2654abSrjs * on issues that will occur when the ECN NONCE stuff 41288c2654abSrjs * is put into SCTP for cross checking. 41298c2654abSrjs */ 41308c2654abSrjs send_forward_tsn(stcb, asoc); 41318c2654abSrjs 41328c2654abSrjs /* ECN Nonce: Disable Nonce Sum check when FWD TSN is sent and store resync tsn*/ 41338c2654abSrjs asoc->nonce_sum_check = 0; 41348c2654abSrjs asoc->nonce_resync_tsn = asoc->advanced_peer_ack_point; 41358c2654abSrjs if (lchk) { 41368c2654abSrjs /* Assure a timer is up */ 41378c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_SEND, 41388c2654abSrjs stcb->sctp_ep, stcb, lchk->whoTo); 41398c2654abSrjs } 41408c2654abSrjs } 41418c2654abSrjs } 41428c2654abSrjs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 41438c2654abSrjs if (asoc->fast_retran_loss_recovery == 0) { 41448c2654abSrjs /* out of a RFC2582 Fast recovery window? */ 41458c2654abSrjs if (net->net_ack > 0) { 41468c2654abSrjs /* 41478c2654abSrjs * per section 7.2.3, are there 41488c2654abSrjs * any destinations that had a fast 41498c2654abSrjs * retransmit to them. If so what we 41508c2654abSrjs * need to do is adjust ssthresh and 41518c2654abSrjs * cwnd. 41528c2654abSrjs */ 41538c2654abSrjs struct sctp_tmit_chunk *lchk; 41548c2654abSrjs #ifdef SCTP_HIGH_SPEED 41558c2654abSrjs sctp_hs_cwnd_decrease(net); 41568c2654abSrjs #else 41578c2654abSrjs #ifdef SCTP_CWND_LOGGING 41588c2654abSrjs int old_cwnd = net->cwnd; 41598c2654abSrjs #endif 41608c2654abSrjs net->ssthresh = net->cwnd / 2; 41618c2654abSrjs if (net->ssthresh < (net->mtu*2)) { 41628c2654abSrjs net->ssthresh = 2 * net->mtu; 41638c2654abSrjs } 41648c2654abSrjs net->cwnd = net->ssthresh; 41658c2654abSrjs #ifdef SCTP_CWND_LOGGING 41668c2654abSrjs sctp_log_cwnd(net, (net->cwnd-old_cwnd), 41678c2654abSrjs SCTP_CWND_LOG_FROM_FR); 41688c2654abSrjs #endif 41698c2654abSrjs #endif 41708c2654abSrjs 41718c2654abSrjs lchk = TAILQ_FIRST(&asoc->send_queue); 41728c2654abSrjs 41738c2654abSrjs net->partial_bytes_acked = 0; 41748c2654abSrjs /* Turn on fast recovery window */ 41758c2654abSrjs asoc->fast_retran_loss_recovery = 1; 41768c2654abSrjs if (lchk == NULL) { 41778c2654abSrjs /* Mark end of the window */ 41788c2654abSrjs asoc->fast_recovery_tsn = asoc->sending_seq - 1; 41798c2654abSrjs } else { 41808c2654abSrjs asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 41818c2654abSrjs } 41828c2654abSrjs 41838c2654abSrjs 41848c2654abSrjs /* Disable Nonce Sum Checking and store the resync tsn*/ 41858c2654abSrjs asoc->nonce_sum_check = 0; 41868c2654abSrjs asoc->nonce_resync_tsn = asoc->fast_recovery_tsn + 1; 41878c2654abSrjs 41888c2654abSrjs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 41898c2654abSrjs stcb->sctp_ep, stcb, net); 41908c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_SEND, 41918c2654abSrjs stcb->sctp_ep, stcb, net); 41928c2654abSrjs } 41938c2654abSrjs } else if (net->net_ack > 0) { 41948c2654abSrjs /* 41958c2654abSrjs * Mark a peg that we WOULD have done a cwnd reduction 41968c2654abSrjs * but RFC2582 prevented this action. 41978c2654abSrjs */ 41988c2654abSrjs sctp_pegs[SCTP_FR_INAWINDOW]++; 41998c2654abSrjs } 42008c2654abSrjs } 42018c2654abSrjs 42028c2654abSrjs 42038c2654abSrjs /****************************************************************** 42048c2654abSrjs * Here we do the stuff with ECN Nonce checking. 42058c2654abSrjs * We basically check to see if the nonce sum flag was incorrect 42068c2654abSrjs * or if resynchronization needs to be done. Also if we catch a 42078c2654abSrjs * misbehaving receiver we give him the kick. 42088c2654abSrjs ******************************************************************/ 42098c2654abSrjs 42108c2654abSrjs if (asoc->ecn_nonce_allowed) { 42118c2654abSrjs if (asoc->nonce_sum_check) { 42128c2654abSrjs if (nonce_sum_flag != ((asoc->nonce_sum_expect_base + ecn_seg_sums) & SCTP_SACK_NONCE_SUM)) { 42138c2654abSrjs if (asoc->nonce_wait_for_ecne == 0) { 42148c2654abSrjs struct sctp_tmit_chunk *lchk; 42158c2654abSrjs lchk = TAILQ_FIRST(&asoc->send_queue); 42168c2654abSrjs asoc->nonce_wait_for_ecne = 1; 42178c2654abSrjs if (lchk) { 42188c2654abSrjs asoc->nonce_wait_tsn = lchk->rec.data.TSN_seq; 42198c2654abSrjs } else { 42208c2654abSrjs asoc->nonce_wait_tsn = asoc->sending_seq; 42218c2654abSrjs } 42228c2654abSrjs } else { 42238c2654abSrjs if (compare_with_wrap(asoc->last_acked_seq, asoc->nonce_wait_tsn, MAX_TSN) || 42248c2654abSrjs (asoc->last_acked_seq == asoc->nonce_wait_tsn)) { 42258c2654abSrjs /* Misbehaving peer. We need to react to this guy */ 42268c2654abSrjs printf("Mis-behaving peer detected\n"); 42278c2654abSrjs asoc->ecn_allowed = 0; 42288c2654abSrjs asoc->ecn_nonce_allowed = 0; 42298c2654abSrjs } 42308c2654abSrjs } 42318c2654abSrjs } 42328c2654abSrjs } else { 42338c2654abSrjs /* See if Resynchronization Possible */ 42348c2654abSrjs if (compare_with_wrap(asoc->last_acked_seq, asoc->nonce_resync_tsn, MAX_TSN)) { 42358c2654abSrjs asoc->nonce_sum_check = 1; 42368c2654abSrjs /* now we must calculate what the base 42378c2654abSrjs * is. We do this based on two things, we know 42388c2654abSrjs * the total's for all the segments gap-acked 42398c2654abSrjs * in the SACK, its stored in ecn_seg_sums. 42408c2654abSrjs * We also know the SACK's nonce sum, its 42418c2654abSrjs * in nonce_sum_flag. So we can build a truth 42428c2654abSrjs * table to back-calculate the new value of asoc->nonce_sum_expect_base: 42438c2654abSrjs * 42448c2654abSrjs * SACK-flag-Value Seg-Sums Base 42458c2654abSrjs * 0 0 0 42468c2654abSrjs * 1 0 1 42478c2654abSrjs * 0 1 1 42488c2654abSrjs * 1 1 0 42498c2654abSrjs */ 42508c2654abSrjs asoc->nonce_sum_expect_base = (ecn_seg_sums ^ nonce_sum_flag) & SCTP_SACK_NONCE_SUM; 42518c2654abSrjs } 42528c2654abSrjs } 42538c2654abSrjs } 42548c2654abSrjs /* Now are we exiting loss recovery ? */ 42558c2654abSrjs if (will_exit_fast_recovery) { 42568c2654abSrjs /* Ok, we must exit fast recovery */ 42578c2654abSrjs asoc->fast_retran_loss_recovery = 0; 42588c2654abSrjs } 42598c2654abSrjs if ((asoc->sat_t3_loss_recovery) && 42608c2654abSrjs ((compare_with_wrap(asoc->last_acked_seq, asoc->sat_t3_recovery_tsn, 42618c2654abSrjs MAX_TSN) || 42628c2654abSrjs (asoc->last_acked_seq == asoc->sat_t3_recovery_tsn)))) { 42638c2654abSrjs /* end satellite t3 loss recovery */ 42648c2654abSrjs asoc->sat_t3_loss_recovery = 0; 42658c2654abSrjs } 42668c2654abSrjs /* Adjust and set the new rwnd value */ 42678c2654abSrjs #ifdef SCTP_LOG_RWND 42688c2654abSrjs sctp_log_rwnd_set(SCTP_SET_PEER_RWND_VIA_SACK, 42698c2654abSrjs asoc->peers_rwnd, asoc->total_flight, (asoc->sent_queue_cnt * sctp_peer_chunk_oh), a_rwnd); 42708c2654abSrjs #endif 42718c2654abSrjs 42728c2654abSrjs asoc->peers_rwnd = sctp_sbspace_sub(a_rwnd, 42738c2654abSrjs (u_int32_t)(asoc->total_flight + (asoc->sent_queue_cnt * sctp_peer_chunk_oh))); 42748c2654abSrjs if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) { 42758c2654abSrjs /* SWS sender side engages */ 42768c2654abSrjs asoc->peers_rwnd = 0; 42778c2654abSrjs } 42788c2654abSrjs /* 42798c2654abSrjs * Now we must setup so we have a timer up for anyone with 42808c2654abSrjs * outstanding data. 42818c2654abSrjs */ 42828c2654abSrjs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 42838c2654abSrjs struct sctp_tmit_chunk *chk; 42848c2654abSrjs TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { 42858c2654abSrjs if (chk->whoTo == net && 42868c2654abSrjs (chk->sent < SCTP_DATAGRAM_ACKED || 42878c2654abSrjs chk->sent == SCTP_FORWARD_TSN_SKIP)) { 42888c2654abSrjs /* 42898c2654abSrjs * Not ack'ed and still outstanding to this 42908c2654abSrjs * destination or marked and must be 42918c2654abSrjs * sacked after fwd-tsn sent. 42928c2654abSrjs */ 42938c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_SEND, 42948c2654abSrjs stcb->sctp_ep, stcb, net); 42958c2654abSrjs break; 42968c2654abSrjs } 42978c2654abSrjs } 42988c2654abSrjs } 42998c2654abSrjs } 43008c2654abSrjs 43018c2654abSrjs void 43028c2654abSrjs sctp_update_acked(struct sctp_tcb *stcb, struct sctp_shutdown_chunk *cp, 43038c2654abSrjs struct sctp_nets *netp, int *abort_flag) 43048c2654abSrjs { 43058c2654abSrjs /* Mutate a shutdown into a SACK */ 43068c2654abSrjs struct sctp_sack_chunk sack; 43078c2654abSrjs 43088c2654abSrjs /* Copy cum-ack */ 43098c2654abSrjs sack.sack.cum_tsn_ack = cp->cumulative_tsn_ack; 43108c2654abSrjs /* Arrange so a_rwnd does NOT change */ 43118c2654abSrjs sack.ch.chunk_type = SCTP_SELECTIVE_ACK; 43128c2654abSrjs sack.ch.chunk_flags = 0; 43138c2654abSrjs sack.ch.chunk_length = ntohs(sizeof(struct sctp_sack_chunk)); 43148c2654abSrjs sack.sack.a_rwnd = 43158c2654abSrjs htonl(stcb->asoc.peers_rwnd + stcb->asoc.total_flight); 43168c2654abSrjs /* 43178c2654abSrjs * no gaps in this one. This may cause a temporal view to reneging, 43188c2654abSrjs * but hopefully the second chunk is a true SACK in the packet and 43198c2654abSrjs * will correct this view. One will come soon after no matter what 43208c2654abSrjs * to fix this. 43218c2654abSrjs */ 43228c2654abSrjs sack.sack.num_gap_ack_blks = 0; 43238c2654abSrjs sack.sack.num_dup_tsns = 0; 43248c2654abSrjs /* Now call the SACK processor */ 43258c2654abSrjs sctp_handle_sack(&sack, stcb, netp, abort_flag); 43268c2654abSrjs } 43278c2654abSrjs 43288c2654abSrjs static void 43298c2654abSrjs sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb, 43308c2654abSrjs struct sctp_stream_in *strmin) 43318c2654abSrjs { 43328c2654abSrjs struct sctp_tmit_chunk *chk, *nchk; 43338c2654abSrjs struct sctp_association *asoc; 43348c2654abSrjs int tt; 43358c2654abSrjs 43368c2654abSrjs asoc = &stcb->asoc; 43378c2654abSrjs tt = strmin->last_sequence_delivered; 43388c2654abSrjs /* 43398c2654abSrjs * First deliver anything prior to and including the stream no that 43408c2654abSrjs * came in 43418c2654abSrjs */ 43428c2654abSrjs chk = TAILQ_FIRST(&strmin->inqueue); 43438c2654abSrjs while (chk) { 43448c2654abSrjs nchk = TAILQ_NEXT(chk, sctp_next); 43458c2654abSrjs if (compare_with_wrap(tt, chk->rec.data.stream_seq, MAX_SEQ) || 43468c2654abSrjs (tt == chk->rec.data.stream_seq)) { 43478c2654abSrjs /* this is deliverable now */ 43488c2654abSrjs TAILQ_REMOVE(&strmin->inqueue, chk, sctp_next); 43498c2654abSrjs /* subtract pending on streams */ 43508c2654abSrjs asoc->size_on_all_streams -= chk->send_size; 43518c2654abSrjs asoc->cnt_on_all_streams--; 43528c2654abSrjs /* deliver it to at least the delivery-q */ 43538c2654abSrjs sctp_deliver_data(stcb, &stcb->asoc, chk, 0); 43548c2654abSrjs } else { 43558c2654abSrjs /* no more delivery now. */ 43568c2654abSrjs break; 43578c2654abSrjs } 43588c2654abSrjs chk = nchk; 43598c2654abSrjs } 43608c2654abSrjs /* 43618c2654abSrjs * now we must deliver things in queue the normal way if any 43628c2654abSrjs * are now ready. 43638c2654abSrjs */ 43648c2654abSrjs tt = strmin->last_sequence_delivered + 1; 43658c2654abSrjs chk = TAILQ_FIRST(&strmin->inqueue); 43668c2654abSrjs while (chk) { 43678c2654abSrjs nchk = TAILQ_NEXT(chk, sctp_next); 43688c2654abSrjs if (tt == chk->rec.data.stream_seq) { 43698c2654abSrjs /* this is deliverable now */ 43708c2654abSrjs TAILQ_REMOVE(&strmin->inqueue, chk, sctp_next); 43718c2654abSrjs /* subtract pending on streams */ 43728c2654abSrjs asoc->size_on_all_streams -= chk->send_size; 43738c2654abSrjs asoc->cnt_on_all_streams--; 43748c2654abSrjs /* deliver it to at least the delivery-q */ 43758c2654abSrjs strmin->last_sequence_delivered = 43768c2654abSrjs chk->rec.data.stream_seq; 43778c2654abSrjs sctp_deliver_data(stcb, &stcb->asoc, chk, 0); 43788c2654abSrjs tt = strmin->last_sequence_delivered + 1; 43798c2654abSrjs } else { 43808c2654abSrjs break; 43818c2654abSrjs } 43828c2654abSrjs chk = nchk; 43838c2654abSrjs } 43848c2654abSrjs 43858c2654abSrjs } 43868c2654abSrjs 43878c2654abSrjs void 43888c2654abSrjs sctp_handle_forward_tsn(struct sctp_tcb *stcb, 43898c2654abSrjs struct sctp_forward_tsn_chunk *fwd, int *abort_flag) 43908c2654abSrjs { 43918c2654abSrjs /* 43928c2654abSrjs * ISSUES that MUST be fixed for ECN! When we are the 43938c2654abSrjs * sender of the forward TSN, when the SACK comes back 43948c2654abSrjs * that acknowledges the FWD-TSN we must reset the 43958c2654abSrjs * NONCE sum to match correctly. This will get quite 43968c2654abSrjs * tricky since we may have sent more data interveneing and 43978c2654abSrjs * must carefully account for what the SACK says on the 43988c2654abSrjs * nonce and any gaps that are reported. This work 43998c2654abSrjs * will NOT be done here, but I note it here since 44008c2654abSrjs * it is really related to PR-SCTP and FWD-TSN's 44018c2654abSrjs */ 44028c2654abSrjs 44038c2654abSrjs /* The pr-sctp fwd tsn */ 44048c2654abSrjs /* 44058c2654abSrjs * here we will perform all the data receiver side steps for 44068c2654abSrjs * processing FwdTSN, as required in by pr-sctp draft: 44078c2654abSrjs * 44088c2654abSrjs * Assume we get FwdTSN(x): 44098c2654abSrjs * 44108c2654abSrjs * 1) update local cumTSN to x 44118c2654abSrjs * 2) try to further advance cumTSN to x + others we have 44128c2654abSrjs * 3) examine and update re-ordering queue on pr-in-streams 44138c2654abSrjs * 4) clean up re-assembly queue 44148c2654abSrjs * 5) Send a sack to report where we are. 44158c2654abSrjs */ 44168c2654abSrjs struct sctp_strseq *stseq; 44178c2654abSrjs struct sctp_association *asoc; 44188c2654abSrjs u_int32_t new_cum_tsn, gap, back_out_htsn; 44198c2654abSrjs unsigned int i, cnt_gone, fwd_sz, cumack_set_flag, m_size; 44208c2654abSrjs struct sctp_stream_in *strm; 44218c2654abSrjs struct sctp_tmit_chunk *chk, *at; 44228c2654abSrjs 44238c2654abSrjs cumack_set_flag = 0; 44248c2654abSrjs asoc = &stcb->asoc; 44258c2654abSrjs cnt_gone = 0; 44268c2654abSrjs if ((fwd_sz = ntohs(fwd->ch.chunk_length)) < sizeof(struct sctp_forward_tsn_chunk)) { 44278c2654abSrjs #ifdef SCTP_DEBUG 44288c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 44298c2654abSrjs printf("Bad size too small/big fwd-tsn\n"); 44308c2654abSrjs } 44318c2654abSrjs #endif 44328c2654abSrjs return; 44338c2654abSrjs } 44348c2654abSrjs m_size = (stcb->asoc.mapping_array_size << 3); 44358c2654abSrjs /*************************************************************/ 44368c2654abSrjs /* 1. Here we update local cumTSN and shift the bitmap array */ 44378c2654abSrjs /*************************************************************/ 44388c2654abSrjs new_cum_tsn = ntohl(fwd->new_cumulative_tsn); 44398c2654abSrjs 44408c2654abSrjs if (compare_with_wrap(asoc->cumulative_tsn, new_cum_tsn, MAX_TSN) || 44418c2654abSrjs asoc->cumulative_tsn == new_cum_tsn) { 44428c2654abSrjs /* Already got there ... */ 44438c2654abSrjs return; 44448c2654abSrjs } 44458c2654abSrjs 44468c2654abSrjs back_out_htsn = asoc->highest_tsn_inside_map; 44478c2654abSrjs if (compare_with_wrap(new_cum_tsn, asoc->highest_tsn_inside_map, 44488c2654abSrjs MAX_TSN)) { 44498c2654abSrjs asoc->highest_tsn_inside_map = new_cum_tsn; 44508c2654abSrjs #ifdef SCTP_MAP_LOGGING 44518c2654abSrjs sctp_log_map(0, 0, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT); 44528c2654abSrjs #endif 44538c2654abSrjs } 44548c2654abSrjs /* 44558c2654abSrjs * now we know the new TSN is more advanced, let's find the 44568c2654abSrjs * actual gap 44578c2654abSrjs */ 44588c2654abSrjs if ((compare_with_wrap(new_cum_tsn, asoc->mapping_array_base_tsn, 44598c2654abSrjs MAX_TSN)) || 44608c2654abSrjs (new_cum_tsn == asoc->mapping_array_base_tsn)) { 44618c2654abSrjs gap = new_cum_tsn - asoc->mapping_array_base_tsn; 44628c2654abSrjs } else { 44638c2654abSrjs /* try to prevent underflow here */ 44648c2654abSrjs gap = new_cum_tsn + (MAX_TSN - asoc->mapping_array_base_tsn) + 1; 44658c2654abSrjs } 44668c2654abSrjs 44678c2654abSrjs if (gap >= m_size) { 44688c2654abSrjs asoc->highest_tsn_inside_map = back_out_htsn; 44698c2654abSrjs if ((long)gap > sctp_sbspace(&stcb->sctp_socket->so_rcv)) { 44708c2654abSrjs /* 44718c2654abSrjs * out of range (of single byte chunks in the rwnd I 44728c2654abSrjs * give out) 44738c2654abSrjs * too questionable. better to drop it silently 44748c2654abSrjs */ 44758c2654abSrjs return; 44768c2654abSrjs } 44778c2654abSrjs if (asoc->highest_tsn_inside_map > 44788c2654abSrjs asoc->mapping_array_base_tsn) { 44798c2654abSrjs gap = asoc->highest_tsn_inside_map - 44808c2654abSrjs asoc->mapping_array_base_tsn; 44818c2654abSrjs } else { 44828c2654abSrjs gap = asoc->highest_tsn_inside_map + 44838c2654abSrjs (MAX_TSN - asoc->mapping_array_base_tsn) + 1; 44848c2654abSrjs } 44858c2654abSrjs cumack_set_flag = 1; 44868c2654abSrjs } 44878c2654abSrjs for (i = 0; i <= gap; i++) { 44888c2654abSrjs SCTP_SET_TSN_PRESENT(asoc->mapping_array, i); 44898c2654abSrjs } 44908c2654abSrjs /* 44918c2654abSrjs * Now after marking all, slide thing forward but no 44928c2654abSrjs * sack please. 44938c2654abSrjs */ 44948c2654abSrjs sctp_sack_check(stcb, 0, 0, abort_flag); 44958c2654abSrjs if (*abort_flag) 44968c2654abSrjs return; 44978c2654abSrjs 44988c2654abSrjs if (cumack_set_flag) { 44998c2654abSrjs /* 45008c2654abSrjs * fwd-tsn went outside my gap array - not a 45012e9df72eSandvar * common occurrence. Do the same thing we 45028c2654abSrjs * do when a cookie-echo arrives. 45038c2654abSrjs */ 45048c2654abSrjs asoc->highest_tsn_inside_map = new_cum_tsn - 1; 45058c2654abSrjs asoc->mapping_array_base_tsn = new_cum_tsn; 45068c2654abSrjs asoc->cumulative_tsn = asoc->highest_tsn_inside_map; 45078c2654abSrjs #ifdef SCTP_MAP_LOGGING 45088c2654abSrjs sctp_log_map(0, 3, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT); 45098c2654abSrjs #endif 45108c2654abSrjs asoc->last_echo_tsn = asoc->highest_tsn_inside_map; 45118c2654abSrjs } 45128c2654abSrjs /*************************************************************/ 45138c2654abSrjs /* 2. Clear up re-assembly queue */ 45148c2654abSrjs /*************************************************************/ 45158c2654abSrjs 45168c2654abSrjs /* 45178c2654abSrjs * First service it if pd-api is up, just in case we can 45188c2654abSrjs * progress it forward 45198c2654abSrjs */ 45208c2654abSrjs if (asoc->fragmented_delivery_inprogress) { 45218c2654abSrjs sctp_service_reassembly(stcb, asoc, 0); 45228c2654abSrjs } 45238c2654abSrjs if (!TAILQ_EMPTY(&asoc->reasmqueue)) { 45248c2654abSrjs /* For each one on here see if we need to toss it */ 45258c2654abSrjs /* 45268c2654abSrjs * For now large messages held on the reasmqueue that are 45278c2654abSrjs * complete will be tossed too. We could in theory do more 45288c2654abSrjs * work to spin through and stop after dumping one msg 45298c2654abSrjs * aka seeing the start of a new msg at the head, and call 45308c2654abSrjs * the delivery function... to see if it can be delivered... 45318c2654abSrjs * But for now we just dump everything on the queue. 45328c2654abSrjs */ 45338c2654abSrjs chk = TAILQ_FIRST(&asoc->reasmqueue); 45348c2654abSrjs while (chk) { 45358c2654abSrjs at = TAILQ_NEXT(chk, sctp_next); 45368c2654abSrjs if (compare_with_wrap(asoc->cumulative_tsn, 45378c2654abSrjs chk->rec.data.TSN_seq, MAX_TSN) || 45388c2654abSrjs asoc->cumulative_tsn == chk->rec.data.TSN_seq) { 45398c2654abSrjs /* It needs to be tossed */ 45408c2654abSrjs TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next); 45418c2654abSrjs if (compare_with_wrap(chk->rec.data.TSN_seq, 45428c2654abSrjs asoc->tsn_last_delivered, MAX_TSN)) { 45438c2654abSrjs asoc->tsn_last_delivered = 45448c2654abSrjs chk->rec.data.TSN_seq; 45458c2654abSrjs asoc->str_of_pdapi = 45468c2654abSrjs chk->rec.data.stream_number; 45478c2654abSrjs asoc->ssn_of_pdapi = 45488c2654abSrjs chk->rec.data.stream_seq; 45498c2654abSrjs asoc->fragment_flags = 45508c2654abSrjs chk->rec.data.rcv_flags; 45518c2654abSrjs } 45528c2654abSrjs asoc->size_on_reasm_queue -= chk->send_size; 45538c2654abSrjs asoc->cnt_on_reasm_queue--; 45548c2654abSrjs cnt_gone++; 45558c2654abSrjs 45568c2654abSrjs /* Clear up any stream problem */ 45578c2654abSrjs if ((chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) != 45588c2654abSrjs SCTP_DATA_UNORDERED && 45598c2654abSrjs (compare_with_wrap(chk->rec.data.stream_seq, 45608c2654abSrjs asoc->strmin[chk->rec.data.stream_number].last_sequence_delivered, 45618c2654abSrjs MAX_SEQ))) { 45628c2654abSrjs /* 45638c2654abSrjs * We must dump forward this streams 45648c2654abSrjs * sequence number if the chunk is not 45658c2654abSrjs * unordered that is being skipped. 45668c2654abSrjs * There is a chance that if the peer 45678c2654abSrjs * does not include the last fragment 45688c2654abSrjs * in its FWD-TSN we WILL have a problem 45698c2654abSrjs * here since you would have a partial 45708c2654abSrjs * chunk in queue that may not be 45718c2654abSrjs * deliverable. 45728c2654abSrjs * Also if a Partial delivery API as 45738c2654abSrjs * started the user may get a partial 45748c2654abSrjs * chunk. The next read returning a new 45758c2654abSrjs * chunk... really ugly but I see no way 45768c2654abSrjs * around it! Maybe a notify?? 45778c2654abSrjs */ 45788c2654abSrjs asoc->strmin[chk->rec.data.stream_number].last_sequence_delivered = 45798c2654abSrjs chk->rec.data.stream_seq; 45808c2654abSrjs } 45818c2654abSrjs sctp_m_freem(chk->data); 45828c2654abSrjs chk->data = NULL; 45838c2654abSrjs sctp_free_remote_addr(chk->whoTo); 45848c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk); 45858c2654abSrjs sctppcbinfo.ipi_count_chunk--; 45868c2654abSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) { 45878c2654abSrjs panic("Chunk count is negative"); 45888c2654abSrjs } 45898c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++; 45908c2654abSrjs } else { 45918c2654abSrjs /* 45928c2654abSrjs * Ok we have gone beyond the end of the 45938c2654abSrjs * fwd-tsn's mark. Some checks... 45948c2654abSrjs */ 45958c2654abSrjs if ((asoc->fragmented_delivery_inprogress) && 45968c2654abSrjs (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG)) { 45978c2654abSrjs /* Special case PD-API is up and what we fwd-tsn' 45988c2654abSrjs * over includes one that had the LAST_FRAG. We 45998c2654abSrjs * no longer need to do the PD-API. 46008c2654abSrjs */ 46018c2654abSrjs asoc->fragmented_delivery_inprogress = 0; 46028c2654abSrjs sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION, 46038c2654abSrjs stcb, SCTP_PARTIAL_DELIVERY_ABORTED, (void *)NULL); 46048c2654abSrjs 46058c2654abSrjs } 46068c2654abSrjs break; 46078c2654abSrjs } 46088c2654abSrjs chk = at; 46098c2654abSrjs } 46108c2654abSrjs } 46118c2654abSrjs if (asoc->fragmented_delivery_inprogress) { 46128c2654abSrjs /* 46138c2654abSrjs * Ok we removed cnt_gone chunks in the PD-API queue that 46148c2654abSrjs * were being delivered. So now we must turn off the 46158c2654abSrjs * flag. 46168c2654abSrjs */ 46178c2654abSrjs sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION, 46188c2654abSrjs stcb, SCTP_PARTIAL_DELIVERY_ABORTED, (void *)NULL); 46198c2654abSrjs asoc->fragmented_delivery_inprogress = 0; 46208c2654abSrjs } 46218c2654abSrjs /*************************************************************/ 46228c2654abSrjs /* 3. Update the PR-stream re-ordering queues */ 46238c2654abSrjs /*************************************************************/ 46248c2654abSrjs stseq = (struct sctp_strseq *)((vaddr_t)fwd + sizeof(*fwd)); 46258c2654abSrjs fwd_sz -= sizeof(*fwd); 46268c2654abSrjs { 46278c2654abSrjs /* New method. */ 46288c2654abSrjs int num_str; 46298c2654abSrjs num_str = fwd_sz/sizeof(struct sctp_strseq); 46308c2654abSrjs #ifdef SCTP_DEBUG 46318c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 46328c2654abSrjs printf("Using NEW method, %d strseq's reported in FWD-TSN\n", 46338c2654abSrjs num_str); 46348c2654abSrjs } 46358c2654abSrjs #endif 46368c2654abSrjs for (i = 0; i < num_str; i++) { 46378c2654abSrjs u_int16_t st; 46388c2654abSrjs #if 0 46398c2654abSrjs unsigned char *xx; 46408c2654abSrjs /* Convert */ 46418c2654abSrjs xx = (unsigned char *)&stseq[i]; 46428c2654abSrjs #endif 46438c2654abSrjs st = ntohs(stseq[i].stream); 46448c2654abSrjs stseq[i].stream = st; 46458c2654abSrjs st = ntohs(stseq[i].sequence); 46468c2654abSrjs stseq[i].sequence = st; 46478c2654abSrjs /* now process */ 46488c2654abSrjs if (stseq[i].stream > asoc->streamincnt) { 46498c2654abSrjs #ifdef SCTP_DEBUG 46508c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INDATA1) { 46518c2654abSrjs printf("Bogus stream number %d " 46528c2654abSrjs "streamincnt is %d\n", 46538c2654abSrjs stseq[i].stream, asoc->streamincnt); 46548c2654abSrjs } 46558c2654abSrjs #endif 46568c2654abSrjs /* 46578c2654abSrjs * It is arguable if we should continue. Since 46588c2654abSrjs * the peer sent bogus stream info we may be in 46598c2654abSrjs * deep trouble.. 46608c2654abSrjs * a return may be a better choice? 46618c2654abSrjs */ 46628c2654abSrjs continue; 46638c2654abSrjs } 46648c2654abSrjs strm = &asoc->strmin[stseq[i].stream]; 46658c2654abSrjs if (compare_with_wrap(stseq[i].sequence, 46668c2654abSrjs strm->last_sequence_delivered, MAX_SEQ)) { 46678c2654abSrjs /* Update the sequence number */ 46688c2654abSrjs strm->last_sequence_delivered = 46698c2654abSrjs stseq[i].sequence; 46708c2654abSrjs } 46718c2654abSrjs /* now kick the stream the new way */ 46728c2654abSrjs sctp_kick_prsctp_reorder_queue(stcb, strm); 46738c2654abSrjs } 46748c2654abSrjs } 46758c2654abSrjs } 4676