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 /* 23f4b3ec61Sdh * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/systm.h> 317c478bd9Sstevel@tonic-gate #include <sys/stream.h> 327c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 337c478bd9Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 347c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 357c478bd9Sstevel@tonic-gate #include <sys/socket.h> 367c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 377c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 387c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 397c478bd9Sstevel@tonic-gate #include <sys/socketvar.h> 4045916cd2Sjpk /* swilly code in sys/socketvar.h turns off DEBUG */ 4145916cd2Sjpk #ifdef __lint 4245916cd2Sjpk #define DEBUG 4345916cd2Sjpk #endif 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate #include <inet/common.h> 467c478bd9Sstevel@tonic-gate #include <inet/mi.h> 477c478bd9Sstevel@tonic-gate #include <inet/ip.h> 487c478bd9Sstevel@tonic-gate #include <inet/ip6.h> 497c478bd9Sstevel@tonic-gate #include <inet/sctp_ip.h> 507c478bd9Sstevel@tonic-gate #include <inet/ipclassifier.h> 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate /* 537c478bd9Sstevel@tonic-gate * PR-SCTP comments. 547c478bd9Sstevel@tonic-gate * 557c478bd9Sstevel@tonic-gate * A message can expire before it gets to the transmit list (i.e. it is still 567c478bd9Sstevel@tonic-gate * in the unsent list - unchunked), after it gets to the transmit list, but 577c478bd9Sstevel@tonic-gate * before transmission has actually started, or after transmission has begun. 587c478bd9Sstevel@tonic-gate * Accordingly, we check for the status of a message in sctp_chunkify() when 597c478bd9Sstevel@tonic-gate * the message is being transferred from the unsent list to the transmit list; 607c478bd9Sstevel@tonic-gate * in sctp_get_msg_to_send(), when we get the next chunk from the transmit 617c478bd9Sstevel@tonic-gate * list and in sctp_rexmit() when we get the next chunk to be (re)transmitted. 627c478bd9Sstevel@tonic-gate * When we nuke a message in sctp_chunkify(), all we need to do is take it 637c478bd9Sstevel@tonic-gate * out of the unsent list and update sctp_unsent; when a message is deemed 647c478bd9Sstevel@tonic-gate * timed-out in sctp_get_msg_to_send() we can just take it out of the transmit 657c478bd9Sstevel@tonic-gate * list, update sctp_unsent IFF transmission for the message has not yet begun 667c478bd9Sstevel@tonic-gate * (i.e. !SCTP_CHUNK_ISSENT(meta->b_cont)). However, if transmission for the 677c478bd9Sstevel@tonic-gate * message has started, then we cannot just take it out of the list, we need 687c478bd9Sstevel@tonic-gate * to send Forward TSN chunk to the peer so that the peer can clear its 697c478bd9Sstevel@tonic-gate * fragment list for this message. However, we cannot just send the Forward 707c478bd9Sstevel@tonic-gate * TSN in sctp_get_msg_to_send() because there might be unacked chunks for 717c478bd9Sstevel@tonic-gate * messages preceeding this abandoned message. So, we send a Forward TSN 727c478bd9Sstevel@tonic-gate * IFF all messages prior to this abandoned message has been SACKd, if not 737c478bd9Sstevel@tonic-gate * we defer sending the Forward TSN to sctp_cumack(), which will check for 747c478bd9Sstevel@tonic-gate * this condition and send the Forward TSN via sctp_check_abandoned_msg(). In 757c478bd9Sstevel@tonic-gate * sctp_rexmit() when we check for retransmissions, we need to determine if 767c478bd9Sstevel@tonic-gate * the advanced peer ack point can be moved ahead, and if so, send a Forward 777c478bd9Sstevel@tonic-gate * TSN to the peer instead of retransmitting the chunk. Note that when 787c478bd9Sstevel@tonic-gate * we send a Forward TSN for a message, there may be yet unsent chunks for 797c478bd9Sstevel@tonic-gate * this message; we need to mark all such chunks as abandoned, so that 807c478bd9Sstevel@tonic-gate * sctp_cumack() can take the message out of the transmit list, additionally 817c478bd9Sstevel@tonic-gate * sctp_unsent need to be adjusted. Whenever sctp_unsent is updated (i.e. 827c478bd9Sstevel@tonic-gate * decremented when a message/chunk is deemed abandoned), sockfs needs to 837c478bd9Sstevel@tonic-gate * be notified so that it can adjust its idea of the queued message. 847c478bd9Sstevel@tonic-gate */ 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate #include "sctp_impl.h" 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate static struct kmem_cache *sctp_kmem_ftsn_set_cache; 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate #ifdef DEBUG 917c478bd9Sstevel@tonic-gate static boolean_t sctp_verify_chain(mblk_t *, mblk_t *); 927c478bd9Sstevel@tonic-gate #endif 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate /* 957c478bd9Sstevel@tonic-gate * Called to allocate a header mblk when sending data to SCTP. 967c478bd9Sstevel@tonic-gate * Data will follow in b_cont of this mblk. 977c478bd9Sstevel@tonic-gate */ 987c478bd9Sstevel@tonic-gate mblk_t * 997c478bd9Sstevel@tonic-gate sctp_alloc_hdr(const char *name, int nlen, const char *control, int clen, 1007c478bd9Sstevel@tonic-gate int flags) 1017c478bd9Sstevel@tonic-gate { 1027c478bd9Sstevel@tonic-gate mblk_t *mp; 1037c478bd9Sstevel@tonic-gate struct T_unitdata_req *tudr; 1047c478bd9Sstevel@tonic-gate size_t size; 1057c478bd9Sstevel@tonic-gate int error; 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate size = sizeof (*tudr) + _TPI_ALIGN_TOPT(nlen) + clen; 1087c478bd9Sstevel@tonic-gate size = MAX(size, sizeof (sctp_msg_hdr_t)); 1097c478bd9Sstevel@tonic-gate if (flags & SCTP_CAN_BLOCK) { 1107c478bd9Sstevel@tonic-gate mp = allocb_wait(size, BPRI_MED, 0, &error); 1117c478bd9Sstevel@tonic-gate } else { 1127c478bd9Sstevel@tonic-gate mp = allocb(size, BPRI_MED); 1137c478bd9Sstevel@tonic-gate } 1147c478bd9Sstevel@tonic-gate if (mp) { 1157c478bd9Sstevel@tonic-gate tudr = (struct T_unitdata_req *)mp->b_rptr; 1167c478bd9Sstevel@tonic-gate tudr->PRIM_type = T_UNITDATA_REQ; 1177c478bd9Sstevel@tonic-gate tudr->DEST_length = nlen; 1187c478bd9Sstevel@tonic-gate tudr->DEST_offset = sizeof (*tudr); 1197c478bd9Sstevel@tonic-gate tudr->OPT_length = clen; 1207c478bd9Sstevel@tonic-gate tudr->OPT_offset = (t_scalar_t)(sizeof (*tudr) + 1217c478bd9Sstevel@tonic-gate _TPI_ALIGN_TOPT(nlen)); 1227c478bd9Sstevel@tonic-gate if (nlen > 0) 1237c478bd9Sstevel@tonic-gate bcopy(name, tudr + 1, nlen); 1247c478bd9Sstevel@tonic-gate if (clen > 0) 1257c478bd9Sstevel@tonic-gate bcopy(control, (char *)tudr + tudr->OPT_offset, clen); 1267c478bd9Sstevel@tonic-gate mp->b_wptr += (tudr ->OPT_offset + clen); 1277c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO; 1287c478bd9Sstevel@tonic-gate } 1297c478bd9Sstevel@tonic-gate return (mp); 1307c478bd9Sstevel@tonic-gate } 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate /*ARGSUSED2*/ 1337c478bd9Sstevel@tonic-gate int 1347c478bd9Sstevel@tonic-gate sctp_sendmsg(sctp_t *sctp, mblk_t *mp, int flags) 1357c478bd9Sstevel@tonic-gate { 1367c478bd9Sstevel@tonic-gate sctp_faddr_t *fp = NULL; 1377c478bd9Sstevel@tonic-gate struct T_unitdata_req *tudr; 1387c478bd9Sstevel@tonic-gate int error = 0; 1397c478bd9Sstevel@tonic-gate mblk_t *mproto = mp; 1407c478bd9Sstevel@tonic-gate in6_addr_t *addr; 1417c478bd9Sstevel@tonic-gate in6_addr_t tmpaddr; 1427c478bd9Sstevel@tonic-gate uint16_t sid = sctp->sctp_def_stream; 1437c478bd9Sstevel@tonic-gate uint32_t ppid = sctp->sctp_def_ppid; 1447c478bd9Sstevel@tonic-gate uint32_t context = sctp->sctp_def_context; 1457c478bd9Sstevel@tonic-gate uint16_t msg_flags = sctp->sctp_def_flags; 1467c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *sctp_msg_hdr; 1477c478bd9Sstevel@tonic-gate uint32_t msg_len = 0; 1487c478bd9Sstevel@tonic-gate uint32_t timetolive = sctp->sctp_def_timetolive; 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate ASSERT(DB_TYPE(mproto) == M_PROTO); 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate mp = mp->b_cont; 1537c478bd9Sstevel@tonic-gate ASSERT(mp == NULL || DB_TYPE(mp) == M_DATA); 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate tudr = (struct T_unitdata_req *)mproto->b_rptr; 1567c478bd9Sstevel@tonic-gate ASSERT(tudr->PRIM_type == T_UNITDATA_REQ); 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate /* Get destination address, if specified */ 1597c478bd9Sstevel@tonic-gate if (tudr->DEST_length > 0) { 1607c478bd9Sstevel@tonic-gate sin_t *sin; 1617c478bd9Sstevel@tonic-gate sin6_t *sin6; 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *) 1647c478bd9Sstevel@tonic-gate (mproto->b_rptr + tudr->DEST_offset); 1657c478bd9Sstevel@tonic-gate switch (sin->sin_family) { 1667c478bd9Sstevel@tonic-gate case AF_INET: 1677c478bd9Sstevel@tonic-gate if (tudr->DEST_length < sizeof (*sin)) { 1687c478bd9Sstevel@tonic-gate return (EINVAL); 1697c478bd9Sstevel@tonic-gate } 1707c478bd9Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, &tmpaddr); 1717c478bd9Sstevel@tonic-gate addr = &tmpaddr; 1727c478bd9Sstevel@tonic-gate break; 1737c478bd9Sstevel@tonic-gate case AF_INET6: 1747c478bd9Sstevel@tonic-gate if (tudr->DEST_length < sizeof (*sin6)) { 1757c478bd9Sstevel@tonic-gate return (EINVAL); 1767c478bd9Sstevel@tonic-gate } 1777c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *) 1787c478bd9Sstevel@tonic-gate (mproto->b_rptr + tudr->DEST_offset); 1797c478bd9Sstevel@tonic-gate addr = &sin6->sin6_addr; 1807c478bd9Sstevel@tonic-gate break; 1817c478bd9Sstevel@tonic-gate default: 1827c478bd9Sstevel@tonic-gate return (EAFNOSUPPORT); 1837c478bd9Sstevel@tonic-gate } 1847c478bd9Sstevel@tonic-gate fp = sctp_lookup_faddr(sctp, addr); 1857c478bd9Sstevel@tonic-gate if (fp == NULL) { 1867c478bd9Sstevel@tonic-gate return (EINVAL); 1877c478bd9Sstevel@tonic-gate } 1887c478bd9Sstevel@tonic-gate } 1897c478bd9Sstevel@tonic-gate /* Ancillary Data? */ 1907c478bd9Sstevel@tonic-gate if (tudr->OPT_length > 0) { 1917c478bd9Sstevel@tonic-gate struct cmsghdr *cmsg; 1927c478bd9Sstevel@tonic-gate char *cend; 1937c478bd9Sstevel@tonic-gate struct sctp_sndrcvinfo *sndrcv; 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate cmsg = (struct cmsghdr *)(mproto->b_rptr + tudr->OPT_offset); 1967c478bd9Sstevel@tonic-gate cend = ((char *)cmsg + tudr->OPT_length); 1977c478bd9Sstevel@tonic-gate ASSERT(cend <= (char *)mproto->b_wptr); 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate for (;;) { 2007c478bd9Sstevel@tonic-gate if ((char *)(cmsg + 1) > cend || 2017c478bd9Sstevel@tonic-gate ((char *)cmsg + cmsg->cmsg_len) > cend) { 2027c478bd9Sstevel@tonic-gate break; 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate if ((cmsg->cmsg_level == IPPROTO_SCTP) && 2057c478bd9Sstevel@tonic-gate (cmsg->cmsg_type == SCTP_SNDRCV)) { 2067c478bd9Sstevel@tonic-gate if (cmsg->cmsg_len < 2077c478bd9Sstevel@tonic-gate (sizeof (*sndrcv) + sizeof (*cmsg))) { 2087c478bd9Sstevel@tonic-gate return (EINVAL); 2097c478bd9Sstevel@tonic-gate } 2107c478bd9Sstevel@tonic-gate sndrcv = (struct sctp_sndrcvinfo *)(cmsg + 1); 2117c478bd9Sstevel@tonic-gate sid = sndrcv->sinfo_stream; 2127c478bd9Sstevel@tonic-gate msg_flags = sndrcv->sinfo_flags; 2137c478bd9Sstevel@tonic-gate ppid = sndrcv->sinfo_ppid; 2147c478bd9Sstevel@tonic-gate context = sndrcv->sinfo_context; 2157c478bd9Sstevel@tonic-gate timetolive = sndrcv->sinfo_timetolive; 2167c478bd9Sstevel@tonic-gate break; 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate if (cmsg->cmsg_len > 0) 2197c478bd9Sstevel@tonic-gate cmsg = CMSG_NEXT(cmsg); 2207c478bd9Sstevel@tonic-gate else 2217c478bd9Sstevel@tonic-gate break; 2227c478bd9Sstevel@tonic-gate } 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate if (msg_flags & MSG_ABORT) { 2257c478bd9Sstevel@tonic-gate if (mp && mp->b_cont) { 2267c478bd9Sstevel@tonic-gate mblk_t *pump = msgpullup(mp, -1); 2277c478bd9Sstevel@tonic-gate if (!pump) { 2287c478bd9Sstevel@tonic-gate return (ENOMEM); 2297c478bd9Sstevel@tonic-gate } 2307c478bd9Sstevel@tonic-gate freemsg(mp); 2317c478bd9Sstevel@tonic-gate mp = pump; 2327c478bd9Sstevel@tonic-gate mproto->b_cont = mp; 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate RUN_SCTP(sctp); 2357c478bd9Sstevel@tonic-gate sctp_user_abort(sctp, mp, B_TRUE); 236c9da23f8Skcpoon sctp_assoc_event(sctp, SCTP_COMM_LOST, 0, NULL); 2377c478bd9Sstevel@tonic-gate sctp_clean_death(sctp, ECONNRESET); 2387c478bd9Sstevel@tonic-gate freemsg(mproto); 2397c478bd9Sstevel@tonic-gate goto process_sendq; 2407c478bd9Sstevel@tonic-gate } 2417c478bd9Sstevel@tonic-gate if (mp == NULL) 2427c478bd9Sstevel@tonic-gate goto done; 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate RUN_SCTP(sctp); 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate /* Reject any new data requests if we are shutting down */ 247b34b8d1aSkcpoon if (sctp->sctp_state > SCTPS_ESTABLISHED || 248b34b8d1aSkcpoon (sctp->sctp_connp->conn_state_flags & CONN_CLOSING)) { 2497c478bd9Sstevel@tonic-gate error = EPIPE; 2507c478bd9Sstevel@tonic-gate goto unlock_done; 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate /* Re-use the mproto to store relevant info. */ 2547c478bd9Sstevel@tonic-gate ASSERT(MBLKSIZE(mproto) >= sizeof (*sctp_msg_hdr)); 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate mproto->b_rptr = mproto->b_datap->db_base; 2577c478bd9Sstevel@tonic-gate mproto->b_wptr = mproto->b_rptr + sizeof (*sctp_msg_hdr); 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate sctp_msg_hdr = (sctp_msg_hdr_t *)mproto->b_rptr; 2607c478bd9Sstevel@tonic-gate bzero(sctp_msg_hdr, sizeof (*sctp_msg_hdr)); 2617c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_context = context; 2627c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_sid = sid; 2637c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_ppid = ppid; 2647c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_flags = msg_flags; 2657c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_ttl = MSEC_TO_TICK(timetolive); 2667c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_tob = lbolt64; 2677c478bd9Sstevel@tonic-gate for (; mp != NULL; mp = mp->b_cont) 2687c478bd9Sstevel@tonic-gate msg_len += MBLKL(mp); 2697c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_msglen = msg_len; 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate /* User requested specific destination */ 2727c478bd9Sstevel@tonic-gate SCTP_SET_CHUNK_DEST(mproto, fp); 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate if (sctp->sctp_state >= SCTPS_COOKIE_ECHOED && 2757c478bd9Sstevel@tonic-gate sid >= sctp->sctp_num_ostr) { 2767c478bd9Sstevel@tonic-gate /* Send sendfail event */ 2777c478bd9Sstevel@tonic-gate sctp_sendfail_event(sctp, dupmsg(mproto), SCTP_ERR_BAD_SID, 2787c478bd9Sstevel@tonic-gate B_FALSE); 2797c478bd9Sstevel@tonic-gate error = EINVAL; 2807c478bd9Sstevel@tonic-gate goto unlock_done; 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate /* no data */ 2847c478bd9Sstevel@tonic-gate if (msg_len == 0) { 2857c478bd9Sstevel@tonic-gate sctp_sendfail_event(sctp, dupmsg(mproto), 2867c478bd9Sstevel@tonic-gate SCTP_ERR_NO_USR_DATA, B_FALSE); 2877c478bd9Sstevel@tonic-gate error = EINVAL; 2887c478bd9Sstevel@tonic-gate goto unlock_done; 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate /* Add it to the unsent list */ 2927c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_unsent == NULL) { 2937c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent = sctp->sctp_xmit_unsent_tail = mproto; 2947c478bd9Sstevel@tonic-gate } else { 2957c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent_tail->b_next = mproto; 2967c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent_tail = mproto; 2977c478bd9Sstevel@tonic-gate } 2987c478bd9Sstevel@tonic-gate sctp->sctp_unsent += msg_len; 2997c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_msgcount); 3007c478bd9Sstevel@tonic-gate if (sctp->sctp_state == SCTPS_ESTABLISHED) 30112f47623Skcpoon sctp_output(sctp, UINT_MAX); 3027c478bd9Sstevel@tonic-gate process_sendq: 3037c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 3047c478bd9Sstevel@tonic-gate sctp_process_sendq(sctp); 3057c478bd9Sstevel@tonic-gate return (0); 3067c478bd9Sstevel@tonic-gate unlock_done: 3077c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 3087c478bd9Sstevel@tonic-gate done: 3097c478bd9Sstevel@tonic-gate return (error); 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate void 3137c478bd9Sstevel@tonic-gate sctp_chunkify(sctp_t *sctp, int first_len, int bytes_to_send) 3147c478bd9Sstevel@tonic-gate { 3157c478bd9Sstevel@tonic-gate mblk_t *mp; 3167c478bd9Sstevel@tonic-gate mblk_t *chunk_mp; 3177c478bd9Sstevel@tonic-gate mblk_t *chunk_head; 3187c478bd9Sstevel@tonic-gate mblk_t *chunk_hdr; 3197c478bd9Sstevel@tonic-gate mblk_t *chunk_tail = NULL; 3207c478bd9Sstevel@tonic-gate int count; 3217c478bd9Sstevel@tonic-gate int chunksize; 3227c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 3237c478bd9Sstevel@tonic-gate mblk_t *mdblk = sctp->sctp_xmit_unsent; 3247c478bd9Sstevel@tonic-gate sctp_faddr_t *fp; 3257c478bd9Sstevel@tonic-gate sctp_faddr_t *fp1; 3267c478bd9Sstevel@tonic-gate size_t xtralen; 3277c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *msg_hdr; 328f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate fp = SCTP_CHUNK_DEST(mdblk); 3317c478bd9Sstevel@tonic-gate if (fp == NULL) 3327c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 3337c478bd9Sstevel@tonic-gate if (fp->isv4) 334f4b3ec61Sdh xtralen = sctp->sctp_hdr_len + sctps->sctps_wroff_xtra + 335f4b3ec61Sdh sizeof (*sdc); 3367c478bd9Sstevel@tonic-gate else 337f4b3ec61Sdh xtralen = sctp->sctp_hdr6_len + sctps->sctps_wroff_xtra + 338f4b3ec61Sdh sizeof (*sdc); 3397c478bd9Sstevel@tonic-gate count = chunksize = first_len - sizeof (*sdc); 3407c478bd9Sstevel@tonic-gate nextmsg: 3417c478bd9Sstevel@tonic-gate chunk_mp = mdblk->b_cont; 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate /* 3447c478bd9Sstevel@tonic-gate * If this partially chunked, we ignore the first_len for now 3457c478bd9Sstevel@tonic-gate * and use the one already present. For the unchunked bits, we 3467c478bd9Sstevel@tonic-gate * use the length of the last chunk. 3477c478bd9Sstevel@tonic-gate */ 3487c478bd9Sstevel@tonic-gate if (SCTP_IS_MSG_CHUNKED(mdblk)) { 3497c478bd9Sstevel@tonic-gate int chunk_len; 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate ASSERT(chunk_mp->b_next != NULL); 3527c478bd9Sstevel@tonic-gate mdblk->b_cont = chunk_mp->b_next; 3537c478bd9Sstevel@tonic-gate chunk_mp->b_next = NULL; 3547c478bd9Sstevel@tonic-gate SCTP_MSG_CLEAR_CHUNKED(mdblk); 3557c478bd9Sstevel@tonic-gate mp = mdblk->b_cont; 3567c478bd9Sstevel@tonic-gate while (mp->b_next != NULL) 3577c478bd9Sstevel@tonic-gate mp = mp->b_next; 3587c478bd9Sstevel@tonic-gate chunk_len = ntohs(((sctp_data_hdr_t *)mp->b_rptr)->sdh_len); 3597c478bd9Sstevel@tonic-gate if (fp->sfa_pmss - chunk_len > sizeof (*sdc)) 3607c478bd9Sstevel@tonic-gate count = chunksize = fp->sfa_pmss - chunk_len; 3617c478bd9Sstevel@tonic-gate else 3627c478bd9Sstevel@tonic-gate count = chunksize = fp->sfa_pmss; 3637c478bd9Sstevel@tonic-gate count = chunksize = count - sizeof (*sdc); 3647c478bd9Sstevel@tonic-gate } else { 3657c478bd9Sstevel@tonic-gate msg_hdr = (sctp_msg_hdr_t *)mdblk->b_rptr; 3667c478bd9Sstevel@tonic-gate if (SCTP_MSG_TO_BE_ABANDONED(mdblk, msg_hdr, sctp)) { 3677c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent = mdblk->b_next; 3687c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_unsent == NULL) 3697c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent_tail = NULL; 3707c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_unsent >= msg_hdr->smh_msglen); 3717c478bd9Sstevel@tonic-gate sctp->sctp_unsent -= msg_hdr->smh_msglen; 3727c478bd9Sstevel@tonic-gate mdblk->b_next = NULL; 3737c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_prsctpdrop); 3747c478bd9Sstevel@tonic-gate /* 3757c478bd9Sstevel@tonic-gate * Update ULP the amount of queued data, which is 3767c478bd9Sstevel@tonic-gate * sent-unack'ed + unsent. 3777c478bd9Sstevel@tonic-gate */ 3787c478bd9Sstevel@tonic-gate if (!SCTP_IS_DETACHED(sctp)) { 3797c478bd9Sstevel@tonic-gate sctp->sctp_ulp_xmitted(sctp->sctp_ulpd, 3807c478bd9Sstevel@tonic-gate sctp->sctp_unacked + sctp->sctp_unsent); 3817c478bd9Sstevel@tonic-gate } 3827c478bd9Sstevel@tonic-gate sctp_sendfail_event(sctp, mdblk, 0, B_FALSE); 3837c478bd9Sstevel@tonic-gate goto try_next; 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate mdblk->b_cont = NULL; 3867c478bd9Sstevel@tonic-gate } 3877c478bd9Sstevel@tonic-gate msg_hdr = (sctp_msg_hdr_t *)mdblk->b_rptr; 3887c478bd9Sstevel@tonic-gate nextchunk: 3897c478bd9Sstevel@tonic-gate chunk_head = chunk_mp; 3907c478bd9Sstevel@tonic-gate chunk_tail = NULL; 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate /* Skip as many mblk's as we need */ 3937c478bd9Sstevel@tonic-gate while (chunk_mp != NULL && ((count - MBLKL(chunk_mp)) >= 0)) { 3947c478bd9Sstevel@tonic-gate count -= MBLKL(chunk_mp); 3957c478bd9Sstevel@tonic-gate chunk_tail = chunk_mp; 3967c478bd9Sstevel@tonic-gate chunk_mp = chunk_mp->b_cont; 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate /* Split the chain, if needed */ 3997c478bd9Sstevel@tonic-gate if (chunk_mp != NULL) { 4007c478bd9Sstevel@tonic-gate if (count > 0) { 4017c478bd9Sstevel@tonic-gate mblk_t *split_mp = dupb(chunk_mp); 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate if (split_mp == NULL) { 4047c478bd9Sstevel@tonic-gate if (mdblk->b_cont == NULL) { 4057c478bd9Sstevel@tonic-gate mdblk->b_cont = chunk_head; 4067c478bd9Sstevel@tonic-gate } else { 4077c478bd9Sstevel@tonic-gate SCTP_MSG_SET_CHUNKED(mdblk); 4087c478bd9Sstevel@tonic-gate ASSERT(chunk_head->b_next == NULL); 4097c478bd9Sstevel@tonic-gate chunk_head->b_next = mdblk->b_cont; 4107c478bd9Sstevel@tonic-gate mdblk->b_cont = chunk_head; 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate return; 4137c478bd9Sstevel@tonic-gate } 4147c478bd9Sstevel@tonic-gate if (chunk_tail != NULL) { 4157c478bd9Sstevel@tonic-gate chunk_tail->b_cont = split_mp; 4167c478bd9Sstevel@tonic-gate chunk_tail = chunk_tail->b_cont; 4177c478bd9Sstevel@tonic-gate } else { 4187c478bd9Sstevel@tonic-gate chunk_head = chunk_tail = split_mp; 4197c478bd9Sstevel@tonic-gate } 4207c478bd9Sstevel@tonic-gate chunk_tail->b_wptr = chunk_tail->b_rptr + count; 4217c478bd9Sstevel@tonic-gate chunk_mp->b_rptr = chunk_tail->b_wptr; 4227c478bd9Sstevel@tonic-gate count = 0; 4237c478bd9Sstevel@tonic-gate } else if (chunk_tail == NULL) { 4247c478bd9Sstevel@tonic-gate goto next; 4257c478bd9Sstevel@tonic-gate } else { 4267c478bd9Sstevel@tonic-gate chunk_tail->b_cont = NULL; 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate } 4297c478bd9Sstevel@tonic-gate /* Alloc chunk hdr, if needed */ 4307c478bd9Sstevel@tonic-gate if (DB_REF(chunk_head) > 1 || 4317c478bd9Sstevel@tonic-gate ((intptr_t)chunk_head->b_rptr) & (SCTP_ALIGN - 1) || 4327c478bd9Sstevel@tonic-gate MBLKHEAD(chunk_head) < sizeof (*sdc)) { 4337c478bd9Sstevel@tonic-gate if ((chunk_hdr = allocb(xtralen, BPRI_MED)) == NULL) { 4347c478bd9Sstevel@tonic-gate if (mdblk->b_cont == NULL) { 4357c478bd9Sstevel@tonic-gate if (chunk_mp != NULL) 4367c478bd9Sstevel@tonic-gate linkb(chunk_head, chunk_mp); 4377c478bd9Sstevel@tonic-gate mdblk->b_cont = chunk_head; 4387c478bd9Sstevel@tonic-gate } else { 4397c478bd9Sstevel@tonic-gate SCTP_MSG_SET_CHUNKED(mdblk); 4407c478bd9Sstevel@tonic-gate if (chunk_mp != NULL) 4417c478bd9Sstevel@tonic-gate linkb(chunk_head, chunk_mp); 4427c478bd9Sstevel@tonic-gate ASSERT(chunk_head->b_next == NULL); 4437c478bd9Sstevel@tonic-gate chunk_head->b_next = mdblk->b_cont; 4447c478bd9Sstevel@tonic-gate mdblk->b_cont = chunk_head; 4457c478bd9Sstevel@tonic-gate } 4467c478bd9Sstevel@tonic-gate return; 4477c478bd9Sstevel@tonic-gate } 4487c478bd9Sstevel@tonic-gate chunk_hdr->b_rptr += xtralen - sizeof (*sdc); 4497c478bd9Sstevel@tonic-gate chunk_hdr->b_wptr = chunk_hdr->b_rptr + sizeof (*sdc); 4507c478bd9Sstevel@tonic-gate chunk_hdr->b_cont = chunk_head; 4517c478bd9Sstevel@tonic-gate } else { 4527c478bd9Sstevel@tonic-gate chunk_hdr = chunk_head; 4537c478bd9Sstevel@tonic-gate chunk_hdr->b_rptr -= sizeof (*sdc); 4547c478bd9Sstevel@tonic-gate } 4557c478bd9Sstevel@tonic-gate ASSERT(chunk_hdr->b_datap->db_ref == 1); 4567c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)chunk_hdr->b_rptr; 4577c478bd9Sstevel@tonic-gate sdc->sdh_id = CHUNK_DATA; 4587c478bd9Sstevel@tonic-gate sdc->sdh_flags = 0; 4597c478bd9Sstevel@tonic-gate sdc->sdh_len = htons(sizeof (*sdc) + chunksize - count); 4607c478bd9Sstevel@tonic-gate ASSERT(sdc->sdh_len); 4617c478bd9Sstevel@tonic-gate sdc->sdh_sid = htons(msg_hdr->smh_sid); 4627c478bd9Sstevel@tonic-gate /* 4637c478bd9Sstevel@tonic-gate * We defer assigning the SSN just before sending the chunk, else 4647c478bd9Sstevel@tonic-gate * if we drop the chunk in sctp_get_msg_to_send(), we would need 4657c478bd9Sstevel@tonic-gate * to send a Forward TSN to let the peer know. Some more comments 4667c478bd9Sstevel@tonic-gate * about this in sctp_impl.h for SCTP_CHUNK_SENT. 4677c478bd9Sstevel@tonic-gate */ 4687c478bd9Sstevel@tonic-gate sdc->sdh_payload_id = msg_hdr->smh_ppid; 4697c478bd9Sstevel@tonic-gate 4707c478bd9Sstevel@tonic-gate if (mdblk->b_cont == NULL) { 4717c478bd9Sstevel@tonic-gate mdblk->b_cont = chunk_hdr; 4727c478bd9Sstevel@tonic-gate SCTP_DATA_SET_BBIT(sdc); 4737c478bd9Sstevel@tonic-gate } else { 4747c478bd9Sstevel@tonic-gate mp = mdblk->b_cont; 4757c478bd9Sstevel@tonic-gate while (mp->b_next != NULL) 4767c478bd9Sstevel@tonic-gate mp = mp->b_next; 4777c478bd9Sstevel@tonic-gate mp->b_next = chunk_hdr; 4787c478bd9Sstevel@tonic-gate } 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate bytes_to_send -= (chunksize - count); 4817c478bd9Sstevel@tonic-gate if (chunk_mp != NULL) { 4827c478bd9Sstevel@tonic-gate next: 4837c478bd9Sstevel@tonic-gate count = chunksize = fp->sfa_pmss - sizeof (*sdc); 4847c478bd9Sstevel@tonic-gate goto nextchunk; 4857c478bd9Sstevel@tonic-gate } 4867c478bd9Sstevel@tonic-gate SCTP_DATA_SET_EBIT(sdc); 4877c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent = mdblk->b_next; 4887c478bd9Sstevel@tonic-gate if (mdblk->b_next == NULL) { 4897c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent_tail = NULL; 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate mdblk->b_next = NULL; 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_tail == NULL) { 4947c478bd9Sstevel@tonic-gate sctp->sctp_xmit_head = sctp->sctp_xmit_tail = mdblk; 4957c478bd9Sstevel@tonic-gate } else { 4967c478bd9Sstevel@tonic-gate mp = sctp->sctp_xmit_tail; 4977c478bd9Sstevel@tonic-gate while (mp->b_next != NULL) 4987c478bd9Sstevel@tonic-gate mp = mp->b_next; 4997c478bd9Sstevel@tonic-gate mp->b_next = mdblk; 5007c478bd9Sstevel@tonic-gate mdblk->b_prev = mp; 5017c478bd9Sstevel@tonic-gate } 5027c478bd9Sstevel@tonic-gate try_next: 5037c478bd9Sstevel@tonic-gate if (bytes_to_send > 0 && sctp->sctp_xmit_unsent != NULL) { 5047c478bd9Sstevel@tonic-gate mdblk = sctp->sctp_xmit_unsent; 5057c478bd9Sstevel@tonic-gate fp1 = SCTP_CHUNK_DEST(mdblk); 5067c478bd9Sstevel@tonic-gate if (fp1 == NULL) 5077c478bd9Sstevel@tonic-gate fp1 = sctp->sctp_current; 5087c478bd9Sstevel@tonic-gate if (fp == fp1) { 5097c478bd9Sstevel@tonic-gate size_t len = MBLKL(mdblk->b_cont); 5107c478bd9Sstevel@tonic-gate if ((count > 0) && 5117c478bd9Sstevel@tonic-gate ((len > fp->sfa_pmss - sizeof (*sdc)) || 512b34b8d1aSkcpoon (len <= count))) { 5137c478bd9Sstevel@tonic-gate count -= sizeof (*sdc); 5147c478bd9Sstevel@tonic-gate count = chunksize = count - (count & 0x3); 5157c478bd9Sstevel@tonic-gate } else { 5167c478bd9Sstevel@tonic-gate count = chunksize = fp->sfa_pmss - 5177c478bd9Sstevel@tonic-gate sizeof (*sdc); 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate } else { 5207c478bd9Sstevel@tonic-gate if (fp1->isv4) 5217c478bd9Sstevel@tonic-gate xtralen = sctp->sctp_hdr_len; 5227c478bd9Sstevel@tonic-gate else 5237c478bd9Sstevel@tonic-gate xtralen = sctp->sctp_hdr6_len; 524f4b3ec61Sdh xtralen += sctps->sctps_wroff_xtra + sizeof (*sdc); 5257c478bd9Sstevel@tonic-gate count = chunksize = fp1->sfa_pmss - sizeof (*sdc); 5267c478bd9Sstevel@tonic-gate fp = fp1; 5277c478bd9Sstevel@tonic-gate } 5287c478bd9Sstevel@tonic-gate goto nextmsg; 5297c478bd9Sstevel@tonic-gate } 5307c478bd9Sstevel@tonic-gate } 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate void 5337c478bd9Sstevel@tonic-gate sctp_free_msg(mblk_t *ump) 5347c478bd9Sstevel@tonic-gate { 5357c478bd9Sstevel@tonic-gate mblk_t *mp, *nmp; 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate for (mp = ump->b_cont; mp; mp = nmp) { 5387c478bd9Sstevel@tonic-gate nmp = mp->b_next; 5397c478bd9Sstevel@tonic-gate mp->b_next = mp->b_prev = NULL; 5407c478bd9Sstevel@tonic-gate freemsg(mp); 5417c478bd9Sstevel@tonic-gate } 5427c478bd9Sstevel@tonic-gate ASSERT(!ump->b_prev); 5437c478bd9Sstevel@tonic-gate ump->b_next = NULL; 5447c478bd9Sstevel@tonic-gate freeb(ump); 5457c478bd9Sstevel@tonic-gate } 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate mblk_t * 548df19b344Svi sctp_add_proto_hdr(sctp_t *sctp, sctp_faddr_t *fp, mblk_t *mp, int sacklen, 549df19b344Svi int *error) 5507c478bd9Sstevel@tonic-gate { 5517c478bd9Sstevel@tonic-gate int hdrlen; 5527c478bd9Sstevel@tonic-gate char *hdr; 5537c478bd9Sstevel@tonic-gate int isv4 = fp->isv4; 554f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 5557c478bd9Sstevel@tonic-gate 556df19b344Svi if (error != NULL) 557df19b344Svi *error = 0; 558df19b344Svi 5597c478bd9Sstevel@tonic-gate if (isv4) { 5607c478bd9Sstevel@tonic-gate hdrlen = sctp->sctp_hdr_len; 5617c478bd9Sstevel@tonic-gate hdr = sctp->sctp_iphc; 5627c478bd9Sstevel@tonic-gate } else { 5637c478bd9Sstevel@tonic-gate hdrlen = sctp->sctp_hdr6_len; 5647c478bd9Sstevel@tonic-gate hdr = sctp->sctp_iphc6; 5657c478bd9Sstevel@tonic-gate } 566df19b344Svi /* 567df19b344Svi * A null fp->ire could mean that the address is 'down'. Similarly, 568df19b344Svi * it is possible that the address went down, we tried to send an 569df19b344Svi * heartbeat and ended up setting fp->saddr as unspec because we 57077c67f2fSkcpoon * didn't have any usable source address. In either case 57177c67f2fSkcpoon * sctp_get_ire() will try find an IRE, if available, and set 57277c67f2fSkcpoon * the source address, if needed. If we still don't have any 573df19b344Svi * usable source address, fp->state will be SCTP_FADDRS_UNREACH and 574df19b344Svi * we return EHOSTUNREACH. 575df19b344Svi */ 576df19b344Svi if (fp->ire == NULL || SCTP_IS_ADDR_UNSPEC(fp->isv4, fp->saddr)) { 57777c67f2fSkcpoon sctp_get_ire(sctp, fp); 578df19b344Svi if (fp->state == SCTP_FADDRS_UNREACH) { 579df19b344Svi if (error != NULL) 580df19b344Svi *error = EHOSTUNREACH; 581df19b344Svi return (NULL); 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate } 5847c478bd9Sstevel@tonic-gate /* Copy in IP header. */ 5857c478bd9Sstevel@tonic-gate if ((mp->b_rptr - mp->b_datap->db_base) < 586f4b3ec61Sdh (sctps->sctps_wroff_xtra + hdrlen + sacklen) || DB_REF(mp) > 2 || 58777c67f2fSkcpoon !IS_P2ALIGNED(DB_BASE(mp), sizeof (ire_t *))) { 5887c478bd9Sstevel@tonic-gate mblk_t *nmp; 58977c67f2fSkcpoon 5907c478bd9Sstevel@tonic-gate /* 5917c478bd9Sstevel@tonic-gate * This can happen if IP headers are adjusted after 5927c478bd9Sstevel@tonic-gate * data was moved into chunks, or during retransmission, 5937c478bd9Sstevel@tonic-gate * or things like snoop is running. 5947c478bd9Sstevel@tonic-gate */ 595f4b3ec61Sdh nmp = allocb_cred(sctps->sctps_wroff_xtra + hdrlen + sacklen, 59645916cd2Sjpk CONN_CRED(sctp->sctp_connp)); 5977c478bd9Sstevel@tonic-gate if (nmp == NULL) { 598df19b344Svi if (error != NULL) 599df19b344Svi *error = ENOMEM; 6007c478bd9Sstevel@tonic-gate return (NULL); 6017c478bd9Sstevel@tonic-gate } 602f4b3ec61Sdh nmp->b_rptr += sctps->sctps_wroff_xtra; 6037c478bd9Sstevel@tonic-gate nmp->b_wptr = nmp->b_rptr + hdrlen + sacklen; 6047c478bd9Sstevel@tonic-gate nmp->b_cont = mp; 6057c478bd9Sstevel@tonic-gate mp = nmp; 6067c478bd9Sstevel@tonic-gate } else { 6077c478bd9Sstevel@tonic-gate mp->b_rptr -= (hdrlen + sacklen); 60845916cd2Sjpk mblk_setcred(mp, CONN_CRED(sctp->sctp_connp)); 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate bcopy(hdr, mp->b_rptr, hdrlen); 6117c478bd9Sstevel@tonic-gate if (sacklen) { 6127c478bd9Sstevel@tonic-gate sctp_fill_sack(sctp, mp->b_rptr + hdrlen, sacklen); 6137c478bd9Sstevel@tonic-gate } 6147c478bd9Sstevel@tonic-gate if (fp != sctp->sctp_current) { 6157c478bd9Sstevel@tonic-gate /* change addresses in header */ 6167c478bd9Sstevel@tonic-gate if (isv4) { 6177c478bd9Sstevel@tonic-gate ipha_t *iph = (ipha_t *)mp->b_rptr; 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_IPADDR(&fp->faddr, iph->ipha_dst); 6207c478bd9Sstevel@tonic-gate if (!IN6_IS_ADDR_V4MAPPED_ANY(&fp->saddr)) { 6217c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_IPADDR(&fp->saddr, 6227c478bd9Sstevel@tonic-gate iph->ipha_src); 6237c478bd9Sstevel@tonic-gate } else if (sctp->sctp_bound_to_all) { 6247c478bd9Sstevel@tonic-gate iph->ipha_src = INADDR_ANY; 6257c478bd9Sstevel@tonic-gate } 6267c478bd9Sstevel@tonic-gate } else { 6277c478bd9Sstevel@tonic-gate ((ip6_t *)(mp->b_rptr))->ip6_dst = fp->faddr; 6287c478bd9Sstevel@tonic-gate if (!IN6_IS_ADDR_UNSPECIFIED(&fp->saddr)) { 6297c478bd9Sstevel@tonic-gate ((ip6_t *)(mp->b_rptr))->ip6_src = fp->saddr; 6307c478bd9Sstevel@tonic-gate } else if (sctp->sctp_bound_to_all) { 6317c478bd9Sstevel@tonic-gate V6_SET_ZERO(((ip6_t *)(mp->b_rptr))->ip6_src); 6327c478bd9Sstevel@tonic-gate } 6337c478bd9Sstevel@tonic-gate } 6347c478bd9Sstevel@tonic-gate } 6357c478bd9Sstevel@tonic-gate /* 6367c478bd9Sstevel@tonic-gate * IP will not free this IRE if it is condemned. SCTP needs to 6377c478bd9Sstevel@tonic-gate * free it. 6387c478bd9Sstevel@tonic-gate */ 6397c478bd9Sstevel@tonic-gate if ((fp->ire != NULL) && (fp->ire->ire_marks & IRE_MARK_CONDEMNED)) { 6407c478bd9Sstevel@tonic-gate IRE_REFRELE_NOTR(fp->ire); 6417c478bd9Sstevel@tonic-gate fp->ire = NULL; 6427c478bd9Sstevel@tonic-gate } 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate /* Stash the conn and ire ptr info for IP */ 6457c478bd9Sstevel@tonic-gate SCTP_STASH_IPINFO(mp, fp->ire); 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate return (mp); 6487c478bd9Sstevel@tonic-gate } 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate /* 6517c478bd9Sstevel@tonic-gate * SCTP requires every chunk to be padded so that the total length 6527c478bd9Sstevel@tonic-gate * is a multiple of SCTP_ALIGN. This function returns a mblk with 6537c478bd9Sstevel@tonic-gate * the specified pad length. 6547c478bd9Sstevel@tonic-gate */ 6557c478bd9Sstevel@tonic-gate static mblk_t * 656*121e5416Skcpoon sctp_get_padding(sctp_t *sctp, int pad) 6577c478bd9Sstevel@tonic-gate { 6587c478bd9Sstevel@tonic-gate mblk_t *fill; 6597c478bd9Sstevel@tonic-gate 6607c478bd9Sstevel@tonic-gate ASSERT(pad < SCTP_ALIGN); 661*121e5416Skcpoon ASSERT(sctp->sctp_pad_mp != NULL); 662*121e5416Skcpoon if ((fill = dupb(sctp->sctp_pad_mp)) != NULL) { 6637c478bd9Sstevel@tonic-gate fill->b_wptr += pad; 6647c478bd9Sstevel@tonic-gate return (fill); 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate /* 6687c478bd9Sstevel@tonic-gate * The memory saving path of reusing the sctp_pad_mp 6697c478bd9Sstevel@tonic-gate * fails may be because it has been dupb() too 6707c478bd9Sstevel@tonic-gate * many times (DBLK_REFMAX). Use the memory consuming 6717c478bd9Sstevel@tonic-gate * path of allocating the pad mblk. 6727c478bd9Sstevel@tonic-gate */ 6737c478bd9Sstevel@tonic-gate if ((fill = allocb(SCTP_ALIGN, BPRI_MED)) != NULL) { 6747c478bd9Sstevel@tonic-gate /* Zero it out. SCTP_ALIGN is sizeof (int32_t) */ 6757c478bd9Sstevel@tonic-gate *(int32_t *)fill->b_rptr = 0; 6767c478bd9Sstevel@tonic-gate fill->b_wptr += pad; 6777c478bd9Sstevel@tonic-gate } 6787c478bd9Sstevel@tonic-gate return (fill); 6797c478bd9Sstevel@tonic-gate } 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate static mblk_t * 6827c478bd9Sstevel@tonic-gate sctp_find_fast_rexmit_mblks(sctp_t *sctp, int *total, sctp_faddr_t **fp) 6837c478bd9Sstevel@tonic-gate { 6847c478bd9Sstevel@tonic-gate mblk_t *meta; 6857c478bd9Sstevel@tonic-gate mblk_t *start_mp = NULL; 6867c478bd9Sstevel@tonic-gate mblk_t *end_mp = NULL; 6877c478bd9Sstevel@tonic-gate mblk_t *mp, *nmp; 6887c478bd9Sstevel@tonic-gate mblk_t *fill; 6897c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdh; 6907c478bd9Sstevel@tonic-gate int msglen; 6917c478bd9Sstevel@tonic-gate int extra; 6927c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *msg_hdr; 69377c67f2fSkcpoon sctp_faddr_t *old_fp = NULL; 69477c67f2fSkcpoon sctp_faddr_t *chunk_fp; 695f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 6967c478bd9Sstevel@tonic-gate 6977c478bd9Sstevel@tonic-gate for (meta = sctp->sctp_xmit_head; meta != NULL; meta = meta->b_next) { 6987c478bd9Sstevel@tonic-gate msg_hdr = (sctp_msg_hdr_t *)meta->b_rptr; 6997c478bd9Sstevel@tonic-gate if (SCTP_IS_MSG_ABANDONED(meta) || 7007c478bd9Sstevel@tonic-gate SCTP_MSG_TO_BE_ABANDONED(meta, msg_hdr, sctp)) { 7017c478bd9Sstevel@tonic-gate continue; 7027c478bd9Sstevel@tonic-gate } 7037c478bd9Sstevel@tonic-gate for (mp = meta->b_cont; mp != NULL; mp = mp->b_next) { 7047c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_WANT_REXMIT(mp)) { 7057c478bd9Sstevel@tonic-gate /* 7067c478bd9Sstevel@tonic-gate * Use the same peer address to do fast 70777c67f2fSkcpoon * retransmission. If the original peer 70877c67f2fSkcpoon * address is dead, switch to the current 70977c67f2fSkcpoon * one. Record the old one so that we 71077c67f2fSkcpoon * will pick the chunks sent to the old 71177c67f2fSkcpoon * one for fast retransmission. 7127c478bd9Sstevel@tonic-gate */ 71377c67f2fSkcpoon chunk_fp = SCTP_CHUNK_DEST(mp); 7147c478bd9Sstevel@tonic-gate if (*fp == NULL) { 71577c67f2fSkcpoon *fp = chunk_fp; 71677c67f2fSkcpoon if ((*fp)->state != SCTP_FADDRS_ALIVE) { 71777c67f2fSkcpoon old_fp = *fp; 7187c478bd9Sstevel@tonic-gate *fp = sctp->sctp_current; 71977c67f2fSkcpoon } 72077c67f2fSkcpoon } else if (old_fp == NULL && *fp != chunk_fp) { 72177c67f2fSkcpoon continue; 72277c67f2fSkcpoon } else if (old_fp != NULL && 72377c67f2fSkcpoon old_fp != chunk_fp) { 7247c478bd9Sstevel@tonic-gate continue; 7257c478bd9Sstevel@tonic-gate } 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate sdh = (sctp_data_hdr_t *)mp->b_rptr; 7287c478bd9Sstevel@tonic-gate msglen = ntohs(sdh->sdh_len); 7297c478bd9Sstevel@tonic-gate if ((extra = msglen & (SCTP_ALIGN - 1)) != 0) { 7307c478bd9Sstevel@tonic-gate extra = SCTP_ALIGN - extra; 7317c478bd9Sstevel@tonic-gate } 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate /* 7347c478bd9Sstevel@tonic-gate * We still return at least the first message 7357c478bd9Sstevel@tonic-gate * even if that message cannot fit in as 7367c478bd9Sstevel@tonic-gate * PMTU may have changed. 7377c478bd9Sstevel@tonic-gate */ 7387c478bd9Sstevel@tonic-gate if (*total + msglen + extra > 7397c478bd9Sstevel@tonic-gate (*fp)->sfa_pmss && start_mp != NULL) { 7407c478bd9Sstevel@tonic-gate return (start_mp); 7417c478bd9Sstevel@tonic-gate } 7427c478bd9Sstevel@tonic-gate if ((nmp = dupmsg(mp)) == NULL) 7437c478bd9Sstevel@tonic-gate return (start_mp); 7447c478bd9Sstevel@tonic-gate if (extra > 0) { 745*121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 7467c478bd9Sstevel@tonic-gate if (fill != NULL) { 7477c478bd9Sstevel@tonic-gate linkb(nmp, fill); 7487c478bd9Sstevel@tonic-gate } else { 7497c478bd9Sstevel@tonic-gate return (start_mp); 7507c478bd9Sstevel@tonic-gate } 7517c478bd9Sstevel@tonic-gate } 752f4b3ec61Sdh BUMP_MIB(&sctps->sctps_mib, sctpOutFastRetrans); 75377c67f2fSkcpoon BUMP_LOCAL(sctp->sctp_rxtchunks); 7547c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_REXMIT(mp); 7557c478bd9Sstevel@tonic-gate if (start_mp == NULL) { 7567c478bd9Sstevel@tonic-gate start_mp = nmp; 7577c478bd9Sstevel@tonic-gate } else { 7587c478bd9Sstevel@tonic-gate linkb(end_mp, nmp); 7597c478bd9Sstevel@tonic-gate } 7607c478bd9Sstevel@tonic-gate end_mp = nmp; 7617c478bd9Sstevel@tonic-gate *total += msglen + extra; 7627c478bd9Sstevel@tonic-gate dprint(2, ("sctp_find_fast_rexmit_mblks: " 7637c478bd9Sstevel@tonic-gate "tsn %x\n", sdh->sdh_tsn)); 7647c478bd9Sstevel@tonic-gate } 7657c478bd9Sstevel@tonic-gate } 7667c478bd9Sstevel@tonic-gate } 7677c478bd9Sstevel@tonic-gate /* Clear the flag as there is no more message to be fast rexmitted. */ 7687c478bd9Sstevel@tonic-gate sctp->sctp_chk_fast_rexmit = B_FALSE; 7697c478bd9Sstevel@tonic-gate return (start_mp); 7707c478bd9Sstevel@tonic-gate } 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate /* A debug function just to make sure that a mblk chain is not broken */ 7737c478bd9Sstevel@tonic-gate #ifdef DEBUG 7747c478bd9Sstevel@tonic-gate static boolean_t 7757c478bd9Sstevel@tonic-gate sctp_verify_chain(mblk_t *head, mblk_t *tail) 7767c478bd9Sstevel@tonic-gate { 7777c478bd9Sstevel@tonic-gate mblk_t *mp = head; 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate if (head == NULL || tail == NULL) 7807c478bd9Sstevel@tonic-gate return (B_TRUE); 7817c478bd9Sstevel@tonic-gate while (mp != NULL) { 7827c478bd9Sstevel@tonic-gate if (mp == tail) 7837c478bd9Sstevel@tonic-gate return (B_TRUE); 7847c478bd9Sstevel@tonic-gate mp = mp->b_next; 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate return (B_FALSE); 7877c478bd9Sstevel@tonic-gate } 7887c478bd9Sstevel@tonic-gate #endif 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate /* 7917c478bd9Sstevel@tonic-gate * Gets the next unsent chunk to transmit. Messages that are abandoned are 7927c478bd9Sstevel@tonic-gate * skipped. A message can be abandoned if it has a non-zero timetolive and 7937c478bd9Sstevel@tonic-gate * transmission has not yet started or if it is a partially reliable 7947c478bd9Sstevel@tonic-gate * message and its time is up (assuming we are PR-SCTP aware). 7957c478bd9Sstevel@tonic-gate * 'cansend' is used to determine if need to try and chunkify messages from 7967c478bd9Sstevel@tonic-gate * the unsent list, if any, and also as an input to sctp_chunkify() if so. 7977c478bd9Sstevel@tonic-gate * When called from sctp_rexmit(), we don't want to chunkify, so 'cansend' 7987c478bd9Sstevel@tonic-gate * will be set to 0. 7997c478bd9Sstevel@tonic-gate */ 8007c478bd9Sstevel@tonic-gate mblk_t * 8017c478bd9Sstevel@tonic-gate sctp_get_msg_to_send(sctp_t *sctp, mblk_t **mp, mblk_t *meta, int *error, 8027c478bd9Sstevel@tonic-gate int32_t firstseg, uint32_t cansend, sctp_faddr_t *fp) 8037c478bd9Sstevel@tonic-gate { 8047c478bd9Sstevel@tonic-gate mblk_t *mp1; 8057c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *msg_hdr; 8067c478bd9Sstevel@tonic-gate mblk_t *tmp_meta; 8077c478bd9Sstevel@tonic-gate sctp_faddr_t *fp1; 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate ASSERT(error != NULL && mp != NULL); 8107c478bd9Sstevel@tonic-gate *error = 0; 8117c478bd9Sstevel@tonic-gate 8127c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_current != NULL); 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate chunkified: 8157c478bd9Sstevel@tonic-gate while (meta != NULL) { 8167c478bd9Sstevel@tonic-gate tmp_meta = meta->b_next; 8177c478bd9Sstevel@tonic-gate msg_hdr = (sctp_msg_hdr_t *)meta->b_rptr; 8187c478bd9Sstevel@tonic-gate mp1 = meta->b_cont; 8197c478bd9Sstevel@tonic-gate if (SCTP_IS_MSG_ABANDONED(meta)) 8207c478bd9Sstevel@tonic-gate goto next_msg; 8217c478bd9Sstevel@tonic-gate if (!SCTP_MSG_TO_BE_ABANDONED(meta, msg_hdr, sctp)) { 8227c478bd9Sstevel@tonic-gate while (mp1 != NULL) { 8237c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_CANSEND(mp1)) { 8247c478bd9Sstevel@tonic-gate *mp = mp1; 8257c478bd9Sstevel@tonic-gate #ifdef DEBUG 8267c478bd9Sstevel@tonic-gate ASSERT(sctp_verify_chain( 8277c478bd9Sstevel@tonic-gate sctp->sctp_xmit_head, meta)); 8287c478bd9Sstevel@tonic-gate #endif 8297c478bd9Sstevel@tonic-gate return (meta); 8307c478bd9Sstevel@tonic-gate } 8317c478bd9Sstevel@tonic-gate mp1 = mp1->b_next; 8327c478bd9Sstevel@tonic-gate } 8337c478bd9Sstevel@tonic-gate goto next_msg; 8347c478bd9Sstevel@tonic-gate } 8357c478bd9Sstevel@tonic-gate /* 8367c478bd9Sstevel@tonic-gate * If we come here and the first chunk is sent, then we 8377c478bd9Sstevel@tonic-gate * we are PR-SCTP aware, in which case if the cumulative 8387c478bd9Sstevel@tonic-gate * TSN has moved upto or beyond the first chunk (which 8397c478bd9Sstevel@tonic-gate * means all the previous messages have been cumulative 8407c478bd9Sstevel@tonic-gate * SACK'd), then we send a Forward TSN with the last 8417c478bd9Sstevel@tonic-gate * chunk that was sent in this message. If we can't send 8427c478bd9Sstevel@tonic-gate * a Forward TSN because previous non-abandoned messages 8437c478bd9Sstevel@tonic-gate * have not been acked then we will defer the Forward TSN 8447c478bd9Sstevel@tonic-gate * to sctp_rexmit() or sctp_cumack(). 8457c478bd9Sstevel@tonic-gate */ 8467c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_ISSENT(mp1)) { 8477c478bd9Sstevel@tonic-gate *error = sctp_check_abandoned_msg(sctp, meta); 8487c478bd9Sstevel@tonic-gate if (*error != 0) { 8497c478bd9Sstevel@tonic-gate #ifdef DEBUG 8507c478bd9Sstevel@tonic-gate ASSERT(sctp_verify_chain(sctp->sctp_xmit_head, 8517c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail)); 8527c478bd9Sstevel@tonic-gate #endif 8537c478bd9Sstevel@tonic-gate return (NULL); 8547c478bd9Sstevel@tonic-gate } 8557c478bd9Sstevel@tonic-gate goto next_msg; 8567c478bd9Sstevel@tonic-gate } 8577c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_prsctpdrop); 8587c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_unsent >= msg_hdr->smh_msglen); 8597c478bd9Sstevel@tonic-gate if (meta->b_prev == NULL) { 8607c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_xmit_head == meta); 8617c478bd9Sstevel@tonic-gate sctp->sctp_xmit_head = tmp_meta; 8627c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_tail == meta) 8637c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail = tmp_meta; 8647c478bd9Sstevel@tonic-gate meta->b_next = NULL; 8657c478bd9Sstevel@tonic-gate if (tmp_meta != NULL) 8667c478bd9Sstevel@tonic-gate tmp_meta->b_prev = NULL; 8677c478bd9Sstevel@tonic-gate } else if (meta->b_next == NULL) { 8687c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_tail == meta) 8697c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail = meta->b_prev; 8707c478bd9Sstevel@tonic-gate meta->b_prev->b_next = NULL; 8717c478bd9Sstevel@tonic-gate meta->b_prev = NULL; 8727c478bd9Sstevel@tonic-gate } else { 8737c478bd9Sstevel@tonic-gate meta->b_prev->b_next = tmp_meta; 8747c478bd9Sstevel@tonic-gate tmp_meta->b_prev = meta->b_prev; 8757c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_tail == meta) 8767c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail = tmp_meta; 8777c478bd9Sstevel@tonic-gate meta->b_prev = NULL; 8787c478bd9Sstevel@tonic-gate meta->b_next = NULL; 8797c478bd9Sstevel@tonic-gate } 8807c478bd9Sstevel@tonic-gate sctp->sctp_unsent -= msg_hdr->smh_msglen; 8817c478bd9Sstevel@tonic-gate /* 8827c478bd9Sstevel@tonic-gate * Update ULP the amount of queued data, which is 8837c478bd9Sstevel@tonic-gate * sent-unack'ed + unsent. 8847c478bd9Sstevel@tonic-gate */ 8857c478bd9Sstevel@tonic-gate if (!SCTP_IS_DETACHED(sctp)) { 8867c478bd9Sstevel@tonic-gate sctp->sctp_ulp_xmitted(sctp->sctp_ulpd, 8877c478bd9Sstevel@tonic-gate sctp->sctp_unacked + sctp->sctp_unsent); 8887c478bd9Sstevel@tonic-gate } 8897c478bd9Sstevel@tonic-gate sctp_sendfail_event(sctp, meta, 0, B_TRUE); 8907c478bd9Sstevel@tonic-gate next_msg: 8917c478bd9Sstevel@tonic-gate meta = tmp_meta; 8927c478bd9Sstevel@tonic-gate } 8937c478bd9Sstevel@tonic-gate /* chunkify, if needed */ 8947c478bd9Sstevel@tonic-gate if (cansend > 0 && sctp->sctp_xmit_unsent != NULL) { 8957c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_unsent > 0); 8967c478bd9Sstevel@tonic-gate if (fp == NULL) { 8977c478bd9Sstevel@tonic-gate fp = SCTP_CHUNK_DEST(sctp->sctp_xmit_unsent); 8987c478bd9Sstevel@tonic-gate if (fp == NULL || fp->state != SCTP_FADDRS_ALIVE) 8997c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 9007c478bd9Sstevel@tonic-gate } else { 9017c478bd9Sstevel@tonic-gate /* 9027c478bd9Sstevel@tonic-gate * If user specified destination, try to honor that. 9037c478bd9Sstevel@tonic-gate */ 9047c478bd9Sstevel@tonic-gate fp1 = SCTP_CHUNK_DEST(sctp->sctp_xmit_unsent); 9057c478bd9Sstevel@tonic-gate if (fp1 != NULL && fp1->state == SCTP_FADDRS_ALIVE && 9067c478bd9Sstevel@tonic-gate fp1 != fp) { 9077c478bd9Sstevel@tonic-gate goto chunk_done; 9087c478bd9Sstevel@tonic-gate } 9097c478bd9Sstevel@tonic-gate } 9107c478bd9Sstevel@tonic-gate sctp_chunkify(sctp, fp->sfa_pmss - firstseg, cansend); 9117c478bd9Sstevel@tonic-gate if ((meta = sctp->sctp_xmit_tail) == NULL) 9127c478bd9Sstevel@tonic-gate goto chunk_done; 9137c478bd9Sstevel@tonic-gate /* 9147c478bd9Sstevel@tonic-gate * sctp_chunkify() won't advance sctp_xmit_tail if it adds 9157c478bd9Sstevel@tonic-gate * new chunk(s) to the tail, so we need to skip the 9167c478bd9Sstevel@tonic-gate * sctp_xmit_tail, which would have already been processed. 9177c478bd9Sstevel@tonic-gate * This could happen when there is unacked chunks, but 9187c478bd9Sstevel@tonic-gate * nothing new to send. 9197c478bd9Sstevel@tonic-gate * When sctp_chunkify() is called when the transmit queue 9207c478bd9Sstevel@tonic-gate * is empty then we need to start from sctp_xmit_tail. 9217c478bd9Sstevel@tonic-gate */ 9227c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_ISSENT(sctp->sctp_xmit_tail->b_cont)) { 9237c478bd9Sstevel@tonic-gate #ifdef DEBUG 9247c478bd9Sstevel@tonic-gate mp1 = sctp->sctp_xmit_tail->b_cont; 9257c478bd9Sstevel@tonic-gate while (mp1 != NULL) { 9267c478bd9Sstevel@tonic-gate ASSERT(!SCTP_CHUNK_CANSEND(mp1)); 9277c478bd9Sstevel@tonic-gate mp1 = mp1->b_next; 9287c478bd9Sstevel@tonic-gate } 9297c478bd9Sstevel@tonic-gate #endif 9307c478bd9Sstevel@tonic-gate if ((meta = sctp->sctp_xmit_tail->b_next) == NULL) 9317c478bd9Sstevel@tonic-gate goto chunk_done; 9327c478bd9Sstevel@tonic-gate } 9337c478bd9Sstevel@tonic-gate goto chunkified; 9347c478bd9Sstevel@tonic-gate } 9357c478bd9Sstevel@tonic-gate chunk_done: 9367c478bd9Sstevel@tonic-gate #ifdef DEBUG 9377c478bd9Sstevel@tonic-gate ASSERT(sctp_verify_chain(sctp->sctp_xmit_head, sctp->sctp_xmit_tail)); 9387c478bd9Sstevel@tonic-gate #endif 9397c478bd9Sstevel@tonic-gate return (NULL); 9407c478bd9Sstevel@tonic-gate } 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate void 9437c478bd9Sstevel@tonic-gate sctp_fast_rexmit(sctp_t *sctp) 9447c478bd9Sstevel@tonic-gate { 9457c478bd9Sstevel@tonic-gate mblk_t *mp, *head; 9467c478bd9Sstevel@tonic-gate int pktlen = 0; 9477c478bd9Sstevel@tonic-gate sctp_faddr_t *fp = NULL; 948f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 9497c478bd9Sstevel@tonic-gate 9507c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_xmit_head != NULL); 9517c478bd9Sstevel@tonic-gate mp = sctp_find_fast_rexmit_mblks(sctp, &pktlen, &fp); 95277c67f2fSkcpoon if (mp == NULL) { 953f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_fr_not_found); 9547c478bd9Sstevel@tonic-gate return; 95577c67f2fSkcpoon } 956df19b344Svi if ((head = sctp_add_proto_hdr(sctp, fp, mp, 0, NULL)) == NULL) { 9577c478bd9Sstevel@tonic-gate freemsg(mp); 958f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_fr_add_hdr); 9597c478bd9Sstevel@tonic-gate return; 9607c478bd9Sstevel@tonic-gate } 9617c478bd9Sstevel@tonic-gate if ((pktlen > fp->sfa_pmss) && fp->isv4) { 9627c478bd9Sstevel@tonic-gate ipha_t *iph = (ipha_t *)head->b_rptr; 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate iph->ipha_fragment_offset_and_flags = 0; 9657c478bd9Sstevel@tonic-gate } 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate sctp_set_iplen(sctp, head); 9687c478bd9Sstevel@tonic-gate sctp_add_sendq(sctp, head); 9697c478bd9Sstevel@tonic-gate sctp->sctp_active = fp->lastactive = lbolt64; 9707c478bd9Sstevel@tonic-gate } 9717c478bd9Sstevel@tonic-gate 9727c478bd9Sstevel@tonic-gate void 97312f47623Skcpoon sctp_output(sctp_t *sctp, uint_t num_pkt) 9747c478bd9Sstevel@tonic-gate { 9757c478bd9Sstevel@tonic-gate mblk_t *mp = NULL; 9767c478bd9Sstevel@tonic-gate mblk_t *nmp; 9777c478bd9Sstevel@tonic-gate mblk_t *head; 9787c478bd9Sstevel@tonic-gate mblk_t *meta = sctp->sctp_xmit_tail; 9797c478bd9Sstevel@tonic-gate mblk_t *fill = NULL; 9807c478bd9Sstevel@tonic-gate uint16_t chunklen; 9817c478bd9Sstevel@tonic-gate uint32_t cansend; 9827c478bd9Sstevel@tonic-gate int32_t seglen; 9837c478bd9Sstevel@tonic-gate int32_t xtralen; 9847c478bd9Sstevel@tonic-gate int32_t sacklen; 9857c478bd9Sstevel@tonic-gate int32_t pad = 0; 9867c478bd9Sstevel@tonic-gate int32_t pathmax; 9877c478bd9Sstevel@tonic-gate int extra; 9887c478bd9Sstevel@tonic-gate int64_t now = lbolt64; 9897c478bd9Sstevel@tonic-gate sctp_faddr_t *fp; 9907c478bd9Sstevel@tonic-gate sctp_faddr_t *lfp; 9917c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 9927c478bd9Sstevel@tonic-gate int error; 993df19b344Svi boolean_t notsent = B_TRUE; 99412f47623Skcpoon sctp_stack_t *sctps = sctp->sctp_sctps; 9957c478bd9Sstevel@tonic-gate 9967c478bd9Sstevel@tonic-gate if (sctp->sctp_ftsn == sctp->sctp_lastacked + 1) { 9977c478bd9Sstevel@tonic-gate sacklen = 0; 9987c478bd9Sstevel@tonic-gate } else { 9997c478bd9Sstevel@tonic-gate /* send a SACK chunk */ 10007c478bd9Sstevel@tonic-gate sacklen = sizeof (sctp_chunk_hdr_t) + 10017c478bd9Sstevel@tonic-gate sizeof (sctp_sack_chunk_t) + 10027c478bd9Sstevel@tonic-gate (sizeof (sctp_sack_frag_t) * sctp->sctp_sack_gaps); 10037c478bd9Sstevel@tonic-gate lfp = sctp->sctp_lastdata; 10047c478bd9Sstevel@tonic-gate ASSERT(lfp != NULL); 10057c478bd9Sstevel@tonic-gate if (lfp->state != SCTP_FADDRS_ALIVE) 10067c478bd9Sstevel@tonic-gate lfp = sctp->sctp_current; 10077c478bd9Sstevel@tonic-gate } 10087c478bd9Sstevel@tonic-gate 10097c478bd9Sstevel@tonic-gate cansend = sctp->sctp_frwnd; 10107c478bd9Sstevel@tonic-gate if (sctp->sctp_unsent < cansend) 10117c478bd9Sstevel@tonic-gate cansend = sctp->sctp_unsent; 10127c478bd9Sstevel@tonic-gate if ((cansend < sctp->sctp_current->sfa_pmss / 2) && 10137c478bd9Sstevel@tonic-gate sctp->sctp_unacked && 10147c478bd9Sstevel@tonic-gate (sctp->sctp_unacked < sctp->sctp_current->sfa_pmss) && 10157c478bd9Sstevel@tonic-gate !sctp->sctp_ndelay) { 10167c478bd9Sstevel@tonic-gate head = NULL; 10177c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 10187c478bd9Sstevel@tonic-gate goto unsent_data; 10197c478bd9Sstevel@tonic-gate } 10207c478bd9Sstevel@tonic-gate if (meta != NULL) 10217c478bd9Sstevel@tonic-gate mp = meta->b_cont; 102212f47623Skcpoon while (cansend > 0 && num_pkt-- != 0) { 10237c478bd9Sstevel@tonic-gate pad = 0; 10247c478bd9Sstevel@tonic-gate 10257c478bd9Sstevel@tonic-gate /* 10267c478bd9Sstevel@tonic-gate * Find first segment eligible for transmit. 10277c478bd9Sstevel@tonic-gate */ 10287c478bd9Sstevel@tonic-gate while (mp != NULL) { 10297c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_CANSEND(mp)) 10307c478bd9Sstevel@tonic-gate break; 10317c478bd9Sstevel@tonic-gate mp = mp->b_next; 10327c478bd9Sstevel@tonic-gate } 10337c478bd9Sstevel@tonic-gate if (mp == NULL) { 10347c478bd9Sstevel@tonic-gate meta = sctp_get_msg_to_send(sctp, &mp, 10357c478bd9Sstevel@tonic-gate meta == NULL ? NULL : meta->b_next, &error, sacklen, 10367c478bd9Sstevel@tonic-gate cansend, NULL); 10377c478bd9Sstevel@tonic-gate if (error != 0 || meta == NULL) { 10387c478bd9Sstevel@tonic-gate head = NULL; 10397c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 10407c478bd9Sstevel@tonic-gate goto unsent_data; 10417c478bd9Sstevel@tonic-gate } 10427c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail = meta; 10437c478bd9Sstevel@tonic-gate } 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 10467c478bd9Sstevel@tonic-gate seglen = ntohs(sdc->sdh_len); 10477c478bd9Sstevel@tonic-gate xtralen = sizeof (*sdc); 10487c478bd9Sstevel@tonic-gate chunklen = seglen - xtralen; 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate /* 10517c478bd9Sstevel@tonic-gate * Check rwnd. 10527c478bd9Sstevel@tonic-gate */ 10537c478bd9Sstevel@tonic-gate if (chunklen > cansend) { 10547c478bd9Sstevel@tonic-gate head = NULL; 10557c478bd9Sstevel@tonic-gate fp = SCTP_CHUNK_DEST(meta); 10567c478bd9Sstevel@tonic-gate if (fp == NULL || fp->state != SCTP_FADDRS_ALIVE) 10577c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 10587c478bd9Sstevel@tonic-gate goto unsent_data; 10597c478bd9Sstevel@tonic-gate } 10607c478bd9Sstevel@tonic-gate if ((extra = seglen & (SCTP_ALIGN - 1)) != 0) 10617c478bd9Sstevel@tonic-gate extra = SCTP_ALIGN - extra; 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate /* 10647c478bd9Sstevel@tonic-gate * Pick destination address, and check cwnd. 10657c478bd9Sstevel@tonic-gate */ 10667c478bd9Sstevel@tonic-gate if (sacklen > 0 && (seglen + extra <= lfp->cwnd - lfp->suna) && 10677c478bd9Sstevel@tonic-gate (seglen + sacklen + extra <= lfp->sfa_pmss)) { 10687c478bd9Sstevel@tonic-gate /* 10697c478bd9Sstevel@tonic-gate * Only include SACK chunk if it can be bundled 10707c478bd9Sstevel@tonic-gate * with a data chunk, and sent to sctp_lastdata. 10717c478bd9Sstevel@tonic-gate */ 10727c478bd9Sstevel@tonic-gate pathmax = lfp->cwnd - lfp->suna; 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate fp = lfp; 10757c478bd9Sstevel@tonic-gate if ((nmp = dupmsg(mp)) == NULL) { 10767c478bd9Sstevel@tonic-gate head = NULL; 10777c478bd9Sstevel@tonic-gate goto unsent_data; 10787c478bd9Sstevel@tonic-gate } 10797c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_FLAGS(nmp); 1080df19b344Svi head = sctp_add_proto_hdr(sctp, fp, nmp, sacklen, 1081df19b344Svi &error); 10827c478bd9Sstevel@tonic-gate if (head == NULL) { 1083df19b344Svi /* 1084df19b344Svi * If none of the source addresses are 1085df19b344Svi * available (i.e error == EHOSTUNREACH), 1086df19b344Svi * pretend we have sent the data. We will 1087df19b344Svi * eventually time out trying to retramsmit 1088df19b344Svi * the data if the interface never comes up. 1089df19b344Svi * If we have already sent some stuff (i.e., 1090df19b344Svi * notsent is B_FALSE) then we are fine, else 1091df19b344Svi * just mark this packet as sent. 1092df19b344Svi */ 1093df19b344Svi if (notsent && error == EHOSTUNREACH) { 1094df19b344Svi SCTP_CHUNK_SENT(sctp, mp, sdc, 1095df19b344Svi fp, chunklen, meta); 1096df19b344Svi } 10977c478bd9Sstevel@tonic-gate freemsg(nmp); 1098f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_output_failed); 10997c478bd9Sstevel@tonic-gate goto unsent_data; 11007c478bd9Sstevel@tonic-gate } 11017c478bd9Sstevel@tonic-gate seglen += sacklen; 11027c478bd9Sstevel@tonic-gate xtralen += sacklen; 11037c478bd9Sstevel@tonic-gate sacklen = 0; 11047c478bd9Sstevel@tonic-gate } else { 11057c478bd9Sstevel@tonic-gate fp = SCTP_CHUNK_DEST(meta); 11067c478bd9Sstevel@tonic-gate if (fp == NULL || fp->state != SCTP_FADDRS_ALIVE) 11077c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 11087c478bd9Sstevel@tonic-gate /* 11097c478bd9Sstevel@tonic-gate * If we haven't sent data to this destination for 11107c478bd9Sstevel@tonic-gate * a while, do slow start again. 11117c478bd9Sstevel@tonic-gate */ 11127c478bd9Sstevel@tonic-gate if (now - fp->lastactive > fp->rto) { 111312f47623Skcpoon SET_CWND(fp, fp->sfa_pmss, 111412f47623Skcpoon sctps->sctps_slow_start_after_idle); 11157c478bd9Sstevel@tonic-gate } 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate pathmax = fp->cwnd - fp->suna; 11187c478bd9Sstevel@tonic-gate if (seglen + extra > pathmax) { 11197c478bd9Sstevel@tonic-gate head = NULL; 11207c478bd9Sstevel@tonic-gate goto unsent_data; 11217c478bd9Sstevel@tonic-gate } 11227c478bd9Sstevel@tonic-gate if ((nmp = dupmsg(mp)) == NULL) { 11237c478bd9Sstevel@tonic-gate head = NULL; 11247c478bd9Sstevel@tonic-gate goto unsent_data; 11257c478bd9Sstevel@tonic-gate } 11267c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_FLAGS(nmp); 1127df19b344Svi head = sctp_add_proto_hdr(sctp, fp, nmp, 0, &error); 11287c478bd9Sstevel@tonic-gate if (head == NULL) { 1129df19b344Svi /* 1130df19b344Svi * If none of the source addresses are 1131df19b344Svi * available (i.e error == EHOSTUNREACH), 1132df19b344Svi * pretend we have sent the data. We will 1133df19b344Svi * eventually time out trying to retramsmit 1134df19b344Svi * the data if the interface never comes up. 1135df19b344Svi * If we have already sent some stuff (i.e., 1136df19b344Svi * notsent is B_FALSE) then we are fine, else 1137df19b344Svi * just mark this packet as sent. 1138df19b344Svi */ 1139df19b344Svi if (notsent && error == EHOSTUNREACH) { 1140df19b344Svi SCTP_CHUNK_SENT(sctp, mp, sdc, 1141df19b344Svi fp, chunklen, meta); 1142df19b344Svi } 11437c478bd9Sstevel@tonic-gate freemsg(nmp); 1144f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_output_failed); 11457c478bd9Sstevel@tonic-gate goto unsent_data; 11467c478bd9Sstevel@tonic-gate } 11477c478bd9Sstevel@tonic-gate } 114877c67f2fSkcpoon fp->lastactive = now; 11497c478bd9Sstevel@tonic-gate if (pathmax > fp->sfa_pmss) 11507c478bd9Sstevel@tonic-gate pathmax = fp->sfa_pmss; 11517c478bd9Sstevel@tonic-gate SCTP_CHUNK_SENT(sctp, mp, sdc, fp, chunklen, meta); 11527c478bd9Sstevel@tonic-gate mp = mp->b_next; 11537c478bd9Sstevel@tonic-gate 11547c478bd9Sstevel@tonic-gate /* Use this chunk to measure RTT? */ 11557c478bd9Sstevel@tonic-gate if (sctp->sctp_out_time == 0) { 11567c478bd9Sstevel@tonic-gate sctp->sctp_out_time = now; 11577c478bd9Sstevel@tonic-gate sctp->sctp_rtt_tsn = sctp->sctp_ltsn - 1; 115877c67f2fSkcpoon ASSERT(sctp->sctp_rtt_tsn == ntohl(sdc->sdh_tsn)); 11597c478bd9Sstevel@tonic-gate } 11607c478bd9Sstevel@tonic-gate if (extra > 0) { 1161*121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 11627c478bd9Sstevel@tonic-gate if (fill != NULL) { 11637c478bd9Sstevel@tonic-gate linkb(head, fill); 11647c478bd9Sstevel@tonic-gate pad = extra; 11657c478bd9Sstevel@tonic-gate seglen += extra; 11667c478bd9Sstevel@tonic-gate } else { 11677c478bd9Sstevel@tonic-gate goto unsent_data; 11687c478bd9Sstevel@tonic-gate } 11697c478bd9Sstevel@tonic-gate } 11707c478bd9Sstevel@tonic-gate /* See if we can bundle more. */ 11717c478bd9Sstevel@tonic-gate while (seglen < pathmax) { 11727c478bd9Sstevel@tonic-gate int32_t new_len; 11737c478bd9Sstevel@tonic-gate int32_t new_xtralen; 11747c478bd9Sstevel@tonic-gate 11757c478bd9Sstevel@tonic-gate while (mp != NULL) { 11767c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_CANSEND(mp)) 11777c478bd9Sstevel@tonic-gate break; 11787c478bd9Sstevel@tonic-gate mp = mp->b_next; 11797c478bd9Sstevel@tonic-gate } 11807c478bd9Sstevel@tonic-gate if (mp == NULL) { 11817c478bd9Sstevel@tonic-gate meta = sctp_get_msg_to_send(sctp, &mp, 11827c478bd9Sstevel@tonic-gate meta->b_next, &error, seglen, 11837c478bd9Sstevel@tonic-gate (seglen - xtralen) >= cansend ? 0 : 11847c478bd9Sstevel@tonic-gate cansend - seglen, fp); 11857c478bd9Sstevel@tonic-gate if (error != 0 || meta == NULL) 11867c478bd9Sstevel@tonic-gate break; 11877c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail = meta; 11887c478bd9Sstevel@tonic-gate } 11897c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 11907c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp) && SCTP_CHUNK_DEST(meta) && 11917c478bd9Sstevel@tonic-gate fp != SCTP_CHUNK_DEST(meta)) { 11927c478bd9Sstevel@tonic-gate break; 11937c478bd9Sstevel@tonic-gate } 11947c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 11957c478bd9Sstevel@tonic-gate chunklen = ntohs(sdc->sdh_len); 11967c478bd9Sstevel@tonic-gate if ((extra = chunklen & (SCTP_ALIGN - 1)) != 0) 11977c478bd9Sstevel@tonic-gate extra = SCTP_ALIGN - extra; 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate new_len = seglen + chunklen; 12007c478bd9Sstevel@tonic-gate new_xtralen = xtralen + sizeof (*sdc); 12017c478bd9Sstevel@tonic-gate chunklen -= sizeof (*sdc); 12027c478bd9Sstevel@tonic-gate 12037c478bd9Sstevel@tonic-gate if (new_len - new_xtralen > cansend || 12047c478bd9Sstevel@tonic-gate new_len + extra > pathmax) { 12057c478bd9Sstevel@tonic-gate break; 12067c478bd9Sstevel@tonic-gate } 12077c478bd9Sstevel@tonic-gate if ((nmp = dupmsg(mp)) == NULL) 12087c478bd9Sstevel@tonic-gate break; 12097c478bd9Sstevel@tonic-gate if (extra > 0) { 1210*121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 12117c478bd9Sstevel@tonic-gate if (fill != NULL) { 12127c478bd9Sstevel@tonic-gate pad += extra; 12137c478bd9Sstevel@tonic-gate new_len += extra; 12147c478bd9Sstevel@tonic-gate linkb(nmp, fill); 12157c478bd9Sstevel@tonic-gate } else { 12167c478bd9Sstevel@tonic-gate freemsg(nmp); 12177c478bd9Sstevel@tonic-gate break; 12187c478bd9Sstevel@tonic-gate } 12197c478bd9Sstevel@tonic-gate } 12207c478bd9Sstevel@tonic-gate seglen = new_len; 12217c478bd9Sstevel@tonic-gate xtralen = new_xtralen; 12227c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_FLAGS(nmp); 12237c478bd9Sstevel@tonic-gate SCTP_CHUNK_SENT(sctp, mp, sdc, fp, chunklen, meta); 12247c478bd9Sstevel@tonic-gate linkb(head, nmp); 12257c478bd9Sstevel@tonic-gate mp = mp->b_next; 12267c478bd9Sstevel@tonic-gate } 12277c478bd9Sstevel@tonic-gate if ((seglen > fp->sfa_pmss) && fp->isv4) { 12287c478bd9Sstevel@tonic-gate ipha_t *iph = (ipha_t *)head->b_rptr; 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate /* 12317c478bd9Sstevel@tonic-gate * Path MTU is different from what we thought it would 12327c478bd9Sstevel@tonic-gate * be when we created chunks, or IP headers have grown. 12337c478bd9Sstevel@tonic-gate * Need to clear the DF bit. 12347c478bd9Sstevel@tonic-gate */ 12357c478bd9Sstevel@tonic-gate iph->ipha_fragment_offset_and_flags = 0; 12367c478bd9Sstevel@tonic-gate } 12377c478bd9Sstevel@tonic-gate /* xmit segment */ 12387c478bd9Sstevel@tonic-gate ASSERT(cansend >= seglen - pad - xtralen); 12397c478bd9Sstevel@tonic-gate cansend -= (seglen - pad - xtralen); 12407c478bd9Sstevel@tonic-gate dprint(2, ("sctp_output: Sending packet %d bytes, tsn %x " 124145916cd2Sjpk "ssn %d to %p (rwnd %d, cansend %d, lastack_rxd %x)\n", 124245916cd2Sjpk seglen - xtralen, ntohl(sdc->sdh_tsn), 124345916cd2Sjpk ntohs(sdc->sdh_ssn), (void *)fp, sctp->sctp_frwnd, 124445916cd2Sjpk cansend, sctp->sctp_lastack_rxd)); 12457c478bd9Sstevel@tonic-gate sctp_set_iplen(sctp, head); 12467c478bd9Sstevel@tonic-gate sctp_add_sendq(sctp, head); 12477c478bd9Sstevel@tonic-gate /* arm rto timer (if not set) */ 12487c478bd9Sstevel@tonic-gate if (!fp->timer_running) 12497c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->rto); 1250df19b344Svi notsent = B_FALSE; 12517c478bd9Sstevel@tonic-gate } 12527c478bd9Sstevel@tonic-gate sctp->sctp_active = now; 12537c478bd9Sstevel@tonic-gate return; 12547c478bd9Sstevel@tonic-gate unsent_data: 12557c478bd9Sstevel@tonic-gate /* arm persist timer (if rto timer not set) */ 12567c478bd9Sstevel@tonic-gate if (!fp->timer_running) 12577c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->rto); 12587c478bd9Sstevel@tonic-gate if (head != NULL) 12597c478bd9Sstevel@tonic-gate freemsg(head); 12607c478bd9Sstevel@tonic-gate } 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate /* 12637c478bd9Sstevel@tonic-gate * The following two functions initialize and destroy the cache 12647c478bd9Sstevel@tonic-gate * associated with the sets used for PR-SCTP. 12657c478bd9Sstevel@tonic-gate */ 12667c478bd9Sstevel@tonic-gate void 12677c478bd9Sstevel@tonic-gate sctp_ftsn_sets_init(void) 12687c478bd9Sstevel@tonic-gate { 12697c478bd9Sstevel@tonic-gate sctp_kmem_ftsn_set_cache = kmem_cache_create("sctp_ftsn_set_cache", 12707c478bd9Sstevel@tonic-gate sizeof (sctp_ftsn_set_t), 0, NULL, NULL, NULL, NULL, 12717c478bd9Sstevel@tonic-gate NULL, 0); 12727c478bd9Sstevel@tonic-gate } 12737c478bd9Sstevel@tonic-gate 12747c478bd9Sstevel@tonic-gate void 12757c478bd9Sstevel@tonic-gate sctp_ftsn_sets_fini(void) 12767c478bd9Sstevel@tonic-gate { 12777c478bd9Sstevel@tonic-gate kmem_cache_destroy(sctp_kmem_ftsn_set_cache); 12787c478bd9Sstevel@tonic-gate } 12797c478bd9Sstevel@tonic-gate 12807c478bd9Sstevel@tonic-gate 12817c478bd9Sstevel@tonic-gate /* Free PR-SCTP sets */ 12827c478bd9Sstevel@tonic-gate void 12837c478bd9Sstevel@tonic-gate sctp_free_ftsn_set(sctp_ftsn_set_t *s) 12847c478bd9Sstevel@tonic-gate { 12857c478bd9Sstevel@tonic-gate sctp_ftsn_set_t *p; 12867c478bd9Sstevel@tonic-gate 12877c478bd9Sstevel@tonic-gate while (s != NULL) { 12887c478bd9Sstevel@tonic-gate p = s->next; 12897c478bd9Sstevel@tonic-gate s->next = NULL; 12907c478bd9Sstevel@tonic-gate kmem_cache_free(sctp_kmem_ftsn_set_cache, s); 12917c478bd9Sstevel@tonic-gate s = p; 12927c478bd9Sstevel@tonic-gate } 12937c478bd9Sstevel@tonic-gate } 12947c478bd9Sstevel@tonic-gate 12957c478bd9Sstevel@tonic-gate /* 12967c478bd9Sstevel@tonic-gate * Given a message meta block, meta, this routine creates or modifies 12977c478bd9Sstevel@tonic-gate * the set that will be used to generate a Forward TSN chunk. If the 12987c478bd9Sstevel@tonic-gate * entry for stream id, sid, for this message already exists, the 12997c478bd9Sstevel@tonic-gate * sequence number, ssn, is updated if it is greater than the existing 13007c478bd9Sstevel@tonic-gate * one. If an entry for this sid does not exist, one is created if 13017c478bd9Sstevel@tonic-gate * the size does not exceed fp->sfa_pmss. We return false in case 13027c478bd9Sstevel@tonic-gate * or an error. 13037c478bd9Sstevel@tonic-gate */ 13047c478bd9Sstevel@tonic-gate boolean_t 13057c478bd9Sstevel@tonic-gate sctp_add_ftsn_set(sctp_ftsn_set_t **s, sctp_faddr_t *fp, mblk_t *meta, 13067c478bd9Sstevel@tonic-gate uint_t *nsets, uint32_t *slen) 13077c478bd9Sstevel@tonic-gate { 13087c478bd9Sstevel@tonic-gate sctp_ftsn_set_t *p; 13097c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *msg_hdr = (sctp_msg_hdr_t *)meta->b_rptr; 13107c478bd9Sstevel@tonic-gate uint16_t sid = htons(msg_hdr->smh_sid); 13117c478bd9Sstevel@tonic-gate /* msg_hdr->smh_ssn is already in NBO */ 13127c478bd9Sstevel@tonic-gate uint16_t ssn = msg_hdr->smh_ssn; 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate ASSERT(s != NULL && nsets != NULL); 13157c478bd9Sstevel@tonic-gate ASSERT((*nsets == 0 && *s == NULL) || (*nsets > 0 && *s != NULL)); 13167c478bd9Sstevel@tonic-gate 13177c478bd9Sstevel@tonic-gate if (*s == NULL) { 13187c478bd9Sstevel@tonic-gate ASSERT((*slen + sizeof (uint32_t)) <= fp->sfa_pmss); 13197c478bd9Sstevel@tonic-gate *s = kmem_cache_alloc(sctp_kmem_ftsn_set_cache, KM_NOSLEEP); 13207c478bd9Sstevel@tonic-gate if (*s == NULL) 13217c478bd9Sstevel@tonic-gate return (B_FALSE); 13227c478bd9Sstevel@tonic-gate (*s)->ftsn_entries.ftsn_sid = sid; 13237c478bd9Sstevel@tonic-gate (*s)->ftsn_entries.ftsn_ssn = ssn; 13247c478bd9Sstevel@tonic-gate (*s)->next = NULL; 13257c478bd9Sstevel@tonic-gate *nsets = 1; 13267c478bd9Sstevel@tonic-gate *slen += sizeof (uint32_t); 13277c478bd9Sstevel@tonic-gate return (B_TRUE); 13287c478bd9Sstevel@tonic-gate } 13297c478bd9Sstevel@tonic-gate for (p = *s; p->next != NULL; p = p->next) { 13307c478bd9Sstevel@tonic-gate if (p->ftsn_entries.ftsn_sid == sid) { 13317c478bd9Sstevel@tonic-gate if (SSN_GT(ssn, p->ftsn_entries.ftsn_ssn)) 13327c478bd9Sstevel@tonic-gate p->ftsn_entries.ftsn_ssn = ssn; 13337c478bd9Sstevel@tonic-gate return (B_TRUE); 13347c478bd9Sstevel@tonic-gate } 13357c478bd9Sstevel@tonic-gate } 13367c478bd9Sstevel@tonic-gate /* the last one */ 13377c478bd9Sstevel@tonic-gate if (p->ftsn_entries.ftsn_sid == sid) { 13387c478bd9Sstevel@tonic-gate if (SSN_GT(ssn, p->ftsn_entries.ftsn_ssn)) 13397c478bd9Sstevel@tonic-gate p->ftsn_entries.ftsn_ssn = ssn; 13407c478bd9Sstevel@tonic-gate } else { 13417c478bd9Sstevel@tonic-gate if ((*slen + sizeof (uint32_t)) > fp->sfa_pmss) 13427c478bd9Sstevel@tonic-gate return (B_FALSE); 13437c478bd9Sstevel@tonic-gate p->next = kmem_cache_alloc(sctp_kmem_ftsn_set_cache, 13447c478bd9Sstevel@tonic-gate KM_NOSLEEP); 13457c478bd9Sstevel@tonic-gate if (p->next == NULL) 13467c478bd9Sstevel@tonic-gate return (B_FALSE); 13477c478bd9Sstevel@tonic-gate p = p->next; 13487c478bd9Sstevel@tonic-gate p->ftsn_entries.ftsn_sid = sid; 13497c478bd9Sstevel@tonic-gate p->ftsn_entries.ftsn_ssn = ssn; 13507c478bd9Sstevel@tonic-gate p->next = NULL; 13517c478bd9Sstevel@tonic-gate (*nsets)++; 13527c478bd9Sstevel@tonic-gate *slen += sizeof (uint32_t); 13537c478bd9Sstevel@tonic-gate } 13547c478bd9Sstevel@tonic-gate return (B_TRUE); 13557c478bd9Sstevel@tonic-gate } 13567c478bd9Sstevel@tonic-gate 13577c478bd9Sstevel@tonic-gate /* 13587c478bd9Sstevel@tonic-gate * Given a set of stream id - sequence number pairs, this routing creates 13597c478bd9Sstevel@tonic-gate * a Forward TSN chunk. The cumulative TSN (advanced peer ack point) 13607c478bd9Sstevel@tonic-gate * for the chunk is obtained from sctp->sctp_adv_pap. The caller 13617c478bd9Sstevel@tonic-gate * will add the IP/SCTP header. 13627c478bd9Sstevel@tonic-gate */ 13637c478bd9Sstevel@tonic-gate mblk_t * 13647c478bd9Sstevel@tonic-gate sctp_make_ftsn_chunk(sctp_t *sctp, sctp_faddr_t *fp, sctp_ftsn_set_t *sets, 13657c478bd9Sstevel@tonic-gate uint_t nsets, uint32_t seglen) 13667c478bd9Sstevel@tonic-gate { 13677c478bd9Sstevel@tonic-gate mblk_t *ftsn_mp; 13687c478bd9Sstevel@tonic-gate sctp_chunk_hdr_t *ch_hdr; 13697c478bd9Sstevel@tonic-gate uint32_t *advtsn; 13707c478bd9Sstevel@tonic-gate uint16_t schlen; 13717c478bd9Sstevel@tonic-gate size_t xtralen; 13727c478bd9Sstevel@tonic-gate ftsn_entry_t *ftsn_entry; 1373f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 13747c478bd9Sstevel@tonic-gate 13757c478bd9Sstevel@tonic-gate seglen += sizeof (sctp_chunk_hdr_t); 13767c478bd9Sstevel@tonic-gate if (fp->isv4) 1377f4b3ec61Sdh xtralen = sctp->sctp_hdr_len + sctps->sctps_wroff_xtra; 13787c478bd9Sstevel@tonic-gate else 1379f4b3ec61Sdh xtralen = sctp->sctp_hdr6_len + sctps->sctps_wroff_xtra; 138045916cd2Sjpk ftsn_mp = allocb_cred(xtralen + seglen, CONN_CRED(sctp->sctp_connp)); 13817c478bd9Sstevel@tonic-gate if (ftsn_mp == NULL) 13827c478bd9Sstevel@tonic-gate return (NULL); 13837c478bd9Sstevel@tonic-gate ftsn_mp->b_rptr += xtralen; 13847c478bd9Sstevel@tonic-gate ftsn_mp->b_wptr = ftsn_mp->b_rptr + seglen; 13857c478bd9Sstevel@tonic-gate 13867c478bd9Sstevel@tonic-gate ch_hdr = (sctp_chunk_hdr_t *)ftsn_mp->b_rptr; 13877c478bd9Sstevel@tonic-gate ch_hdr->sch_id = CHUNK_FORWARD_TSN; 13887c478bd9Sstevel@tonic-gate ch_hdr->sch_flags = 0; 13897c478bd9Sstevel@tonic-gate /* 13907c478bd9Sstevel@tonic-gate * The cast here should not be an issue since seglen is 13917c478bd9Sstevel@tonic-gate * the length of the Forward TSN chunk. 13927c478bd9Sstevel@tonic-gate */ 13937c478bd9Sstevel@tonic-gate schlen = (uint16_t)seglen; 13947c478bd9Sstevel@tonic-gate U16_TO_ABE16(schlen, &(ch_hdr->sch_len)); 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate advtsn = (uint32_t *)(ch_hdr + 1); 13977c478bd9Sstevel@tonic-gate U32_TO_ABE32(sctp->sctp_adv_pap, advtsn); 13987c478bd9Sstevel@tonic-gate ftsn_entry = (ftsn_entry_t *)(advtsn + 1); 13997c478bd9Sstevel@tonic-gate while (nsets > 0) { 14007c478bd9Sstevel@tonic-gate ASSERT((uchar_t *)&ftsn_entry[1] <= ftsn_mp->b_wptr); 14017c478bd9Sstevel@tonic-gate ftsn_entry->ftsn_sid = sets->ftsn_entries.ftsn_sid; 14027c478bd9Sstevel@tonic-gate ftsn_entry->ftsn_ssn = sets->ftsn_entries.ftsn_ssn; 14037c478bd9Sstevel@tonic-gate ftsn_entry++; 14047c478bd9Sstevel@tonic-gate sets = sets->next; 14057c478bd9Sstevel@tonic-gate nsets--; 14067c478bd9Sstevel@tonic-gate } 14077c478bd9Sstevel@tonic-gate return (ftsn_mp); 14087c478bd9Sstevel@tonic-gate } 14097c478bd9Sstevel@tonic-gate 14107c478bd9Sstevel@tonic-gate /* 14117c478bd9Sstevel@tonic-gate * Given a starting message, the routine steps through all the 14127c478bd9Sstevel@tonic-gate * messages whose TSN is less than sctp->sctp_adv_pap and creates 14137c478bd9Sstevel@tonic-gate * ftsn sets. The ftsn sets is then used to create an Forward TSN 14147c478bd9Sstevel@tonic-gate * chunk. All the messages, that have chunks that are included in the 14157c478bd9Sstevel@tonic-gate * ftsn sets, are flagged abandonded. If a message is partially sent 14167c478bd9Sstevel@tonic-gate * and is deemed abandoned, all remaining unsent chunks are marked 14177c478bd9Sstevel@tonic-gate * abandoned and are deducted from sctp_unsent. 14187c478bd9Sstevel@tonic-gate */ 14197c478bd9Sstevel@tonic-gate void 14207c478bd9Sstevel@tonic-gate sctp_make_ftsns(sctp_t *sctp, mblk_t *meta, mblk_t *mp, mblk_t **nmp, 14217c478bd9Sstevel@tonic-gate sctp_faddr_t *fp, uint32_t *seglen) 14227c478bd9Sstevel@tonic-gate { 14237c478bd9Sstevel@tonic-gate mblk_t *mp1 = mp; 14247c478bd9Sstevel@tonic-gate mblk_t *mp_head = mp; 14257c478bd9Sstevel@tonic-gate mblk_t *meta_head = meta; 14267c478bd9Sstevel@tonic-gate mblk_t *head; 14277c478bd9Sstevel@tonic-gate sctp_ftsn_set_t *sets = NULL; 14287c478bd9Sstevel@tonic-gate uint_t nsets = 0; 14297c478bd9Sstevel@tonic-gate uint16_t clen; 14307c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 14317c478bd9Sstevel@tonic-gate uint32_t sacklen; 14327c478bd9Sstevel@tonic-gate uint32_t adv_pap = sctp->sctp_adv_pap; 14337c478bd9Sstevel@tonic-gate uint32_t unsent = 0; 14347c478bd9Sstevel@tonic-gate boolean_t ubit; 1435f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 14367c478bd9Sstevel@tonic-gate 14377c478bd9Sstevel@tonic-gate *seglen = sizeof (uint32_t); 14387c478bd9Sstevel@tonic-gate 14397c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 14407c478bd9Sstevel@tonic-gate while (meta != NULL && 14417c478bd9Sstevel@tonic-gate SEQ_GEQ(sctp->sctp_adv_pap, ntohl(sdc->sdh_tsn))) { 14427c478bd9Sstevel@tonic-gate /* 14437c478bd9Sstevel@tonic-gate * Skip adding FTSN sets for un-ordered messages as they do 14447c478bd9Sstevel@tonic-gate * not have SSNs. 14457c478bd9Sstevel@tonic-gate */ 14467c478bd9Sstevel@tonic-gate ubit = SCTP_DATA_GET_UBIT(sdc); 14477c478bd9Sstevel@tonic-gate if (!ubit && 14487c478bd9Sstevel@tonic-gate !sctp_add_ftsn_set(&sets, fp, meta, &nsets, seglen)) { 14497c478bd9Sstevel@tonic-gate meta = NULL; 14507c478bd9Sstevel@tonic-gate sctp->sctp_adv_pap = adv_pap; 14517c478bd9Sstevel@tonic-gate goto ftsn_done; 14527c478bd9Sstevel@tonic-gate } 14537c478bd9Sstevel@tonic-gate while (mp1 != NULL && SCTP_CHUNK_ISSENT(mp1)) { 14547c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 14557c478bd9Sstevel@tonic-gate adv_pap = ntohl(sdc->sdh_tsn); 14567c478bd9Sstevel@tonic-gate mp1 = mp1->b_next; 14577c478bd9Sstevel@tonic-gate } 14587c478bd9Sstevel@tonic-gate meta = meta->b_next; 14597c478bd9Sstevel@tonic-gate if (meta != NULL) { 14607c478bd9Sstevel@tonic-gate mp1 = meta->b_cont; 14617c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp1)) 14627c478bd9Sstevel@tonic-gate break; 14637c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 14647c478bd9Sstevel@tonic-gate } 14657c478bd9Sstevel@tonic-gate } 14667c478bd9Sstevel@tonic-gate ftsn_done: 14677c478bd9Sstevel@tonic-gate /* 14687c478bd9Sstevel@tonic-gate * Can't compare with sets == NULL, since we don't add any 14697c478bd9Sstevel@tonic-gate * sets for un-ordered messages. 14707c478bd9Sstevel@tonic-gate */ 14717c478bd9Sstevel@tonic-gate if (meta == meta_head) 14727c478bd9Sstevel@tonic-gate return; 14737c478bd9Sstevel@tonic-gate *nmp = sctp_make_ftsn_chunk(sctp, fp, sets, nsets, *seglen); 14747c478bd9Sstevel@tonic-gate sctp_free_ftsn_set(sets); 14757c478bd9Sstevel@tonic-gate if (*nmp == NULL) 14767c478bd9Sstevel@tonic-gate return; 14777c478bd9Sstevel@tonic-gate if (sctp->sctp_ftsn == sctp->sctp_lastacked + 1) { 14787c478bd9Sstevel@tonic-gate sacklen = 0; 14797c478bd9Sstevel@tonic-gate } else { 14807c478bd9Sstevel@tonic-gate sacklen = sizeof (sctp_chunk_hdr_t) + 14817c478bd9Sstevel@tonic-gate sizeof (sctp_sack_chunk_t) + 14827c478bd9Sstevel@tonic-gate (sizeof (sctp_sack_frag_t) * sctp->sctp_sack_gaps); 14837c478bd9Sstevel@tonic-gate if (*seglen + sacklen > sctp->sctp_lastdata->sfa_pmss) { 14847c478bd9Sstevel@tonic-gate /* piggybacked SACK doesn't fit */ 14857c478bd9Sstevel@tonic-gate sacklen = 0; 14867c478bd9Sstevel@tonic-gate } else { 14877c478bd9Sstevel@tonic-gate fp = sctp->sctp_lastdata; 14887c478bd9Sstevel@tonic-gate } 14897c478bd9Sstevel@tonic-gate } 1490df19b344Svi head = sctp_add_proto_hdr(sctp, fp, *nmp, sacklen, NULL); 14917c478bd9Sstevel@tonic-gate if (head == NULL) { 14927c478bd9Sstevel@tonic-gate freemsg(*nmp); 14937c478bd9Sstevel@tonic-gate *nmp = NULL; 1494f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_send_ftsn_failed); 14957c478bd9Sstevel@tonic-gate return; 14967c478bd9Sstevel@tonic-gate } 14977c478bd9Sstevel@tonic-gate *seglen += sacklen; 14987c478bd9Sstevel@tonic-gate *nmp = head; 14997c478bd9Sstevel@tonic-gate 15007c478bd9Sstevel@tonic-gate /* 15017c478bd9Sstevel@tonic-gate * XXXNeed to optimise this, the reason it is done here is so 15027c478bd9Sstevel@tonic-gate * that we don't have to undo in case of failure. 15037c478bd9Sstevel@tonic-gate */ 15047c478bd9Sstevel@tonic-gate mp1 = mp_head; 15057c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 15067c478bd9Sstevel@tonic-gate while (meta_head != NULL && 15077c478bd9Sstevel@tonic-gate SEQ_GEQ(sctp->sctp_adv_pap, ntohl(sdc->sdh_tsn))) { 15087c478bd9Sstevel@tonic-gate if (!SCTP_IS_MSG_ABANDONED(meta_head)) 15097c478bd9Sstevel@tonic-gate SCTP_MSG_SET_ABANDONED(meta_head); 15107c478bd9Sstevel@tonic-gate while (mp1 != NULL && SCTP_CHUNK_ISSENT(mp1)) { 15117c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 15127c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISACKED(mp1)) { 15137c478bd9Sstevel@tonic-gate clen = ntohs(sdc->sdh_len) - sizeof (*sdc); 15147c478bd9Sstevel@tonic-gate SCTP_CHUNK_SENT(sctp, mp1, sdc, fp, clen, 15157c478bd9Sstevel@tonic-gate meta_head); 15167c478bd9Sstevel@tonic-gate } 15177c478bd9Sstevel@tonic-gate mp1 = mp1->b_next; 15187c478bd9Sstevel@tonic-gate } 15197c478bd9Sstevel@tonic-gate while (mp1 != NULL) { 15207c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 15217c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ABANDONED(mp1)) { 15227c478bd9Sstevel@tonic-gate ASSERT(!SCTP_CHUNK_ISSENT(mp1)); 15237c478bd9Sstevel@tonic-gate unsent += ntohs(sdc->sdh_len) - sizeof (*sdc); 15247c478bd9Sstevel@tonic-gate SCTP_ABANDON_CHUNK(mp1); 15257c478bd9Sstevel@tonic-gate } 15267c478bd9Sstevel@tonic-gate mp1 = mp1->b_next; 15277c478bd9Sstevel@tonic-gate } 15287c478bd9Sstevel@tonic-gate meta_head = meta_head->b_next; 15297c478bd9Sstevel@tonic-gate if (meta_head != NULL) { 15307c478bd9Sstevel@tonic-gate mp1 = meta_head->b_cont; 15317c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp1)) 15327c478bd9Sstevel@tonic-gate break; 15337c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 15347c478bd9Sstevel@tonic-gate } 15357c478bd9Sstevel@tonic-gate } 15367c478bd9Sstevel@tonic-gate if (unsent > 0) { 15377c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_unsent >= unsent); 15387c478bd9Sstevel@tonic-gate sctp->sctp_unsent -= unsent; 15397c478bd9Sstevel@tonic-gate /* 15407c478bd9Sstevel@tonic-gate * Update ULP the amount of queued data, which is 15417c478bd9Sstevel@tonic-gate * sent-unack'ed + unsent. 15427c478bd9Sstevel@tonic-gate */ 15437c478bd9Sstevel@tonic-gate if (!SCTP_IS_DETACHED(sctp)) { 15447c478bd9Sstevel@tonic-gate sctp->sctp_ulp_xmitted(sctp->sctp_ulpd, 15457c478bd9Sstevel@tonic-gate sctp->sctp_unacked + sctp->sctp_unsent); 15467c478bd9Sstevel@tonic-gate } 15477c478bd9Sstevel@tonic-gate } 15487c478bd9Sstevel@tonic-gate } 15497c478bd9Sstevel@tonic-gate 15507c478bd9Sstevel@tonic-gate /* 15517c478bd9Sstevel@tonic-gate * This function steps through messages starting at meta and checks if 15527c478bd9Sstevel@tonic-gate * the message is abandoned. It stops when it hits an unsent chunk or 15537c478bd9Sstevel@tonic-gate * a message that has all its chunk acked. This is the only place 15547c478bd9Sstevel@tonic-gate * where the sctp_adv_pap is moved forward to indicated abandoned 15557c478bd9Sstevel@tonic-gate * messages. 15567c478bd9Sstevel@tonic-gate */ 15577c478bd9Sstevel@tonic-gate void 15587c478bd9Sstevel@tonic-gate sctp_check_adv_ack_pt(sctp_t *sctp, mblk_t *meta, mblk_t *mp) 15597c478bd9Sstevel@tonic-gate { 15607c478bd9Sstevel@tonic-gate uint32_t tsn = sctp->sctp_adv_pap; 15617c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 15627c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *msg_hdr; 15637c478bd9Sstevel@tonic-gate 15647c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 15657c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 15667c478bd9Sstevel@tonic-gate ASSERT(SEQ_GT(ntohl(sdc->sdh_tsn), sctp->sctp_lastack_rxd)); 15677c478bd9Sstevel@tonic-gate msg_hdr = (sctp_msg_hdr_t *)meta->b_rptr; 15687c478bd9Sstevel@tonic-gate if (!SCTP_IS_MSG_ABANDONED(meta) && 15697c478bd9Sstevel@tonic-gate !SCTP_MSG_TO_BE_ABANDONED(meta, msg_hdr, sctp)) { 15707c478bd9Sstevel@tonic-gate return; 15717c478bd9Sstevel@tonic-gate } 15727c478bd9Sstevel@tonic-gate while (meta != NULL) { 15737c478bd9Sstevel@tonic-gate while (mp != NULL && SCTP_CHUNK_ISSENT(mp)) { 15747c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 15757c478bd9Sstevel@tonic-gate tsn = ntohl(sdc->sdh_tsn); 15767c478bd9Sstevel@tonic-gate mp = mp->b_next; 15777c478bd9Sstevel@tonic-gate } 15787c478bd9Sstevel@tonic-gate if (mp != NULL) 15797c478bd9Sstevel@tonic-gate break; 15807c478bd9Sstevel@tonic-gate /* 15817c478bd9Sstevel@tonic-gate * We continue checking for successive messages only if there 15827c478bd9Sstevel@tonic-gate * is a chunk marked for retransmission. Else, we might 15837c478bd9Sstevel@tonic-gate * end up sending FTSN prematurely for chunks that have been 15847c478bd9Sstevel@tonic-gate * sent, but not yet acked. 15857c478bd9Sstevel@tonic-gate */ 15867c478bd9Sstevel@tonic-gate if ((meta = meta->b_next) != NULL) { 15877c478bd9Sstevel@tonic-gate msg_hdr = (sctp_msg_hdr_t *)meta->b_rptr; 15887c478bd9Sstevel@tonic-gate if (!SCTP_IS_MSG_ABANDONED(meta) && 15897c478bd9Sstevel@tonic-gate !SCTP_MSG_TO_BE_ABANDONED(meta, msg_hdr, sctp)) { 15907c478bd9Sstevel@tonic-gate break; 15917c478bd9Sstevel@tonic-gate } 15927c478bd9Sstevel@tonic-gate for (mp = meta->b_cont; mp != NULL; mp = mp->b_next) { 15937c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp)) { 15947c478bd9Sstevel@tonic-gate sctp->sctp_adv_pap = tsn; 15957c478bd9Sstevel@tonic-gate return; 15967c478bd9Sstevel@tonic-gate } 15977c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_WANT_REXMIT(mp)) 15987c478bd9Sstevel@tonic-gate break; 15997c478bd9Sstevel@tonic-gate } 16007c478bd9Sstevel@tonic-gate if (mp == NULL) 16017c478bd9Sstevel@tonic-gate break; 16027c478bd9Sstevel@tonic-gate } 16037c478bd9Sstevel@tonic-gate } 16047c478bd9Sstevel@tonic-gate sctp->sctp_adv_pap = tsn; 16057c478bd9Sstevel@tonic-gate } 16067c478bd9Sstevel@tonic-gate 160777c67f2fSkcpoon 160877c67f2fSkcpoon /* 160977c67f2fSkcpoon * Determine if we should bundle a data chunk with the chunk being 161077c67f2fSkcpoon * retransmitted. We bundle if 161177c67f2fSkcpoon * 161277c67f2fSkcpoon * - the chunk is sent to the same destination and unack'ed. 161377c67f2fSkcpoon * 161477c67f2fSkcpoon * OR 161577c67f2fSkcpoon * 161677c67f2fSkcpoon * - the chunk is unsent, i.e. new data. 161777c67f2fSkcpoon */ 161877c67f2fSkcpoon #define SCTP_CHUNK_RX_CANBUNDLE(mp, fp) \ 161977c67f2fSkcpoon (!SCTP_CHUNK_ABANDONED((mp)) && \ 162077c67f2fSkcpoon ((SCTP_CHUNK_ISSENT((mp)) && (SCTP_CHUNK_DEST(mp) == (fp) && \ 162177c67f2fSkcpoon !SCTP_CHUNK_ISACKED(mp))) || \ 162277c67f2fSkcpoon (((mp)->b_flag & (SCTP_CHUNK_FLAG_REXMIT|SCTP_CHUNK_FLAG_SENT)) != \ 162377c67f2fSkcpoon SCTP_CHUNK_FLAG_SENT))) 162477c67f2fSkcpoon 16257c478bd9Sstevel@tonic-gate /* 16267c478bd9Sstevel@tonic-gate * Retransmit first segment which hasn't been acked with cumtsn or send 16277c478bd9Sstevel@tonic-gate * a Forward TSN chunk, if appropriate. 16287c478bd9Sstevel@tonic-gate */ 16297c478bd9Sstevel@tonic-gate void 16307c478bd9Sstevel@tonic-gate sctp_rexmit(sctp_t *sctp, sctp_faddr_t *oldfp) 16317c478bd9Sstevel@tonic-gate { 16327c478bd9Sstevel@tonic-gate mblk_t *mp; 16337c478bd9Sstevel@tonic-gate mblk_t *nmp = NULL; 16347c478bd9Sstevel@tonic-gate mblk_t *head; 16357c478bd9Sstevel@tonic-gate mblk_t *meta = sctp->sctp_xmit_head; 16367c478bd9Sstevel@tonic-gate mblk_t *fill; 16377c478bd9Sstevel@tonic-gate uint32_t seglen = 0; 16387c478bd9Sstevel@tonic-gate uint32_t sacklen; 16397c478bd9Sstevel@tonic-gate uint16_t chunklen; 16407c478bd9Sstevel@tonic-gate int extra; 16417c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 16427c478bd9Sstevel@tonic-gate sctp_faddr_t *fp; 16437c478bd9Sstevel@tonic-gate uint32_t adv_pap = sctp->sctp_adv_pap; 16447c478bd9Sstevel@tonic-gate boolean_t do_ftsn = B_FALSE; 16457c478bd9Sstevel@tonic-gate boolean_t ftsn_check = B_TRUE; 164677c67f2fSkcpoon uint32_t first_ua_tsn; 164777c67f2fSkcpoon sctp_msg_hdr_t *mhdr; 1648f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 16497c478bd9Sstevel@tonic-gate 16507c478bd9Sstevel@tonic-gate while (meta != NULL) { 16517c478bd9Sstevel@tonic-gate for (mp = meta->b_cont; mp != NULL; mp = mp->b_next) { 16527c478bd9Sstevel@tonic-gate uint32_t tsn; 16537c478bd9Sstevel@tonic-gate 16547c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp)) 16557c478bd9Sstevel@tonic-gate goto window_probe; 16567c478bd9Sstevel@tonic-gate /* 16577c478bd9Sstevel@tonic-gate * We break in the following cases - 16587c478bd9Sstevel@tonic-gate * 16597c478bd9Sstevel@tonic-gate * if the advanced peer ack point includes the next 16607c478bd9Sstevel@tonic-gate * chunk to be retransmited - possibly the Forward 16617c478bd9Sstevel@tonic-gate * TSN was lost. 16627c478bd9Sstevel@tonic-gate * 16637c478bd9Sstevel@tonic-gate * if we are PRSCTP aware and the next chunk to be 16647c478bd9Sstevel@tonic-gate * retransmitted is now abandoned 16657c478bd9Sstevel@tonic-gate * 16667c478bd9Sstevel@tonic-gate * if the next chunk to be retransmitted is for 16677c478bd9Sstevel@tonic-gate * the dest on which the timer went off. (this 16687c478bd9Sstevel@tonic-gate * message is not abandoned). 16697c478bd9Sstevel@tonic-gate * 16707c478bd9Sstevel@tonic-gate * We check for Forward TSN only for the first 16717c478bd9Sstevel@tonic-gate * eligible chunk to be retransmitted. The reason 16727c478bd9Sstevel@tonic-gate * being if the first eligible chunk is skipped (say 16737c478bd9Sstevel@tonic-gate * it was sent to a destination other than oldfp) 16747c478bd9Sstevel@tonic-gate * then we cannot advance the cum TSN via Forward 16757c478bd9Sstevel@tonic-gate * TSN chunk. 16767c478bd9Sstevel@tonic-gate * 16777c478bd9Sstevel@tonic-gate * Also, ftsn_check is B_TRUE only for the first 16787c478bd9Sstevel@tonic-gate * eligible chunk, it will be B_FALSE for all 16797c478bd9Sstevel@tonic-gate * subsequent candidate messages for retransmission. 16807c478bd9Sstevel@tonic-gate */ 16817c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 16827c478bd9Sstevel@tonic-gate tsn = ntohl(sdc->sdh_tsn); 16837c478bd9Sstevel@tonic-gate if (SEQ_GT(tsn, sctp->sctp_lastack_rxd)) { 16847c478bd9Sstevel@tonic-gate if (sctp->sctp_prsctp_aware && ftsn_check) { 16857c478bd9Sstevel@tonic-gate if (SEQ_GEQ(sctp->sctp_adv_pap, tsn)) { 16867c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_prsctp_aware); 16877c478bd9Sstevel@tonic-gate do_ftsn = B_TRUE; 16887c478bd9Sstevel@tonic-gate goto out; 16897c478bd9Sstevel@tonic-gate } else { 16907c478bd9Sstevel@tonic-gate sctp_check_adv_ack_pt(sctp, 16917c478bd9Sstevel@tonic-gate meta, mp); 16927c478bd9Sstevel@tonic-gate if (SEQ_GT(sctp->sctp_adv_pap, 16937c478bd9Sstevel@tonic-gate adv_pap)) { 16947c478bd9Sstevel@tonic-gate do_ftsn = B_TRUE; 16957c478bd9Sstevel@tonic-gate goto out; 16967c478bd9Sstevel@tonic-gate } 16977c478bd9Sstevel@tonic-gate } 16987c478bd9Sstevel@tonic-gate ftsn_check = B_FALSE; 16997c478bd9Sstevel@tonic-gate } 17007c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_DEST(mp) == oldfp) 17017c478bd9Sstevel@tonic-gate goto out; 17027c478bd9Sstevel@tonic-gate } 17037c478bd9Sstevel@tonic-gate } 17047c478bd9Sstevel@tonic-gate meta = meta->b_next; 17057c478bd9Sstevel@tonic-gate if (meta != NULL && sctp->sctp_prsctp_aware) { 170677c67f2fSkcpoon mhdr = (sctp_msg_hdr_t *)meta->b_rptr; 17077c478bd9Sstevel@tonic-gate 17087c478bd9Sstevel@tonic-gate while (meta != NULL && (SCTP_IS_MSG_ABANDONED(meta) || 17097c478bd9Sstevel@tonic-gate SCTP_MSG_TO_BE_ABANDONED(meta, mhdr, sctp))) { 17107c478bd9Sstevel@tonic-gate meta = meta->b_next; 17117c478bd9Sstevel@tonic-gate } 17127c478bd9Sstevel@tonic-gate } 17137c478bd9Sstevel@tonic-gate } 17147c478bd9Sstevel@tonic-gate window_probe: 17157c478bd9Sstevel@tonic-gate /* 17167c478bd9Sstevel@tonic-gate * Retransmit fired for a destination which didn't have 17177c478bd9Sstevel@tonic-gate * any unacked data pending. 17187c478bd9Sstevel@tonic-gate */ 1719769b977dSvi if (sctp->sctp_unacked == 0 && sctp->sctp_unsent != 0) { 17207c478bd9Sstevel@tonic-gate /* 17217c478bd9Sstevel@tonic-gate * Send a window probe. Inflate frwnd to allow 17227c478bd9Sstevel@tonic-gate * sending one segment. 17237c478bd9Sstevel@tonic-gate */ 1724769b977dSvi if (sctp->sctp_frwnd < (oldfp->sfa_pmss - sizeof (*sdc))) 17257c478bd9Sstevel@tonic-gate sctp->sctp_frwnd = oldfp->sfa_pmss - sizeof (*sdc); 172612f47623Skcpoon 1727769b977dSvi /* next TSN to send */ 1728769b977dSvi sctp->sctp_rxt_nxttsn = sctp->sctp_ltsn; 172912f47623Skcpoon 173012f47623Skcpoon /* 173112f47623Skcpoon * The above sctp_frwnd adjustment is coarse. The "changed" 173212f47623Skcpoon * sctp_frwnd may allow us to send more than 1 packet. So 173312f47623Skcpoon * tell sctp_output() to send only 1 packet. 173412f47623Skcpoon */ 173512f47623Skcpoon sctp_output(sctp, 1); 173612f47623Skcpoon 1737769b977dSvi /* Last sent TSN */ 1738769b977dSvi sctp->sctp_rxt_maxtsn = sctp->sctp_ltsn - 1; 1739769b977dSvi ASSERT(sctp->sctp_rxt_maxtsn >= sctp->sctp_rxt_nxttsn); 1740769b977dSvi sctp->sctp_zero_win_probe = B_TRUE; 1741f4b3ec61Sdh BUMP_MIB(&sctps->sctps_mib, sctpOutWinProbe); 17427c478bd9Sstevel@tonic-gate } 17437c478bd9Sstevel@tonic-gate return; 17447c478bd9Sstevel@tonic-gate out: 1745769b977dSvi /* 174612f47623Skcpoon * After a time out, assume that everything has left the network. So 174712f47623Skcpoon * we can clear rxt_unacked for the original peer address. 174812f47623Skcpoon */ 174912f47623Skcpoon oldfp->rxt_unacked = 0; 175012f47623Skcpoon 175112f47623Skcpoon /* 175212f47623Skcpoon * If we were probing for zero window, don't adjust retransmission 1753769b977dSvi * variables, but the timer is still backed off. 1754769b977dSvi */ 1755769b977dSvi if (sctp->sctp_zero_win_probe) { 1756769b977dSvi mblk_t *pkt; 1757769b977dSvi uint_t pkt_len; 1758769b977dSvi 1759769b977dSvi /* 1760769b977dSvi * Get the Zero Win Probe for retrasmission, sctp_rxt_nxttsn 1761769b977dSvi * and sctp_rxt_maxtsn will specify the ZWP packet. 1762769b977dSvi */ 1763769b977dSvi fp = oldfp; 1764769b977dSvi if (oldfp->state != SCTP_FADDRS_ALIVE) 1765769b977dSvi fp = sctp_rotate_faddr(sctp, oldfp); 1766769b977dSvi pkt = sctp_rexmit_packet(sctp, &meta, &mp, fp, &pkt_len); 1767769b977dSvi if (pkt != NULL) { 1768769b977dSvi ASSERT(pkt_len <= fp->sfa_pmss); 1769769b977dSvi sctp_set_iplen(sctp, pkt); 1770769b977dSvi sctp_add_sendq(sctp, pkt); 1771769b977dSvi } else { 1772f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_ss_rexmit_failed); 1773769b977dSvi } 177412f47623Skcpoon 177512f47623Skcpoon /* 177612f47623Skcpoon * The strikes will be clear by sctp_faddr_alive() when the 177712f47623Skcpoon * other side sends us an ack. 177812f47623Skcpoon */ 1779769b977dSvi oldfp->strikes++; 1780769b977dSvi sctp->sctp_strikes++; 178112f47623Skcpoon 1782769b977dSvi SCTP_CALC_RXT(oldfp, sctp->sctp_rto_max); 1783769b977dSvi if (oldfp != fp && oldfp->suna != 0) 1784769b977dSvi SCTP_FADDR_TIMER_RESTART(sctp, oldfp, fp->rto); 1785769b977dSvi SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->rto); 1786f4b3ec61Sdh BUMP_MIB(&sctps->sctps_mib, sctpOutWinProbe); 1787769b977dSvi return; 1788769b977dSvi } 1789769b977dSvi 17907c478bd9Sstevel@tonic-gate /* 17917c478bd9Sstevel@tonic-gate * Enter slowstart for this destination 17927c478bd9Sstevel@tonic-gate */ 17937c478bd9Sstevel@tonic-gate oldfp->ssthresh = oldfp->cwnd / 2; 17947c478bd9Sstevel@tonic-gate if (oldfp->ssthresh < 2 * oldfp->sfa_pmss) 17957c478bd9Sstevel@tonic-gate oldfp->ssthresh = 2 * oldfp->sfa_pmss; 17967c478bd9Sstevel@tonic-gate oldfp->cwnd = oldfp->sfa_pmss; 17977c478bd9Sstevel@tonic-gate oldfp->pba = 0; 17987c478bd9Sstevel@tonic-gate fp = sctp_rotate_faddr(sctp, oldfp); 17997c478bd9Sstevel@tonic-gate ASSERT(fp != NULL); 18007c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 18017c478bd9Sstevel@tonic-gate 180277c67f2fSkcpoon first_ua_tsn = ntohl(sdc->sdh_tsn); 18037c478bd9Sstevel@tonic-gate if (do_ftsn) { 18047c478bd9Sstevel@tonic-gate sctp_make_ftsns(sctp, meta, mp, &nmp, fp, &seglen); 18057c478bd9Sstevel@tonic-gate if (nmp == NULL) { 18067c478bd9Sstevel@tonic-gate sctp->sctp_adv_pap = adv_pap; 18077c478bd9Sstevel@tonic-gate goto restart_timer; 18087c478bd9Sstevel@tonic-gate } 18097c478bd9Sstevel@tonic-gate head = nmp; 181077c67f2fSkcpoon /* 181177c67f2fSkcpoon * Move to the next unabandoned chunk. XXXCheck if meta will 181277c67f2fSkcpoon * always be marked abandoned. 181377c67f2fSkcpoon */ 181477c67f2fSkcpoon while (meta != NULL && SCTP_IS_MSG_ABANDONED(meta)) 181577c67f2fSkcpoon meta = meta->b_next; 18167c478bd9Sstevel@tonic-gate if (meta != NULL) 181777c67f2fSkcpoon mp = mp->b_cont; 181877c67f2fSkcpoon else 181977c67f2fSkcpoon mp = NULL; 18207c478bd9Sstevel@tonic-gate goto try_bundle; 18217c478bd9Sstevel@tonic-gate } 18227c478bd9Sstevel@tonic-gate seglen = ntohs(sdc->sdh_len); 18237c478bd9Sstevel@tonic-gate chunklen = seglen - sizeof (*sdc); 18247c478bd9Sstevel@tonic-gate if ((extra = seglen & (SCTP_ALIGN - 1)) != 0) 18257c478bd9Sstevel@tonic-gate extra = SCTP_ALIGN - extra; 18267c478bd9Sstevel@tonic-gate 182777c67f2fSkcpoon /* Find out if we need to piggyback SACK. */ 18287c478bd9Sstevel@tonic-gate if (sctp->sctp_ftsn == sctp->sctp_lastacked + 1) { 18297c478bd9Sstevel@tonic-gate sacklen = 0; 18307c478bd9Sstevel@tonic-gate } else { 18317c478bd9Sstevel@tonic-gate sacklen = sizeof (sctp_chunk_hdr_t) + 18327c478bd9Sstevel@tonic-gate sizeof (sctp_sack_chunk_t) + 18337c478bd9Sstevel@tonic-gate (sizeof (sctp_sack_frag_t) * sctp->sctp_sack_gaps); 18347c478bd9Sstevel@tonic-gate if (seglen + sacklen > sctp->sctp_lastdata->sfa_pmss) { 18357c478bd9Sstevel@tonic-gate /* piggybacked SACK doesn't fit */ 18367c478bd9Sstevel@tonic-gate sacklen = 0; 18377c478bd9Sstevel@tonic-gate } else { 183877c67f2fSkcpoon /* 183977c67f2fSkcpoon * OK, we have room to send SACK back. But we 184077c67f2fSkcpoon * should send it back to the last fp where we 184177c67f2fSkcpoon * receive data from, unless sctp_lastdata equals 184277c67f2fSkcpoon * oldfp, then we should probably not send it 184377c67f2fSkcpoon * back to that fp. Also we should check that 184477c67f2fSkcpoon * the fp is alive. 184577c67f2fSkcpoon */ 184677c67f2fSkcpoon if (sctp->sctp_lastdata != oldfp && 184777c67f2fSkcpoon sctp->sctp_lastdata->state == SCTP_FADDRS_ALIVE) { 184877c67f2fSkcpoon fp = sctp->sctp_lastdata; 184977c67f2fSkcpoon } 18507c478bd9Sstevel@tonic-gate } 18517c478bd9Sstevel@tonic-gate } 18527c478bd9Sstevel@tonic-gate 185377c67f2fSkcpoon /* 185477c67f2fSkcpoon * Cancel RTT measurement if the retransmitted TSN is before the 185577c67f2fSkcpoon * TSN used for timimg. 185677c67f2fSkcpoon */ 185777c67f2fSkcpoon if (sctp->sctp_out_time != 0 && 185877c67f2fSkcpoon SEQ_GEQ(sctp->sctp_rtt_tsn, sdc->sdh_tsn)) { 185977c67f2fSkcpoon sctp->sctp_out_time = 0; 186077c67f2fSkcpoon } 186177c67f2fSkcpoon /* Clear the counter as the RTT calculation may be off. */ 186277c67f2fSkcpoon fp->rtt_updates = 0; 186377c67f2fSkcpoon oldfp->rtt_updates = 0; 186477c67f2fSkcpoon 186577c67f2fSkcpoon /* 186677c67f2fSkcpoon * After a timeout, we should change the current faddr so that 186777c67f2fSkcpoon * new chunks will be sent to the alternate address. 186877c67f2fSkcpoon */ 186977c67f2fSkcpoon sctp_set_faddr_current(sctp, fp); 187077c67f2fSkcpoon 18717c478bd9Sstevel@tonic-gate nmp = dupmsg(mp); 18727c478bd9Sstevel@tonic-gate if (nmp == NULL) 18737c478bd9Sstevel@tonic-gate goto restart_timer; 18747c478bd9Sstevel@tonic-gate if (extra > 0) { 1875*121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 18767c478bd9Sstevel@tonic-gate if (fill != NULL) { 18777c478bd9Sstevel@tonic-gate linkb(nmp, fill); 18787c478bd9Sstevel@tonic-gate seglen += extra; 18797c478bd9Sstevel@tonic-gate } else { 18807c478bd9Sstevel@tonic-gate freemsg(nmp); 18817c478bd9Sstevel@tonic-gate goto restart_timer; 18827c478bd9Sstevel@tonic-gate } 18837c478bd9Sstevel@tonic-gate } 18847c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_FLAGS(nmp); 1885df19b344Svi head = sctp_add_proto_hdr(sctp, fp, nmp, sacklen, NULL); 18867c478bd9Sstevel@tonic-gate if (head == NULL) { 18877c478bd9Sstevel@tonic-gate freemsg(nmp); 1888f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_rexmit_failed); 18897c478bd9Sstevel@tonic-gate goto restart_timer; 18907c478bd9Sstevel@tonic-gate } 18917c478bd9Sstevel@tonic-gate seglen += sacklen; 18927c478bd9Sstevel@tonic-gate 18937c478bd9Sstevel@tonic-gate SCTP_CHUNK_SENT(sctp, mp, sdc, fp, chunklen, meta); 18947c478bd9Sstevel@tonic-gate 18957c478bd9Sstevel@tonic-gate mp = mp->b_next; 189677c67f2fSkcpoon 18977c478bd9Sstevel@tonic-gate try_bundle: 189812f47623Skcpoon /* We can at least and at most send 1 packet at timeout. */ 18997c478bd9Sstevel@tonic-gate while (seglen < fp->sfa_pmss) { 19007c478bd9Sstevel@tonic-gate int32_t new_len; 19017c478bd9Sstevel@tonic-gate 190277c67f2fSkcpoon /* Go through the list to find more chunks to be bundled. */ 19037c478bd9Sstevel@tonic-gate while (mp != NULL) { 190477c67f2fSkcpoon /* Check if the chunk can be bundled. */ 190577c67f2fSkcpoon if (SCTP_CHUNK_RX_CANBUNDLE(mp, oldfp)) 19067c478bd9Sstevel@tonic-gate break; 19077c478bd9Sstevel@tonic-gate mp = mp->b_next; 19087c478bd9Sstevel@tonic-gate } 190977c67f2fSkcpoon /* Go to the next message. */ 19107c478bd9Sstevel@tonic-gate if (mp == NULL) { 191177c67f2fSkcpoon for (meta = meta->b_next; meta != NULL; 191277c67f2fSkcpoon meta = meta->b_next) { 191377c67f2fSkcpoon mhdr = (sctp_msg_hdr_t *)meta->b_rptr; 191477c67f2fSkcpoon 191577c67f2fSkcpoon if (SCTP_IS_MSG_ABANDONED(meta) || 191677c67f2fSkcpoon SCTP_MSG_TO_BE_ABANDONED(meta, mhdr, 191777c67f2fSkcpoon sctp)) { 191877c67f2fSkcpoon continue; 191977c67f2fSkcpoon } 192077c67f2fSkcpoon 192177c67f2fSkcpoon mp = meta->b_cont; 192277c67f2fSkcpoon goto try_bundle; 192377c67f2fSkcpoon } 192477c67f2fSkcpoon /* No more chunk to be bundled. */ 192577c67f2fSkcpoon break; 19267c478bd9Sstevel@tonic-gate } 192777c67f2fSkcpoon 19287c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 192977c67f2fSkcpoon new_len = ntohs(sdc->sdh_len); 193077c67f2fSkcpoon chunklen = new_len - sizeof (*sdc); 19317c478bd9Sstevel@tonic-gate 193277c67f2fSkcpoon if ((extra = new_len & (SCTP_ALIGN - 1)) != 0) 193377c67f2fSkcpoon extra = SCTP_ALIGN - extra; 193477c67f2fSkcpoon if ((new_len = seglen + new_len + extra) > fp->sfa_pmss) 193577c67f2fSkcpoon break; 193677c67f2fSkcpoon if ((nmp = dupmsg(mp)) == NULL) 193777c67f2fSkcpoon break; 19387c478bd9Sstevel@tonic-gate 193977c67f2fSkcpoon if (extra > 0) { 1940*121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 19417c478bd9Sstevel@tonic-gate if (fill != NULL) { 194277c67f2fSkcpoon linkb(nmp, fill); 19437c478bd9Sstevel@tonic-gate } else { 194477c67f2fSkcpoon freemsg(nmp); 19457c478bd9Sstevel@tonic-gate break; 19467c478bd9Sstevel@tonic-gate } 19477c478bd9Sstevel@tonic-gate } 194877c67f2fSkcpoon linkb(head, nmp); 19497c478bd9Sstevel@tonic-gate 19507c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_FLAGS(nmp); 19517c478bd9Sstevel@tonic-gate SCTP_CHUNK_SENT(sctp, mp, sdc, fp, chunklen, meta); 195277c67f2fSkcpoon 195377c67f2fSkcpoon seglen = new_len; 19547c478bd9Sstevel@tonic-gate mp = mp->b_next; 19557c478bd9Sstevel@tonic-gate } 195677c67f2fSkcpoon done_bundle: 19577c478bd9Sstevel@tonic-gate if ((seglen > fp->sfa_pmss) && fp->isv4) { 19587c478bd9Sstevel@tonic-gate ipha_t *iph = (ipha_t *)head->b_rptr; 19597c478bd9Sstevel@tonic-gate 19607c478bd9Sstevel@tonic-gate /* 19617c478bd9Sstevel@tonic-gate * Path MTU is different from path we thought it would 19627c478bd9Sstevel@tonic-gate * be when we created chunks, or IP headers have grown. 19637c478bd9Sstevel@tonic-gate * Need to clear the DF bit. 19647c478bd9Sstevel@tonic-gate */ 19657c478bd9Sstevel@tonic-gate iph->ipha_fragment_offset_and_flags = 0; 19667c478bd9Sstevel@tonic-gate } 196712f47623Skcpoon fp->rxt_unacked += seglen; 196812f47623Skcpoon 19697c478bd9Sstevel@tonic-gate dprint(2, ("sctp_rexmit: Sending packet %d bytes, tsn %x " 19707c478bd9Sstevel@tonic-gate "ssn %d to %p (rwnd %d, lastack_rxd %x)\n", 197145916cd2Sjpk seglen, ntohl(sdc->sdh_tsn), ntohs(sdc->sdh_ssn), 197245916cd2Sjpk (void *)fp, sctp->sctp_frwnd, sctp->sctp_lastack_rxd)); 19737c478bd9Sstevel@tonic-gate 197477c67f2fSkcpoon sctp->sctp_rexmitting = B_TRUE; 197577c67f2fSkcpoon sctp->sctp_rxt_nxttsn = first_ua_tsn; 197677c67f2fSkcpoon sctp->sctp_rxt_maxtsn = sctp->sctp_ltsn - 1; 19777c478bd9Sstevel@tonic-gate sctp_set_iplen(sctp, head); 19787c478bd9Sstevel@tonic-gate sctp_add_sendq(sctp, head); 19797c478bd9Sstevel@tonic-gate 19807c478bd9Sstevel@tonic-gate /* 198177c67f2fSkcpoon * Restart the oldfp timer with exponential backoff and 198277c67f2fSkcpoon * the new fp timer for the retransmitted chunks. 19837c478bd9Sstevel@tonic-gate */ 19847c478bd9Sstevel@tonic-gate restart_timer: 19857c478bd9Sstevel@tonic-gate oldfp->strikes++; 19867c478bd9Sstevel@tonic-gate sctp->sctp_strikes++; 19877c478bd9Sstevel@tonic-gate SCTP_CALC_RXT(oldfp, sctp->sctp_rto_max); 19887c478bd9Sstevel@tonic-gate if (oldfp->suna != 0) 19897c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, oldfp, oldfp->rto); 19907c478bd9Sstevel@tonic-gate sctp->sctp_active = lbolt64; 199177c67f2fSkcpoon 199277c67f2fSkcpoon /* 199377c67f2fSkcpoon * Should we restart the timer of the new fp? If there is 199477c67f2fSkcpoon * outstanding data to the new fp, the timer should be 199577c67f2fSkcpoon * running already. So restarting it means that the timer 199677c67f2fSkcpoon * will fire later for those outstanding data. But if 199777c67f2fSkcpoon * we don't restart it, the timer will fire too early for the 199877c67f2fSkcpoon * just retransmitted chunks to the new fp. The reason is that we 199977c67f2fSkcpoon * don't keep a timestamp on when a chunk is retransmitted. 200077c67f2fSkcpoon * So when the timer fires, it will just search for the 200177c67f2fSkcpoon * chunk with the earliest TSN sent to new fp. This probably 200277c67f2fSkcpoon * is the chunk we just retransmitted. So for now, let's 200377c67f2fSkcpoon * be conservative and restart the timer of the new fp. 200477c67f2fSkcpoon */ 200577c67f2fSkcpoon SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->rto); 20067c478bd9Sstevel@tonic-gate } 20077c478bd9Sstevel@tonic-gate 20087c478bd9Sstevel@tonic-gate /* 20097c478bd9Sstevel@tonic-gate * The SCTP write put procedure called from IP. 20107c478bd9Sstevel@tonic-gate */ 20117c478bd9Sstevel@tonic-gate void 20127c478bd9Sstevel@tonic-gate sctp_wput(queue_t *q, mblk_t *mp) 20137c478bd9Sstevel@tonic-gate { 20147c478bd9Sstevel@tonic-gate uchar_t *rptr; 20157c478bd9Sstevel@tonic-gate t_scalar_t type; 20167c478bd9Sstevel@tonic-gate 20177c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 20187c478bd9Sstevel@tonic-gate case M_IOCTL: 20197c478bd9Sstevel@tonic-gate sctp_wput_ioctl(q, mp); 20207c478bd9Sstevel@tonic-gate break; 20217c478bd9Sstevel@tonic-gate case M_DATA: 20227c478bd9Sstevel@tonic-gate /* Should be handled in sctp_output() */ 20237c478bd9Sstevel@tonic-gate ASSERT(0); 20247c478bd9Sstevel@tonic-gate freemsg(mp); 20257c478bd9Sstevel@tonic-gate break; 20267c478bd9Sstevel@tonic-gate case M_PROTO: 20277c478bd9Sstevel@tonic-gate case M_PCPROTO: 20287c478bd9Sstevel@tonic-gate rptr = mp->b_rptr; 20297c478bd9Sstevel@tonic-gate if ((mp->b_wptr - rptr) >= sizeof (t_scalar_t)) { 20307c478bd9Sstevel@tonic-gate type = ((union T_primitives *)rptr)->type; 20317c478bd9Sstevel@tonic-gate /* 20327c478bd9Sstevel@tonic-gate * There is no "standard" way on how to respond 20337c478bd9Sstevel@tonic-gate * to T_CAPABILITY_REQ if a module does not 20347c478bd9Sstevel@tonic-gate * understand it. And the current TI mod 20357c478bd9Sstevel@tonic-gate * has problems handling an error ack. So we 20367c478bd9Sstevel@tonic-gate * catch the request here and reply with a response 20377c478bd9Sstevel@tonic-gate * which the TI mod knows how to respond to. 20387c478bd9Sstevel@tonic-gate */ 20397c478bd9Sstevel@tonic-gate switch (type) { 20407c478bd9Sstevel@tonic-gate case T_CAPABILITY_REQ: 20417c478bd9Sstevel@tonic-gate (void) putnextctl1(RD(q), M_ERROR, EPROTO); 20427c478bd9Sstevel@tonic-gate break; 20437c478bd9Sstevel@tonic-gate default: 20447c478bd9Sstevel@tonic-gate if ((mp = mi_tpi_err_ack_alloc(mp, 20457c478bd9Sstevel@tonic-gate TNOTSUPPORT, 0)) != NULL) { 20467c478bd9Sstevel@tonic-gate qreply(q, mp); 20477c478bd9Sstevel@tonic-gate return; 20487c478bd9Sstevel@tonic-gate } 20497c478bd9Sstevel@tonic-gate } 20507c478bd9Sstevel@tonic-gate } 20517c478bd9Sstevel@tonic-gate /* FALLTHRU */ 20527c478bd9Sstevel@tonic-gate default: 20537c478bd9Sstevel@tonic-gate freemsg(mp); 20547c478bd9Sstevel@tonic-gate return; 20557c478bd9Sstevel@tonic-gate } 20567c478bd9Sstevel@tonic-gate } 205777c67f2fSkcpoon 205877c67f2fSkcpoon /* 205977c67f2fSkcpoon * This function is called by sctp_ss_rexmit() to create a packet 206077c67f2fSkcpoon * to be retransmitted to the given fp. The given meta and mp 206177c67f2fSkcpoon * parameters are respectively the sctp_msg_hdr_t and the mblk of the 206212f47623Skcpoon * first chunk to be retransmitted. This is also called when we want 2063769b977dSvi * to retransmit a zero window probe from sctp_rexmit() or when we 2064769b977dSvi * want to retransmit the zero window probe after the window has 2065769b977dSvi * opened from sctp_got_sack(). 206677c67f2fSkcpoon */ 2067769b977dSvi mblk_t * 206877c67f2fSkcpoon sctp_rexmit_packet(sctp_t *sctp, mblk_t **meta, mblk_t **mp, sctp_faddr_t *fp, 206977c67f2fSkcpoon uint_t *packet_len) 207077c67f2fSkcpoon { 207177c67f2fSkcpoon uint32_t seglen = 0; 207277c67f2fSkcpoon uint16_t chunklen; 207377c67f2fSkcpoon int extra; 207477c67f2fSkcpoon mblk_t *nmp; 207577c67f2fSkcpoon mblk_t *head; 207677c67f2fSkcpoon mblk_t *fill; 207777c67f2fSkcpoon sctp_data_hdr_t *sdc; 207877c67f2fSkcpoon sctp_msg_hdr_t *mhdr; 207977c67f2fSkcpoon 208077c67f2fSkcpoon sdc = (sctp_data_hdr_t *)(*mp)->b_rptr; 208177c67f2fSkcpoon seglen = ntohs(sdc->sdh_len); 208277c67f2fSkcpoon chunklen = seglen - sizeof (*sdc); 208377c67f2fSkcpoon if ((extra = seglen & (SCTP_ALIGN - 1)) != 0) 208477c67f2fSkcpoon extra = SCTP_ALIGN - extra; 208577c67f2fSkcpoon 208677c67f2fSkcpoon nmp = dupmsg(*mp); 208777c67f2fSkcpoon if (nmp == NULL) 208877c67f2fSkcpoon return (NULL); 208977c67f2fSkcpoon if (extra > 0) { 2090*121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 209177c67f2fSkcpoon if (fill != NULL) { 209277c67f2fSkcpoon linkb(nmp, fill); 209377c67f2fSkcpoon seglen += extra; 209477c67f2fSkcpoon } else { 209577c67f2fSkcpoon freemsg(nmp); 209677c67f2fSkcpoon return (NULL); 209777c67f2fSkcpoon } 209877c67f2fSkcpoon } 209977c67f2fSkcpoon SCTP_CHUNK_CLEAR_FLAGS(nmp); 210077c67f2fSkcpoon head = sctp_add_proto_hdr(sctp, fp, nmp, 0, NULL); 210177c67f2fSkcpoon if (head == NULL) { 210277c67f2fSkcpoon freemsg(nmp); 210377c67f2fSkcpoon return (NULL); 210477c67f2fSkcpoon } 210577c67f2fSkcpoon SCTP_CHUNK_SENT(sctp, *mp, sdc, fp, chunklen, *meta); 2106769b977dSvi /* 2107769b977dSvi * Don't update the TSN if we are doing a Zero Win Probe. 2108769b977dSvi */ 2109769b977dSvi if (!sctp->sctp_zero_win_probe) 2110769b977dSvi sctp->sctp_rxt_nxttsn = ntohl(sdc->sdh_tsn); 211177c67f2fSkcpoon *mp = (*mp)->b_next; 211277c67f2fSkcpoon 211377c67f2fSkcpoon try_bundle: 211477c67f2fSkcpoon while (seglen < fp->sfa_pmss) { 211577c67f2fSkcpoon int32_t new_len; 211677c67f2fSkcpoon 211777c67f2fSkcpoon /* 211877c67f2fSkcpoon * Go through the list to find more chunks to be bundled. 211977c67f2fSkcpoon * We should only retransmit sent by unack'ed chunks. Since 212077c67f2fSkcpoon * they were sent before, the peer's receive window should 212177c67f2fSkcpoon * be able to receive them. 212277c67f2fSkcpoon */ 212377c67f2fSkcpoon while (*mp != NULL) { 212477c67f2fSkcpoon /* Check if the chunk can be bundled. */ 212577c67f2fSkcpoon if (SCTP_CHUNK_ISSENT(*mp) && !SCTP_CHUNK_ISACKED(*mp)) 212677c67f2fSkcpoon break; 212777c67f2fSkcpoon *mp = (*mp)->b_next; 212877c67f2fSkcpoon } 212977c67f2fSkcpoon /* Go to the next message. */ 213077c67f2fSkcpoon if (*mp == NULL) { 213177c67f2fSkcpoon for (*meta = (*meta)->b_next; *meta != NULL; 213277c67f2fSkcpoon *meta = (*meta)->b_next) { 213377c67f2fSkcpoon mhdr = (sctp_msg_hdr_t *)(*meta)->b_rptr; 213477c67f2fSkcpoon 213577c67f2fSkcpoon if (SCTP_IS_MSG_ABANDONED(*meta) || 213677c67f2fSkcpoon SCTP_MSG_TO_BE_ABANDONED(*meta, mhdr, 213777c67f2fSkcpoon sctp)) { 213877c67f2fSkcpoon continue; 213977c67f2fSkcpoon } 214077c67f2fSkcpoon 214177c67f2fSkcpoon *mp = (*meta)->b_cont; 214277c67f2fSkcpoon goto try_bundle; 214377c67f2fSkcpoon } 214477c67f2fSkcpoon /* No more chunk to be bundled. */ 214577c67f2fSkcpoon break; 214677c67f2fSkcpoon } 214777c67f2fSkcpoon 214877c67f2fSkcpoon sdc = (sctp_data_hdr_t *)(*mp)->b_rptr; 214977c67f2fSkcpoon /* Don't bundle chunks beyond sctp_rxt_maxtsn. */ 215077c67f2fSkcpoon if (SEQ_GT(ntohl(sdc->sdh_tsn), sctp->sctp_rxt_maxtsn)) 215177c67f2fSkcpoon break; 215277c67f2fSkcpoon new_len = ntohs(sdc->sdh_len); 215377c67f2fSkcpoon chunklen = new_len - sizeof (*sdc); 215477c67f2fSkcpoon 215577c67f2fSkcpoon if ((extra = new_len & (SCTP_ALIGN - 1)) != 0) 215677c67f2fSkcpoon extra = SCTP_ALIGN - extra; 215777c67f2fSkcpoon if ((new_len = seglen + new_len + extra) > fp->sfa_pmss) 215877c67f2fSkcpoon break; 215977c67f2fSkcpoon if ((nmp = dupmsg(*mp)) == NULL) 216077c67f2fSkcpoon break; 216177c67f2fSkcpoon 216277c67f2fSkcpoon if (extra > 0) { 2163*121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 216477c67f2fSkcpoon if (fill != NULL) { 216577c67f2fSkcpoon linkb(nmp, fill); 216677c67f2fSkcpoon } else { 216777c67f2fSkcpoon freemsg(nmp); 216877c67f2fSkcpoon break; 216977c67f2fSkcpoon } 217077c67f2fSkcpoon } 217177c67f2fSkcpoon linkb(head, nmp); 217277c67f2fSkcpoon 217377c67f2fSkcpoon SCTP_CHUNK_CLEAR_FLAGS(nmp); 217477c67f2fSkcpoon SCTP_CHUNK_SENT(sctp, *mp, sdc, fp, chunklen, *meta); 2175769b977dSvi /* 2176769b977dSvi * Don't update the TSN if we are doing a Zero Win Probe. 2177769b977dSvi */ 2178769b977dSvi if (!sctp->sctp_zero_win_probe) 2179769b977dSvi sctp->sctp_rxt_nxttsn = ntohl(sdc->sdh_tsn); 218077c67f2fSkcpoon 218177c67f2fSkcpoon seglen = new_len; 218277c67f2fSkcpoon *mp = (*mp)->b_next; 218377c67f2fSkcpoon } 218477c67f2fSkcpoon *packet_len = seglen; 218512f47623Skcpoon fp->rxt_unacked += seglen; 218677c67f2fSkcpoon return (head); 218777c67f2fSkcpoon } 218877c67f2fSkcpoon 218977c67f2fSkcpoon /* 219077c67f2fSkcpoon * sctp_ss_rexmit() is called when we get a SACK after a timeout which 219177c67f2fSkcpoon * advances the cum_tsn but the cum_tsn is still less than what we have sent 219277c67f2fSkcpoon * (sctp_rxt_maxtsn) at the time of the timeout. This SACK is a "partial" 219377c67f2fSkcpoon * SACK. We retransmit unacked chunks without having to wait for another 219477c67f2fSkcpoon * timeout. The rationale is that the SACK should not be "partial" if all the 219577c67f2fSkcpoon * lost chunks have been retransmitted. Since the SACK is "partial," 219677c67f2fSkcpoon * the chunks between the cum_tsn and the sctp_rxt_maxtsn should still 219777c67f2fSkcpoon * be missing. It is better for us to retransmit them now instead 219877c67f2fSkcpoon * of waiting for a timeout. 219977c67f2fSkcpoon */ 220077c67f2fSkcpoon void 220177c67f2fSkcpoon sctp_ss_rexmit(sctp_t *sctp) 220277c67f2fSkcpoon { 220377c67f2fSkcpoon mblk_t *meta; 220477c67f2fSkcpoon mblk_t *mp; 220577c67f2fSkcpoon mblk_t *pkt; 220677c67f2fSkcpoon sctp_faddr_t *fp; 220777c67f2fSkcpoon uint_t pkt_len; 220877c67f2fSkcpoon uint32_t tot_wnd; 220977c67f2fSkcpoon sctp_data_hdr_t *sdc; 221077c67f2fSkcpoon int burst; 2211f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 221277c67f2fSkcpoon 2213769b977dSvi ASSERT(!sctp->sctp_zero_win_probe); 2214769b977dSvi 221577c67f2fSkcpoon /* 221677c67f2fSkcpoon * If the last cum ack is smaller than what we have just 221777c67f2fSkcpoon * retransmitted, simply return. 221877c67f2fSkcpoon */ 221977c67f2fSkcpoon if (SEQ_GEQ(sctp->sctp_lastack_rxd, sctp->sctp_rxt_nxttsn)) 222077c67f2fSkcpoon sctp->sctp_rxt_nxttsn = sctp->sctp_lastack_rxd + 1; 222177c67f2fSkcpoon else 222277c67f2fSkcpoon return; 222377c67f2fSkcpoon ASSERT(SEQ_LEQ(sctp->sctp_rxt_nxttsn, sctp->sctp_rxt_maxtsn)); 222477c67f2fSkcpoon 222577c67f2fSkcpoon /* 222677c67f2fSkcpoon * After a timer fires, sctp_current should be set to the new 222777c67f2fSkcpoon * fp where the retransmitted chunks are sent. 222877c67f2fSkcpoon */ 222977c67f2fSkcpoon fp = sctp->sctp_current; 223077c67f2fSkcpoon 223177c67f2fSkcpoon /* 223212f47623Skcpoon * Since we are retransmitting, we only need to use cwnd to determine 223312f47623Skcpoon * how much we can send as we were allowed (by peer's receive window) 223412f47623Skcpoon * to send those retransmitted chunks previously when they are first 223512f47623Skcpoon * sent. If we record how much we have retransmitted but 223612f47623Skcpoon * unacknowledged using rxt_unacked, then the amount we can now send 223712f47623Skcpoon * is equal to cwnd minus rxt_unacked. 223812f47623Skcpoon * 223912f47623Skcpoon * The field rxt_unacked is incremented when we retransmit a packet 224012f47623Skcpoon * and decremented when we got a SACK acknowledging something. And 224112f47623Skcpoon * it is reset when the retransmission timer fires as we assume that 224212f47623Skcpoon * all packets have left the network after a timeout. If this 224312f47623Skcpoon * assumption is not true, it means that after a timeout, we can 224412f47623Skcpoon * get a SACK acknowledging more than rxt_unacked (its value only 224512f47623Skcpoon * contains what is retransmitted when the timer fires). So 224612f47623Skcpoon * rxt_unacked will become very big (it is an unsiged int so going 224712f47623Skcpoon * negative means that the value is huge). This is the reason we 224812f47623Skcpoon * always send at least 1 MSS bytes. 224912f47623Skcpoon * 225012f47623Skcpoon * The reason why we do not have an accurate count is that we 225112f47623Skcpoon * only know how many packets are outstanding (using the TSN numbers). 225212f47623Skcpoon * But we do not know how many bytes those packets contain. To 225312f47623Skcpoon * have an accurate count, we need to walk through the send list. 225412f47623Skcpoon * As it is not really important to have an accurate count during 225512f47623Skcpoon * retransmission, we skip this walk to save some time. This should 225612f47623Skcpoon * not make the retransmission too aggressive to cause congestion. 225777c67f2fSkcpoon */ 225812f47623Skcpoon if (fp->cwnd <= fp->rxt_unacked) 225912f47623Skcpoon tot_wnd = fp->sfa_pmss; 226077c67f2fSkcpoon else 226112f47623Skcpoon tot_wnd = fp->cwnd - fp->rxt_unacked; 226277c67f2fSkcpoon 226377c67f2fSkcpoon /* Find the first unack'ed chunk */ 226477c67f2fSkcpoon for (meta = sctp->sctp_xmit_head; meta != NULL; meta = meta->b_next) { 226577c67f2fSkcpoon sctp_msg_hdr_t *mhdr = (sctp_msg_hdr_t *)meta->b_rptr; 226677c67f2fSkcpoon 226777c67f2fSkcpoon if (SCTP_IS_MSG_ABANDONED(meta) || 226877c67f2fSkcpoon SCTP_MSG_TO_BE_ABANDONED(meta, mhdr, sctp)) { 226977c67f2fSkcpoon continue; 227077c67f2fSkcpoon } 227177c67f2fSkcpoon 227277c67f2fSkcpoon for (mp = meta->b_cont; mp != NULL; mp = mp->b_next) { 227377c67f2fSkcpoon /* Again, this may not be possible */ 227477c67f2fSkcpoon if (!SCTP_CHUNK_ISSENT(mp)) 227577c67f2fSkcpoon return; 227677c67f2fSkcpoon sdc = (sctp_data_hdr_t *)mp->b_rptr; 227777c67f2fSkcpoon if (ntohl(sdc->sdh_tsn) == sctp->sctp_rxt_nxttsn) 227877c67f2fSkcpoon goto found_msg; 227977c67f2fSkcpoon } 228077c67f2fSkcpoon } 228177c67f2fSkcpoon 228277c67f2fSkcpoon /* Everything is abandoned... */ 228377c67f2fSkcpoon return; 228477c67f2fSkcpoon 228577c67f2fSkcpoon found_msg: 228677c67f2fSkcpoon if (!fp->timer_running) 228777c67f2fSkcpoon SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->rto); 228877c67f2fSkcpoon pkt = sctp_rexmit_packet(sctp, &meta, &mp, fp, &pkt_len); 228977c67f2fSkcpoon if (pkt == NULL) { 2290f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_ss_rexmit_failed); 229177c67f2fSkcpoon return; 229277c67f2fSkcpoon } 229377c67f2fSkcpoon if ((pkt_len > fp->sfa_pmss) && fp->isv4) { 229477c67f2fSkcpoon ipha_t *iph = (ipha_t *)pkt->b_rptr; 229577c67f2fSkcpoon 229677c67f2fSkcpoon /* 229777c67f2fSkcpoon * Path MTU is different from path we thought it would 229877c67f2fSkcpoon * be when we created chunks, or IP headers have grown. 229977c67f2fSkcpoon * Need to clear the DF bit. 230077c67f2fSkcpoon */ 230177c67f2fSkcpoon iph->ipha_fragment_offset_and_flags = 0; 230277c67f2fSkcpoon } 230377c67f2fSkcpoon sctp_set_iplen(sctp, pkt); 230477c67f2fSkcpoon sctp_add_sendq(sctp, pkt); 230577c67f2fSkcpoon 230677c67f2fSkcpoon /* Check and see if there is more chunk to be retransmitted. */ 230777c67f2fSkcpoon if (tot_wnd <= pkt_len || tot_wnd - pkt_len < fp->sfa_pmss || 230877c67f2fSkcpoon meta == NULL) 230977c67f2fSkcpoon return; 231077c67f2fSkcpoon if (mp == NULL) 231177c67f2fSkcpoon meta = meta->b_next; 231277c67f2fSkcpoon if (meta == NULL) 231377c67f2fSkcpoon return; 231477c67f2fSkcpoon 231577c67f2fSkcpoon /* Retransmit another packet if the window allows. */ 2316f4b3ec61Sdh for (tot_wnd -= pkt_len, burst = sctps->sctps_maxburst - 1; 231777c67f2fSkcpoon meta != NULL && burst > 0; meta = meta->b_next, burst--) { 231877c67f2fSkcpoon if (mp == NULL) 231977c67f2fSkcpoon mp = meta->b_cont; 232077c67f2fSkcpoon for (; mp != NULL; mp = mp->b_next) { 232177c67f2fSkcpoon /* Again, this may not be possible */ 232277c67f2fSkcpoon if (!SCTP_CHUNK_ISSENT(mp)) 232377c67f2fSkcpoon return; 232477c67f2fSkcpoon if (!SCTP_CHUNK_ISACKED(mp)) 232577c67f2fSkcpoon goto found_msg; 232677c67f2fSkcpoon } 232777c67f2fSkcpoon } 232877c67f2fSkcpoon } 2329