17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 545916cd2Sjpk * Common Development and Distribution License (the "License"). 645916cd2Sjpk * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 2177c67f2fSkcpoon 227c478bd9Sstevel@tonic-gate /* 23de8c4a14SErik Nordmark * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <sys/types.h> 287c478bd9Sstevel@tonic-gate #include <sys/systm.h> 297c478bd9Sstevel@tonic-gate #include <sys/stream.h> 307c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 317c478bd9Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 327c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 337c478bd9Sstevel@tonic-gate #include <sys/socket.h> 347c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 357c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 367c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 377c478bd9Sstevel@tonic-gate #include <sys/socketvar.h> 387c478bd9Sstevel@tonic-gate #include <inet/common.h> 397c478bd9Sstevel@tonic-gate #include <inet/mi.h> 407c478bd9Sstevel@tonic-gate #include <inet/ip.h> 417c478bd9Sstevel@tonic-gate #include <inet/ip6.h> 427c478bd9Sstevel@tonic-gate #include <inet/sctp_ip.h> 437c478bd9Sstevel@tonic-gate #include <inet/ipclassifier.h> 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate /* 467c478bd9Sstevel@tonic-gate * PR-SCTP comments. 477c478bd9Sstevel@tonic-gate * 487c478bd9Sstevel@tonic-gate * A message can expire before it gets to the transmit list (i.e. it is still 497c478bd9Sstevel@tonic-gate * in the unsent list - unchunked), after it gets to the transmit list, but 507c478bd9Sstevel@tonic-gate * before transmission has actually started, or after transmission has begun. 517c478bd9Sstevel@tonic-gate * Accordingly, we check for the status of a message in sctp_chunkify() when 527c478bd9Sstevel@tonic-gate * the message is being transferred from the unsent list to the transmit list; 537c478bd9Sstevel@tonic-gate * in sctp_get_msg_to_send(), when we get the next chunk from the transmit 547c478bd9Sstevel@tonic-gate * list and in sctp_rexmit() when we get the next chunk to be (re)transmitted. 557c478bd9Sstevel@tonic-gate * When we nuke a message in sctp_chunkify(), all we need to do is take it 567c478bd9Sstevel@tonic-gate * out of the unsent list and update sctp_unsent; when a message is deemed 577c478bd9Sstevel@tonic-gate * timed-out in sctp_get_msg_to_send() we can just take it out of the transmit 587c478bd9Sstevel@tonic-gate * list, update sctp_unsent IFF transmission for the message has not yet begun 597c478bd9Sstevel@tonic-gate * (i.e. !SCTP_CHUNK_ISSENT(meta->b_cont)). However, if transmission for the 607c478bd9Sstevel@tonic-gate * message has started, then we cannot just take it out of the list, we need 617c478bd9Sstevel@tonic-gate * to send Forward TSN chunk to the peer so that the peer can clear its 627c478bd9Sstevel@tonic-gate * fragment list for this message. However, we cannot just send the Forward 637c478bd9Sstevel@tonic-gate * TSN in sctp_get_msg_to_send() because there might be unacked chunks for 647c478bd9Sstevel@tonic-gate * messages preceeding this abandoned message. So, we send a Forward TSN 657c478bd9Sstevel@tonic-gate * IFF all messages prior to this abandoned message has been SACKd, if not 667c478bd9Sstevel@tonic-gate * we defer sending the Forward TSN to sctp_cumack(), which will check for 677c478bd9Sstevel@tonic-gate * this condition and send the Forward TSN via sctp_check_abandoned_msg(). In 687c478bd9Sstevel@tonic-gate * sctp_rexmit() when we check for retransmissions, we need to determine if 697c478bd9Sstevel@tonic-gate * the advanced peer ack point can be moved ahead, and if so, send a Forward 707c478bd9Sstevel@tonic-gate * TSN to the peer instead of retransmitting the chunk. Note that when 717c478bd9Sstevel@tonic-gate * we send a Forward TSN for a message, there may be yet unsent chunks for 727c478bd9Sstevel@tonic-gate * this message; we need to mark all such chunks as abandoned, so that 737c478bd9Sstevel@tonic-gate * sctp_cumack() can take the message out of the transmit list, additionally 747c478bd9Sstevel@tonic-gate * sctp_unsent need to be adjusted. Whenever sctp_unsent is updated (i.e. 757c478bd9Sstevel@tonic-gate * decremented when a message/chunk is deemed abandoned), sockfs needs to 767c478bd9Sstevel@tonic-gate * be notified so that it can adjust its idea of the queued message. 777c478bd9Sstevel@tonic-gate */ 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate #include "sctp_impl.h" 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate static struct kmem_cache *sctp_kmem_ftsn_set_cache; 82*1e109b40SNick Street static mblk_t *sctp_chunkify(sctp_t *, int, int, int); 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate #ifdef DEBUG 857c478bd9Sstevel@tonic-gate static boolean_t sctp_verify_chain(mblk_t *, mblk_t *); 867c478bd9Sstevel@tonic-gate #endif 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate /* 897c478bd9Sstevel@tonic-gate * Called to allocate a header mblk when sending data to SCTP. 907c478bd9Sstevel@tonic-gate * Data will follow in b_cont of this mblk. 917c478bd9Sstevel@tonic-gate */ 927c478bd9Sstevel@tonic-gate mblk_t * 937c478bd9Sstevel@tonic-gate sctp_alloc_hdr(const char *name, int nlen, const char *control, int clen, 947c478bd9Sstevel@tonic-gate int flags) 957c478bd9Sstevel@tonic-gate { 967c478bd9Sstevel@tonic-gate mblk_t *mp; 977c478bd9Sstevel@tonic-gate struct T_unitdata_req *tudr; 987c478bd9Sstevel@tonic-gate size_t size; 997c478bd9Sstevel@tonic-gate int error; 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate size = sizeof (*tudr) + _TPI_ALIGN_TOPT(nlen) + clen; 1027c478bd9Sstevel@tonic-gate size = MAX(size, sizeof (sctp_msg_hdr_t)); 1037c478bd9Sstevel@tonic-gate if (flags & SCTP_CAN_BLOCK) { 1047c478bd9Sstevel@tonic-gate mp = allocb_wait(size, BPRI_MED, 0, &error); 1057c478bd9Sstevel@tonic-gate } else { 1067c478bd9Sstevel@tonic-gate mp = allocb(size, BPRI_MED); 1077c478bd9Sstevel@tonic-gate } 1087c478bd9Sstevel@tonic-gate if (mp) { 1097c478bd9Sstevel@tonic-gate tudr = (struct T_unitdata_req *)mp->b_rptr; 1107c478bd9Sstevel@tonic-gate tudr->PRIM_type = T_UNITDATA_REQ; 1117c478bd9Sstevel@tonic-gate tudr->DEST_length = nlen; 1127c478bd9Sstevel@tonic-gate tudr->DEST_offset = sizeof (*tudr); 1137c478bd9Sstevel@tonic-gate tudr->OPT_length = clen; 1147c478bd9Sstevel@tonic-gate tudr->OPT_offset = (t_scalar_t)(sizeof (*tudr) + 1157c478bd9Sstevel@tonic-gate _TPI_ALIGN_TOPT(nlen)); 1167c478bd9Sstevel@tonic-gate if (nlen > 0) 1177c478bd9Sstevel@tonic-gate bcopy(name, tudr + 1, nlen); 1187c478bd9Sstevel@tonic-gate if (clen > 0) 1197c478bd9Sstevel@tonic-gate bcopy(control, (char *)tudr + tudr->OPT_offset, clen); 1207c478bd9Sstevel@tonic-gate mp->b_wptr += (tudr ->OPT_offset + clen); 1217c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO; 1227c478bd9Sstevel@tonic-gate } 1237c478bd9Sstevel@tonic-gate return (mp); 1247c478bd9Sstevel@tonic-gate } 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate /*ARGSUSED2*/ 1277c478bd9Sstevel@tonic-gate int 1287c478bd9Sstevel@tonic-gate sctp_sendmsg(sctp_t *sctp, mblk_t *mp, int flags) 1297c478bd9Sstevel@tonic-gate { 1307c478bd9Sstevel@tonic-gate sctp_faddr_t *fp = NULL; 1317c478bd9Sstevel@tonic-gate struct T_unitdata_req *tudr; 1327c478bd9Sstevel@tonic-gate int error = 0; 1337c478bd9Sstevel@tonic-gate mblk_t *mproto = mp; 1347c478bd9Sstevel@tonic-gate in6_addr_t *addr; 1357c478bd9Sstevel@tonic-gate in6_addr_t tmpaddr; 1367c478bd9Sstevel@tonic-gate uint16_t sid = sctp->sctp_def_stream; 1377c478bd9Sstevel@tonic-gate uint32_t ppid = sctp->sctp_def_ppid; 1387c478bd9Sstevel@tonic-gate uint32_t context = sctp->sctp_def_context; 1397c478bd9Sstevel@tonic-gate uint16_t msg_flags = sctp->sctp_def_flags; 1407c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *sctp_msg_hdr; 1417c478bd9Sstevel@tonic-gate uint32_t msg_len = 0; 1427c478bd9Sstevel@tonic-gate uint32_t timetolive = sctp->sctp_def_timetolive; 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate ASSERT(DB_TYPE(mproto) == M_PROTO); 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate mp = mp->b_cont; 1477c478bd9Sstevel@tonic-gate ASSERT(mp == NULL || DB_TYPE(mp) == M_DATA); 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate tudr = (struct T_unitdata_req *)mproto->b_rptr; 1507c478bd9Sstevel@tonic-gate ASSERT(tudr->PRIM_type == T_UNITDATA_REQ); 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate /* Get destination address, if specified */ 1537c478bd9Sstevel@tonic-gate if (tudr->DEST_length > 0) { 1547c478bd9Sstevel@tonic-gate sin_t *sin; 1557c478bd9Sstevel@tonic-gate sin6_t *sin6; 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *) 1587c478bd9Sstevel@tonic-gate (mproto->b_rptr + tudr->DEST_offset); 1597c478bd9Sstevel@tonic-gate switch (sin->sin_family) { 1607c478bd9Sstevel@tonic-gate case AF_INET: 1617c478bd9Sstevel@tonic-gate if (tudr->DEST_length < sizeof (*sin)) { 1627c478bd9Sstevel@tonic-gate return (EINVAL); 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, &tmpaddr); 1657c478bd9Sstevel@tonic-gate addr = &tmpaddr; 1667c478bd9Sstevel@tonic-gate break; 1677c478bd9Sstevel@tonic-gate case AF_INET6: 1687c478bd9Sstevel@tonic-gate if (tudr->DEST_length < sizeof (*sin6)) { 1697c478bd9Sstevel@tonic-gate return (EINVAL); 1707c478bd9Sstevel@tonic-gate } 1717c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *) 1727c478bd9Sstevel@tonic-gate (mproto->b_rptr + tudr->DEST_offset); 1737c478bd9Sstevel@tonic-gate addr = &sin6->sin6_addr; 1747c478bd9Sstevel@tonic-gate break; 1757c478bd9Sstevel@tonic-gate default: 1767c478bd9Sstevel@tonic-gate return (EAFNOSUPPORT); 1777c478bd9Sstevel@tonic-gate } 1787c478bd9Sstevel@tonic-gate fp = sctp_lookup_faddr(sctp, addr); 1797c478bd9Sstevel@tonic-gate if (fp == NULL) { 1807c478bd9Sstevel@tonic-gate return (EINVAL); 1817c478bd9Sstevel@tonic-gate } 1827c478bd9Sstevel@tonic-gate } 1837c478bd9Sstevel@tonic-gate /* Ancillary Data? */ 1847c478bd9Sstevel@tonic-gate if (tudr->OPT_length > 0) { 1857c478bd9Sstevel@tonic-gate struct cmsghdr *cmsg; 1867c478bd9Sstevel@tonic-gate char *cend; 1877c478bd9Sstevel@tonic-gate struct sctp_sndrcvinfo *sndrcv; 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate cmsg = (struct cmsghdr *)(mproto->b_rptr + tudr->OPT_offset); 1907c478bd9Sstevel@tonic-gate cend = ((char *)cmsg + tudr->OPT_length); 1917c478bd9Sstevel@tonic-gate ASSERT(cend <= (char *)mproto->b_wptr); 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate for (;;) { 1947c478bd9Sstevel@tonic-gate if ((char *)(cmsg + 1) > cend || 1957c478bd9Sstevel@tonic-gate ((char *)cmsg + cmsg->cmsg_len) > cend) { 1967c478bd9Sstevel@tonic-gate break; 1977c478bd9Sstevel@tonic-gate } 1987c478bd9Sstevel@tonic-gate if ((cmsg->cmsg_level == IPPROTO_SCTP) && 1997c478bd9Sstevel@tonic-gate (cmsg->cmsg_type == SCTP_SNDRCV)) { 2007c478bd9Sstevel@tonic-gate if (cmsg->cmsg_len < 2017c478bd9Sstevel@tonic-gate (sizeof (*sndrcv) + sizeof (*cmsg))) { 2027c478bd9Sstevel@tonic-gate return (EINVAL); 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate sndrcv = (struct sctp_sndrcvinfo *)(cmsg + 1); 2057c478bd9Sstevel@tonic-gate sid = sndrcv->sinfo_stream; 2067c478bd9Sstevel@tonic-gate msg_flags = sndrcv->sinfo_flags; 2077c478bd9Sstevel@tonic-gate ppid = sndrcv->sinfo_ppid; 2087c478bd9Sstevel@tonic-gate context = sndrcv->sinfo_context; 2097c478bd9Sstevel@tonic-gate timetolive = sndrcv->sinfo_timetolive; 2107c478bd9Sstevel@tonic-gate break; 2117c478bd9Sstevel@tonic-gate } 2127c478bd9Sstevel@tonic-gate if (cmsg->cmsg_len > 0) 2137c478bd9Sstevel@tonic-gate cmsg = CMSG_NEXT(cmsg); 2147c478bd9Sstevel@tonic-gate else 2157c478bd9Sstevel@tonic-gate break; 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate if (msg_flags & MSG_ABORT) { 2197c478bd9Sstevel@tonic-gate if (mp && mp->b_cont) { 2207c478bd9Sstevel@tonic-gate mblk_t *pump = msgpullup(mp, -1); 2217c478bd9Sstevel@tonic-gate if (!pump) { 2227c478bd9Sstevel@tonic-gate return (ENOMEM); 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate freemsg(mp); 2257c478bd9Sstevel@tonic-gate mp = pump; 2267c478bd9Sstevel@tonic-gate mproto->b_cont = mp; 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate RUN_SCTP(sctp); 229e6f13f86SKacheong Poon sctp_user_abort(sctp, mp); 2307c478bd9Sstevel@tonic-gate freemsg(mproto); 2317c478bd9Sstevel@tonic-gate goto process_sendq; 2327c478bd9Sstevel@tonic-gate } 2337c478bd9Sstevel@tonic-gate if (mp == NULL) 2347c478bd9Sstevel@tonic-gate goto done; 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate RUN_SCTP(sctp); 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate /* Reject any new data requests if we are shutting down */ 239b34b8d1aSkcpoon if (sctp->sctp_state > SCTPS_ESTABLISHED || 240b34b8d1aSkcpoon (sctp->sctp_connp->conn_state_flags & CONN_CLOSING)) { 2417c478bd9Sstevel@tonic-gate error = EPIPE; 2427c478bd9Sstevel@tonic-gate goto unlock_done; 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate /* Re-use the mproto to store relevant info. */ 2467c478bd9Sstevel@tonic-gate ASSERT(MBLKSIZE(mproto) >= sizeof (*sctp_msg_hdr)); 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate mproto->b_rptr = mproto->b_datap->db_base; 2497c478bd9Sstevel@tonic-gate mproto->b_wptr = mproto->b_rptr + sizeof (*sctp_msg_hdr); 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate sctp_msg_hdr = (sctp_msg_hdr_t *)mproto->b_rptr; 2527c478bd9Sstevel@tonic-gate bzero(sctp_msg_hdr, sizeof (*sctp_msg_hdr)); 2537c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_context = context; 2547c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_sid = sid; 2557c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_ppid = ppid; 2567c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_flags = msg_flags; 2577c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_ttl = MSEC_TO_TICK(timetolive); 2587c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_tob = lbolt64; 2597c478bd9Sstevel@tonic-gate for (; mp != NULL; mp = mp->b_cont) 2607c478bd9Sstevel@tonic-gate msg_len += MBLKL(mp); 2617c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_msglen = msg_len; 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate /* User requested specific destination */ 2647c478bd9Sstevel@tonic-gate SCTP_SET_CHUNK_DEST(mproto, fp); 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate if (sctp->sctp_state >= SCTPS_COOKIE_ECHOED && 2677c478bd9Sstevel@tonic-gate sid >= sctp->sctp_num_ostr) { 2687c478bd9Sstevel@tonic-gate /* Send sendfail event */ 2697c478bd9Sstevel@tonic-gate sctp_sendfail_event(sctp, dupmsg(mproto), SCTP_ERR_BAD_SID, 2707c478bd9Sstevel@tonic-gate B_FALSE); 2717c478bd9Sstevel@tonic-gate error = EINVAL; 2727c478bd9Sstevel@tonic-gate goto unlock_done; 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate /* no data */ 2767c478bd9Sstevel@tonic-gate if (msg_len == 0) { 2777c478bd9Sstevel@tonic-gate sctp_sendfail_event(sctp, dupmsg(mproto), 2787c478bd9Sstevel@tonic-gate SCTP_ERR_NO_USR_DATA, B_FALSE); 2797c478bd9Sstevel@tonic-gate error = EINVAL; 2807c478bd9Sstevel@tonic-gate goto unlock_done; 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate /* Add it to the unsent list */ 2847c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_unsent == NULL) { 2857c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent = sctp->sctp_xmit_unsent_tail = mproto; 2867c478bd9Sstevel@tonic-gate } else { 2877c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent_tail->b_next = mproto; 2887c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent_tail = mproto; 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate sctp->sctp_unsent += msg_len; 2917c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_msgcount); 2920f1702c5SYu Xiangning /* 2930f1702c5SYu Xiangning * Notify sockfs if the tx queue is full. 2940f1702c5SYu Xiangning */ 2950f1702c5SYu Xiangning if (SCTP_TXQ_LEN(sctp) >= sctp->sctp_xmit_hiwater) { 2960f1702c5SYu Xiangning sctp->sctp_txq_full = 1; 2970f1702c5SYu Xiangning sctp->sctp_ulp_xmitted(sctp->sctp_ulpd, B_TRUE); 2980f1702c5SYu Xiangning } 2997c478bd9Sstevel@tonic-gate if (sctp->sctp_state == SCTPS_ESTABLISHED) 30012f47623Skcpoon sctp_output(sctp, UINT_MAX); 3017c478bd9Sstevel@tonic-gate process_sendq: 3027c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 3037c478bd9Sstevel@tonic-gate sctp_process_sendq(sctp); 3047c478bd9Sstevel@tonic-gate return (0); 3057c478bd9Sstevel@tonic-gate unlock_done: 3067c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 3077c478bd9Sstevel@tonic-gate done: 3087c478bd9Sstevel@tonic-gate return (error); 3097c478bd9Sstevel@tonic-gate } 3107c478bd9Sstevel@tonic-gate 311*1e109b40SNick Street /* 312*1e109b40SNick Street * While there are messages on sctp_xmit_unsent, detach each one. For each: 313*1e109b40SNick Street * allocate space for the chunk header, fill in the data chunk, and fill in 314*1e109b40SNick Street * the chunk header. Then append it to sctp_xmit_tail. 315*1e109b40SNick Street * Return after appending as many bytes as required (bytes_to_send). 316*1e109b40SNick Street * We also return if we've appended one or more chunks, and find a subsequent 317*1e109b40SNick Street * unsent message is too big to fit in the segment. 318*1e109b40SNick Street */ 319*1e109b40SNick Street mblk_t * 320*1e109b40SNick Street sctp_chunkify(sctp_t *sctp, int mss, int firstseg_len, int bytes_to_send) 3217c478bd9Sstevel@tonic-gate { 3227c478bd9Sstevel@tonic-gate mblk_t *mp; 3237c478bd9Sstevel@tonic-gate mblk_t *chunk_mp; 3247c478bd9Sstevel@tonic-gate mblk_t *chunk_head; 3257c478bd9Sstevel@tonic-gate mblk_t *chunk_hdr; 3267c478bd9Sstevel@tonic-gate mblk_t *chunk_tail = NULL; 3277c478bd9Sstevel@tonic-gate int count; 3287c478bd9Sstevel@tonic-gate int chunksize; 3297c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 3307c478bd9Sstevel@tonic-gate mblk_t *mdblk = sctp->sctp_xmit_unsent; 3317c478bd9Sstevel@tonic-gate sctp_faddr_t *fp; 3327c478bd9Sstevel@tonic-gate sctp_faddr_t *fp1; 3337c478bd9Sstevel@tonic-gate size_t xtralen; 3347c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *msg_hdr; 335*1e109b40SNick Street sctp_stack_t *sctps = sctp->sctp_sctps; 336*1e109b40SNick Street sctp_msg_hdr_t *next_msg_hdr; 337*1e109b40SNick Street size_t nextlen; 338*1e109b40SNick Street int remaining_len = mss - firstseg_len; 339*1e109b40SNick Street 340*1e109b40SNick Street ASSERT(remaining_len >= 0); 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate fp = SCTP_CHUNK_DEST(mdblk); 3437c478bd9Sstevel@tonic-gate if (fp == NULL) 3447c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 3457c478bd9Sstevel@tonic-gate if (fp->isv4) 346f4b3ec61Sdh xtralen = sctp->sctp_hdr_len + sctps->sctps_wroff_xtra + 347f4b3ec61Sdh sizeof (*sdc); 3487c478bd9Sstevel@tonic-gate else 349f4b3ec61Sdh xtralen = sctp->sctp_hdr6_len + sctps->sctps_wroff_xtra + 350f4b3ec61Sdh sizeof (*sdc); 351*1e109b40SNick Street count = chunksize = remaining_len - sizeof (*sdc); 3527c478bd9Sstevel@tonic-gate nextmsg: 353*1e109b40SNick Street next_msg_hdr = (sctp_msg_hdr_t *)sctp->sctp_xmit_unsent->b_rptr; 354*1e109b40SNick Street nextlen = next_msg_hdr->smh_msglen; 355*1e109b40SNick Street /* 356*1e109b40SNick Street * Will the entire next message fit in the current packet ? 357*1e109b40SNick Street * if not, leave it on the unsent list. 358*1e109b40SNick Street */ 359*1e109b40SNick Street if ((firstseg_len != 0) && (nextlen > remaining_len)) 360*1e109b40SNick Street return (NULL); 361*1e109b40SNick Street 3627c478bd9Sstevel@tonic-gate chunk_mp = mdblk->b_cont; 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate /* 365*1e109b40SNick Street * If this partially chunked, we ignore the next one for now and 366*1e109b40SNick Street * use the one already present. For the unchunked bits, we use the 367*1e109b40SNick Street * length of the last chunk. 3687c478bd9Sstevel@tonic-gate */ 3697c478bd9Sstevel@tonic-gate if (SCTP_IS_MSG_CHUNKED(mdblk)) { 3707c478bd9Sstevel@tonic-gate int chunk_len; 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate ASSERT(chunk_mp->b_next != NULL); 3737c478bd9Sstevel@tonic-gate mdblk->b_cont = chunk_mp->b_next; 3747c478bd9Sstevel@tonic-gate chunk_mp->b_next = NULL; 3757c478bd9Sstevel@tonic-gate SCTP_MSG_CLEAR_CHUNKED(mdblk); 3767c478bd9Sstevel@tonic-gate mp = mdblk->b_cont; 3777c478bd9Sstevel@tonic-gate while (mp->b_next != NULL) 3787c478bd9Sstevel@tonic-gate mp = mp->b_next; 3797c478bd9Sstevel@tonic-gate chunk_len = ntohs(((sctp_data_hdr_t *)mp->b_rptr)->sdh_len); 3807c478bd9Sstevel@tonic-gate if (fp->sfa_pmss - chunk_len > sizeof (*sdc)) 3817c478bd9Sstevel@tonic-gate count = chunksize = fp->sfa_pmss - chunk_len; 3827c478bd9Sstevel@tonic-gate else 3837c478bd9Sstevel@tonic-gate count = chunksize = fp->sfa_pmss; 3847c478bd9Sstevel@tonic-gate count = chunksize = count - sizeof (*sdc); 3857c478bd9Sstevel@tonic-gate } else { 3867c478bd9Sstevel@tonic-gate msg_hdr = (sctp_msg_hdr_t *)mdblk->b_rptr; 3877c478bd9Sstevel@tonic-gate if (SCTP_MSG_TO_BE_ABANDONED(mdblk, msg_hdr, sctp)) { 3887c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent = mdblk->b_next; 3897c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_unsent == NULL) 3907c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent_tail = NULL; 3917c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_unsent >= msg_hdr->smh_msglen); 3927c478bd9Sstevel@tonic-gate sctp->sctp_unsent -= msg_hdr->smh_msglen; 3937c478bd9Sstevel@tonic-gate mdblk->b_next = NULL; 3947c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_prsctpdrop); 3957c478bd9Sstevel@tonic-gate /* 3967c478bd9Sstevel@tonic-gate * Update ULP the amount of queued data, which is 3977c478bd9Sstevel@tonic-gate * sent-unack'ed + unsent. 3987c478bd9Sstevel@tonic-gate */ 3990f1702c5SYu Xiangning if (!SCTP_IS_DETACHED(sctp)) 4000f1702c5SYu Xiangning SCTP_TXQ_UPDATE(sctp); 4017c478bd9Sstevel@tonic-gate sctp_sendfail_event(sctp, mdblk, 0, B_FALSE); 4027c478bd9Sstevel@tonic-gate goto try_next; 4037c478bd9Sstevel@tonic-gate } 4047c478bd9Sstevel@tonic-gate mdblk->b_cont = NULL; 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate msg_hdr = (sctp_msg_hdr_t *)mdblk->b_rptr; 4077c478bd9Sstevel@tonic-gate nextchunk: 4087c478bd9Sstevel@tonic-gate chunk_head = chunk_mp; 4097c478bd9Sstevel@tonic-gate chunk_tail = NULL; 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate /* Skip as many mblk's as we need */ 4127c478bd9Sstevel@tonic-gate while (chunk_mp != NULL && ((count - MBLKL(chunk_mp)) >= 0)) { 4137c478bd9Sstevel@tonic-gate count -= MBLKL(chunk_mp); 4147c478bd9Sstevel@tonic-gate chunk_tail = chunk_mp; 4157c478bd9Sstevel@tonic-gate chunk_mp = chunk_mp->b_cont; 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate /* Split the chain, if needed */ 4187c478bd9Sstevel@tonic-gate if (chunk_mp != NULL) { 4197c478bd9Sstevel@tonic-gate if (count > 0) { 4207c478bd9Sstevel@tonic-gate mblk_t *split_mp = dupb(chunk_mp); 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate if (split_mp == NULL) { 4237c478bd9Sstevel@tonic-gate if (mdblk->b_cont == NULL) { 4247c478bd9Sstevel@tonic-gate mdblk->b_cont = chunk_head; 4257c478bd9Sstevel@tonic-gate } else { 4267c478bd9Sstevel@tonic-gate SCTP_MSG_SET_CHUNKED(mdblk); 4277c478bd9Sstevel@tonic-gate ASSERT(chunk_head->b_next == NULL); 4287c478bd9Sstevel@tonic-gate chunk_head->b_next = mdblk->b_cont; 4297c478bd9Sstevel@tonic-gate mdblk->b_cont = chunk_head; 4307c478bd9Sstevel@tonic-gate } 431*1e109b40SNick Street return (sctp->sctp_xmit_tail); 4327c478bd9Sstevel@tonic-gate } 4337c478bd9Sstevel@tonic-gate if (chunk_tail != NULL) { 4347c478bd9Sstevel@tonic-gate chunk_tail->b_cont = split_mp; 4357c478bd9Sstevel@tonic-gate chunk_tail = chunk_tail->b_cont; 4367c478bd9Sstevel@tonic-gate } else { 4377c478bd9Sstevel@tonic-gate chunk_head = chunk_tail = split_mp; 4387c478bd9Sstevel@tonic-gate } 4397c478bd9Sstevel@tonic-gate chunk_tail->b_wptr = chunk_tail->b_rptr + count; 4407c478bd9Sstevel@tonic-gate chunk_mp->b_rptr = chunk_tail->b_wptr; 4417c478bd9Sstevel@tonic-gate count = 0; 4427c478bd9Sstevel@tonic-gate } else if (chunk_tail == NULL) { 4437c478bd9Sstevel@tonic-gate goto next; 4447c478bd9Sstevel@tonic-gate } else { 4457c478bd9Sstevel@tonic-gate chunk_tail->b_cont = NULL; 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate } 4487c478bd9Sstevel@tonic-gate /* Alloc chunk hdr, if needed */ 4497c478bd9Sstevel@tonic-gate if (DB_REF(chunk_head) > 1 || 4507c478bd9Sstevel@tonic-gate ((intptr_t)chunk_head->b_rptr) & (SCTP_ALIGN - 1) || 4517c478bd9Sstevel@tonic-gate MBLKHEAD(chunk_head) < sizeof (*sdc)) { 4527c478bd9Sstevel@tonic-gate if ((chunk_hdr = allocb(xtralen, BPRI_MED)) == NULL) { 4537c478bd9Sstevel@tonic-gate if (mdblk->b_cont == NULL) { 4547c478bd9Sstevel@tonic-gate if (chunk_mp != NULL) 4557c478bd9Sstevel@tonic-gate linkb(chunk_head, chunk_mp); 4567c478bd9Sstevel@tonic-gate mdblk->b_cont = chunk_head; 4577c478bd9Sstevel@tonic-gate } else { 4587c478bd9Sstevel@tonic-gate SCTP_MSG_SET_CHUNKED(mdblk); 4597c478bd9Sstevel@tonic-gate if (chunk_mp != NULL) 4607c478bd9Sstevel@tonic-gate linkb(chunk_head, chunk_mp); 4617c478bd9Sstevel@tonic-gate ASSERT(chunk_head->b_next == NULL); 4627c478bd9Sstevel@tonic-gate chunk_head->b_next = mdblk->b_cont; 4637c478bd9Sstevel@tonic-gate mdblk->b_cont = chunk_head; 4647c478bd9Sstevel@tonic-gate } 465*1e109b40SNick Street return (sctp->sctp_xmit_tail); 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate chunk_hdr->b_rptr += xtralen - sizeof (*sdc); 4687c478bd9Sstevel@tonic-gate chunk_hdr->b_wptr = chunk_hdr->b_rptr + sizeof (*sdc); 4697c478bd9Sstevel@tonic-gate chunk_hdr->b_cont = chunk_head; 4707c478bd9Sstevel@tonic-gate } else { 4717c478bd9Sstevel@tonic-gate chunk_hdr = chunk_head; 4727c478bd9Sstevel@tonic-gate chunk_hdr->b_rptr -= sizeof (*sdc); 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate ASSERT(chunk_hdr->b_datap->db_ref == 1); 4757c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)chunk_hdr->b_rptr; 4767c478bd9Sstevel@tonic-gate sdc->sdh_id = CHUNK_DATA; 4777c478bd9Sstevel@tonic-gate sdc->sdh_flags = 0; 4787c478bd9Sstevel@tonic-gate sdc->sdh_len = htons(sizeof (*sdc) + chunksize - count); 4797c478bd9Sstevel@tonic-gate ASSERT(sdc->sdh_len); 4807c478bd9Sstevel@tonic-gate sdc->sdh_sid = htons(msg_hdr->smh_sid); 4817c478bd9Sstevel@tonic-gate /* 4827c478bd9Sstevel@tonic-gate * We defer assigning the SSN just before sending the chunk, else 4837c478bd9Sstevel@tonic-gate * if we drop the chunk in sctp_get_msg_to_send(), we would need 4847c478bd9Sstevel@tonic-gate * to send a Forward TSN to let the peer know. Some more comments 4857c478bd9Sstevel@tonic-gate * about this in sctp_impl.h for SCTP_CHUNK_SENT. 4867c478bd9Sstevel@tonic-gate */ 4877c478bd9Sstevel@tonic-gate sdc->sdh_payload_id = msg_hdr->smh_ppid; 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate if (mdblk->b_cont == NULL) { 4907c478bd9Sstevel@tonic-gate mdblk->b_cont = chunk_hdr; 4917c478bd9Sstevel@tonic-gate SCTP_DATA_SET_BBIT(sdc); 4927c478bd9Sstevel@tonic-gate } else { 4937c478bd9Sstevel@tonic-gate mp = mdblk->b_cont; 4947c478bd9Sstevel@tonic-gate while (mp->b_next != NULL) 4957c478bd9Sstevel@tonic-gate mp = mp->b_next; 4967c478bd9Sstevel@tonic-gate mp->b_next = chunk_hdr; 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate bytes_to_send -= (chunksize - count); 5007c478bd9Sstevel@tonic-gate if (chunk_mp != NULL) { 5017c478bd9Sstevel@tonic-gate next: 5027c478bd9Sstevel@tonic-gate count = chunksize = fp->sfa_pmss - sizeof (*sdc); 5037c478bd9Sstevel@tonic-gate goto nextchunk; 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate SCTP_DATA_SET_EBIT(sdc); 5067c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent = mdblk->b_next; 5077c478bd9Sstevel@tonic-gate if (mdblk->b_next == NULL) { 5087c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent_tail = NULL; 5097c478bd9Sstevel@tonic-gate } 5107c478bd9Sstevel@tonic-gate mdblk->b_next = NULL; 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_tail == NULL) { 5137c478bd9Sstevel@tonic-gate sctp->sctp_xmit_head = sctp->sctp_xmit_tail = mdblk; 5147c478bd9Sstevel@tonic-gate } else { 5157c478bd9Sstevel@tonic-gate mp = sctp->sctp_xmit_tail; 5167c478bd9Sstevel@tonic-gate while (mp->b_next != NULL) 5177c478bd9Sstevel@tonic-gate mp = mp->b_next; 5187c478bd9Sstevel@tonic-gate mp->b_next = mdblk; 5197c478bd9Sstevel@tonic-gate mdblk->b_prev = mp; 5207c478bd9Sstevel@tonic-gate } 5217c478bd9Sstevel@tonic-gate try_next: 5227c478bd9Sstevel@tonic-gate if (bytes_to_send > 0 && sctp->sctp_xmit_unsent != NULL) { 5237c478bd9Sstevel@tonic-gate mdblk = sctp->sctp_xmit_unsent; 5247c478bd9Sstevel@tonic-gate fp1 = SCTP_CHUNK_DEST(mdblk); 5257c478bd9Sstevel@tonic-gate if (fp1 == NULL) 5267c478bd9Sstevel@tonic-gate fp1 = sctp->sctp_current; 5277c478bd9Sstevel@tonic-gate if (fp == fp1) { 5287c478bd9Sstevel@tonic-gate size_t len = MBLKL(mdblk->b_cont); 5297c478bd9Sstevel@tonic-gate if ((count > 0) && 5307c478bd9Sstevel@tonic-gate ((len > fp->sfa_pmss - sizeof (*sdc)) || 531b34b8d1aSkcpoon (len <= count))) { 5327c478bd9Sstevel@tonic-gate count -= sizeof (*sdc); 5337c478bd9Sstevel@tonic-gate count = chunksize = count - (count & 0x3); 5347c478bd9Sstevel@tonic-gate } else { 5357c478bd9Sstevel@tonic-gate count = chunksize = fp->sfa_pmss - 5367c478bd9Sstevel@tonic-gate sizeof (*sdc); 5377c478bd9Sstevel@tonic-gate } 5387c478bd9Sstevel@tonic-gate } else { 5397c478bd9Sstevel@tonic-gate if (fp1->isv4) 5407c478bd9Sstevel@tonic-gate xtralen = sctp->sctp_hdr_len; 5417c478bd9Sstevel@tonic-gate else 5427c478bd9Sstevel@tonic-gate xtralen = sctp->sctp_hdr6_len; 543f4b3ec61Sdh xtralen += sctps->sctps_wroff_xtra + sizeof (*sdc); 5447c478bd9Sstevel@tonic-gate count = chunksize = fp1->sfa_pmss - sizeof (*sdc); 5457c478bd9Sstevel@tonic-gate fp = fp1; 5467c478bd9Sstevel@tonic-gate } 5477c478bd9Sstevel@tonic-gate goto nextmsg; 5487c478bd9Sstevel@tonic-gate } 549*1e109b40SNick Street return (sctp->sctp_xmit_tail); 5507c478bd9Sstevel@tonic-gate } 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate void 5537c478bd9Sstevel@tonic-gate sctp_free_msg(mblk_t *ump) 5547c478bd9Sstevel@tonic-gate { 5557c478bd9Sstevel@tonic-gate mblk_t *mp, *nmp; 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate for (mp = ump->b_cont; mp; mp = nmp) { 5587c478bd9Sstevel@tonic-gate nmp = mp->b_next; 5597c478bd9Sstevel@tonic-gate mp->b_next = mp->b_prev = NULL; 5607c478bd9Sstevel@tonic-gate freemsg(mp); 5617c478bd9Sstevel@tonic-gate } 5627c478bd9Sstevel@tonic-gate ASSERT(!ump->b_prev); 5637c478bd9Sstevel@tonic-gate ump->b_next = NULL; 5647c478bd9Sstevel@tonic-gate freeb(ump); 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate mblk_t * 568df19b344Svi sctp_add_proto_hdr(sctp_t *sctp, sctp_faddr_t *fp, mblk_t *mp, int sacklen, 569df19b344Svi int *error) 5707c478bd9Sstevel@tonic-gate { 5717c478bd9Sstevel@tonic-gate int hdrlen; 5727c478bd9Sstevel@tonic-gate char *hdr; 5737c478bd9Sstevel@tonic-gate int isv4 = fp->isv4; 574f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 5757c478bd9Sstevel@tonic-gate 576df19b344Svi if (error != NULL) 577df19b344Svi *error = 0; 578df19b344Svi 5797c478bd9Sstevel@tonic-gate if (isv4) { 5807c478bd9Sstevel@tonic-gate hdrlen = sctp->sctp_hdr_len; 5817c478bd9Sstevel@tonic-gate hdr = sctp->sctp_iphc; 5827c478bd9Sstevel@tonic-gate } else { 5837c478bd9Sstevel@tonic-gate hdrlen = sctp->sctp_hdr6_len; 5847c478bd9Sstevel@tonic-gate hdr = sctp->sctp_iphc6; 5857c478bd9Sstevel@tonic-gate } 586df19b344Svi /* 587df19b344Svi * A null fp->ire could mean that the address is 'down'. Similarly, 588df19b344Svi * it is possible that the address went down, we tried to send an 589df19b344Svi * heartbeat and ended up setting fp->saddr as unspec because we 59077c67f2fSkcpoon * didn't have any usable source address. In either case 59177c67f2fSkcpoon * sctp_get_ire() will try find an IRE, if available, and set 59277c67f2fSkcpoon * the source address, if needed. If we still don't have any 593df19b344Svi * usable source address, fp->state will be SCTP_FADDRS_UNREACH and 594df19b344Svi * we return EHOSTUNREACH. 595df19b344Svi */ 596df19b344Svi if (fp->ire == NULL || SCTP_IS_ADDR_UNSPEC(fp->isv4, fp->saddr)) { 59777c67f2fSkcpoon sctp_get_ire(sctp, fp); 598df19b344Svi if (fp->state == SCTP_FADDRS_UNREACH) { 599df19b344Svi if (error != NULL) 600df19b344Svi *error = EHOSTUNREACH; 601df19b344Svi return (NULL); 6027c478bd9Sstevel@tonic-gate } 6037c478bd9Sstevel@tonic-gate } 6047c478bd9Sstevel@tonic-gate /* Copy in IP header. */ 6057c478bd9Sstevel@tonic-gate if ((mp->b_rptr - mp->b_datap->db_base) < 606f4b3ec61Sdh (sctps->sctps_wroff_xtra + hdrlen + sacklen) || DB_REF(mp) > 2 || 60777c67f2fSkcpoon !IS_P2ALIGNED(DB_BASE(mp), sizeof (ire_t *))) { 6087c478bd9Sstevel@tonic-gate mblk_t *nmp; 60977c67f2fSkcpoon 6107c478bd9Sstevel@tonic-gate /* 6117c478bd9Sstevel@tonic-gate * This can happen if IP headers are adjusted after 6127c478bd9Sstevel@tonic-gate * data was moved into chunks, or during retransmission, 6137c478bd9Sstevel@tonic-gate * or things like snoop is running. 6147c478bd9Sstevel@tonic-gate */ 615f4b3ec61Sdh nmp = allocb_cred(sctps->sctps_wroff_xtra + hdrlen + sacklen, 616de8c4a14SErik Nordmark CONN_CRED(sctp->sctp_connp), sctp->sctp_cpid); 6177c478bd9Sstevel@tonic-gate if (nmp == NULL) { 618df19b344Svi if (error != NULL) 619df19b344Svi *error = ENOMEM; 6207c478bd9Sstevel@tonic-gate return (NULL); 6217c478bd9Sstevel@tonic-gate } 622f4b3ec61Sdh nmp->b_rptr += sctps->sctps_wroff_xtra; 6237c478bd9Sstevel@tonic-gate nmp->b_wptr = nmp->b_rptr + hdrlen + sacklen; 6247c478bd9Sstevel@tonic-gate nmp->b_cont = mp; 6257c478bd9Sstevel@tonic-gate mp = nmp; 6267c478bd9Sstevel@tonic-gate } else { 6277c478bd9Sstevel@tonic-gate mp->b_rptr -= (hdrlen + sacklen); 628de8c4a14SErik Nordmark mblk_setcred(mp, CONN_CRED(sctp->sctp_connp), sctp->sctp_cpid); 6297c478bd9Sstevel@tonic-gate } 6307c478bd9Sstevel@tonic-gate bcopy(hdr, mp->b_rptr, hdrlen); 6317c478bd9Sstevel@tonic-gate if (sacklen) { 6327c478bd9Sstevel@tonic-gate sctp_fill_sack(sctp, mp->b_rptr + hdrlen, sacklen); 6337c478bd9Sstevel@tonic-gate } 6347c478bd9Sstevel@tonic-gate if (fp != sctp->sctp_current) { 6357c478bd9Sstevel@tonic-gate /* change addresses in header */ 6367c478bd9Sstevel@tonic-gate if (isv4) { 6377c478bd9Sstevel@tonic-gate ipha_t *iph = (ipha_t *)mp->b_rptr; 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_IPADDR(&fp->faddr, iph->ipha_dst); 6407c478bd9Sstevel@tonic-gate if (!IN6_IS_ADDR_V4MAPPED_ANY(&fp->saddr)) { 6417c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_IPADDR(&fp->saddr, 6427c478bd9Sstevel@tonic-gate iph->ipha_src); 6437c478bd9Sstevel@tonic-gate } else if (sctp->sctp_bound_to_all) { 6447c478bd9Sstevel@tonic-gate iph->ipha_src = INADDR_ANY; 6457c478bd9Sstevel@tonic-gate } 6467c478bd9Sstevel@tonic-gate } else { 6477c478bd9Sstevel@tonic-gate ((ip6_t *)(mp->b_rptr))->ip6_dst = fp->faddr; 6487c478bd9Sstevel@tonic-gate if (!IN6_IS_ADDR_UNSPECIFIED(&fp->saddr)) { 6497c478bd9Sstevel@tonic-gate ((ip6_t *)(mp->b_rptr))->ip6_src = fp->saddr; 6507c478bd9Sstevel@tonic-gate } else if (sctp->sctp_bound_to_all) { 6517c478bd9Sstevel@tonic-gate V6_SET_ZERO(((ip6_t *)(mp->b_rptr))->ip6_src); 6527c478bd9Sstevel@tonic-gate } 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate /* 6567c478bd9Sstevel@tonic-gate * IP will not free this IRE if it is condemned. SCTP needs to 6577c478bd9Sstevel@tonic-gate * free it. 6587c478bd9Sstevel@tonic-gate */ 6597c478bd9Sstevel@tonic-gate if ((fp->ire != NULL) && (fp->ire->ire_marks & IRE_MARK_CONDEMNED)) { 6607c478bd9Sstevel@tonic-gate IRE_REFRELE_NOTR(fp->ire); 6617c478bd9Sstevel@tonic-gate fp->ire = NULL; 6627c478bd9Sstevel@tonic-gate } 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate /* Stash the conn and ire ptr info for IP */ 6657c478bd9Sstevel@tonic-gate SCTP_STASH_IPINFO(mp, fp->ire); 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate return (mp); 6687c478bd9Sstevel@tonic-gate } 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate /* 6717c478bd9Sstevel@tonic-gate * SCTP requires every chunk to be padded so that the total length 6727c478bd9Sstevel@tonic-gate * is a multiple of SCTP_ALIGN. This function returns a mblk with 6737c478bd9Sstevel@tonic-gate * the specified pad length. 6747c478bd9Sstevel@tonic-gate */ 6757c478bd9Sstevel@tonic-gate static mblk_t * 676121e5416Skcpoon sctp_get_padding(sctp_t *sctp, int pad) 6777c478bd9Sstevel@tonic-gate { 6787c478bd9Sstevel@tonic-gate mblk_t *fill; 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate ASSERT(pad < SCTP_ALIGN); 681121e5416Skcpoon ASSERT(sctp->sctp_pad_mp != NULL); 682121e5416Skcpoon if ((fill = dupb(sctp->sctp_pad_mp)) != NULL) { 6837c478bd9Sstevel@tonic-gate fill->b_wptr += pad; 6847c478bd9Sstevel@tonic-gate return (fill); 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate /* 6887c478bd9Sstevel@tonic-gate * The memory saving path of reusing the sctp_pad_mp 6897c478bd9Sstevel@tonic-gate * fails may be because it has been dupb() too 6907c478bd9Sstevel@tonic-gate * many times (DBLK_REFMAX). Use the memory consuming 6917c478bd9Sstevel@tonic-gate * path of allocating the pad mblk. 6927c478bd9Sstevel@tonic-gate */ 6937c478bd9Sstevel@tonic-gate if ((fill = allocb(SCTP_ALIGN, BPRI_MED)) != NULL) { 6947c478bd9Sstevel@tonic-gate /* Zero it out. SCTP_ALIGN is sizeof (int32_t) */ 6957c478bd9Sstevel@tonic-gate *(int32_t *)fill->b_rptr = 0; 6967c478bd9Sstevel@tonic-gate fill->b_wptr += pad; 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate return (fill); 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate static mblk_t * 7027c478bd9Sstevel@tonic-gate sctp_find_fast_rexmit_mblks(sctp_t *sctp, int *total, sctp_faddr_t **fp) 7037c478bd9Sstevel@tonic-gate { 7047c478bd9Sstevel@tonic-gate mblk_t *meta; 7057c478bd9Sstevel@tonic-gate mblk_t *start_mp = NULL; 7067c478bd9Sstevel@tonic-gate mblk_t *end_mp = NULL; 7077c478bd9Sstevel@tonic-gate mblk_t *mp, *nmp; 7087c478bd9Sstevel@tonic-gate mblk_t *fill; 7097c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdh; 7107c478bd9Sstevel@tonic-gate int msglen; 7117c478bd9Sstevel@tonic-gate int extra; 7127c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *msg_hdr; 71377c67f2fSkcpoon sctp_faddr_t *old_fp = NULL; 71477c67f2fSkcpoon sctp_faddr_t *chunk_fp; 715f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate for (meta = sctp->sctp_xmit_head; meta != NULL; meta = meta->b_next) { 7187c478bd9Sstevel@tonic-gate msg_hdr = (sctp_msg_hdr_t *)meta->b_rptr; 7197c478bd9Sstevel@tonic-gate if (SCTP_IS_MSG_ABANDONED(meta) || 7207c478bd9Sstevel@tonic-gate SCTP_MSG_TO_BE_ABANDONED(meta, msg_hdr, sctp)) { 7217c478bd9Sstevel@tonic-gate continue; 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate for (mp = meta->b_cont; mp != NULL; mp = mp->b_next) { 7247c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_WANT_REXMIT(mp)) { 7257c478bd9Sstevel@tonic-gate /* 7267c478bd9Sstevel@tonic-gate * Use the same peer address to do fast 72777c67f2fSkcpoon * retransmission. If the original peer 72877c67f2fSkcpoon * address is dead, switch to the current 72977c67f2fSkcpoon * one. Record the old one so that we 73077c67f2fSkcpoon * will pick the chunks sent to the old 73177c67f2fSkcpoon * one for fast retransmission. 7327c478bd9Sstevel@tonic-gate */ 73377c67f2fSkcpoon chunk_fp = SCTP_CHUNK_DEST(mp); 7347c478bd9Sstevel@tonic-gate if (*fp == NULL) { 73577c67f2fSkcpoon *fp = chunk_fp; 73677c67f2fSkcpoon if ((*fp)->state != SCTP_FADDRS_ALIVE) { 73777c67f2fSkcpoon old_fp = *fp; 7387c478bd9Sstevel@tonic-gate *fp = sctp->sctp_current; 73977c67f2fSkcpoon } 74077c67f2fSkcpoon } else if (old_fp == NULL && *fp != chunk_fp) { 74177c67f2fSkcpoon continue; 74277c67f2fSkcpoon } else if (old_fp != NULL && 74377c67f2fSkcpoon old_fp != chunk_fp) { 7447c478bd9Sstevel@tonic-gate continue; 7457c478bd9Sstevel@tonic-gate } 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate sdh = (sctp_data_hdr_t *)mp->b_rptr; 7487c478bd9Sstevel@tonic-gate msglen = ntohs(sdh->sdh_len); 7497c478bd9Sstevel@tonic-gate if ((extra = msglen & (SCTP_ALIGN - 1)) != 0) { 7507c478bd9Sstevel@tonic-gate extra = SCTP_ALIGN - extra; 7517c478bd9Sstevel@tonic-gate } 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate /* 7547c478bd9Sstevel@tonic-gate * We still return at least the first message 7557c478bd9Sstevel@tonic-gate * even if that message cannot fit in as 7567c478bd9Sstevel@tonic-gate * PMTU may have changed. 7577c478bd9Sstevel@tonic-gate */ 7587c478bd9Sstevel@tonic-gate if (*total + msglen + extra > 7597c478bd9Sstevel@tonic-gate (*fp)->sfa_pmss && start_mp != NULL) { 7607c478bd9Sstevel@tonic-gate return (start_mp); 7617c478bd9Sstevel@tonic-gate } 7627c478bd9Sstevel@tonic-gate if ((nmp = dupmsg(mp)) == NULL) 7637c478bd9Sstevel@tonic-gate return (start_mp); 7647c478bd9Sstevel@tonic-gate if (extra > 0) { 765121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 7667c478bd9Sstevel@tonic-gate if (fill != NULL) { 7677c478bd9Sstevel@tonic-gate linkb(nmp, fill); 7687c478bd9Sstevel@tonic-gate } else { 7697c478bd9Sstevel@tonic-gate return (start_mp); 7707c478bd9Sstevel@tonic-gate } 7717c478bd9Sstevel@tonic-gate } 772f4b3ec61Sdh BUMP_MIB(&sctps->sctps_mib, sctpOutFastRetrans); 77377c67f2fSkcpoon BUMP_LOCAL(sctp->sctp_rxtchunks); 7747c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_REXMIT(mp); 7757c478bd9Sstevel@tonic-gate if (start_mp == NULL) { 7767c478bd9Sstevel@tonic-gate start_mp = nmp; 7777c478bd9Sstevel@tonic-gate } else { 7787c478bd9Sstevel@tonic-gate linkb(end_mp, nmp); 7797c478bd9Sstevel@tonic-gate } 7807c478bd9Sstevel@tonic-gate end_mp = nmp; 7817c478bd9Sstevel@tonic-gate *total += msglen + extra; 7827c478bd9Sstevel@tonic-gate dprint(2, ("sctp_find_fast_rexmit_mblks: " 7837c478bd9Sstevel@tonic-gate "tsn %x\n", sdh->sdh_tsn)); 7847c478bd9Sstevel@tonic-gate } 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate } 7877c478bd9Sstevel@tonic-gate /* Clear the flag as there is no more message to be fast rexmitted. */ 7887c478bd9Sstevel@tonic-gate sctp->sctp_chk_fast_rexmit = B_FALSE; 7897c478bd9Sstevel@tonic-gate return (start_mp); 7907c478bd9Sstevel@tonic-gate } 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate /* A debug function just to make sure that a mblk chain is not broken */ 7937c478bd9Sstevel@tonic-gate #ifdef DEBUG 7947c478bd9Sstevel@tonic-gate static boolean_t 7957c478bd9Sstevel@tonic-gate sctp_verify_chain(mblk_t *head, mblk_t *tail) 7967c478bd9Sstevel@tonic-gate { 7977c478bd9Sstevel@tonic-gate mblk_t *mp = head; 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate if (head == NULL || tail == NULL) 8007c478bd9Sstevel@tonic-gate return (B_TRUE); 8017c478bd9Sstevel@tonic-gate while (mp != NULL) { 8027c478bd9Sstevel@tonic-gate if (mp == tail) 8037c478bd9Sstevel@tonic-gate return (B_TRUE); 8047c478bd9Sstevel@tonic-gate mp = mp->b_next; 8057c478bd9Sstevel@tonic-gate } 8067c478bd9Sstevel@tonic-gate return (B_FALSE); 8077c478bd9Sstevel@tonic-gate } 8087c478bd9Sstevel@tonic-gate #endif 8097c478bd9Sstevel@tonic-gate 8107c478bd9Sstevel@tonic-gate /* 8117c478bd9Sstevel@tonic-gate * Gets the next unsent chunk to transmit. Messages that are abandoned are 8127c478bd9Sstevel@tonic-gate * skipped. A message can be abandoned if it has a non-zero timetolive and 8137c478bd9Sstevel@tonic-gate * transmission has not yet started or if it is a partially reliable 8147c478bd9Sstevel@tonic-gate * message and its time is up (assuming we are PR-SCTP aware). 815*1e109b40SNick Street * We only return a chunk if it will fit entirely in the current packet. 8167c478bd9Sstevel@tonic-gate * 'cansend' is used to determine if need to try and chunkify messages from 8177c478bd9Sstevel@tonic-gate * the unsent list, if any, and also as an input to sctp_chunkify() if so. 8182dd25cf1SGeorge Shepherd * 819*1e109b40SNick Street * firstseg_len indicates the space already used, cansend represents remaining 820*1e109b40SNick Street * space in the window, ((sfa_pmss - firstseg_len) can therefore reasonably 8212dd25cf1SGeorge Shepherd * be used to compute the cansend arg). 8227c478bd9Sstevel@tonic-gate */ 8237c478bd9Sstevel@tonic-gate mblk_t * 8247c478bd9Sstevel@tonic-gate sctp_get_msg_to_send(sctp_t *sctp, mblk_t **mp, mblk_t *meta, int *error, 825*1e109b40SNick Street int32_t firstseg_len, uint32_t cansend, sctp_faddr_t *fp) 8267c478bd9Sstevel@tonic-gate { 8277c478bd9Sstevel@tonic-gate mblk_t *mp1; 8287c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *msg_hdr; 8297c478bd9Sstevel@tonic-gate mblk_t *tmp_meta; 8307c478bd9Sstevel@tonic-gate sctp_faddr_t *fp1; 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate ASSERT(error != NULL && mp != NULL); 8337c478bd9Sstevel@tonic-gate *error = 0; 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_current != NULL); 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate chunkified: 8387c478bd9Sstevel@tonic-gate while (meta != NULL) { 8397c478bd9Sstevel@tonic-gate tmp_meta = meta->b_next; 8407c478bd9Sstevel@tonic-gate msg_hdr = (sctp_msg_hdr_t *)meta->b_rptr; 8417c478bd9Sstevel@tonic-gate mp1 = meta->b_cont; 8427c478bd9Sstevel@tonic-gate if (SCTP_IS_MSG_ABANDONED(meta)) 8437c478bd9Sstevel@tonic-gate goto next_msg; 8447c478bd9Sstevel@tonic-gate if (!SCTP_MSG_TO_BE_ABANDONED(meta, msg_hdr, sctp)) { 8457c478bd9Sstevel@tonic-gate while (mp1 != NULL) { 8467c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_CANSEND(mp1)) { 8477c478bd9Sstevel@tonic-gate *mp = mp1; 8487c478bd9Sstevel@tonic-gate #ifdef DEBUG 8497c478bd9Sstevel@tonic-gate ASSERT(sctp_verify_chain( 8507c478bd9Sstevel@tonic-gate sctp->sctp_xmit_head, meta)); 8517c478bd9Sstevel@tonic-gate #endif 8527c478bd9Sstevel@tonic-gate return (meta); 8537c478bd9Sstevel@tonic-gate } 8547c478bd9Sstevel@tonic-gate mp1 = mp1->b_next; 8557c478bd9Sstevel@tonic-gate } 8567c478bd9Sstevel@tonic-gate goto next_msg; 8577c478bd9Sstevel@tonic-gate } 8587c478bd9Sstevel@tonic-gate /* 8597c478bd9Sstevel@tonic-gate * If we come here and the first chunk is sent, then we 8607c478bd9Sstevel@tonic-gate * we are PR-SCTP aware, in which case if the cumulative 8617c478bd9Sstevel@tonic-gate * TSN has moved upto or beyond the first chunk (which 8627c478bd9Sstevel@tonic-gate * means all the previous messages have been cumulative 8637c478bd9Sstevel@tonic-gate * SACK'd), then we send a Forward TSN with the last 8647c478bd9Sstevel@tonic-gate * chunk that was sent in this message. If we can't send 8657c478bd9Sstevel@tonic-gate * a Forward TSN because previous non-abandoned messages 8667c478bd9Sstevel@tonic-gate * have not been acked then we will defer the Forward TSN 8677c478bd9Sstevel@tonic-gate * to sctp_rexmit() or sctp_cumack(). 8687c478bd9Sstevel@tonic-gate */ 8697c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_ISSENT(mp1)) { 8707c478bd9Sstevel@tonic-gate *error = sctp_check_abandoned_msg(sctp, meta); 8717c478bd9Sstevel@tonic-gate if (*error != 0) { 8727c478bd9Sstevel@tonic-gate #ifdef DEBUG 8737c478bd9Sstevel@tonic-gate ASSERT(sctp_verify_chain(sctp->sctp_xmit_head, 8747c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail)); 8757c478bd9Sstevel@tonic-gate #endif 8767c478bd9Sstevel@tonic-gate return (NULL); 8777c478bd9Sstevel@tonic-gate } 8787c478bd9Sstevel@tonic-gate goto next_msg; 8797c478bd9Sstevel@tonic-gate } 8807c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_prsctpdrop); 8817c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_unsent >= msg_hdr->smh_msglen); 8827c478bd9Sstevel@tonic-gate if (meta->b_prev == NULL) { 8837c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_xmit_head == meta); 8847c478bd9Sstevel@tonic-gate sctp->sctp_xmit_head = tmp_meta; 8857c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_tail == meta) 8867c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail = tmp_meta; 8877c478bd9Sstevel@tonic-gate meta->b_next = NULL; 8887c478bd9Sstevel@tonic-gate if (tmp_meta != NULL) 8897c478bd9Sstevel@tonic-gate tmp_meta->b_prev = NULL; 8907c478bd9Sstevel@tonic-gate } else if (meta->b_next == NULL) { 8917c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_tail == meta) 8927c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail = meta->b_prev; 8937c478bd9Sstevel@tonic-gate meta->b_prev->b_next = NULL; 8947c478bd9Sstevel@tonic-gate meta->b_prev = NULL; 8957c478bd9Sstevel@tonic-gate } else { 8967c478bd9Sstevel@tonic-gate meta->b_prev->b_next = tmp_meta; 8977c478bd9Sstevel@tonic-gate tmp_meta->b_prev = meta->b_prev; 8987c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_tail == meta) 8997c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail = tmp_meta; 9007c478bd9Sstevel@tonic-gate meta->b_prev = NULL; 9017c478bd9Sstevel@tonic-gate meta->b_next = NULL; 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate sctp->sctp_unsent -= msg_hdr->smh_msglen; 9047c478bd9Sstevel@tonic-gate /* 9057c478bd9Sstevel@tonic-gate * Update ULP the amount of queued data, which is 9067c478bd9Sstevel@tonic-gate * sent-unack'ed + unsent. 9077c478bd9Sstevel@tonic-gate */ 9080f1702c5SYu Xiangning if (!SCTP_IS_DETACHED(sctp)) 9090f1702c5SYu Xiangning SCTP_TXQ_UPDATE(sctp); 9107c478bd9Sstevel@tonic-gate sctp_sendfail_event(sctp, meta, 0, B_TRUE); 9117c478bd9Sstevel@tonic-gate next_msg: 9127c478bd9Sstevel@tonic-gate meta = tmp_meta; 9137c478bd9Sstevel@tonic-gate } 9147c478bd9Sstevel@tonic-gate /* chunkify, if needed */ 9157c478bd9Sstevel@tonic-gate if (cansend > 0 && sctp->sctp_xmit_unsent != NULL) { 9167c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_unsent > 0); 9177c478bd9Sstevel@tonic-gate if (fp == NULL) { 9187c478bd9Sstevel@tonic-gate fp = SCTP_CHUNK_DEST(sctp->sctp_xmit_unsent); 9197c478bd9Sstevel@tonic-gate if (fp == NULL || fp->state != SCTP_FADDRS_ALIVE) 9207c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 9217c478bd9Sstevel@tonic-gate } else { 9227c478bd9Sstevel@tonic-gate /* 9237c478bd9Sstevel@tonic-gate * If user specified destination, try to honor that. 9247c478bd9Sstevel@tonic-gate */ 9257c478bd9Sstevel@tonic-gate fp1 = SCTP_CHUNK_DEST(sctp->sctp_xmit_unsent); 9267c478bd9Sstevel@tonic-gate if (fp1 != NULL && fp1->state == SCTP_FADDRS_ALIVE && 9277c478bd9Sstevel@tonic-gate fp1 != fp) { 9287c478bd9Sstevel@tonic-gate goto chunk_done; 9297c478bd9Sstevel@tonic-gate } 9307c478bd9Sstevel@tonic-gate } 931*1e109b40SNick Street meta = sctp_chunkify(sctp, fp->sfa_pmss, firstseg_len, cansend); 932*1e109b40SNick Street if (meta == NULL) 9337c478bd9Sstevel@tonic-gate goto chunk_done; 9347c478bd9Sstevel@tonic-gate /* 9357c478bd9Sstevel@tonic-gate * sctp_chunkify() won't advance sctp_xmit_tail if it adds 9367c478bd9Sstevel@tonic-gate * new chunk(s) to the tail, so we need to skip the 9377c478bd9Sstevel@tonic-gate * sctp_xmit_tail, which would have already been processed. 9387c478bd9Sstevel@tonic-gate * This could happen when there is unacked chunks, but 9397c478bd9Sstevel@tonic-gate * nothing new to send. 9407c478bd9Sstevel@tonic-gate * When sctp_chunkify() is called when the transmit queue 9417c478bd9Sstevel@tonic-gate * is empty then we need to start from sctp_xmit_tail. 9427c478bd9Sstevel@tonic-gate */ 9437c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_ISSENT(sctp->sctp_xmit_tail->b_cont)) { 9447c478bd9Sstevel@tonic-gate #ifdef DEBUG 9457c478bd9Sstevel@tonic-gate mp1 = sctp->sctp_xmit_tail->b_cont; 9467c478bd9Sstevel@tonic-gate while (mp1 != NULL) { 9477c478bd9Sstevel@tonic-gate ASSERT(!SCTP_CHUNK_CANSEND(mp1)); 9487c478bd9Sstevel@tonic-gate mp1 = mp1->b_next; 9497c478bd9Sstevel@tonic-gate } 9507c478bd9Sstevel@tonic-gate #endif 9517c478bd9Sstevel@tonic-gate if ((meta = sctp->sctp_xmit_tail->b_next) == NULL) 9527c478bd9Sstevel@tonic-gate goto chunk_done; 9537c478bd9Sstevel@tonic-gate } 9547c478bd9Sstevel@tonic-gate goto chunkified; 9557c478bd9Sstevel@tonic-gate } 9567c478bd9Sstevel@tonic-gate chunk_done: 9577c478bd9Sstevel@tonic-gate #ifdef DEBUG 9587c478bd9Sstevel@tonic-gate ASSERT(sctp_verify_chain(sctp->sctp_xmit_head, sctp->sctp_xmit_tail)); 9597c478bd9Sstevel@tonic-gate #endif 9607c478bd9Sstevel@tonic-gate return (NULL); 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate void 9647c478bd9Sstevel@tonic-gate sctp_fast_rexmit(sctp_t *sctp) 9657c478bd9Sstevel@tonic-gate { 9667c478bd9Sstevel@tonic-gate mblk_t *mp, *head; 9677c478bd9Sstevel@tonic-gate int pktlen = 0; 9687c478bd9Sstevel@tonic-gate sctp_faddr_t *fp = NULL; 969f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_xmit_head != NULL); 9727c478bd9Sstevel@tonic-gate mp = sctp_find_fast_rexmit_mblks(sctp, &pktlen, &fp); 97377c67f2fSkcpoon if (mp == NULL) { 974f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_fr_not_found); 9757c478bd9Sstevel@tonic-gate return; 97677c67f2fSkcpoon } 977df19b344Svi if ((head = sctp_add_proto_hdr(sctp, fp, mp, 0, NULL)) == NULL) { 9787c478bd9Sstevel@tonic-gate freemsg(mp); 979f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_fr_add_hdr); 9807c478bd9Sstevel@tonic-gate return; 9817c478bd9Sstevel@tonic-gate } 9827c478bd9Sstevel@tonic-gate if ((pktlen > fp->sfa_pmss) && fp->isv4) { 9837c478bd9Sstevel@tonic-gate ipha_t *iph = (ipha_t *)head->b_rptr; 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate iph->ipha_fragment_offset_and_flags = 0; 9867c478bd9Sstevel@tonic-gate } 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate sctp_set_iplen(sctp, head); 9897c478bd9Sstevel@tonic-gate sctp_add_sendq(sctp, head); 9907c478bd9Sstevel@tonic-gate sctp->sctp_active = fp->lastactive = lbolt64; 9917c478bd9Sstevel@tonic-gate } 9927c478bd9Sstevel@tonic-gate 9937c478bd9Sstevel@tonic-gate void 99412f47623Skcpoon sctp_output(sctp_t *sctp, uint_t num_pkt) 9957c478bd9Sstevel@tonic-gate { 9967c478bd9Sstevel@tonic-gate mblk_t *mp = NULL; 9977c478bd9Sstevel@tonic-gate mblk_t *nmp; 9987c478bd9Sstevel@tonic-gate mblk_t *head; 9997c478bd9Sstevel@tonic-gate mblk_t *meta = sctp->sctp_xmit_tail; 10007c478bd9Sstevel@tonic-gate mblk_t *fill = NULL; 10017c478bd9Sstevel@tonic-gate uint16_t chunklen; 10027c478bd9Sstevel@tonic-gate uint32_t cansend; 10037c478bd9Sstevel@tonic-gate int32_t seglen; 10047c478bd9Sstevel@tonic-gate int32_t xtralen; 10057c478bd9Sstevel@tonic-gate int32_t sacklen; 10067c478bd9Sstevel@tonic-gate int32_t pad = 0; 10077c478bd9Sstevel@tonic-gate int32_t pathmax; 10087c478bd9Sstevel@tonic-gate int extra; 10097c478bd9Sstevel@tonic-gate int64_t now = lbolt64; 10107c478bd9Sstevel@tonic-gate sctp_faddr_t *fp; 10117c478bd9Sstevel@tonic-gate sctp_faddr_t *lfp; 10127c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 10137c478bd9Sstevel@tonic-gate int error; 1014df19b344Svi boolean_t notsent = B_TRUE; 101512f47623Skcpoon sctp_stack_t *sctps = sctp->sctp_sctps; 10167c478bd9Sstevel@tonic-gate 10177c478bd9Sstevel@tonic-gate if (sctp->sctp_ftsn == sctp->sctp_lastacked + 1) { 10187c478bd9Sstevel@tonic-gate sacklen = 0; 10197c478bd9Sstevel@tonic-gate } else { 10207c478bd9Sstevel@tonic-gate /* send a SACK chunk */ 10217c478bd9Sstevel@tonic-gate sacklen = sizeof (sctp_chunk_hdr_t) + 10227c478bd9Sstevel@tonic-gate sizeof (sctp_sack_chunk_t) + 10237c478bd9Sstevel@tonic-gate (sizeof (sctp_sack_frag_t) * sctp->sctp_sack_gaps); 10247c478bd9Sstevel@tonic-gate lfp = sctp->sctp_lastdata; 10257c478bd9Sstevel@tonic-gate ASSERT(lfp != NULL); 10267c478bd9Sstevel@tonic-gate if (lfp->state != SCTP_FADDRS_ALIVE) 10277c478bd9Sstevel@tonic-gate lfp = sctp->sctp_current; 10287c478bd9Sstevel@tonic-gate } 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate cansend = sctp->sctp_frwnd; 10317c478bd9Sstevel@tonic-gate if (sctp->sctp_unsent < cansend) 10327c478bd9Sstevel@tonic-gate cansend = sctp->sctp_unsent; 1033518f8adfSGeorge Shepherd 1034518f8adfSGeorge Shepherd /* 1035518f8adfSGeorge Shepherd * Start persist timer if unable to send or when 1036518f8adfSGeorge Shepherd * trying to send into a zero window. This timer 1037518f8adfSGeorge Shepherd * ensures the blocked send attempt is retried. 1038518f8adfSGeorge Shepherd */ 10397c478bd9Sstevel@tonic-gate if ((cansend < sctp->sctp_current->sfa_pmss / 2) && 1040518f8adfSGeorge Shepherd (sctp->sctp_unacked != 0) && 10417c478bd9Sstevel@tonic-gate (sctp->sctp_unacked < sctp->sctp_current->sfa_pmss) && 1042518f8adfSGeorge Shepherd !sctp->sctp_ndelay || 1043518f8adfSGeorge Shepherd (cansend == 0 && sctp->sctp_unacked == 0 && 1044518f8adfSGeorge Shepherd sctp->sctp_unsent != 0)) { 10457c478bd9Sstevel@tonic-gate head = NULL; 10467c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 10477c478bd9Sstevel@tonic-gate goto unsent_data; 10487c478bd9Sstevel@tonic-gate } 10497c478bd9Sstevel@tonic-gate if (meta != NULL) 10507c478bd9Sstevel@tonic-gate mp = meta->b_cont; 105112f47623Skcpoon while (cansend > 0 && num_pkt-- != 0) { 10527c478bd9Sstevel@tonic-gate pad = 0; 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate /* 10557c478bd9Sstevel@tonic-gate * Find first segment eligible for transmit. 10567c478bd9Sstevel@tonic-gate */ 10577c478bd9Sstevel@tonic-gate while (mp != NULL) { 10587c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_CANSEND(mp)) 10597c478bd9Sstevel@tonic-gate break; 10607c478bd9Sstevel@tonic-gate mp = mp->b_next; 10617c478bd9Sstevel@tonic-gate } 10627c478bd9Sstevel@tonic-gate if (mp == NULL) { 10637c478bd9Sstevel@tonic-gate meta = sctp_get_msg_to_send(sctp, &mp, 10647c478bd9Sstevel@tonic-gate meta == NULL ? NULL : meta->b_next, &error, sacklen, 10657c478bd9Sstevel@tonic-gate cansend, NULL); 10667c478bd9Sstevel@tonic-gate if (error != 0 || meta == NULL) { 10677c478bd9Sstevel@tonic-gate head = NULL; 10687c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 10697c478bd9Sstevel@tonic-gate goto unsent_data; 10707c478bd9Sstevel@tonic-gate } 10717c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail = meta; 10727c478bd9Sstevel@tonic-gate } 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 10757c478bd9Sstevel@tonic-gate seglen = ntohs(sdc->sdh_len); 10767c478bd9Sstevel@tonic-gate xtralen = sizeof (*sdc); 10777c478bd9Sstevel@tonic-gate chunklen = seglen - xtralen; 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate /* 10807c478bd9Sstevel@tonic-gate * Check rwnd. 10817c478bd9Sstevel@tonic-gate */ 10827c478bd9Sstevel@tonic-gate if (chunklen > cansend) { 10837c478bd9Sstevel@tonic-gate head = NULL; 10847c478bd9Sstevel@tonic-gate fp = SCTP_CHUNK_DEST(meta); 10857c478bd9Sstevel@tonic-gate if (fp == NULL || fp->state != SCTP_FADDRS_ALIVE) 10867c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 10877c478bd9Sstevel@tonic-gate goto unsent_data; 10887c478bd9Sstevel@tonic-gate } 10897c478bd9Sstevel@tonic-gate if ((extra = seglen & (SCTP_ALIGN - 1)) != 0) 10907c478bd9Sstevel@tonic-gate extra = SCTP_ALIGN - extra; 10917c478bd9Sstevel@tonic-gate 10927c478bd9Sstevel@tonic-gate /* 10937c478bd9Sstevel@tonic-gate * Pick destination address, and check cwnd. 10947c478bd9Sstevel@tonic-gate */ 10957c478bd9Sstevel@tonic-gate if (sacklen > 0 && (seglen + extra <= lfp->cwnd - lfp->suna) && 10967c478bd9Sstevel@tonic-gate (seglen + sacklen + extra <= lfp->sfa_pmss)) { 10977c478bd9Sstevel@tonic-gate /* 10987c478bd9Sstevel@tonic-gate * Only include SACK chunk if it can be bundled 10997c478bd9Sstevel@tonic-gate * with a data chunk, and sent to sctp_lastdata. 11007c478bd9Sstevel@tonic-gate */ 11017c478bd9Sstevel@tonic-gate pathmax = lfp->cwnd - lfp->suna; 11027c478bd9Sstevel@tonic-gate 11037c478bd9Sstevel@tonic-gate fp = lfp; 11047c478bd9Sstevel@tonic-gate if ((nmp = dupmsg(mp)) == NULL) { 11057c478bd9Sstevel@tonic-gate head = NULL; 11067c478bd9Sstevel@tonic-gate goto unsent_data; 11077c478bd9Sstevel@tonic-gate } 11087c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_FLAGS(nmp); 1109df19b344Svi head = sctp_add_proto_hdr(sctp, fp, nmp, sacklen, 1110df19b344Svi &error); 11117c478bd9Sstevel@tonic-gate if (head == NULL) { 1112df19b344Svi /* 1113df19b344Svi * If none of the source addresses are 1114df19b344Svi * available (i.e error == EHOSTUNREACH), 1115df19b344Svi * pretend we have sent the data. We will 1116df19b344Svi * eventually time out trying to retramsmit 1117df19b344Svi * the data if the interface never comes up. 1118df19b344Svi * If we have already sent some stuff (i.e., 1119df19b344Svi * notsent is B_FALSE) then we are fine, else 1120df19b344Svi * just mark this packet as sent. 1121df19b344Svi */ 1122df19b344Svi if (notsent && error == EHOSTUNREACH) { 1123df19b344Svi SCTP_CHUNK_SENT(sctp, mp, sdc, 1124df19b344Svi fp, chunklen, meta); 1125df19b344Svi } 11267c478bd9Sstevel@tonic-gate freemsg(nmp); 1127f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_output_failed); 11287c478bd9Sstevel@tonic-gate goto unsent_data; 11297c478bd9Sstevel@tonic-gate } 11307c478bd9Sstevel@tonic-gate seglen += sacklen; 11317c478bd9Sstevel@tonic-gate xtralen += sacklen; 11327c478bd9Sstevel@tonic-gate sacklen = 0; 11337c478bd9Sstevel@tonic-gate } else { 11347c478bd9Sstevel@tonic-gate fp = SCTP_CHUNK_DEST(meta); 11357c478bd9Sstevel@tonic-gate if (fp == NULL || fp->state != SCTP_FADDRS_ALIVE) 11367c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 11377c478bd9Sstevel@tonic-gate /* 11387c478bd9Sstevel@tonic-gate * If we haven't sent data to this destination for 11397c478bd9Sstevel@tonic-gate * a while, do slow start again. 11407c478bd9Sstevel@tonic-gate */ 11417c478bd9Sstevel@tonic-gate if (now - fp->lastactive > fp->rto) { 114212f47623Skcpoon SET_CWND(fp, fp->sfa_pmss, 114312f47623Skcpoon sctps->sctps_slow_start_after_idle); 11447c478bd9Sstevel@tonic-gate } 11457c478bd9Sstevel@tonic-gate 11467c478bd9Sstevel@tonic-gate pathmax = fp->cwnd - fp->suna; 11477c478bd9Sstevel@tonic-gate if (seglen + extra > pathmax) { 11487c478bd9Sstevel@tonic-gate head = NULL; 11497c478bd9Sstevel@tonic-gate goto unsent_data; 11507c478bd9Sstevel@tonic-gate } 11517c478bd9Sstevel@tonic-gate if ((nmp = dupmsg(mp)) == NULL) { 11527c478bd9Sstevel@tonic-gate head = NULL; 11537c478bd9Sstevel@tonic-gate goto unsent_data; 11547c478bd9Sstevel@tonic-gate } 11557c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_FLAGS(nmp); 1156df19b344Svi head = sctp_add_proto_hdr(sctp, fp, nmp, 0, &error); 11577c478bd9Sstevel@tonic-gate if (head == NULL) { 1158df19b344Svi /* 1159df19b344Svi * If none of the source addresses are 1160df19b344Svi * available (i.e error == EHOSTUNREACH), 1161df19b344Svi * pretend we have sent the data. We will 1162df19b344Svi * eventually time out trying to retramsmit 1163df19b344Svi * the data if the interface never comes up. 1164df19b344Svi * If we have already sent some stuff (i.e., 1165df19b344Svi * notsent is B_FALSE) then we are fine, else 1166df19b344Svi * just mark this packet as sent. 1167df19b344Svi */ 1168df19b344Svi if (notsent && error == EHOSTUNREACH) { 1169df19b344Svi SCTP_CHUNK_SENT(sctp, mp, sdc, 1170df19b344Svi fp, chunklen, meta); 1171df19b344Svi } 11727c478bd9Sstevel@tonic-gate freemsg(nmp); 1173f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_output_failed); 11747c478bd9Sstevel@tonic-gate goto unsent_data; 11757c478bd9Sstevel@tonic-gate } 11767c478bd9Sstevel@tonic-gate } 117777c67f2fSkcpoon fp->lastactive = now; 11787c478bd9Sstevel@tonic-gate if (pathmax > fp->sfa_pmss) 11797c478bd9Sstevel@tonic-gate pathmax = fp->sfa_pmss; 11807c478bd9Sstevel@tonic-gate SCTP_CHUNK_SENT(sctp, mp, sdc, fp, chunklen, meta); 11817c478bd9Sstevel@tonic-gate mp = mp->b_next; 11827c478bd9Sstevel@tonic-gate 11837c478bd9Sstevel@tonic-gate /* Use this chunk to measure RTT? */ 11847c478bd9Sstevel@tonic-gate if (sctp->sctp_out_time == 0) { 11857c478bd9Sstevel@tonic-gate sctp->sctp_out_time = now; 11867c478bd9Sstevel@tonic-gate sctp->sctp_rtt_tsn = sctp->sctp_ltsn - 1; 118777c67f2fSkcpoon ASSERT(sctp->sctp_rtt_tsn == ntohl(sdc->sdh_tsn)); 11887c478bd9Sstevel@tonic-gate } 11897c478bd9Sstevel@tonic-gate if (extra > 0) { 1190121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 11917c478bd9Sstevel@tonic-gate if (fill != NULL) { 11927c478bd9Sstevel@tonic-gate linkb(head, fill); 11937c478bd9Sstevel@tonic-gate pad = extra; 11947c478bd9Sstevel@tonic-gate seglen += extra; 11957c478bd9Sstevel@tonic-gate } else { 11967c478bd9Sstevel@tonic-gate goto unsent_data; 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate } 1199*1e109b40SNick Street /* 1200*1e109b40SNick Street * Bundle chunks. We linkb() the chunks together to send 1201*1e109b40SNick Street * downstream in a single packet. 1202*1e109b40SNick Street * Partial chunks MUST NOT be bundled with full chunks, so we 1203*1e109b40SNick Street * rely on sctp_get_msg_to_send() to only return messages that 1204*1e109b40SNick Street * will fit entirely in the current packet. 1205*1e109b40SNick Street */ 12067c478bd9Sstevel@tonic-gate while (seglen < pathmax) { 12077c478bd9Sstevel@tonic-gate int32_t new_len; 12087c478bd9Sstevel@tonic-gate int32_t new_xtralen; 12097c478bd9Sstevel@tonic-gate 12107c478bd9Sstevel@tonic-gate while (mp != NULL) { 12117c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_CANSEND(mp)) 12127c478bd9Sstevel@tonic-gate break; 12137c478bd9Sstevel@tonic-gate mp = mp->b_next; 12147c478bd9Sstevel@tonic-gate } 12157c478bd9Sstevel@tonic-gate if (mp == NULL) { 12167c478bd9Sstevel@tonic-gate meta = sctp_get_msg_to_send(sctp, &mp, 12177c478bd9Sstevel@tonic-gate meta->b_next, &error, seglen, 12187c478bd9Sstevel@tonic-gate (seglen - xtralen) >= cansend ? 0 : 12197c478bd9Sstevel@tonic-gate cansend - seglen, fp); 1220*1e109b40SNick Street if (error != 0) 1221*1e109b40SNick Street break; 1222*1e109b40SNick Street /* If no more eligible chunks, cease bundling */ 1223*1e109b40SNick Street if (meta == NULL) 12247c478bd9Sstevel@tonic-gate break; 12257c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail = meta; 12267c478bd9Sstevel@tonic-gate } 12277c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 12287c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp) && SCTP_CHUNK_DEST(meta) && 12297c478bd9Sstevel@tonic-gate fp != SCTP_CHUNK_DEST(meta)) { 12307c478bd9Sstevel@tonic-gate break; 12317c478bd9Sstevel@tonic-gate } 12327c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 12337c478bd9Sstevel@tonic-gate chunklen = ntohs(sdc->sdh_len); 12347c478bd9Sstevel@tonic-gate if ((extra = chunklen & (SCTP_ALIGN - 1)) != 0) 12357c478bd9Sstevel@tonic-gate extra = SCTP_ALIGN - extra; 12367c478bd9Sstevel@tonic-gate 12377c478bd9Sstevel@tonic-gate new_len = seglen + chunklen; 12387c478bd9Sstevel@tonic-gate new_xtralen = xtralen + sizeof (*sdc); 12397c478bd9Sstevel@tonic-gate chunklen -= sizeof (*sdc); 12407c478bd9Sstevel@tonic-gate 12417c478bd9Sstevel@tonic-gate if (new_len - new_xtralen > cansend || 12427c478bd9Sstevel@tonic-gate new_len + extra > pathmax) { 12437c478bd9Sstevel@tonic-gate break; 12447c478bd9Sstevel@tonic-gate } 12457c478bd9Sstevel@tonic-gate if ((nmp = dupmsg(mp)) == NULL) 12467c478bd9Sstevel@tonic-gate break; 12477c478bd9Sstevel@tonic-gate if (extra > 0) { 1248121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 12497c478bd9Sstevel@tonic-gate if (fill != NULL) { 12507c478bd9Sstevel@tonic-gate pad += extra; 12517c478bd9Sstevel@tonic-gate new_len += extra; 12527c478bd9Sstevel@tonic-gate linkb(nmp, fill); 12537c478bd9Sstevel@tonic-gate } else { 12547c478bd9Sstevel@tonic-gate freemsg(nmp); 12557c478bd9Sstevel@tonic-gate break; 12567c478bd9Sstevel@tonic-gate } 12577c478bd9Sstevel@tonic-gate } 12587c478bd9Sstevel@tonic-gate seglen = new_len; 12597c478bd9Sstevel@tonic-gate xtralen = new_xtralen; 12607c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_FLAGS(nmp); 12617c478bd9Sstevel@tonic-gate SCTP_CHUNK_SENT(sctp, mp, sdc, fp, chunklen, meta); 12627c478bd9Sstevel@tonic-gate linkb(head, nmp); 12637c478bd9Sstevel@tonic-gate mp = mp->b_next; 12647c478bd9Sstevel@tonic-gate } 12657c478bd9Sstevel@tonic-gate if ((seglen > fp->sfa_pmss) && fp->isv4) { 12667c478bd9Sstevel@tonic-gate ipha_t *iph = (ipha_t *)head->b_rptr; 12677c478bd9Sstevel@tonic-gate 12687c478bd9Sstevel@tonic-gate /* 12697c478bd9Sstevel@tonic-gate * Path MTU is different from what we thought it would 12707c478bd9Sstevel@tonic-gate * be when we created chunks, or IP headers have grown. 12717c478bd9Sstevel@tonic-gate * Need to clear the DF bit. 12727c478bd9Sstevel@tonic-gate */ 12737c478bd9Sstevel@tonic-gate iph->ipha_fragment_offset_and_flags = 0; 12747c478bd9Sstevel@tonic-gate } 12757c478bd9Sstevel@tonic-gate /* xmit segment */ 12767c478bd9Sstevel@tonic-gate ASSERT(cansend >= seglen - pad - xtralen); 12777c478bd9Sstevel@tonic-gate cansend -= (seglen - pad - xtralen); 12787c478bd9Sstevel@tonic-gate dprint(2, ("sctp_output: Sending packet %d bytes, tsn %x " 127945916cd2Sjpk "ssn %d to %p (rwnd %d, cansend %d, lastack_rxd %x)\n", 128045916cd2Sjpk seglen - xtralen, ntohl(sdc->sdh_tsn), 128145916cd2Sjpk ntohs(sdc->sdh_ssn), (void *)fp, sctp->sctp_frwnd, 128245916cd2Sjpk cansend, sctp->sctp_lastack_rxd)); 12837c478bd9Sstevel@tonic-gate sctp_set_iplen(sctp, head); 12847c478bd9Sstevel@tonic-gate sctp_add_sendq(sctp, head); 12857c478bd9Sstevel@tonic-gate /* arm rto timer (if not set) */ 12867c478bd9Sstevel@tonic-gate if (!fp->timer_running) 12877c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->rto); 1288df19b344Svi notsent = B_FALSE; 12897c478bd9Sstevel@tonic-gate } 12907c478bd9Sstevel@tonic-gate sctp->sctp_active = now; 12917c478bd9Sstevel@tonic-gate return; 12927c478bd9Sstevel@tonic-gate unsent_data: 12937c478bd9Sstevel@tonic-gate /* arm persist timer (if rto timer not set) */ 12947c478bd9Sstevel@tonic-gate if (!fp->timer_running) 12957c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->rto); 12967c478bd9Sstevel@tonic-gate if (head != NULL) 12977c478bd9Sstevel@tonic-gate freemsg(head); 12987c478bd9Sstevel@tonic-gate } 12997c478bd9Sstevel@tonic-gate 13007c478bd9Sstevel@tonic-gate /* 13017c478bd9Sstevel@tonic-gate * The following two functions initialize and destroy the cache 13027c478bd9Sstevel@tonic-gate * associated with the sets used for PR-SCTP. 13037c478bd9Sstevel@tonic-gate */ 13047c478bd9Sstevel@tonic-gate void 13057c478bd9Sstevel@tonic-gate sctp_ftsn_sets_init(void) 13067c478bd9Sstevel@tonic-gate { 13077c478bd9Sstevel@tonic-gate sctp_kmem_ftsn_set_cache = kmem_cache_create("sctp_ftsn_set_cache", 13087c478bd9Sstevel@tonic-gate sizeof (sctp_ftsn_set_t), 0, NULL, NULL, NULL, NULL, 13097c478bd9Sstevel@tonic-gate NULL, 0); 13107c478bd9Sstevel@tonic-gate } 13117c478bd9Sstevel@tonic-gate 13127c478bd9Sstevel@tonic-gate void 13137c478bd9Sstevel@tonic-gate sctp_ftsn_sets_fini(void) 13147c478bd9Sstevel@tonic-gate { 13157c478bd9Sstevel@tonic-gate kmem_cache_destroy(sctp_kmem_ftsn_set_cache); 13167c478bd9Sstevel@tonic-gate } 13177c478bd9Sstevel@tonic-gate 13187c478bd9Sstevel@tonic-gate 13197c478bd9Sstevel@tonic-gate /* Free PR-SCTP sets */ 13207c478bd9Sstevel@tonic-gate void 13217c478bd9Sstevel@tonic-gate sctp_free_ftsn_set(sctp_ftsn_set_t *s) 13227c478bd9Sstevel@tonic-gate { 13237c478bd9Sstevel@tonic-gate sctp_ftsn_set_t *p; 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate while (s != NULL) { 13267c478bd9Sstevel@tonic-gate p = s->next; 13277c478bd9Sstevel@tonic-gate s->next = NULL; 13287c478bd9Sstevel@tonic-gate kmem_cache_free(sctp_kmem_ftsn_set_cache, s); 13297c478bd9Sstevel@tonic-gate s = p; 13307c478bd9Sstevel@tonic-gate } 13317c478bd9Sstevel@tonic-gate } 13327c478bd9Sstevel@tonic-gate 13337c478bd9Sstevel@tonic-gate /* 13347c478bd9Sstevel@tonic-gate * Given a message meta block, meta, this routine creates or modifies 13357c478bd9Sstevel@tonic-gate * the set that will be used to generate a Forward TSN chunk. If the 13367c478bd9Sstevel@tonic-gate * entry for stream id, sid, for this message already exists, the 13377c478bd9Sstevel@tonic-gate * sequence number, ssn, is updated if it is greater than the existing 13387c478bd9Sstevel@tonic-gate * one. If an entry for this sid does not exist, one is created if 13397c478bd9Sstevel@tonic-gate * the size does not exceed fp->sfa_pmss. We return false in case 13407c478bd9Sstevel@tonic-gate * or an error. 13417c478bd9Sstevel@tonic-gate */ 13427c478bd9Sstevel@tonic-gate boolean_t 13437c478bd9Sstevel@tonic-gate sctp_add_ftsn_set(sctp_ftsn_set_t **s, sctp_faddr_t *fp, mblk_t *meta, 13447c478bd9Sstevel@tonic-gate uint_t *nsets, uint32_t *slen) 13457c478bd9Sstevel@tonic-gate { 13467c478bd9Sstevel@tonic-gate sctp_ftsn_set_t *p; 13477c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *msg_hdr = (sctp_msg_hdr_t *)meta->b_rptr; 13487c478bd9Sstevel@tonic-gate uint16_t sid = htons(msg_hdr->smh_sid); 13497c478bd9Sstevel@tonic-gate /* msg_hdr->smh_ssn is already in NBO */ 13507c478bd9Sstevel@tonic-gate uint16_t ssn = msg_hdr->smh_ssn; 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate ASSERT(s != NULL && nsets != NULL); 13537c478bd9Sstevel@tonic-gate ASSERT((*nsets == 0 && *s == NULL) || (*nsets > 0 && *s != NULL)); 13547c478bd9Sstevel@tonic-gate 13557c478bd9Sstevel@tonic-gate if (*s == NULL) { 13567c478bd9Sstevel@tonic-gate ASSERT((*slen + sizeof (uint32_t)) <= fp->sfa_pmss); 13577c478bd9Sstevel@tonic-gate *s = kmem_cache_alloc(sctp_kmem_ftsn_set_cache, KM_NOSLEEP); 13587c478bd9Sstevel@tonic-gate if (*s == NULL) 13597c478bd9Sstevel@tonic-gate return (B_FALSE); 13607c478bd9Sstevel@tonic-gate (*s)->ftsn_entries.ftsn_sid = sid; 13617c478bd9Sstevel@tonic-gate (*s)->ftsn_entries.ftsn_ssn = ssn; 13627c478bd9Sstevel@tonic-gate (*s)->next = NULL; 13637c478bd9Sstevel@tonic-gate *nsets = 1; 13647c478bd9Sstevel@tonic-gate *slen += sizeof (uint32_t); 13657c478bd9Sstevel@tonic-gate return (B_TRUE); 13667c478bd9Sstevel@tonic-gate } 13677c478bd9Sstevel@tonic-gate for (p = *s; p->next != NULL; p = p->next) { 13687c478bd9Sstevel@tonic-gate if (p->ftsn_entries.ftsn_sid == sid) { 13697c478bd9Sstevel@tonic-gate if (SSN_GT(ssn, p->ftsn_entries.ftsn_ssn)) 13707c478bd9Sstevel@tonic-gate p->ftsn_entries.ftsn_ssn = ssn; 13717c478bd9Sstevel@tonic-gate return (B_TRUE); 13727c478bd9Sstevel@tonic-gate } 13737c478bd9Sstevel@tonic-gate } 13747c478bd9Sstevel@tonic-gate /* the last one */ 13757c478bd9Sstevel@tonic-gate if (p->ftsn_entries.ftsn_sid == sid) { 13767c478bd9Sstevel@tonic-gate if (SSN_GT(ssn, p->ftsn_entries.ftsn_ssn)) 13777c478bd9Sstevel@tonic-gate p->ftsn_entries.ftsn_ssn = ssn; 13787c478bd9Sstevel@tonic-gate } else { 13797c478bd9Sstevel@tonic-gate if ((*slen + sizeof (uint32_t)) > fp->sfa_pmss) 13807c478bd9Sstevel@tonic-gate return (B_FALSE); 13817c478bd9Sstevel@tonic-gate p->next = kmem_cache_alloc(sctp_kmem_ftsn_set_cache, 13827c478bd9Sstevel@tonic-gate KM_NOSLEEP); 13837c478bd9Sstevel@tonic-gate if (p->next == NULL) 13847c478bd9Sstevel@tonic-gate return (B_FALSE); 13857c478bd9Sstevel@tonic-gate p = p->next; 13867c478bd9Sstevel@tonic-gate p->ftsn_entries.ftsn_sid = sid; 13877c478bd9Sstevel@tonic-gate p->ftsn_entries.ftsn_ssn = ssn; 13887c478bd9Sstevel@tonic-gate p->next = NULL; 13897c478bd9Sstevel@tonic-gate (*nsets)++; 13907c478bd9Sstevel@tonic-gate *slen += sizeof (uint32_t); 13917c478bd9Sstevel@tonic-gate } 13927c478bd9Sstevel@tonic-gate return (B_TRUE); 13937c478bd9Sstevel@tonic-gate } 13947c478bd9Sstevel@tonic-gate 13957c478bd9Sstevel@tonic-gate /* 13967c478bd9Sstevel@tonic-gate * Given a set of stream id - sequence number pairs, this routing creates 13977c478bd9Sstevel@tonic-gate * a Forward TSN chunk. The cumulative TSN (advanced peer ack point) 13987c478bd9Sstevel@tonic-gate * for the chunk is obtained from sctp->sctp_adv_pap. The caller 13997c478bd9Sstevel@tonic-gate * will add the IP/SCTP header. 14007c478bd9Sstevel@tonic-gate */ 14017c478bd9Sstevel@tonic-gate mblk_t * 14027c478bd9Sstevel@tonic-gate sctp_make_ftsn_chunk(sctp_t *sctp, sctp_faddr_t *fp, sctp_ftsn_set_t *sets, 14037c478bd9Sstevel@tonic-gate uint_t nsets, uint32_t seglen) 14047c478bd9Sstevel@tonic-gate { 14057c478bd9Sstevel@tonic-gate mblk_t *ftsn_mp; 14067c478bd9Sstevel@tonic-gate sctp_chunk_hdr_t *ch_hdr; 14077c478bd9Sstevel@tonic-gate uint32_t *advtsn; 14087c478bd9Sstevel@tonic-gate uint16_t schlen; 14097c478bd9Sstevel@tonic-gate size_t xtralen; 14107c478bd9Sstevel@tonic-gate ftsn_entry_t *ftsn_entry; 1411f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate seglen += sizeof (sctp_chunk_hdr_t); 14147c478bd9Sstevel@tonic-gate if (fp->isv4) 1415f4b3ec61Sdh xtralen = sctp->sctp_hdr_len + sctps->sctps_wroff_xtra; 14167c478bd9Sstevel@tonic-gate else 1417f4b3ec61Sdh xtralen = sctp->sctp_hdr6_len + sctps->sctps_wroff_xtra; 1418de8c4a14SErik Nordmark ftsn_mp = allocb_cred(xtralen + seglen, CONN_CRED(sctp->sctp_connp), 1419de8c4a14SErik Nordmark sctp->sctp_cpid); 14207c478bd9Sstevel@tonic-gate if (ftsn_mp == NULL) 14217c478bd9Sstevel@tonic-gate return (NULL); 14227c478bd9Sstevel@tonic-gate ftsn_mp->b_rptr += xtralen; 14237c478bd9Sstevel@tonic-gate ftsn_mp->b_wptr = ftsn_mp->b_rptr + seglen; 14247c478bd9Sstevel@tonic-gate 14257c478bd9Sstevel@tonic-gate ch_hdr = (sctp_chunk_hdr_t *)ftsn_mp->b_rptr; 14267c478bd9Sstevel@tonic-gate ch_hdr->sch_id = CHUNK_FORWARD_TSN; 14277c478bd9Sstevel@tonic-gate ch_hdr->sch_flags = 0; 14287c478bd9Sstevel@tonic-gate /* 14297c478bd9Sstevel@tonic-gate * The cast here should not be an issue since seglen is 14307c478bd9Sstevel@tonic-gate * the length of the Forward TSN chunk. 14317c478bd9Sstevel@tonic-gate */ 14327c478bd9Sstevel@tonic-gate schlen = (uint16_t)seglen; 14337c478bd9Sstevel@tonic-gate U16_TO_ABE16(schlen, &(ch_hdr->sch_len)); 14347c478bd9Sstevel@tonic-gate 14357c478bd9Sstevel@tonic-gate advtsn = (uint32_t *)(ch_hdr + 1); 14367c478bd9Sstevel@tonic-gate U32_TO_ABE32(sctp->sctp_adv_pap, advtsn); 14377c478bd9Sstevel@tonic-gate ftsn_entry = (ftsn_entry_t *)(advtsn + 1); 14387c478bd9Sstevel@tonic-gate while (nsets > 0) { 14397c478bd9Sstevel@tonic-gate ASSERT((uchar_t *)&ftsn_entry[1] <= ftsn_mp->b_wptr); 14407c478bd9Sstevel@tonic-gate ftsn_entry->ftsn_sid = sets->ftsn_entries.ftsn_sid; 14417c478bd9Sstevel@tonic-gate ftsn_entry->ftsn_ssn = sets->ftsn_entries.ftsn_ssn; 14427c478bd9Sstevel@tonic-gate ftsn_entry++; 14437c478bd9Sstevel@tonic-gate sets = sets->next; 14447c478bd9Sstevel@tonic-gate nsets--; 14457c478bd9Sstevel@tonic-gate } 14467c478bd9Sstevel@tonic-gate return (ftsn_mp); 14477c478bd9Sstevel@tonic-gate } 14487c478bd9Sstevel@tonic-gate 14497c478bd9Sstevel@tonic-gate /* 14507c478bd9Sstevel@tonic-gate * Given a starting message, the routine steps through all the 14517c478bd9Sstevel@tonic-gate * messages whose TSN is less than sctp->sctp_adv_pap and creates 14527c478bd9Sstevel@tonic-gate * ftsn sets. The ftsn sets is then used to create an Forward TSN 14537c478bd9Sstevel@tonic-gate * chunk. All the messages, that have chunks that are included in the 14547c478bd9Sstevel@tonic-gate * ftsn sets, are flagged abandonded. If a message is partially sent 14557c478bd9Sstevel@tonic-gate * and is deemed abandoned, all remaining unsent chunks are marked 14567c478bd9Sstevel@tonic-gate * abandoned and are deducted from sctp_unsent. 14577c478bd9Sstevel@tonic-gate */ 14587c478bd9Sstevel@tonic-gate void 14597c478bd9Sstevel@tonic-gate sctp_make_ftsns(sctp_t *sctp, mblk_t *meta, mblk_t *mp, mblk_t **nmp, 14607c478bd9Sstevel@tonic-gate sctp_faddr_t *fp, uint32_t *seglen) 14617c478bd9Sstevel@tonic-gate { 14627c478bd9Sstevel@tonic-gate mblk_t *mp1 = mp; 14637c478bd9Sstevel@tonic-gate mblk_t *mp_head = mp; 14647c478bd9Sstevel@tonic-gate mblk_t *meta_head = meta; 14657c478bd9Sstevel@tonic-gate mblk_t *head; 14667c478bd9Sstevel@tonic-gate sctp_ftsn_set_t *sets = NULL; 14677c478bd9Sstevel@tonic-gate uint_t nsets = 0; 14687c478bd9Sstevel@tonic-gate uint16_t clen; 14697c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 14707c478bd9Sstevel@tonic-gate uint32_t sacklen; 14717c478bd9Sstevel@tonic-gate uint32_t adv_pap = sctp->sctp_adv_pap; 14727c478bd9Sstevel@tonic-gate uint32_t unsent = 0; 14737c478bd9Sstevel@tonic-gate boolean_t ubit; 1474f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 14757c478bd9Sstevel@tonic-gate 14767c478bd9Sstevel@tonic-gate *seglen = sizeof (uint32_t); 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 14797c478bd9Sstevel@tonic-gate while (meta != NULL && 14807c478bd9Sstevel@tonic-gate SEQ_GEQ(sctp->sctp_adv_pap, ntohl(sdc->sdh_tsn))) { 14817c478bd9Sstevel@tonic-gate /* 14827c478bd9Sstevel@tonic-gate * Skip adding FTSN sets for un-ordered messages as they do 14837c478bd9Sstevel@tonic-gate * not have SSNs. 14847c478bd9Sstevel@tonic-gate */ 14857c478bd9Sstevel@tonic-gate ubit = SCTP_DATA_GET_UBIT(sdc); 14867c478bd9Sstevel@tonic-gate if (!ubit && 14877c478bd9Sstevel@tonic-gate !sctp_add_ftsn_set(&sets, fp, meta, &nsets, seglen)) { 14887c478bd9Sstevel@tonic-gate meta = NULL; 14897c478bd9Sstevel@tonic-gate sctp->sctp_adv_pap = adv_pap; 14907c478bd9Sstevel@tonic-gate goto ftsn_done; 14917c478bd9Sstevel@tonic-gate } 14927c478bd9Sstevel@tonic-gate while (mp1 != NULL && SCTP_CHUNK_ISSENT(mp1)) { 14937c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 14947c478bd9Sstevel@tonic-gate adv_pap = ntohl(sdc->sdh_tsn); 14957c478bd9Sstevel@tonic-gate mp1 = mp1->b_next; 14967c478bd9Sstevel@tonic-gate } 14977c478bd9Sstevel@tonic-gate meta = meta->b_next; 14987c478bd9Sstevel@tonic-gate if (meta != NULL) { 14997c478bd9Sstevel@tonic-gate mp1 = meta->b_cont; 15007c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp1)) 15017c478bd9Sstevel@tonic-gate break; 15027c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 15037c478bd9Sstevel@tonic-gate } 15047c478bd9Sstevel@tonic-gate } 15057c478bd9Sstevel@tonic-gate ftsn_done: 15067c478bd9Sstevel@tonic-gate /* 15077c478bd9Sstevel@tonic-gate * Can't compare with sets == NULL, since we don't add any 15087c478bd9Sstevel@tonic-gate * sets for un-ordered messages. 15097c478bd9Sstevel@tonic-gate */ 15107c478bd9Sstevel@tonic-gate if (meta == meta_head) 15117c478bd9Sstevel@tonic-gate return; 15127c478bd9Sstevel@tonic-gate *nmp = sctp_make_ftsn_chunk(sctp, fp, sets, nsets, *seglen); 15137c478bd9Sstevel@tonic-gate sctp_free_ftsn_set(sets); 15147c478bd9Sstevel@tonic-gate if (*nmp == NULL) 15157c478bd9Sstevel@tonic-gate return; 15167c478bd9Sstevel@tonic-gate if (sctp->sctp_ftsn == sctp->sctp_lastacked + 1) { 15177c478bd9Sstevel@tonic-gate sacklen = 0; 15187c478bd9Sstevel@tonic-gate } else { 15197c478bd9Sstevel@tonic-gate sacklen = sizeof (sctp_chunk_hdr_t) + 15207c478bd9Sstevel@tonic-gate sizeof (sctp_sack_chunk_t) + 15217c478bd9Sstevel@tonic-gate (sizeof (sctp_sack_frag_t) * sctp->sctp_sack_gaps); 15227c478bd9Sstevel@tonic-gate if (*seglen + sacklen > sctp->sctp_lastdata->sfa_pmss) { 15237c478bd9Sstevel@tonic-gate /* piggybacked SACK doesn't fit */ 15247c478bd9Sstevel@tonic-gate sacklen = 0; 15257c478bd9Sstevel@tonic-gate } else { 15267c478bd9Sstevel@tonic-gate fp = sctp->sctp_lastdata; 15277c478bd9Sstevel@tonic-gate } 15287c478bd9Sstevel@tonic-gate } 1529df19b344Svi head = sctp_add_proto_hdr(sctp, fp, *nmp, sacklen, NULL); 15307c478bd9Sstevel@tonic-gate if (head == NULL) { 15317c478bd9Sstevel@tonic-gate freemsg(*nmp); 15327c478bd9Sstevel@tonic-gate *nmp = NULL; 1533f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_send_ftsn_failed); 15347c478bd9Sstevel@tonic-gate return; 15357c478bd9Sstevel@tonic-gate } 15367c478bd9Sstevel@tonic-gate *seglen += sacklen; 15377c478bd9Sstevel@tonic-gate *nmp = head; 15387c478bd9Sstevel@tonic-gate 15397c478bd9Sstevel@tonic-gate /* 15407c478bd9Sstevel@tonic-gate * XXXNeed to optimise this, the reason it is done here is so 15417c478bd9Sstevel@tonic-gate * that we don't have to undo in case of failure. 15427c478bd9Sstevel@tonic-gate */ 15437c478bd9Sstevel@tonic-gate mp1 = mp_head; 15447c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 15457c478bd9Sstevel@tonic-gate while (meta_head != NULL && 15467c478bd9Sstevel@tonic-gate SEQ_GEQ(sctp->sctp_adv_pap, ntohl(sdc->sdh_tsn))) { 15477c478bd9Sstevel@tonic-gate if (!SCTP_IS_MSG_ABANDONED(meta_head)) 15487c478bd9Sstevel@tonic-gate SCTP_MSG_SET_ABANDONED(meta_head); 15497c478bd9Sstevel@tonic-gate while (mp1 != NULL && SCTP_CHUNK_ISSENT(mp1)) { 15507c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 15517c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISACKED(mp1)) { 15527c478bd9Sstevel@tonic-gate clen = ntohs(sdc->sdh_len) - sizeof (*sdc); 15537c478bd9Sstevel@tonic-gate SCTP_CHUNK_SENT(sctp, mp1, sdc, fp, clen, 15547c478bd9Sstevel@tonic-gate meta_head); 15557c478bd9Sstevel@tonic-gate } 15567c478bd9Sstevel@tonic-gate mp1 = mp1->b_next; 15577c478bd9Sstevel@tonic-gate } 15587c478bd9Sstevel@tonic-gate while (mp1 != NULL) { 15597c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 15607c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ABANDONED(mp1)) { 15617c478bd9Sstevel@tonic-gate ASSERT(!SCTP_CHUNK_ISSENT(mp1)); 15627c478bd9Sstevel@tonic-gate unsent += ntohs(sdc->sdh_len) - sizeof (*sdc); 15637c478bd9Sstevel@tonic-gate SCTP_ABANDON_CHUNK(mp1); 15647c478bd9Sstevel@tonic-gate } 15657c478bd9Sstevel@tonic-gate mp1 = mp1->b_next; 15667c478bd9Sstevel@tonic-gate } 15677c478bd9Sstevel@tonic-gate meta_head = meta_head->b_next; 15687c478bd9Sstevel@tonic-gate if (meta_head != NULL) { 15697c478bd9Sstevel@tonic-gate mp1 = meta_head->b_cont; 15707c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp1)) 15717c478bd9Sstevel@tonic-gate break; 15727c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 15737c478bd9Sstevel@tonic-gate } 15747c478bd9Sstevel@tonic-gate } 15757c478bd9Sstevel@tonic-gate if (unsent > 0) { 15767c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_unsent >= unsent); 15777c478bd9Sstevel@tonic-gate sctp->sctp_unsent -= unsent; 15787c478bd9Sstevel@tonic-gate /* 15797c478bd9Sstevel@tonic-gate * Update ULP the amount of queued data, which is 15807c478bd9Sstevel@tonic-gate * sent-unack'ed + unsent. 15817c478bd9Sstevel@tonic-gate */ 15820f1702c5SYu Xiangning if (!SCTP_IS_DETACHED(sctp)) 15830f1702c5SYu Xiangning SCTP_TXQ_UPDATE(sctp); 15847c478bd9Sstevel@tonic-gate } 15857c478bd9Sstevel@tonic-gate } 15867c478bd9Sstevel@tonic-gate 15877c478bd9Sstevel@tonic-gate /* 15887c478bd9Sstevel@tonic-gate * This function steps through messages starting at meta and checks if 15897c478bd9Sstevel@tonic-gate * the message is abandoned. It stops when it hits an unsent chunk or 15907c478bd9Sstevel@tonic-gate * a message that has all its chunk acked. This is the only place 15917c478bd9Sstevel@tonic-gate * where the sctp_adv_pap is moved forward to indicated abandoned 15927c478bd9Sstevel@tonic-gate * messages. 15937c478bd9Sstevel@tonic-gate */ 15947c478bd9Sstevel@tonic-gate void 15957c478bd9Sstevel@tonic-gate sctp_check_adv_ack_pt(sctp_t *sctp, mblk_t *meta, mblk_t *mp) 15967c478bd9Sstevel@tonic-gate { 15977c478bd9Sstevel@tonic-gate uint32_t tsn = sctp->sctp_adv_pap; 15987c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 15997c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *msg_hdr; 16007c478bd9Sstevel@tonic-gate 16017c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 16027c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 16037c478bd9Sstevel@tonic-gate ASSERT(SEQ_GT(ntohl(sdc->sdh_tsn), sctp->sctp_lastack_rxd)); 16047c478bd9Sstevel@tonic-gate msg_hdr = (sctp_msg_hdr_t *)meta->b_rptr; 16057c478bd9Sstevel@tonic-gate if (!SCTP_IS_MSG_ABANDONED(meta) && 16067c478bd9Sstevel@tonic-gate !SCTP_MSG_TO_BE_ABANDONED(meta, msg_hdr, sctp)) { 16077c478bd9Sstevel@tonic-gate return; 16087c478bd9Sstevel@tonic-gate } 16097c478bd9Sstevel@tonic-gate while (meta != NULL) { 16107c478bd9Sstevel@tonic-gate while (mp != NULL && SCTP_CHUNK_ISSENT(mp)) { 16117c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 16127c478bd9Sstevel@tonic-gate tsn = ntohl(sdc->sdh_tsn); 16137c478bd9Sstevel@tonic-gate mp = mp->b_next; 16147c478bd9Sstevel@tonic-gate } 16157c478bd9Sstevel@tonic-gate if (mp != NULL) 16167c478bd9Sstevel@tonic-gate break; 16177c478bd9Sstevel@tonic-gate /* 16187c478bd9Sstevel@tonic-gate * We continue checking for successive messages only if there 16197c478bd9Sstevel@tonic-gate * is a chunk marked for retransmission. Else, we might 16207c478bd9Sstevel@tonic-gate * end up sending FTSN prematurely for chunks that have been 16217c478bd9Sstevel@tonic-gate * sent, but not yet acked. 16227c478bd9Sstevel@tonic-gate */ 16237c478bd9Sstevel@tonic-gate if ((meta = meta->b_next) != NULL) { 16247c478bd9Sstevel@tonic-gate msg_hdr = (sctp_msg_hdr_t *)meta->b_rptr; 16257c478bd9Sstevel@tonic-gate if (!SCTP_IS_MSG_ABANDONED(meta) && 16267c478bd9Sstevel@tonic-gate !SCTP_MSG_TO_BE_ABANDONED(meta, msg_hdr, sctp)) { 16277c478bd9Sstevel@tonic-gate break; 16287c478bd9Sstevel@tonic-gate } 16297c478bd9Sstevel@tonic-gate for (mp = meta->b_cont; mp != NULL; mp = mp->b_next) { 16307c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp)) { 16317c478bd9Sstevel@tonic-gate sctp->sctp_adv_pap = tsn; 16327c478bd9Sstevel@tonic-gate return; 16337c478bd9Sstevel@tonic-gate } 16347c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_WANT_REXMIT(mp)) 16357c478bd9Sstevel@tonic-gate break; 16367c478bd9Sstevel@tonic-gate } 16377c478bd9Sstevel@tonic-gate if (mp == NULL) 16387c478bd9Sstevel@tonic-gate break; 16397c478bd9Sstevel@tonic-gate } 16407c478bd9Sstevel@tonic-gate } 16417c478bd9Sstevel@tonic-gate sctp->sctp_adv_pap = tsn; 16427c478bd9Sstevel@tonic-gate } 16437c478bd9Sstevel@tonic-gate 164477c67f2fSkcpoon 164577c67f2fSkcpoon /* 164677c67f2fSkcpoon * Determine if we should bundle a data chunk with the chunk being 164777c67f2fSkcpoon * retransmitted. We bundle if 164877c67f2fSkcpoon * 164977c67f2fSkcpoon * - the chunk is sent to the same destination and unack'ed. 165077c67f2fSkcpoon * 165177c67f2fSkcpoon * OR 165277c67f2fSkcpoon * 165377c67f2fSkcpoon * - the chunk is unsent, i.e. new data. 165477c67f2fSkcpoon */ 165577c67f2fSkcpoon #define SCTP_CHUNK_RX_CANBUNDLE(mp, fp) \ 165677c67f2fSkcpoon (!SCTP_CHUNK_ABANDONED((mp)) && \ 165777c67f2fSkcpoon ((SCTP_CHUNK_ISSENT((mp)) && (SCTP_CHUNK_DEST(mp) == (fp) && \ 165877c67f2fSkcpoon !SCTP_CHUNK_ISACKED(mp))) || \ 165977c67f2fSkcpoon (((mp)->b_flag & (SCTP_CHUNK_FLAG_REXMIT|SCTP_CHUNK_FLAG_SENT)) != \ 166077c67f2fSkcpoon SCTP_CHUNK_FLAG_SENT))) 166177c67f2fSkcpoon 16627c478bd9Sstevel@tonic-gate /* 16637c478bd9Sstevel@tonic-gate * Retransmit first segment which hasn't been acked with cumtsn or send 16647c478bd9Sstevel@tonic-gate * a Forward TSN chunk, if appropriate. 16657c478bd9Sstevel@tonic-gate */ 16667c478bd9Sstevel@tonic-gate void 16677c478bd9Sstevel@tonic-gate sctp_rexmit(sctp_t *sctp, sctp_faddr_t *oldfp) 16687c478bd9Sstevel@tonic-gate { 16697c478bd9Sstevel@tonic-gate mblk_t *mp; 16707c478bd9Sstevel@tonic-gate mblk_t *nmp = NULL; 16717c478bd9Sstevel@tonic-gate mblk_t *head; 16727c478bd9Sstevel@tonic-gate mblk_t *meta = sctp->sctp_xmit_head; 16737c478bd9Sstevel@tonic-gate mblk_t *fill; 16747c478bd9Sstevel@tonic-gate uint32_t seglen = 0; 16757c478bd9Sstevel@tonic-gate uint32_t sacklen; 16767c478bd9Sstevel@tonic-gate uint16_t chunklen; 16777c478bd9Sstevel@tonic-gate int extra; 16787c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 16797c478bd9Sstevel@tonic-gate sctp_faddr_t *fp; 16807c478bd9Sstevel@tonic-gate uint32_t adv_pap = sctp->sctp_adv_pap; 16817c478bd9Sstevel@tonic-gate boolean_t do_ftsn = B_FALSE; 16827c478bd9Sstevel@tonic-gate boolean_t ftsn_check = B_TRUE; 168377c67f2fSkcpoon uint32_t first_ua_tsn; 168477c67f2fSkcpoon sctp_msg_hdr_t *mhdr; 1685f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 16862dd25cf1SGeorge Shepherd int error; 16877c478bd9Sstevel@tonic-gate 16887c478bd9Sstevel@tonic-gate while (meta != NULL) { 16897c478bd9Sstevel@tonic-gate for (mp = meta->b_cont; mp != NULL; mp = mp->b_next) { 16907c478bd9Sstevel@tonic-gate uint32_t tsn; 16917c478bd9Sstevel@tonic-gate 16927c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp)) 16937c478bd9Sstevel@tonic-gate goto window_probe; 16947c478bd9Sstevel@tonic-gate /* 16957c478bd9Sstevel@tonic-gate * We break in the following cases - 16967c478bd9Sstevel@tonic-gate * 16977c478bd9Sstevel@tonic-gate * if the advanced peer ack point includes the next 16987c478bd9Sstevel@tonic-gate * chunk to be retransmited - possibly the Forward 16997c478bd9Sstevel@tonic-gate * TSN was lost. 17007c478bd9Sstevel@tonic-gate * 17017c478bd9Sstevel@tonic-gate * if we are PRSCTP aware and the next chunk to be 17027c478bd9Sstevel@tonic-gate * retransmitted is now abandoned 17037c478bd9Sstevel@tonic-gate * 17047c478bd9Sstevel@tonic-gate * if the next chunk to be retransmitted is for 17057c478bd9Sstevel@tonic-gate * the dest on which the timer went off. (this 17067c478bd9Sstevel@tonic-gate * message is not abandoned). 17077c478bd9Sstevel@tonic-gate * 17087c478bd9Sstevel@tonic-gate * We check for Forward TSN only for the first 17097c478bd9Sstevel@tonic-gate * eligible chunk to be retransmitted. The reason 17107c478bd9Sstevel@tonic-gate * being if the first eligible chunk is skipped (say 17117c478bd9Sstevel@tonic-gate * it was sent to a destination other than oldfp) 17127c478bd9Sstevel@tonic-gate * then we cannot advance the cum TSN via Forward 17137c478bd9Sstevel@tonic-gate * TSN chunk. 17147c478bd9Sstevel@tonic-gate * 17157c478bd9Sstevel@tonic-gate * Also, ftsn_check is B_TRUE only for the first 17167c478bd9Sstevel@tonic-gate * eligible chunk, it will be B_FALSE for all 17177c478bd9Sstevel@tonic-gate * subsequent candidate messages for retransmission. 17187c478bd9Sstevel@tonic-gate */ 17197c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 17207c478bd9Sstevel@tonic-gate tsn = ntohl(sdc->sdh_tsn); 17217c478bd9Sstevel@tonic-gate if (SEQ_GT(tsn, sctp->sctp_lastack_rxd)) { 17227c478bd9Sstevel@tonic-gate if (sctp->sctp_prsctp_aware && ftsn_check) { 17237c478bd9Sstevel@tonic-gate if (SEQ_GEQ(sctp->sctp_adv_pap, tsn)) { 17247c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_prsctp_aware); 17257c478bd9Sstevel@tonic-gate do_ftsn = B_TRUE; 17267c478bd9Sstevel@tonic-gate goto out; 17277c478bd9Sstevel@tonic-gate } else { 17287c478bd9Sstevel@tonic-gate sctp_check_adv_ack_pt(sctp, 17297c478bd9Sstevel@tonic-gate meta, mp); 17307c478bd9Sstevel@tonic-gate if (SEQ_GT(sctp->sctp_adv_pap, 17317c478bd9Sstevel@tonic-gate adv_pap)) { 17327c478bd9Sstevel@tonic-gate do_ftsn = B_TRUE; 17337c478bd9Sstevel@tonic-gate goto out; 17347c478bd9Sstevel@tonic-gate } 17357c478bd9Sstevel@tonic-gate } 17367c478bd9Sstevel@tonic-gate ftsn_check = B_FALSE; 17377c478bd9Sstevel@tonic-gate } 17387c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_DEST(mp) == oldfp) 17397c478bd9Sstevel@tonic-gate goto out; 17407c478bd9Sstevel@tonic-gate } 17417c478bd9Sstevel@tonic-gate } 17427c478bd9Sstevel@tonic-gate meta = meta->b_next; 17437c478bd9Sstevel@tonic-gate if (meta != NULL && sctp->sctp_prsctp_aware) { 174477c67f2fSkcpoon mhdr = (sctp_msg_hdr_t *)meta->b_rptr; 17457c478bd9Sstevel@tonic-gate 17467c478bd9Sstevel@tonic-gate while (meta != NULL && (SCTP_IS_MSG_ABANDONED(meta) || 17477c478bd9Sstevel@tonic-gate SCTP_MSG_TO_BE_ABANDONED(meta, mhdr, sctp))) { 17487c478bd9Sstevel@tonic-gate meta = meta->b_next; 17497c478bd9Sstevel@tonic-gate } 17507c478bd9Sstevel@tonic-gate } 17517c478bd9Sstevel@tonic-gate } 17527c478bd9Sstevel@tonic-gate window_probe: 17537c478bd9Sstevel@tonic-gate /* 17547c478bd9Sstevel@tonic-gate * Retransmit fired for a destination which didn't have 17557c478bd9Sstevel@tonic-gate * any unacked data pending. 17567c478bd9Sstevel@tonic-gate */ 1757769b977dSvi if (sctp->sctp_unacked == 0 && sctp->sctp_unsent != 0) { 17587c478bd9Sstevel@tonic-gate /* 17597c478bd9Sstevel@tonic-gate * Send a window probe. Inflate frwnd to allow 17607c478bd9Sstevel@tonic-gate * sending one segment. 17617c478bd9Sstevel@tonic-gate */ 1762769b977dSvi if (sctp->sctp_frwnd < (oldfp->sfa_pmss - sizeof (*sdc))) 17637c478bd9Sstevel@tonic-gate sctp->sctp_frwnd = oldfp->sfa_pmss - sizeof (*sdc); 176412f47623Skcpoon 1765769b977dSvi /* next TSN to send */ 1766769b977dSvi sctp->sctp_rxt_nxttsn = sctp->sctp_ltsn; 176712f47623Skcpoon 176812f47623Skcpoon /* 176912f47623Skcpoon * The above sctp_frwnd adjustment is coarse. The "changed" 177012f47623Skcpoon * sctp_frwnd may allow us to send more than 1 packet. So 177112f47623Skcpoon * tell sctp_output() to send only 1 packet. 177212f47623Skcpoon */ 177312f47623Skcpoon sctp_output(sctp, 1); 177412f47623Skcpoon 1775769b977dSvi /* Last sent TSN */ 1776769b977dSvi sctp->sctp_rxt_maxtsn = sctp->sctp_ltsn - 1; 1777769b977dSvi ASSERT(sctp->sctp_rxt_maxtsn >= sctp->sctp_rxt_nxttsn); 1778769b977dSvi sctp->sctp_zero_win_probe = B_TRUE; 1779f4b3ec61Sdh BUMP_MIB(&sctps->sctps_mib, sctpOutWinProbe); 17807c478bd9Sstevel@tonic-gate } 17817c478bd9Sstevel@tonic-gate return; 17827c478bd9Sstevel@tonic-gate out: 1783769b977dSvi /* 178412f47623Skcpoon * After a time out, assume that everything has left the network. So 178512f47623Skcpoon * we can clear rxt_unacked for the original peer address. 178612f47623Skcpoon */ 178712f47623Skcpoon oldfp->rxt_unacked = 0; 178812f47623Skcpoon 178912f47623Skcpoon /* 179012f47623Skcpoon * If we were probing for zero window, don't adjust retransmission 1791769b977dSvi * variables, but the timer is still backed off. 1792769b977dSvi */ 1793769b977dSvi if (sctp->sctp_zero_win_probe) { 1794769b977dSvi mblk_t *pkt; 1795769b977dSvi uint_t pkt_len; 1796769b977dSvi 1797769b977dSvi /* 1798769b977dSvi * Get the Zero Win Probe for retrasmission, sctp_rxt_nxttsn 1799769b977dSvi * and sctp_rxt_maxtsn will specify the ZWP packet. 1800769b977dSvi */ 1801769b977dSvi fp = oldfp; 1802769b977dSvi if (oldfp->state != SCTP_FADDRS_ALIVE) 1803769b977dSvi fp = sctp_rotate_faddr(sctp, oldfp); 1804769b977dSvi pkt = sctp_rexmit_packet(sctp, &meta, &mp, fp, &pkt_len); 1805769b977dSvi if (pkt != NULL) { 1806769b977dSvi ASSERT(pkt_len <= fp->sfa_pmss); 1807769b977dSvi sctp_set_iplen(sctp, pkt); 1808769b977dSvi sctp_add_sendq(sctp, pkt); 1809769b977dSvi } else { 1810f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_ss_rexmit_failed); 1811769b977dSvi } 181212f47623Skcpoon 181312f47623Skcpoon /* 181412f47623Skcpoon * The strikes will be clear by sctp_faddr_alive() when the 181512f47623Skcpoon * other side sends us an ack. 181612f47623Skcpoon */ 1817769b977dSvi oldfp->strikes++; 1818769b977dSvi sctp->sctp_strikes++; 181912f47623Skcpoon 1820769b977dSvi SCTP_CALC_RXT(oldfp, sctp->sctp_rto_max); 1821769b977dSvi if (oldfp != fp && oldfp->suna != 0) 1822769b977dSvi SCTP_FADDR_TIMER_RESTART(sctp, oldfp, fp->rto); 1823769b977dSvi SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->rto); 1824f4b3ec61Sdh BUMP_MIB(&sctps->sctps_mib, sctpOutWinProbe); 1825769b977dSvi return; 1826769b977dSvi } 1827769b977dSvi 18287c478bd9Sstevel@tonic-gate /* 18297c478bd9Sstevel@tonic-gate * Enter slowstart for this destination 18307c478bd9Sstevel@tonic-gate */ 18317c478bd9Sstevel@tonic-gate oldfp->ssthresh = oldfp->cwnd / 2; 18327c478bd9Sstevel@tonic-gate if (oldfp->ssthresh < 2 * oldfp->sfa_pmss) 18337c478bd9Sstevel@tonic-gate oldfp->ssthresh = 2 * oldfp->sfa_pmss; 18347c478bd9Sstevel@tonic-gate oldfp->cwnd = oldfp->sfa_pmss; 18357c478bd9Sstevel@tonic-gate oldfp->pba = 0; 18367c478bd9Sstevel@tonic-gate fp = sctp_rotate_faddr(sctp, oldfp); 18377c478bd9Sstevel@tonic-gate ASSERT(fp != NULL); 18387c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 18397c478bd9Sstevel@tonic-gate 184077c67f2fSkcpoon first_ua_tsn = ntohl(sdc->sdh_tsn); 18417c478bd9Sstevel@tonic-gate if (do_ftsn) { 18427c478bd9Sstevel@tonic-gate sctp_make_ftsns(sctp, meta, mp, &nmp, fp, &seglen); 18437c478bd9Sstevel@tonic-gate if (nmp == NULL) { 18447c478bd9Sstevel@tonic-gate sctp->sctp_adv_pap = adv_pap; 18457c478bd9Sstevel@tonic-gate goto restart_timer; 18467c478bd9Sstevel@tonic-gate } 18477c478bd9Sstevel@tonic-gate head = nmp; 184877c67f2fSkcpoon /* 184977c67f2fSkcpoon * Move to the next unabandoned chunk. XXXCheck if meta will 185077c67f2fSkcpoon * always be marked abandoned. 185177c67f2fSkcpoon */ 185277c67f2fSkcpoon while (meta != NULL && SCTP_IS_MSG_ABANDONED(meta)) 185377c67f2fSkcpoon meta = meta->b_next; 18547c478bd9Sstevel@tonic-gate if (meta != NULL) 185577c67f2fSkcpoon mp = mp->b_cont; 185677c67f2fSkcpoon else 185777c67f2fSkcpoon mp = NULL; 18587c478bd9Sstevel@tonic-gate goto try_bundle; 18597c478bd9Sstevel@tonic-gate } 18607c478bd9Sstevel@tonic-gate seglen = ntohs(sdc->sdh_len); 18617c478bd9Sstevel@tonic-gate chunklen = seglen - sizeof (*sdc); 18627c478bd9Sstevel@tonic-gate if ((extra = seglen & (SCTP_ALIGN - 1)) != 0) 18637c478bd9Sstevel@tonic-gate extra = SCTP_ALIGN - extra; 18647c478bd9Sstevel@tonic-gate 186577c67f2fSkcpoon /* Find out if we need to piggyback SACK. */ 18667c478bd9Sstevel@tonic-gate if (sctp->sctp_ftsn == sctp->sctp_lastacked + 1) { 18677c478bd9Sstevel@tonic-gate sacklen = 0; 18687c478bd9Sstevel@tonic-gate } else { 18697c478bd9Sstevel@tonic-gate sacklen = sizeof (sctp_chunk_hdr_t) + 18707c478bd9Sstevel@tonic-gate sizeof (sctp_sack_chunk_t) + 18717c478bd9Sstevel@tonic-gate (sizeof (sctp_sack_frag_t) * sctp->sctp_sack_gaps); 18727c478bd9Sstevel@tonic-gate if (seglen + sacklen > sctp->sctp_lastdata->sfa_pmss) { 18737c478bd9Sstevel@tonic-gate /* piggybacked SACK doesn't fit */ 18747c478bd9Sstevel@tonic-gate sacklen = 0; 18757c478bd9Sstevel@tonic-gate } else { 187677c67f2fSkcpoon /* 187777c67f2fSkcpoon * OK, we have room to send SACK back. But we 187877c67f2fSkcpoon * should send it back to the last fp where we 187977c67f2fSkcpoon * receive data from, unless sctp_lastdata equals 188077c67f2fSkcpoon * oldfp, then we should probably not send it 188177c67f2fSkcpoon * back to that fp. Also we should check that 188277c67f2fSkcpoon * the fp is alive. 188377c67f2fSkcpoon */ 188477c67f2fSkcpoon if (sctp->sctp_lastdata != oldfp && 188577c67f2fSkcpoon sctp->sctp_lastdata->state == SCTP_FADDRS_ALIVE) { 188677c67f2fSkcpoon fp = sctp->sctp_lastdata; 188777c67f2fSkcpoon } 18887c478bd9Sstevel@tonic-gate } 18897c478bd9Sstevel@tonic-gate } 18907c478bd9Sstevel@tonic-gate 189177c67f2fSkcpoon /* 189277c67f2fSkcpoon * Cancel RTT measurement if the retransmitted TSN is before the 189377c67f2fSkcpoon * TSN used for timimg. 189477c67f2fSkcpoon */ 189577c67f2fSkcpoon if (sctp->sctp_out_time != 0 && 189677c67f2fSkcpoon SEQ_GEQ(sctp->sctp_rtt_tsn, sdc->sdh_tsn)) { 189777c67f2fSkcpoon sctp->sctp_out_time = 0; 189877c67f2fSkcpoon } 189977c67f2fSkcpoon /* Clear the counter as the RTT calculation may be off. */ 190077c67f2fSkcpoon fp->rtt_updates = 0; 190177c67f2fSkcpoon oldfp->rtt_updates = 0; 190277c67f2fSkcpoon 190377c67f2fSkcpoon /* 190477c67f2fSkcpoon * After a timeout, we should change the current faddr so that 190577c67f2fSkcpoon * new chunks will be sent to the alternate address. 190677c67f2fSkcpoon */ 190777c67f2fSkcpoon sctp_set_faddr_current(sctp, fp); 190877c67f2fSkcpoon 19097c478bd9Sstevel@tonic-gate nmp = dupmsg(mp); 19107c478bd9Sstevel@tonic-gate if (nmp == NULL) 19117c478bd9Sstevel@tonic-gate goto restart_timer; 19127c478bd9Sstevel@tonic-gate if (extra > 0) { 1913121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 19147c478bd9Sstevel@tonic-gate if (fill != NULL) { 19157c478bd9Sstevel@tonic-gate linkb(nmp, fill); 19167c478bd9Sstevel@tonic-gate seglen += extra; 19177c478bd9Sstevel@tonic-gate } else { 19187c478bd9Sstevel@tonic-gate freemsg(nmp); 19197c478bd9Sstevel@tonic-gate goto restart_timer; 19207c478bd9Sstevel@tonic-gate } 19217c478bd9Sstevel@tonic-gate } 19227c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_FLAGS(nmp); 1923df19b344Svi head = sctp_add_proto_hdr(sctp, fp, nmp, sacklen, NULL); 19247c478bd9Sstevel@tonic-gate if (head == NULL) { 19257c478bd9Sstevel@tonic-gate freemsg(nmp); 1926f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_rexmit_failed); 19277c478bd9Sstevel@tonic-gate goto restart_timer; 19287c478bd9Sstevel@tonic-gate } 19297c478bd9Sstevel@tonic-gate seglen += sacklen; 19307c478bd9Sstevel@tonic-gate 19317c478bd9Sstevel@tonic-gate SCTP_CHUNK_SENT(sctp, mp, sdc, fp, chunklen, meta); 19327c478bd9Sstevel@tonic-gate 19337c478bd9Sstevel@tonic-gate mp = mp->b_next; 193477c67f2fSkcpoon 19357c478bd9Sstevel@tonic-gate try_bundle: 193612f47623Skcpoon /* We can at least and at most send 1 packet at timeout. */ 19377c478bd9Sstevel@tonic-gate while (seglen < fp->sfa_pmss) { 19387c478bd9Sstevel@tonic-gate int32_t new_len; 19397c478bd9Sstevel@tonic-gate 194077c67f2fSkcpoon /* Go through the list to find more chunks to be bundled. */ 19417c478bd9Sstevel@tonic-gate while (mp != NULL) { 194277c67f2fSkcpoon /* Check if the chunk can be bundled. */ 194377c67f2fSkcpoon if (SCTP_CHUNK_RX_CANBUNDLE(mp, oldfp)) 19447c478bd9Sstevel@tonic-gate break; 19457c478bd9Sstevel@tonic-gate mp = mp->b_next; 19467c478bd9Sstevel@tonic-gate } 194777c67f2fSkcpoon /* Go to the next message. */ 19487c478bd9Sstevel@tonic-gate if (mp == NULL) { 194977c67f2fSkcpoon for (meta = meta->b_next; meta != NULL; 195077c67f2fSkcpoon meta = meta->b_next) { 195177c67f2fSkcpoon mhdr = (sctp_msg_hdr_t *)meta->b_rptr; 195277c67f2fSkcpoon 195377c67f2fSkcpoon if (SCTP_IS_MSG_ABANDONED(meta) || 195477c67f2fSkcpoon SCTP_MSG_TO_BE_ABANDONED(meta, mhdr, 195577c67f2fSkcpoon sctp)) { 195677c67f2fSkcpoon continue; 195777c67f2fSkcpoon } 195877c67f2fSkcpoon 195977c67f2fSkcpoon mp = meta->b_cont; 196077c67f2fSkcpoon goto try_bundle; 196177c67f2fSkcpoon } 19622dd25cf1SGeorge Shepherd /* 19632dd25cf1SGeorge Shepherd * Check if there is a new message which potentially 19642dd25cf1SGeorge Shepherd * could be bundled with this retransmission. 19652dd25cf1SGeorge Shepherd */ 19662dd25cf1SGeorge Shepherd meta = sctp_get_msg_to_send(sctp, &mp, NULL, &error, 19672dd25cf1SGeorge Shepherd seglen, fp->sfa_pmss - seglen, NULL); 19682dd25cf1SGeorge Shepherd if (error != 0 || meta == NULL) { 19692dd25cf1SGeorge Shepherd /* No more chunk to be bundled. */ 19702dd25cf1SGeorge Shepherd break; 19712dd25cf1SGeorge Shepherd } else { 19722dd25cf1SGeorge Shepherd goto try_bundle; 19732dd25cf1SGeorge Shepherd } 19747c478bd9Sstevel@tonic-gate } 197577c67f2fSkcpoon 19767c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 197777c67f2fSkcpoon new_len = ntohs(sdc->sdh_len); 197877c67f2fSkcpoon chunklen = new_len - sizeof (*sdc); 19797c478bd9Sstevel@tonic-gate 198077c67f2fSkcpoon if ((extra = new_len & (SCTP_ALIGN - 1)) != 0) 198177c67f2fSkcpoon extra = SCTP_ALIGN - extra; 198277c67f2fSkcpoon if ((new_len = seglen + new_len + extra) > fp->sfa_pmss) 198377c67f2fSkcpoon break; 198477c67f2fSkcpoon if ((nmp = dupmsg(mp)) == NULL) 198577c67f2fSkcpoon break; 19867c478bd9Sstevel@tonic-gate 198777c67f2fSkcpoon if (extra > 0) { 1988121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 19897c478bd9Sstevel@tonic-gate if (fill != NULL) { 199077c67f2fSkcpoon linkb(nmp, fill); 19917c478bd9Sstevel@tonic-gate } else { 199277c67f2fSkcpoon freemsg(nmp); 19937c478bd9Sstevel@tonic-gate break; 19947c478bd9Sstevel@tonic-gate } 19957c478bd9Sstevel@tonic-gate } 199677c67f2fSkcpoon linkb(head, nmp); 19977c478bd9Sstevel@tonic-gate 19987c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_FLAGS(nmp); 19997c478bd9Sstevel@tonic-gate SCTP_CHUNK_SENT(sctp, mp, sdc, fp, chunklen, meta); 200077c67f2fSkcpoon 200177c67f2fSkcpoon seglen = new_len; 20027c478bd9Sstevel@tonic-gate mp = mp->b_next; 20037c478bd9Sstevel@tonic-gate } 200477c67f2fSkcpoon done_bundle: 20057c478bd9Sstevel@tonic-gate if ((seglen > fp->sfa_pmss) && fp->isv4) { 20067c478bd9Sstevel@tonic-gate ipha_t *iph = (ipha_t *)head->b_rptr; 20077c478bd9Sstevel@tonic-gate 20087c478bd9Sstevel@tonic-gate /* 20097c478bd9Sstevel@tonic-gate * Path MTU is different from path we thought it would 20107c478bd9Sstevel@tonic-gate * be when we created chunks, or IP headers have grown. 20117c478bd9Sstevel@tonic-gate * Need to clear the DF bit. 20127c478bd9Sstevel@tonic-gate */ 20137c478bd9Sstevel@tonic-gate iph->ipha_fragment_offset_and_flags = 0; 20147c478bd9Sstevel@tonic-gate } 201512f47623Skcpoon fp->rxt_unacked += seglen; 201612f47623Skcpoon 20177c478bd9Sstevel@tonic-gate dprint(2, ("sctp_rexmit: Sending packet %d bytes, tsn %x " 20187c478bd9Sstevel@tonic-gate "ssn %d to %p (rwnd %d, lastack_rxd %x)\n", 201945916cd2Sjpk seglen, ntohl(sdc->sdh_tsn), ntohs(sdc->sdh_ssn), 202045916cd2Sjpk (void *)fp, sctp->sctp_frwnd, sctp->sctp_lastack_rxd)); 20217c478bd9Sstevel@tonic-gate 202277c67f2fSkcpoon sctp->sctp_rexmitting = B_TRUE; 202377c67f2fSkcpoon sctp->sctp_rxt_nxttsn = first_ua_tsn; 202477c67f2fSkcpoon sctp->sctp_rxt_maxtsn = sctp->sctp_ltsn - 1; 20257c478bd9Sstevel@tonic-gate sctp_set_iplen(sctp, head); 20267c478bd9Sstevel@tonic-gate sctp_add_sendq(sctp, head); 20277c478bd9Sstevel@tonic-gate 20287c478bd9Sstevel@tonic-gate /* 202977c67f2fSkcpoon * Restart the oldfp timer with exponential backoff and 203077c67f2fSkcpoon * the new fp timer for the retransmitted chunks. 20317c478bd9Sstevel@tonic-gate */ 20327c478bd9Sstevel@tonic-gate restart_timer: 20337c478bd9Sstevel@tonic-gate oldfp->strikes++; 20347c478bd9Sstevel@tonic-gate sctp->sctp_strikes++; 20357c478bd9Sstevel@tonic-gate SCTP_CALC_RXT(oldfp, sctp->sctp_rto_max); 2036c31292eeSkcpoon /* 2037c31292eeSkcpoon * If there is still some data in the oldfp, restart the 2038c31292eeSkcpoon * retransmission timer. If there is no data, the heartbeat will 2039c31292eeSkcpoon * continue to run so it will do its job in checking the reachability 2040c31292eeSkcpoon * of the oldfp. 2041c31292eeSkcpoon */ 2042c31292eeSkcpoon if (oldfp != fp && oldfp->suna != 0) 20437c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, oldfp, oldfp->rto); 204477c67f2fSkcpoon 204577c67f2fSkcpoon /* 204677c67f2fSkcpoon * Should we restart the timer of the new fp? If there is 204777c67f2fSkcpoon * outstanding data to the new fp, the timer should be 204877c67f2fSkcpoon * running already. So restarting it means that the timer 204977c67f2fSkcpoon * will fire later for those outstanding data. But if 205077c67f2fSkcpoon * we don't restart it, the timer will fire too early for the 205177c67f2fSkcpoon * just retransmitted chunks to the new fp. The reason is that we 205277c67f2fSkcpoon * don't keep a timestamp on when a chunk is retransmitted. 205377c67f2fSkcpoon * So when the timer fires, it will just search for the 205477c67f2fSkcpoon * chunk with the earliest TSN sent to new fp. This probably 205577c67f2fSkcpoon * is the chunk we just retransmitted. So for now, let's 205677c67f2fSkcpoon * be conservative and restart the timer of the new fp. 205777c67f2fSkcpoon */ 205877c67f2fSkcpoon SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->rto); 2059c31292eeSkcpoon 2060c31292eeSkcpoon sctp->sctp_active = lbolt64; 20617c478bd9Sstevel@tonic-gate } 20627c478bd9Sstevel@tonic-gate 206377c67f2fSkcpoon /* 206477c67f2fSkcpoon * This function is called by sctp_ss_rexmit() to create a packet 206577c67f2fSkcpoon * to be retransmitted to the given fp. The given meta and mp 206677c67f2fSkcpoon * parameters are respectively the sctp_msg_hdr_t and the mblk of the 206712f47623Skcpoon * first chunk to be retransmitted. This is also called when we want 2068769b977dSvi * to retransmit a zero window probe from sctp_rexmit() or when we 2069769b977dSvi * want to retransmit the zero window probe after the window has 2070769b977dSvi * opened from sctp_got_sack(). 207177c67f2fSkcpoon */ 2072769b977dSvi mblk_t * 207377c67f2fSkcpoon sctp_rexmit_packet(sctp_t *sctp, mblk_t **meta, mblk_t **mp, sctp_faddr_t *fp, 207477c67f2fSkcpoon uint_t *packet_len) 207577c67f2fSkcpoon { 207677c67f2fSkcpoon uint32_t seglen = 0; 207777c67f2fSkcpoon uint16_t chunklen; 207877c67f2fSkcpoon int extra; 207977c67f2fSkcpoon mblk_t *nmp; 208077c67f2fSkcpoon mblk_t *head; 208177c67f2fSkcpoon mblk_t *fill; 208277c67f2fSkcpoon sctp_data_hdr_t *sdc; 208377c67f2fSkcpoon sctp_msg_hdr_t *mhdr; 208477c67f2fSkcpoon 208577c67f2fSkcpoon sdc = (sctp_data_hdr_t *)(*mp)->b_rptr; 208677c67f2fSkcpoon seglen = ntohs(sdc->sdh_len); 208777c67f2fSkcpoon chunklen = seglen - sizeof (*sdc); 208877c67f2fSkcpoon if ((extra = seglen & (SCTP_ALIGN - 1)) != 0) 208977c67f2fSkcpoon extra = SCTP_ALIGN - extra; 209077c67f2fSkcpoon 209177c67f2fSkcpoon nmp = dupmsg(*mp); 209277c67f2fSkcpoon if (nmp == NULL) 209377c67f2fSkcpoon return (NULL); 209477c67f2fSkcpoon if (extra > 0) { 2095121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 209677c67f2fSkcpoon if (fill != NULL) { 209777c67f2fSkcpoon linkb(nmp, fill); 209877c67f2fSkcpoon seglen += extra; 209977c67f2fSkcpoon } else { 210077c67f2fSkcpoon freemsg(nmp); 210177c67f2fSkcpoon return (NULL); 210277c67f2fSkcpoon } 210377c67f2fSkcpoon } 210477c67f2fSkcpoon SCTP_CHUNK_CLEAR_FLAGS(nmp); 210577c67f2fSkcpoon head = sctp_add_proto_hdr(sctp, fp, nmp, 0, NULL); 210677c67f2fSkcpoon if (head == NULL) { 210777c67f2fSkcpoon freemsg(nmp); 210877c67f2fSkcpoon return (NULL); 210977c67f2fSkcpoon } 211077c67f2fSkcpoon SCTP_CHUNK_SENT(sctp, *mp, sdc, fp, chunklen, *meta); 2111769b977dSvi /* 2112769b977dSvi * Don't update the TSN if we are doing a Zero Win Probe. 2113769b977dSvi */ 2114769b977dSvi if (!sctp->sctp_zero_win_probe) 2115769b977dSvi sctp->sctp_rxt_nxttsn = ntohl(sdc->sdh_tsn); 211677c67f2fSkcpoon *mp = (*mp)->b_next; 211777c67f2fSkcpoon 211877c67f2fSkcpoon try_bundle: 211977c67f2fSkcpoon while (seglen < fp->sfa_pmss) { 212077c67f2fSkcpoon int32_t new_len; 212177c67f2fSkcpoon 212277c67f2fSkcpoon /* 212377c67f2fSkcpoon * Go through the list to find more chunks to be bundled. 212477c67f2fSkcpoon * We should only retransmit sent by unack'ed chunks. Since 212577c67f2fSkcpoon * they were sent before, the peer's receive window should 212677c67f2fSkcpoon * be able to receive them. 212777c67f2fSkcpoon */ 212877c67f2fSkcpoon while (*mp != NULL) { 212977c67f2fSkcpoon /* Check if the chunk can be bundled. */ 213077c67f2fSkcpoon if (SCTP_CHUNK_ISSENT(*mp) && !SCTP_CHUNK_ISACKED(*mp)) 213177c67f2fSkcpoon break; 213277c67f2fSkcpoon *mp = (*mp)->b_next; 213377c67f2fSkcpoon } 213477c67f2fSkcpoon /* Go to the next message. */ 213577c67f2fSkcpoon if (*mp == NULL) { 213677c67f2fSkcpoon for (*meta = (*meta)->b_next; *meta != NULL; 213777c67f2fSkcpoon *meta = (*meta)->b_next) { 213877c67f2fSkcpoon mhdr = (sctp_msg_hdr_t *)(*meta)->b_rptr; 213977c67f2fSkcpoon 214077c67f2fSkcpoon if (SCTP_IS_MSG_ABANDONED(*meta) || 214177c67f2fSkcpoon SCTP_MSG_TO_BE_ABANDONED(*meta, mhdr, 214277c67f2fSkcpoon sctp)) { 214377c67f2fSkcpoon continue; 214477c67f2fSkcpoon } 214577c67f2fSkcpoon 214677c67f2fSkcpoon *mp = (*meta)->b_cont; 214777c67f2fSkcpoon goto try_bundle; 214877c67f2fSkcpoon } 214977c67f2fSkcpoon /* No more chunk to be bundled. */ 215077c67f2fSkcpoon break; 215177c67f2fSkcpoon } 215277c67f2fSkcpoon 215377c67f2fSkcpoon sdc = (sctp_data_hdr_t *)(*mp)->b_rptr; 215477c67f2fSkcpoon /* Don't bundle chunks beyond sctp_rxt_maxtsn. */ 215577c67f2fSkcpoon if (SEQ_GT(ntohl(sdc->sdh_tsn), sctp->sctp_rxt_maxtsn)) 215677c67f2fSkcpoon break; 215777c67f2fSkcpoon new_len = ntohs(sdc->sdh_len); 215877c67f2fSkcpoon chunklen = new_len - sizeof (*sdc); 215977c67f2fSkcpoon 216077c67f2fSkcpoon if ((extra = new_len & (SCTP_ALIGN - 1)) != 0) 216177c67f2fSkcpoon extra = SCTP_ALIGN - extra; 216277c67f2fSkcpoon if ((new_len = seglen + new_len + extra) > fp->sfa_pmss) 216377c67f2fSkcpoon break; 216477c67f2fSkcpoon if ((nmp = dupmsg(*mp)) == NULL) 216577c67f2fSkcpoon break; 216677c67f2fSkcpoon 216777c67f2fSkcpoon if (extra > 0) { 2168121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 216977c67f2fSkcpoon if (fill != NULL) { 217077c67f2fSkcpoon linkb(nmp, fill); 217177c67f2fSkcpoon } else { 217277c67f2fSkcpoon freemsg(nmp); 217377c67f2fSkcpoon break; 217477c67f2fSkcpoon } 217577c67f2fSkcpoon } 217677c67f2fSkcpoon linkb(head, nmp); 217777c67f2fSkcpoon 217877c67f2fSkcpoon SCTP_CHUNK_CLEAR_FLAGS(nmp); 217977c67f2fSkcpoon SCTP_CHUNK_SENT(sctp, *mp, sdc, fp, chunklen, *meta); 2180769b977dSvi /* 2181769b977dSvi * Don't update the TSN if we are doing a Zero Win Probe. 2182769b977dSvi */ 2183769b977dSvi if (!sctp->sctp_zero_win_probe) 2184769b977dSvi sctp->sctp_rxt_nxttsn = ntohl(sdc->sdh_tsn); 218577c67f2fSkcpoon 218677c67f2fSkcpoon seglen = new_len; 218777c67f2fSkcpoon *mp = (*mp)->b_next; 218877c67f2fSkcpoon } 218977c67f2fSkcpoon *packet_len = seglen; 219012f47623Skcpoon fp->rxt_unacked += seglen; 219177c67f2fSkcpoon return (head); 219277c67f2fSkcpoon } 219377c67f2fSkcpoon 219477c67f2fSkcpoon /* 219577c67f2fSkcpoon * sctp_ss_rexmit() is called when we get a SACK after a timeout which 219677c67f2fSkcpoon * advances the cum_tsn but the cum_tsn is still less than what we have sent 219777c67f2fSkcpoon * (sctp_rxt_maxtsn) at the time of the timeout. This SACK is a "partial" 219877c67f2fSkcpoon * SACK. We retransmit unacked chunks without having to wait for another 219977c67f2fSkcpoon * timeout. The rationale is that the SACK should not be "partial" if all the 220077c67f2fSkcpoon * lost chunks have been retransmitted. Since the SACK is "partial," 220177c67f2fSkcpoon * the chunks between the cum_tsn and the sctp_rxt_maxtsn should still 220277c67f2fSkcpoon * be missing. It is better for us to retransmit them now instead 220377c67f2fSkcpoon * of waiting for a timeout. 220477c67f2fSkcpoon */ 220577c67f2fSkcpoon void 220677c67f2fSkcpoon sctp_ss_rexmit(sctp_t *sctp) 220777c67f2fSkcpoon { 220877c67f2fSkcpoon mblk_t *meta; 220977c67f2fSkcpoon mblk_t *mp; 221077c67f2fSkcpoon mblk_t *pkt; 221177c67f2fSkcpoon sctp_faddr_t *fp; 221277c67f2fSkcpoon uint_t pkt_len; 221377c67f2fSkcpoon uint32_t tot_wnd; 221477c67f2fSkcpoon sctp_data_hdr_t *sdc; 221577c67f2fSkcpoon int burst; 2216f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 221777c67f2fSkcpoon 2218769b977dSvi ASSERT(!sctp->sctp_zero_win_probe); 2219769b977dSvi 222077c67f2fSkcpoon /* 222177c67f2fSkcpoon * If the last cum ack is smaller than what we have just 222277c67f2fSkcpoon * retransmitted, simply return. 222377c67f2fSkcpoon */ 222477c67f2fSkcpoon if (SEQ_GEQ(sctp->sctp_lastack_rxd, sctp->sctp_rxt_nxttsn)) 222577c67f2fSkcpoon sctp->sctp_rxt_nxttsn = sctp->sctp_lastack_rxd + 1; 222677c67f2fSkcpoon else 222777c67f2fSkcpoon return; 222877c67f2fSkcpoon ASSERT(SEQ_LEQ(sctp->sctp_rxt_nxttsn, sctp->sctp_rxt_maxtsn)); 222977c67f2fSkcpoon 223077c67f2fSkcpoon /* 223177c67f2fSkcpoon * After a timer fires, sctp_current should be set to the new 223277c67f2fSkcpoon * fp where the retransmitted chunks are sent. 223377c67f2fSkcpoon */ 223477c67f2fSkcpoon fp = sctp->sctp_current; 223577c67f2fSkcpoon 223677c67f2fSkcpoon /* 223712f47623Skcpoon * Since we are retransmitting, we only need to use cwnd to determine 223812f47623Skcpoon * how much we can send as we were allowed (by peer's receive window) 223912f47623Skcpoon * to send those retransmitted chunks previously when they are first 224012f47623Skcpoon * sent. If we record how much we have retransmitted but 224112f47623Skcpoon * unacknowledged using rxt_unacked, then the amount we can now send 224212f47623Skcpoon * is equal to cwnd minus rxt_unacked. 224312f47623Skcpoon * 224412f47623Skcpoon * The field rxt_unacked is incremented when we retransmit a packet 224512f47623Skcpoon * and decremented when we got a SACK acknowledging something. And 224612f47623Skcpoon * it is reset when the retransmission timer fires as we assume that 224712f47623Skcpoon * all packets have left the network after a timeout. If this 224812f47623Skcpoon * assumption is not true, it means that after a timeout, we can 224912f47623Skcpoon * get a SACK acknowledging more than rxt_unacked (its value only 225012f47623Skcpoon * contains what is retransmitted when the timer fires). So 225112f47623Skcpoon * rxt_unacked will become very big (it is an unsiged int so going 225212f47623Skcpoon * negative means that the value is huge). This is the reason we 225312f47623Skcpoon * always send at least 1 MSS bytes. 225412f47623Skcpoon * 225512f47623Skcpoon * The reason why we do not have an accurate count is that we 225612f47623Skcpoon * only know how many packets are outstanding (using the TSN numbers). 225712f47623Skcpoon * But we do not know how many bytes those packets contain. To 225812f47623Skcpoon * have an accurate count, we need to walk through the send list. 225912f47623Skcpoon * As it is not really important to have an accurate count during 226012f47623Skcpoon * retransmission, we skip this walk to save some time. This should 226112f47623Skcpoon * not make the retransmission too aggressive to cause congestion. 226277c67f2fSkcpoon */ 226312f47623Skcpoon if (fp->cwnd <= fp->rxt_unacked) 226412f47623Skcpoon tot_wnd = fp->sfa_pmss; 226577c67f2fSkcpoon else 226612f47623Skcpoon tot_wnd = fp->cwnd - fp->rxt_unacked; 226777c67f2fSkcpoon 226877c67f2fSkcpoon /* Find the first unack'ed chunk */ 226977c67f2fSkcpoon for (meta = sctp->sctp_xmit_head; meta != NULL; meta = meta->b_next) { 227077c67f2fSkcpoon sctp_msg_hdr_t *mhdr = (sctp_msg_hdr_t *)meta->b_rptr; 227177c67f2fSkcpoon 227277c67f2fSkcpoon if (SCTP_IS_MSG_ABANDONED(meta) || 227377c67f2fSkcpoon SCTP_MSG_TO_BE_ABANDONED(meta, mhdr, sctp)) { 227477c67f2fSkcpoon continue; 227577c67f2fSkcpoon } 227677c67f2fSkcpoon 227777c67f2fSkcpoon for (mp = meta->b_cont; mp != NULL; mp = mp->b_next) { 227877c67f2fSkcpoon /* Again, this may not be possible */ 227977c67f2fSkcpoon if (!SCTP_CHUNK_ISSENT(mp)) 228077c67f2fSkcpoon return; 228177c67f2fSkcpoon sdc = (sctp_data_hdr_t *)mp->b_rptr; 228277c67f2fSkcpoon if (ntohl(sdc->sdh_tsn) == sctp->sctp_rxt_nxttsn) 228377c67f2fSkcpoon goto found_msg; 228477c67f2fSkcpoon } 228577c67f2fSkcpoon } 228677c67f2fSkcpoon 228777c67f2fSkcpoon /* Everything is abandoned... */ 228877c67f2fSkcpoon return; 228977c67f2fSkcpoon 229077c67f2fSkcpoon found_msg: 229177c67f2fSkcpoon if (!fp->timer_running) 229277c67f2fSkcpoon SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->rto); 229377c67f2fSkcpoon pkt = sctp_rexmit_packet(sctp, &meta, &mp, fp, &pkt_len); 229477c67f2fSkcpoon if (pkt == NULL) { 2295f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_ss_rexmit_failed); 229677c67f2fSkcpoon return; 229777c67f2fSkcpoon } 229877c67f2fSkcpoon if ((pkt_len > fp->sfa_pmss) && fp->isv4) { 229977c67f2fSkcpoon ipha_t *iph = (ipha_t *)pkt->b_rptr; 230077c67f2fSkcpoon 230177c67f2fSkcpoon /* 230277c67f2fSkcpoon * Path MTU is different from path we thought it would 230377c67f2fSkcpoon * be when we created chunks, or IP headers have grown. 230477c67f2fSkcpoon * Need to clear the DF bit. 230577c67f2fSkcpoon */ 230677c67f2fSkcpoon iph->ipha_fragment_offset_and_flags = 0; 230777c67f2fSkcpoon } 230877c67f2fSkcpoon sctp_set_iplen(sctp, pkt); 230977c67f2fSkcpoon sctp_add_sendq(sctp, pkt); 231077c67f2fSkcpoon 231177c67f2fSkcpoon /* Check and see if there is more chunk to be retransmitted. */ 231277c67f2fSkcpoon if (tot_wnd <= pkt_len || tot_wnd - pkt_len < fp->sfa_pmss || 231377c67f2fSkcpoon meta == NULL) 231477c67f2fSkcpoon return; 231577c67f2fSkcpoon if (mp == NULL) 231677c67f2fSkcpoon meta = meta->b_next; 231777c67f2fSkcpoon if (meta == NULL) 231877c67f2fSkcpoon return; 231977c67f2fSkcpoon 232077c67f2fSkcpoon /* Retransmit another packet if the window allows. */ 2321f4b3ec61Sdh for (tot_wnd -= pkt_len, burst = sctps->sctps_maxburst - 1; 232277c67f2fSkcpoon meta != NULL && burst > 0; meta = meta->b_next, burst--) { 232377c67f2fSkcpoon if (mp == NULL) 232477c67f2fSkcpoon mp = meta->b_cont; 232577c67f2fSkcpoon for (; mp != NULL; mp = mp->b_next) { 232677c67f2fSkcpoon /* Again, this may not be possible */ 232777c67f2fSkcpoon if (!SCTP_CHUNK_ISSENT(mp)) 232877c67f2fSkcpoon return; 232977c67f2fSkcpoon if (!SCTP_CHUNK_ISACKED(mp)) 233077c67f2fSkcpoon goto found_msg; 233177c67f2fSkcpoon } 233277c67f2fSkcpoon } 233377c67f2fSkcpoon } 2334