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 /* 23e6f13f86SKacheong Poon * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <sys/types.h> 287c478bd9Sstevel@tonic-gate #include <sys/systm.h> 297c478bd9Sstevel@tonic-gate #include <sys/stream.h> 307c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 317c478bd9Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 327c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 337c478bd9Sstevel@tonic-gate #include <sys/socket.h> 347c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 357c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 367c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 377c478bd9Sstevel@tonic-gate #include <sys/socketvar.h> 387c478bd9Sstevel@tonic-gate #include <inet/common.h> 397c478bd9Sstevel@tonic-gate #include <inet/mi.h> 407c478bd9Sstevel@tonic-gate #include <inet/ip.h> 417c478bd9Sstevel@tonic-gate #include <inet/ip6.h> 427c478bd9Sstevel@tonic-gate #include <inet/sctp_ip.h> 437c478bd9Sstevel@tonic-gate #include <inet/ipclassifier.h> 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate /* 467c478bd9Sstevel@tonic-gate * PR-SCTP comments. 477c478bd9Sstevel@tonic-gate * 487c478bd9Sstevel@tonic-gate * A message can expire before it gets to the transmit list (i.e. it is still 497c478bd9Sstevel@tonic-gate * in the unsent list - unchunked), after it gets to the transmit list, but 507c478bd9Sstevel@tonic-gate * before transmission has actually started, or after transmission has begun. 517c478bd9Sstevel@tonic-gate * Accordingly, we check for the status of a message in sctp_chunkify() when 527c478bd9Sstevel@tonic-gate * the message is being transferred from the unsent list to the transmit list; 537c478bd9Sstevel@tonic-gate * in sctp_get_msg_to_send(), when we get the next chunk from the transmit 547c478bd9Sstevel@tonic-gate * list and in sctp_rexmit() when we get the next chunk to be (re)transmitted. 557c478bd9Sstevel@tonic-gate * When we nuke a message in sctp_chunkify(), all we need to do is take it 567c478bd9Sstevel@tonic-gate * out of the unsent list and update sctp_unsent; when a message is deemed 577c478bd9Sstevel@tonic-gate * timed-out in sctp_get_msg_to_send() we can just take it out of the transmit 587c478bd9Sstevel@tonic-gate * list, update sctp_unsent IFF transmission for the message has not yet begun 597c478bd9Sstevel@tonic-gate * (i.e. !SCTP_CHUNK_ISSENT(meta->b_cont)). However, if transmission for the 607c478bd9Sstevel@tonic-gate * message has started, then we cannot just take it out of the list, we need 617c478bd9Sstevel@tonic-gate * to send Forward TSN chunk to the peer so that the peer can clear its 627c478bd9Sstevel@tonic-gate * fragment list for this message. However, we cannot just send the Forward 637c478bd9Sstevel@tonic-gate * TSN in sctp_get_msg_to_send() because there might be unacked chunks for 647c478bd9Sstevel@tonic-gate * messages preceeding this abandoned message. So, we send a Forward TSN 657c478bd9Sstevel@tonic-gate * IFF all messages prior to this abandoned message has been SACKd, if not 667c478bd9Sstevel@tonic-gate * we defer sending the Forward TSN to sctp_cumack(), which will check for 677c478bd9Sstevel@tonic-gate * this condition and send the Forward TSN via sctp_check_abandoned_msg(). In 687c478bd9Sstevel@tonic-gate * sctp_rexmit() when we check for retransmissions, we need to determine if 697c478bd9Sstevel@tonic-gate * the advanced peer ack point can be moved ahead, and if so, send a Forward 707c478bd9Sstevel@tonic-gate * TSN to the peer instead of retransmitting the chunk. Note that when 717c478bd9Sstevel@tonic-gate * we send a Forward TSN for a message, there may be yet unsent chunks for 727c478bd9Sstevel@tonic-gate * this message; we need to mark all such chunks as abandoned, so that 737c478bd9Sstevel@tonic-gate * sctp_cumack() can take the message out of the transmit list, additionally 747c478bd9Sstevel@tonic-gate * sctp_unsent need to be adjusted. Whenever sctp_unsent is updated (i.e. 757c478bd9Sstevel@tonic-gate * decremented when a message/chunk is deemed abandoned), sockfs needs to 767c478bd9Sstevel@tonic-gate * be notified so that it can adjust its idea of the queued message. 777c478bd9Sstevel@tonic-gate */ 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate #include "sctp_impl.h" 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate static struct kmem_cache *sctp_kmem_ftsn_set_cache; 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate #ifdef DEBUG 847c478bd9Sstevel@tonic-gate static boolean_t sctp_verify_chain(mblk_t *, mblk_t *); 857c478bd9Sstevel@tonic-gate #endif 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate /* 887c478bd9Sstevel@tonic-gate * Called to allocate a header mblk when sending data to SCTP. 897c478bd9Sstevel@tonic-gate * Data will follow in b_cont of this mblk. 907c478bd9Sstevel@tonic-gate */ 917c478bd9Sstevel@tonic-gate mblk_t * 927c478bd9Sstevel@tonic-gate sctp_alloc_hdr(const char *name, int nlen, const char *control, int clen, 937c478bd9Sstevel@tonic-gate int flags) 947c478bd9Sstevel@tonic-gate { 957c478bd9Sstevel@tonic-gate mblk_t *mp; 967c478bd9Sstevel@tonic-gate struct T_unitdata_req *tudr; 977c478bd9Sstevel@tonic-gate size_t size; 987c478bd9Sstevel@tonic-gate int error; 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate size = sizeof (*tudr) + _TPI_ALIGN_TOPT(nlen) + clen; 1017c478bd9Sstevel@tonic-gate size = MAX(size, sizeof (sctp_msg_hdr_t)); 1027c478bd9Sstevel@tonic-gate if (flags & SCTP_CAN_BLOCK) { 1037c478bd9Sstevel@tonic-gate mp = allocb_wait(size, BPRI_MED, 0, &error); 1047c478bd9Sstevel@tonic-gate } else { 1057c478bd9Sstevel@tonic-gate mp = allocb(size, BPRI_MED); 1067c478bd9Sstevel@tonic-gate } 1077c478bd9Sstevel@tonic-gate if (mp) { 1087c478bd9Sstevel@tonic-gate tudr = (struct T_unitdata_req *)mp->b_rptr; 1097c478bd9Sstevel@tonic-gate tudr->PRIM_type = T_UNITDATA_REQ; 1107c478bd9Sstevel@tonic-gate tudr->DEST_length = nlen; 1117c478bd9Sstevel@tonic-gate tudr->DEST_offset = sizeof (*tudr); 1127c478bd9Sstevel@tonic-gate tudr->OPT_length = clen; 1137c478bd9Sstevel@tonic-gate tudr->OPT_offset = (t_scalar_t)(sizeof (*tudr) + 1147c478bd9Sstevel@tonic-gate _TPI_ALIGN_TOPT(nlen)); 1157c478bd9Sstevel@tonic-gate if (nlen > 0) 1167c478bd9Sstevel@tonic-gate bcopy(name, tudr + 1, nlen); 1177c478bd9Sstevel@tonic-gate if (clen > 0) 1187c478bd9Sstevel@tonic-gate bcopy(control, (char *)tudr + tudr->OPT_offset, clen); 1197c478bd9Sstevel@tonic-gate mp->b_wptr += (tudr ->OPT_offset + clen); 1207c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO; 1217c478bd9Sstevel@tonic-gate } 1227c478bd9Sstevel@tonic-gate return (mp); 1237c478bd9Sstevel@tonic-gate } 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate /*ARGSUSED2*/ 1267c478bd9Sstevel@tonic-gate int 1277c478bd9Sstevel@tonic-gate sctp_sendmsg(sctp_t *sctp, mblk_t *mp, int flags) 1287c478bd9Sstevel@tonic-gate { 1297c478bd9Sstevel@tonic-gate sctp_faddr_t *fp = NULL; 1307c478bd9Sstevel@tonic-gate struct T_unitdata_req *tudr; 1317c478bd9Sstevel@tonic-gate int error = 0; 1327c478bd9Sstevel@tonic-gate mblk_t *mproto = mp; 1337c478bd9Sstevel@tonic-gate in6_addr_t *addr; 1347c478bd9Sstevel@tonic-gate in6_addr_t tmpaddr; 1357c478bd9Sstevel@tonic-gate uint16_t sid = sctp->sctp_def_stream; 1367c478bd9Sstevel@tonic-gate uint32_t ppid = sctp->sctp_def_ppid; 1377c478bd9Sstevel@tonic-gate uint32_t context = sctp->sctp_def_context; 1387c478bd9Sstevel@tonic-gate uint16_t msg_flags = sctp->sctp_def_flags; 1397c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *sctp_msg_hdr; 1407c478bd9Sstevel@tonic-gate uint32_t msg_len = 0; 1417c478bd9Sstevel@tonic-gate uint32_t timetolive = sctp->sctp_def_timetolive; 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate ASSERT(DB_TYPE(mproto) == M_PROTO); 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate mp = mp->b_cont; 1467c478bd9Sstevel@tonic-gate ASSERT(mp == NULL || DB_TYPE(mp) == M_DATA); 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate tudr = (struct T_unitdata_req *)mproto->b_rptr; 1497c478bd9Sstevel@tonic-gate ASSERT(tudr->PRIM_type == T_UNITDATA_REQ); 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate /* Get destination address, if specified */ 1527c478bd9Sstevel@tonic-gate if (tudr->DEST_length > 0) { 1537c478bd9Sstevel@tonic-gate sin_t *sin; 1547c478bd9Sstevel@tonic-gate sin6_t *sin6; 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *) 1577c478bd9Sstevel@tonic-gate (mproto->b_rptr + tudr->DEST_offset); 1587c478bd9Sstevel@tonic-gate switch (sin->sin_family) { 1597c478bd9Sstevel@tonic-gate case AF_INET: 1607c478bd9Sstevel@tonic-gate if (tudr->DEST_length < sizeof (*sin)) { 1617c478bd9Sstevel@tonic-gate return (EINVAL); 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, &tmpaddr); 1647c478bd9Sstevel@tonic-gate addr = &tmpaddr; 1657c478bd9Sstevel@tonic-gate break; 1667c478bd9Sstevel@tonic-gate case AF_INET6: 1677c478bd9Sstevel@tonic-gate if (tudr->DEST_length < sizeof (*sin6)) { 1687c478bd9Sstevel@tonic-gate return (EINVAL); 1697c478bd9Sstevel@tonic-gate } 1707c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *) 1717c478bd9Sstevel@tonic-gate (mproto->b_rptr + tudr->DEST_offset); 1727c478bd9Sstevel@tonic-gate addr = &sin6->sin6_addr; 1737c478bd9Sstevel@tonic-gate break; 1747c478bd9Sstevel@tonic-gate default: 1757c478bd9Sstevel@tonic-gate return (EAFNOSUPPORT); 1767c478bd9Sstevel@tonic-gate } 1777c478bd9Sstevel@tonic-gate fp = sctp_lookup_faddr(sctp, addr); 1787c478bd9Sstevel@tonic-gate if (fp == NULL) { 1797c478bd9Sstevel@tonic-gate return (EINVAL); 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate } 1827c478bd9Sstevel@tonic-gate /* Ancillary Data? */ 1837c478bd9Sstevel@tonic-gate if (tudr->OPT_length > 0) { 1847c478bd9Sstevel@tonic-gate struct cmsghdr *cmsg; 1857c478bd9Sstevel@tonic-gate char *cend; 1867c478bd9Sstevel@tonic-gate struct sctp_sndrcvinfo *sndrcv; 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate cmsg = (struct cmsghdr *)(mproto->b_rptr + tudr->OPT_offset); 1897c478bd9Sstevel@tonic-gate cend = ((char *)cmsg + tudr->OPT_length); 1907c478bd9Sstevel@tonic-gate ASSERT(cend <= (char *)mproto->b_wptr); 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate for (;;) { 1937c478bd9Sstevel@tonic-gate if ((char *)(cmsg + 1) > cend || 1947c478bd9Sstevel@tonic-gate ((char *)cmsg + cmsg->cmsg_len) > cend) { 1957c478bd9Sstevel@tonic-gate break; 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate if ((cmsg->cmsg_level == IPPROTO_SCTP) && 1987c478bd9Sstevel@tonic-gate (cmsg->cmsg_type == SCTP_SNDRCV)) { 1997c478bd9Sstevel@tonic-gate if (cmsg->cmsg_len < 2007c478bd9Sstevel@tonic-gate (sizeof (*sndrcv) + sizeof (*cmsg))) { 2017c478bd9Sstevel@tonic-gate return (EINVAL); 2027c478bd9Sstevel@tonic-gate } 2037c478bd9Sstevel@tonic-gate sndrcv = (struct sctp_sndrcvinfo *)(cmsg + 1); 2047c478bd9Sstevel@tonic-gate sid = sndrcv->sinfo_stream; 2057c478bd9Sstevel@tonic-gate msg_flags = sndrcv->sinfo_flags; 2067c478bd9Sstevel@tonic-gate ppid = sndrcv->sinfo_ppid; 2077c478bd9Sstevel@tonic-gate context = sndrcv->sinfo_context; 2087c478bd9Sstevel@tonic-gate timetolive = sndrcv->sinfo_timetolive; 2097c478bd9Sstevel@tonic-gate break; 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate if (cmsg->cmsg_len > 0) 2127c478bd9Sstevel@tonic-gate cmsg = CMSG_NEXT(cmsg); 2137c478bd9Sstevel@tonic-gate else 2147c478bd9Sstevel@tonic-gate break; 2157c478bd9Sstevel@tonic-gate } 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate if (msg_flags & MSG_ABORT) { 2187c478bd9Sstevel@tonic-gate if (mp && mp->b_cont) { 2197c478bd9Sstevel@tonic-gate mblk_t *pump = msgpullup(mp, -1); 2207c478bd9Sstevel@tonic-gate if (!pump) { 2217c478bd9Sstevel@tonic-gate return (ENOMEM); 2227c478bd9Sstevel@tonic-gate } 2237c478bd9Sstevel@tonic-gate freemsg(mp); 2247c478bd9Sstevel@tonic-gate mp = pump; 2257c478bd9Sstevel@tonic-gate mproto->b_cont = mp; 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate RUN_SCTP(sctp); 228e6f13f86SKacheong Poon sctp_user_abort(sctp, mp); 2297c478bd9Sstevel@tonic-gate freemsg(mproto); 2307c478bd9Sstevel@tonic-gate goto process_sendq; 2317c478bd9Sstevel@tonic-gate } 2327c478bd9Sstevel@tonic-gate if (mp == NULL) 2337c478bd9Sstevel@tonic-gate goto done; 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate RUN_SCTP(sctp); 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate /* Reject any new data requests if we are shutting down */ 238b34b8d1aSkcpoon if (sctp->sctp_state > SCTPS_ESTABLISHED || 239b34b8d1aSkcpoon (sctp->sctp_connp->conn_state_flags & CONN_CLOSING)) { 2407c478bd9Sstevel@tonic-gate error = EPIPE; 2417c478bd9Sstevel@tonic-gate goto unlock_done; 2427c478bd9Sstevel@tonic-gate } 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate /* Re-use the mproto to store relevant info. */ 2457c478bd9Sstevel@tonic-gate ASSERT(MBLKSIZE(mproto) >= sizeof (*sctp_msg_hdr)); 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate mproto->b_rptr = mproto->b_datap->db_base; 2487c478bd9Sstevel@tonic-gate mproto->b_wptr = mproto->b_rptr + sizeof (*sctp_msg_hdr); 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate sctp_msg_hdr = (sctp_msg_hdr_t *)mproto->b_rptr; 2517c478bd9Sstevel@tonic-gate bzero(sctp_msg_hdr, sizeof (*sctp_msg_hdr)); 2527c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_context = context; 2537c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_sid = sid; 2547c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_ppid = ppid; 2557c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_flags = msg_flags; 2567c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_ttl = MSEC_TO_TICK(timetolive); 2577c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_tob = lbolt64; 2587c478bd9Sstevel@tonic-gate for (; mp != NULL; mp = mp->b_cont) 2597c478bd9Sstevel@tonic-gate msg_len += MBLKL(mp); 2607c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_msglen = msg_len; 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate /* User requested specific destination */ 2637c478bd9Sstevel@tonic-gate SCTP_SET_CHUNK_DEST(mproto, fp); 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate if (sctp->sctp_state >= SCTPS_COOKIE_ECHOED && 2667c478bd9Sstevel@tonic-gate sid >= sctp->sctp_num_ostr) { 2677c478bd9Sstevel@tonic-gate /* Send sendfail event */ 2687c478bd9Sstevel@tonic-gate sctp_sendfail_event(sctp, dupmsg(mproto), SCTP_ERR_BAD_SID, 2697c478bd9Sstevel@tonic-gate B_FALSE); 2707c478bd9Sstevel@tonic-gate error = EINVAL; 2717c478bd9Sstevel@tonic-gate goto unlock_done; 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate /* no data */ 2757c478bd9Sstevel@tonic-gate if (msg_len == 0) { 2767c478bd9Sstevel@tonic-gate sctp_sendfail_event(sctp, dupmsg(mproto), 2777c478bd9Sstevel@tonic-gate SCTP_ERR_NO_USR_DATA, B_FALSE); 2787c478bd9Sstevel@tonic-gate error = EINVAL; 2797c478bd9Sstevel@tonic-gate goto unlock_done; 2807c478bd9Sstevel@tonic-gate } 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate /* Add it to the unsent list */ 2837c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_unsent == NULL) { 2847c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent = sctp->sctp_xmit_unsent_tail = mproto; 2857c478bd9Sstevel@tonic-gate } else { 2867c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent_tail->b_next = mproto; 2877c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent_tail = mproto; 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate sctp->sctp_unsent += msg_len; 2907c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_msgcount); 291*0f1702c5SYu Xiangning /* 292*0f1702c5SYu Xiangning * Notify sockfs if the tx queue is full. 293*0f1702c5SYu Xiangning */ 294*0f1702c5SYu Xiangning if (SCTP_TXQ_LEN(sctp) >= sctp->sctp_xmit_hiwater) { 295*0f1702c5SYu Xiangning sctp->sctp_txq_full = 1; 296*0f1702c5SYu Xiangning sctp->sctp_ulp_xmitted(sctp->sctp_ulpd, B_TRUE); 297*0f1702c5SYu Xiangning } 2987c478bd9Sstevel@tonic-gate if (sctp->sctp_state == SCTPS_ESTABLISHED) 29912f47623Skcpoon sctp_output(sctp, UINT_MAX); 3007c478bd9Sstevel@tonic-gate process_sendq: 3017c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 3027c478bd9Sstevel@tonic-gate sctp_process_sendq(sctp); 3037c478bd9Sstevel@tonic-gate return (0); 3047c478bd9Sstevel@tonic-gate unlock_done: 3057c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 3067c478bd9Sstevel@tonic-gate done: 3077c478bd9Sstevel@tonic-gate return (error); 3087c478bd9Sstevel@tonic-gate } 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate void 3117c478bd9Sstevel@tonic-gate sctp_chunkify(sctp_t *sctp, int first_len, int bytes_to_send) 3127c478bd9Sstevel@tonic-gate { 3137c478bd9Sstevel@tonic-gate mblk_t *mp; 3147c478bd9Sstevel@tonic-gate mblk_t *chunk_mp; 3157c478bd9Sstevel@tonic-gate mblk_t *chunk_head; 3167c478bd9Sstevel@tonic-gate mblk_t *chunk_hdr; 3177c478bd9Sstevel@tonic-gate mblk_t *chunk_tail = NULL; 3187c478bd9Sstevel@tonic-gate int count; 3197c478bd9Sstevel@tonic-gate int chunksize; 3207c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 3217c478bd9Sstevel@tonic-gate mblk_t *mdblk = sctp->sctp_xmit_unsent; 3227c478bd9Sstevel@tonic-gate sctp_faddr_t *fp; 3237c478bd9Sstevel@tonic-gate sctp_faddr_t *fp1; 3247c478bd9Sstevel@tonic-gate size_t xtralen; 3257c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *msg_hdr; 326f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate fp = SCTP_CHUNK_DEST(mdblk); 3297c478bd9Sstevel@tonic-gate if (fp == NULL) 3307c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 3317c478bd9Sstevel@tonic-gate if (fp->isv4) 332f4b3ec61Sdh xtralen = sctp->sctp_hdr_len + sctps->sctps_wroff_xtra + 333f4b3ec61Sdh sizeof (*sdc); 3347c478bd9Sstevel@tonic-gate else 335f4b3ec61Sdh xtralen = sctp->sctp_hdr6_len + sctps->sctps_wroff_xtra + 336f4b3ec61Sdh sizeof (*sdc); 3377c478bd9Sstevel@tonic-gate count = chunksize = first_len - sizeof (*sdc); 3387c478bd9Sstevel@tonic-gate nextmsg: 3397c478bd9Sstevel@tonic-gate chunk_mp = mdblk->b_cont; 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate /* 3427c478bd9Sstevel@tonic-gate * If this partially chunked, we ignore the first_len for now 3437c478bd9Sstevel@tonic-gate * and use the one already present. For the unchunked bits, we 3447c478bd9Sstevel@tonic-gate * use the length of the last chunk. 3457c478bd9Sstevel@tonic-gate */ 3467c478bd9Sstevel@tonic-gate if (SCTP_IS_MSG_CHUNKED(mdblk)) { 3477c478bd9Sstevel@tonic-gate int chunk_len; 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate ASSERT(chunk_mp->b_next != NULL); 3507c478bd9Sstevel@tonic-gate mdblk->b_cont = chunk_mp->b_next; 3517c478bd9Sstevel@tonic-gate chunk_mp->b_next = NULL; 3527c478bd9Sstevel@tonic-gate SCTP_MSG_CLEAR_CHUNKED(mdblk); 3537c478bd9Sstevel@tonic-gate mp = mdblk->b_cont; 3547c478bd9Sstevel@tonic-gate while (mp->b_next != NULL) 3557c478bd9Sstevel@tonic-gate mp = mp->b_next; 3567c478bd9Sstevel@tonic-gate chunk_len = ntohs(((sctp_data_hdr_t *)mp->b_rptr)->sdh_len); 3577c478bd9Sstevel@tonic-gate if (fp->sfa_pmss - chunk_len > sizeof (*sdc)) 3587c478bd9Sstevel@tonic-gate count = chunksize = fp->sfa_pmss - chunk_len; 3597c478bd9Sstevel@tonic-gate else 3607c478bd9Sstevel@tonic-gate count = chunksize = fp->sfa_pmss; 3617c478bd9Sstevel@tonic-gate count = chunksize = count - sizeof (*sdc); 3627c478bd9Sstevel@tonic-gate } else { 3637c478bd9Sstevel@tonic-gate msg_hdr = (sctp_msg_hdr_t *)mdblk->b_rptr; 3647c478bd9Sstevel@tonic-gate if (SCTP_MSG_TO_BE_ABANDONED(mdblk, msg_hdr, sctp)) { 3657c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent = mdblk->b_next; 3667c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_unsent == NULL) 3677c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent_tail = NULL; 3687c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_unsent >= msg_hdr->smh_msglen); 3697c478bd9Sstevel@tonic-gate sctp->sctp_unsent -= msg_hdr->smh_msglen; 3707c478bd9Sstevel@tonic-gate mdblk->b_next = NULL; 3717c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_prsctpdrop); 3727c478bd9Sstevel@tonic-gate /* 3737c478bd9Sstevel@tonic-gate * Update ULP the amount of queued data, which is 3747c478bd9Sstevel@tonic-gate * sent-unack'ed + unsent. 3757c478bd9Sstevel@tonic-gate */ 376*0f1702c5SYu Xiangning if (!SCTP_IS_DETACHED(sctp)) 377*0f1702c5SYu Xiangning SCTP_TXQ_UPDATE(sctp); 3787c478bd9Sstevel@tonic-gate sctp_sendfail_event(sctp, mdblk, 0, B_FALSE); 3797c478bd9Sstevel@tonic-gate goto try_next; 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate mdblk->b_cont = NULL; 3827c478bd9Sstevel@tonic-gate } 3837c478bd9Sstevel@tonic-gate msg_hdr = (sctp_msg_hdr_t *)mdblk->b_rptr; 3847c478bd9Sstevel@tonic-gate nextchunk: 3857c478bd9Sstevel@tonic-gate chunk_head = chunk_mp; 3867c478bd9Sstevel@tonic-gate chunk_tail = NULL; 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate /* Skip as many mblk's as we need */ 3897c478bd9Sstevel@tonic-gate while (chunk_mp != NULL && ((count - MBLKL(chunk_mp)) >= 0)) { 3907c478bd9Sstevel@tonic-gate count -= MBLKL(chunk_mp); 3917c478bd9Sstevel@tonic-gate chunk_tail = chunk_mp; 3927c478bd9Sstevel@tonic-gate chunk_mp = chunk_mp->b_cont; 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate /* Split the chain, if needed */ 3957c478bd9Sstevel@tonic-gate if (chunk_mp != NULL) { 3967c478bd9Sstevel@tonic-gate if (count > 0) { 3977c478bd9Sstevel@tonic-gate mblk_t *split_mp = dupb(chunk_mp); 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate if (split_mp == NULL) { 4007c478bd9Sstevel@tonic-gate if (mdblk->b_cont == NULL) { 4017c478bd9Sstevel@tonic-gate mdblk->b_cont = chunk_head; 4027c478bd9Sstevel@tonic-gate } else { 4037c478bd9Sstevel@tonic-gate SCTP_MSG_SET_CHUNKED(mdblk); 4047c478bd9Sstevel@tonic-gate ASSERT(chunk_head->b_next == NULL); 4057c478bd9Sstevel@tonic-gate chunk_head->b_next = mdblk->b_cont; 4067c478bd9Sstevel@tonic-gate mdblk->b_cont = chunk_head; 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate return; 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate if (chunk_tail != NULL) { 4117c478bd9Sstevel@tonic-gate chunk_tail->b_cont = split_mp; 4127c478bd9Sstevel@tonic-gate chunk_tail = chunk_tail->b_cont; 4137c478bd9Sstevel@tonic-gate } else { 4147c478bd9Sstevel@tonic-gate chunk_head = chunk_tail = split_mp; 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate chunk_tail->b_wptr = chunk_tail->b_rptr + count; 4177c478bd9Sstevel@tonic-gate chunk_mp->b_rptr = chunk_tail->b_wptr; 4187c478bd9Sstevel@tonic-gate count = 0; 4197c478bd9Sstevel@tonic-gate } else if (chunk_tail == NULL) { 4207c478bd9Sstevel@tonic-gate goto next; 4217c478bd9Sstevel@tonic-gate } else { 4227c478bd9Sstevel@tonic-gate chunk_tail->b_cont = NULL; 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate } 4257c478bd9Sstevel@tonic-gate /* Alloc chunk hdr, if needed */ 4267c478bd9Sstevel@tonic-gate if (DB_REF(chunk_head) > 1 || 4277c478bd9Sstevel@tonic-gate ((intptr_t)chunk_head->b_rptr) & (SCTP_ALIGN - 1) || 4287c478bd9Sstevel@tonic-gate MBLKHEAD(chunk_head) < sizeof (*sdc)) { 4297c478bd9Sstevel@tonic-gate if ((chunk_hdr = allocb(xtralen, BPRI_MED)) == NULL) { 4307c478bd9Sstevel@tonic-gate if (mdblk->b_cont == NULL) { 4317c478bd9Sstevel@tonic-gate if (chunk_mp != NULL) 4327c478bd9Sstevel@tonic-gate linkb(chunk_head, chunk_mp); 4337c478bd9Sstevel@tonic-gate mdblk->b_cont = chunk_head; 4347c478bd9Sstevel@tonic-gate } else { 4357c478bd9Sstevel@tonic-gate SCTP_MSG_SET_CHUNKED(mdblk); 4367c478bd9Sstevel@tonic-gate if (chunk_mp != NULL) 4377c478bd9Sstevel@tonic-gate linkb(chunk_head, chunk_mp); 4387c478bd9Sstevel@tonic-gate ASSERT(chunk_head->b_next == NULL); 4397c478bd9Sstevel@tonic-gate chunk_head->b_next = mdblk->b_cont; 4407c478bd9Sstevel@tonic-gate mdblk->b_cont = chunk_head; 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate return; 4437c478bd9Sstevel@tonic-gate } 4447c478bd9Sstevel@tonic-gate chunk_hdr->b_rptr += xtralen - sizeof (*sdc); 4457c478bd9Sstevel@tonic-gate chunk_hdr->b_wptr = chunk_hdr->b_rptr + sizeof (*sdc); 4467c478bd9Sstevel@tonic-gate chunk_hdr->b_cont = chunk_head; 4477c478bd9Sstevel@tonic-gate } else { 4487c478bd9Sstevel@tonic-gate chunk_hdr = chunk_head; 4497c478bd9Sstevel@tonic-gate chunk_hdr->b_rptr -= sizeof (*sdc); 4507c478bd9Sstevel@tonic-gate } 4517c478bd9Sstevel@tonic-gate ASSERT(chunk_hdr->b_datap->db_ref == 1); 4527c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)chunk_hdr->b_rptr; 4537c478bd9Sstevel@tonic-gate sdc->sdh_id = CHUNK_DATA; 4547c478bd9Sstevel@tonic-gate sdc->sdh_flags = 0; 4557c478bd9Sstevel@tonic-gate sdc->sdh_len = htons(sizeof (*sdc) + chunksize - count); 4567c478bd9Sstevel@tonic-gate ASSERT(sdc->sdh_len); 4577c478bd9Sstevel@tonic-gate sdc->sdh_sid = htons(msg_hdr->smh_sid); 4587c478bd9Sstevel@tonic-gate /* 4597c478bd9Sstevel@tonic-gate * We defer assigning the SSN just before sending the chunk, else 4607c478bd9Sstevel@tonic-gate * if we drop the chunk in sctp_get_msg_to_send(), we would need 4617c478bd9Sstevel@tonic-gate * to send a Forward TSN to let the peer know. Some more comments 4627c478bd9Sstevel@tonic-gate * about this in sctp_impl.h for SCTP_CHUNK_SENT. 4637c478bd9Sstevel@tonic-gate */ 4647c478bd9Sstevel@tonic-gate sdc->sdh_payload_id = msg_hdr->smh_ppid; 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate if (mdblk->b_cont == NULL) { 4677c478bd9Sstevel@tonic-gate mdblk->b_cont = chunk_hdr; 4687c478bd9Sstevel@tonic-gate SCTP_DATA_SET_BBIT(sdc); 4697c478bd9Sstevel@tonic-gate } else { 4707c478bd9Sstevel@tonic-gate mp = mdblk->b_cont; 4717c478bd9Sstevel@tonic-gate while (mp->b_next != NULL) 4727c478bd9Sstevel@tonic-gate mp = mp->b_next; 4737c478bd9Sstevel@tonic-gate mp->b_next = chunk_hdr; 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate bytes_to_send -= (chunksize - count); 4777c478bd9Sstevel@tonic-gate if (chunk_mp != NULL) { 4787c478bd9Sstevel@tonic-gate next: 4797c478bd9Sstevel@tonic-gate count = chunksize = fp->sfa_pmss - sizeof (*sdc); 4807c478bd9Sstevel@tonic-gate goto nextchunk; 4817c478bd9Sstevel@tonic-gate } 4827c478bd9Sstevel@tonic-gate SCTP_DATA_SET_EBIT(sdc); 4837c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent = mdblk->b_next; 4847c478bd9Sstevel@tonic-gate if (mdblk->b_next == NULL) { 4857c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent_tail = NULL; 4867c478bd9Sstevel@tonic-gate } 4877c478bd9Sstevel@tonic-gate mdblk->b_next = NULL; 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_tail == NULL) { 4907c478bd9Sstevel@tonic-gate sctp->sctp_xmit_head = sctp->sctp_xmit_tail = mdblk; 4917c478bd9Sstevel@tonic-gate } else { 4927c478bd9Sstevel@tonic-gate mp = sctp->sctp_xmit_tail; 4937c478bd9Sstevel@tonic-gate while (mp->b_next != NULL) 4947c478bd9Sstevel@tonic-gate mp = mp->b_next; 4957c478bd9Sstevel@tonic-gate mp->b_next = mdblk; 4967c478bd9Sstevel@tonic-gate mdblk->b_prev = mp; 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate try_next: 4997c478bd9Sstevel@tonic-gate if (bytes_to_send > 0 && sctp->sctp_xmit_unsent != NULL) { 5007c478bd9Sstevel@tonic-gate mdblk = sctp->sctp_xmit_unsent; 5017c478bd9Sstevel@tonic-gate fp1 = SCTP_CHUNK_DEST(mdblk); 5027c478bd9Sstevel@tonic-gate if (fp1 == NULL) 5037c478bd9Sstevel@tonic-gate fp1 = sctp->sctp_current; 5047c478bd9Sstevel@tonic-gate if (fp == fp1) { 5057c478bd9Sstevel@tonic-gate size_t len = MBLKL(mdblk->b_cont); 5067c478bd9Sstevel@tonic-gate if ((count > 0) && 5077c478bd9Sstevel@tonic-gate ((len > fp->sfa_pmss - sizeof (*sdc)) || 508b34b8d1aSkcpoon (len <= count))) { 5097c478bd9Sstevel@tonic-gate count -= sizeof (*sdc); 5107c478bd9Sstevel@tonic-gate count = chunksize = count - (count & 0x3); 5117c478bd9Sstevel@tonic-gate } else { 5127c478bd9Sstevel@tonic-gate count = chunksize = fp->sfa_pmss - 5137c478bd9Sstevel@tonic-gate sizeof (*sdc); 5147c478bd9Sstevel@tonic-gate } 5157c478bd9Sstevel@tonic-gate } else { 5167c478bd9Sstevel@tonic-gate if (fp1->isv4) 5177c478bd9Sstevel@tonic-gate xtralen = sctp->sctp_hdr_len; 5187c478bd9Sstevel@tonic-gate else 5197c478bd9Sstevel@tonic-gate xtralen = sctp->sctp_hdr6_len; 520f4b3ec61Sdh xtralen += sctps->sctps_wroff_xtra + sizeof (*sdc); 5217c478bd9Sstevel@tonic-gate count = chunksize = fp1->sfa_pmss - sizeof (*sdc); 5227c478bd9Sstevel@tonic-gate fp = fp1; 5237c478bd9Sstevel@tonic-gate } 5247c478bd9Sstevel@tonic-gate goto nextmsg; 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate void 5297c478bd9Sstevel@tonic-gate sctp_free_msg(mblk_t *ump) 5307c478bd9Sstevel@tonic-gate { 5317c478bd9Sstevel@tonic-gate mblk_t *mp, *nmp; 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate for (mp = ump->b_cont; mp; mp = nmp) { 5347c478bd9Sstevel@tonic-gate nmp = mp->b_next; 5357c478bd9Sstevel@tonic-gate mp->b_next = mp->b_prev = NULL; 5367c478bd9Sstevel@tonic-gate freemsg(mp); 5377c478bd9Sstevel@tonic-gate } 5387c478bd9Sstevel@tonic-gate ASSERT(!ump->b_prev); 5397c478bd9Sstevel@tonic-gate ump->b_next = NULL; 5407c478bd9Sstevel@tonic-gate freeb(ump); 5417c478bd9Sstevel@tonic-gate } 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate mblk_t * 544df19b344Svi sctp_add_proto_hdr(sctp_t *sctp, sctp_faddr_t *fp, mblk_t *mp, int sacklen, 545df19b344Svi int *error) 5467c478bd9Sstevel@tonic-gate { 5477c478bd9Sstevel@tonic-gate int hdrlen; 5487c478bd9Sstevel@tonic-gate char *hdr; 5497c478bd9Sstevel@tonic-gate int isv4 = fp->isv4; 550f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 5517c478bd9Sstevel@tonic-gate 552df19b344Svi if (error != NULL) 553df19b344Svi *error = 0; 554df19b344Svi 5557c478bd9Sstevel@tonic-gate if (isv4) { 5567c478bd9Sstevel@tonic-gate hdrlen = sctp->sctp_hdr_len; 5577c478bd9Sstevel@tonic-gate hdr = sctp->sctp_iphc; 5587c478bd9Sstevel@tonic-gate } else { 5597c478bd9Sstevel@tonic-gate hdrlen = sctp->sctp_hdr6_len; 5607c478bd9Sstevel@tonic-gate hdr = sctp->sctp_iphc6; 5617c478bd9Sstevel@tonic-gate } 562df19b344Svi /* 563df19b344Svi * A null fp->ire could mean that the address is 'down'. Similarly, 564df19b344Svi * it is possible that the address went down, we tried to send an 565df19b344Svi * heartbeat and ended up setting fp->saddr as unspec because we 56677c67f2fSkcpoon * didn't have any usable source address. In either case 56777c67f2fSkcpoon * sctp_get_ire() will try find an IRE, if available, and set 56877c67f2fSkcpoon * the source address, if needed. If we still don't have any 569df19b344Svi * usable source address, fp->state will be SCTP_FADDRS_UNREACH and 570df19b344Svi * we return EHOSTUNREACH. 571df19b344Svi */ 572df19b344Svi if (fp->ire == NULL || SCTP_IS_ADDR_UNSPEC(fp->isv4, fp->saddr)) { 57377c67f2fSkcpoon sctp_get_ire(sctp, fp); 574df19b344Svi if (fp->state == SCTP_FADDRS_UNREACH) { 575df19b344Svi if (error != NULL) 576df19b344Svi *error = EHOSTUNREACH; 577df19b344Svi return (NULL); 5787c478bd9Sstevel@tonic-gate } 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate /* Copy in IP header. */ 5817c478bd9Sstevel@tonic-gate if ((mp->b_rptr - mp->b_datap->db_base) < 582f4b3ec61Sdh (sctps->sctps_wroff_xtra + hdrlen + sacklen) || DB_REF(mp) > 2 || 58377c67f2fSkcpoon !IS_P2ALIGNED(DB_BASE(mp), sizeof (ire_t *))) { 5847c478bd9Sstevel@tonic-gate mblk_t *nmp; 58577c67f2fSkcpoon 5867c478bd9Sstevel@tonic-gate /* 5877c478bd9Sstevel@tonic-gate * This can happen if IP headers are adjusted after 5887c478bd9Sstevel@tonic-gate * data was moved into chunks, or during retransmission, 5897c478bd9Sstevel@tonic-gate * or things like snoop is running. 5907c478bd9Sstevel@tonic-gate */ 591f4b3ec61Sdh nmp = allocb_cred(sctps->sctps_wroff_xtra + hdrlen + sacklen, 59245916cd2Sjpk CONN_CRED(sctp->sctp_connp)); 5937c478bd9Sstevel@tonic-gate if (nmp == NULL) { 594df19b344Svi if (error != NULL) 595df19b344Svi *error = ENOMEM; 5967c478bd9Sstevel@tonic-gate return (NULL); 5977c478bd9Sstevel@tonic-gate } 598f4b3ec61Sdh nmp->b_rptr += sctps->sctps_wroff_xtra; 5997c478bd9Sstevel@tonic-gate nmp->b_wptr = nmp->b_rptr + hdrlen + sacklen; 6007c478bd9Sstevel@tonic-gate nmp->b_cont = mp; 6017c478bd9Sstevel@tonic-gate mp = nmp; 6027c478bd9Sstevel@tonic-gate } else { 6037c478bd9Sstevel@tonic-gate mp->b_rptr -= (hdrlen + sacklen); 60445916cd2Sjpk mblk_setcred(mp, CONN_CRED(sctp->sctp_connp)); 6057c478bd9Sstevel@tonic-gate } 6067c478bd9Sstevel@tonic-gate bcopy(hdr, mp->b_rptr, hdrlen); 6077c478bd9Sstevel@tonic-gate if (sacklen) { 6087c478bd9Sstevel@tonic-gate sctp_fill_sack(sctp, mp->b_rptr + hdrlen, sacklen); 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate if (fp != sctp->sctp_current) { 6117c478bd9Sstevel@tonic-gate /* change addresses in header */ 6127c478bd9Sstevel@tonic-gate if (isv4) { 6137c478bd9Sstevel@tonic-gate ipha_t *iph = (ipha_t *)mp->b_rptr; 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_IPADDR(&fp->faddr, iph->ipha_dst); 6167c478bd9Sstevel@tonic-gate if (!IN6_IS_ADDR_V4MAPPED_ANY(&fp->saddr)) { 6177c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_IPADDR(&fp->saddr, 6187c478bd9Sstevel@tonic-gate iph->ipha_src); 6197c478bd9Sstevel@tonic-gate } else if (sctp->sctp_bound_to_all) { 6207c478bd9Sstevel@tonic-gate iph->ipha_src = INADDR_ANY; 6217c478bd9Sstevel@tonic-gate } 6227c478bd9Sstevel@tonic-gate } else { 6237c478bd9Sstevel@tonic-gate ((ip6_t *)(mp->b_rptr))->ip6_dst = fp->faddr; 6247c478bd9Sstevel@tonic-gate if (!IN6_IS_ADDR_UNSPECIFIED(&fp->saddr)) { 6257c478bd9Sstevel@tonic-gate ((ip6_t *)(mp->b_rptr))->ip6_src = fp->saddr; 6267c478bd9Sstevel@tonic-gate } else if (sctp->sctp_bound_to_all) { 6277c478bd9Sstevel@tonic-gate V6_SET_ZERO(((ip6_t *)(mp->b_rptr))->ip6_src); 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate } 6307c478bd9Sstevel@tonic-gate } 6317c478bd9Sstevel@tonic-gate /* 6327c478bd9Sstevel@tonic-gate * IP will not free this IRE if it is condemned. SCTP needs to 6337c478bd9Sstevel@tonic-gate * free it. 6347c478bd9Sstevel@tonic-gate */ 6357c478bd9Sstevel@tonic-gate if ((fp->ire != NULL) && (fp->ire->ire_marks & IRE_MARK_CONDEMNED)) { 6367c478bd9Sstevel@tonic-gate IRE_REFRELE_NOTR(fp->ire); 6377c478bd9Sstevel@tonic-gate fp->ire = NULL; 6387c478bd9Sstevel@tonic-gate } 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate /* Stash the conn and ire ptr info for IP */ 6417c478bd9Sstevel@tonic-gate SCTP_STASH_IPINFO(mp, fp->ire); 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate return (mp); 6447c478bd9Sstevel@tonic-gate } 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate /* 6477c478bd9Sstevel@tonic-gate * SCTP requires every chunk to be padded so that the total length 6487c478bd9Sstevel@tonic-gate * is a multiple of SCTP_ALIGN. This function returns a mblk with 6497c478bd9Sstevel@tonic-gate * the specified pad length. 6507c478bd9Sstevel@tonic-gate */ 6517c478bd9Sstevel@tonic-gate static mblk_t * 652121e5416Skcpoon sctp_get_padding(sctp_t *sctp, int pad) 6537c478bd9Sstevel@tonic-gate { 6547c478bd9Sstevel@tonic-gate mblk_t *fill; 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate ASSERT(pad < SCTP_ALIGN); 657121e5416Skcpoon ASSERT(sctp->sctp_pad_mp != NULL); 658121e5416Skcpoon if ((fill = dupb(sctp->sctp_pad_mp)) != NULL) { 6597c478bd9Sstevel@tonic-gate fill->b_wptr += pad; 6607c478bd9Sstevel@tonic-gate return (fill); 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate /* 6647c478bd9Sstevel@tonic-gate * The memory saving path of reusing the sctp_pad_mp 6657c478bd9Sstevel@tonic-gate * fails may be because it has been dupb() too 6667c478bd9Sstevel@tonic-gate * many times (DBLK_REFMAX). Use the memory consuming 6677c478bd9Sstevel@tonic-gate * path of allocating the pad mblk. 6687c478bd9Sstevel@tonic-gate */ 6697c478bd9Sstevel@tonic-gate if ((fill = allocb(SCTP_ALIGN, BPRI_MED)) != NULL) { 6707c478bd9Sstevel@tonic-gate /* Zero it out. SCTP_ALIGN is sizeof (int32_t) */ 6717c478bd9Sstevel@tonic-gate *(int32_t *)fill->b_rptr = 0; 6727c478bd9Sstevel@tonic-gate fill->b_wptr += pad; 6737c478bd9Sstevel@tonic-gate } 6747c478bd9Sstevel@tonic-gate return (fill); 6757c478bd9Sstevel@tonic-gate } 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate static mblk_t * 6787c478bd9Sstevel@tonic-gate sctp_find_fast_rexmit_mblks(sctp_t *sctp, int *total, sctp_faddr_t **fp) 6797c478bd9Sstevel@tonic-gate { 6807c478bd9Sstevel@tonic-gate mblk_t *meta; 6817c478bd9Sstevel@tonic-gate mblk_t *start_mp = NULL; 6827c478bd9Sstevel@tonic-gate mblk_t *end_mp = NULL; 6837c478bd9Sstevel@tonic-gate mblk_t *mp, *nmp; 6847c478bd9Sstevel@tonic-gate mblk_t *fill; 6857c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdh; 6867c478bd9Sstevel@tonic-gate int msglen; 6877c478bd9Sstevel@tonic-gate int extra; 6887c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *msg_hdr; 68977c67f2fSkcpoon sctp_faddr_t *old_fp = NULL; 69077c67f2fSkcpoon sctp_faddr_t *chunk_fp; 691f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate for (meta = sctp->sctp_xmit_head; meta != NULL; meta = meta->b_next) { 6947c478bd9Sstevel@tonic-gate msg_hdr = (sctp_msg_hdr_t *)meta->b_rptr; 6957c478bd9Sstevel@tonic-gate if (SCTP_IS_MSG_ABANDONED(meta) || 6967c478bd9Sstevel@tonic-gate SCTP_MSG_TO_BE_ABANDONED(meta, msg_hdr, sctp)) { 6977c478bd9Sstevel@tonic-gate continue; 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate for (mp = meta->b_cont; mp != NULL; mp = mp->b_next) { 7007c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_WANT_REXMIT(mp)) { 7017c478bd9Sstevel@tonic-gate /* 7027c478bd9Sstevel@tonic-gate * Use the same peer address to do fast 70377c67f2fSkcpoon * retransmission. If the original peer 70477c67f2fSkcpoon * address is dead, switch to the current 70577c67f2fSkcpoon * one. Record the old one so that we 70677c67f2fSkcpoon * will pick the chunks sent to the old 70777c67f2fSkcpoon * one for fast retransmission. 7087c478bd9Sstevel@tonic-gate */ 70977c67f2fSkcpoon chunk_fp = SCTP_CHUNK_DEST(mp); 7107c478bd9Sstevel@tonic-gate if (*fp == NULL) { 71177c67f2fSkcpoon *fp = chunk_fp; 71277c67f2fSkcpoon if ((*fp)->state != SCTP_FADDRS_ALIVE) { 71377c67f2fSkcpoon old_fp = *fp; 7147c478bd9Sstevel@tonic-gate *fp = sctp->sctp_current; 71577c67f2fSkcpoon } 71677c67f2fSkcpoon } else if (old_fp == NULL && *fp != chunk_fp) { 71777c67f2fSkcpoon continue; 71877c67f2fSkcpoon } else if (old_fp != NULL && 71977c67f2fSkcpoon old_fp != chunk_fp) { 7207c478bd9Sstevel@tonic-gate continue; 7217c478bd9Sstevel@tonic-gate } 7227c478bd9Sstevel@tonic-gate 7237c478bd9Sstevel@tonic-gate sdh = (sctp_data_hdr_t *)mp->b_rptr; 7247c478bd9Sstevel@tonic-gate msglen = ntohs(sdh->sdh_len); 7257c478bd9Sstevel@tonic-gate if ((extra = msglen & (SCTP_ALIGN - 1)) != 0) { 7267c478bd9Sstevel@tonic-gate extra = SCTP_ALIGN - extra; 7277c478bd9Sstevel@tonic-gate } 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate /* 7307c478bd9Sstevel@tonic-gate * We still return at least the first message 7317c478bd9Sstevel@tonic-gate * even if that message cannot fit in as 7327c478bd9Sstevel@tonic-gate * PMTU may have changed. 7337c478bd9Sstevel@tonic-gate */ 7347c478bd9Sstevel@tonic-gate if (*total + msglen + extra > 7357c478bd9Sstevel@tonic-gate (*fp)->sfa_pmss && start_mp != NULL) { 7367c478bd9Sstevel@tonic-gate return (start_mp); 7377c478bd9Sstevel@tonic-gate } 7387c478bd9Sstevel@tonic-gate if ((nmp = dupmsg(mp)) == NULL) 7397c478bd9Sstevel@tonic-gate return (start_mp); 7407c478bd9Sstevel@tonic-gate if (extra > 0) { 741121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 7427c478bd9Sstevel@tonic-gate if (fill != NULL) { 7437c478bd9Sstevel@tonic-gate linkb(nmp, fill); 7447c478bd9Sstevel@tonic-gate } else { 7457c478bd9Sstevel@tonic-gate return (start_mp); 7467c478bd9Sstevel@tonic-gate } 7477c478bd9Sstevel@tonic-gate } 748f4b3ec61Sdh BUMP_MIB(&sctps->sctps_mib, sctpOutFastRetrans); 74977c67f2fSkcpoon BUMP_LOCAL(sctp->sctp_rxtchunks); 7507c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_REXMIT(mp); 7517c478bd9Sstevel@tonic-gate if (start_mp == NULL) { 7527c478bd9Sstevel@tonic-gate start_mp = nmp; 7537c478bd9Sstevel@tonic-gate } else { 7547c478bd9Sstevel@tonic-gate linkb(end_mp, nmp); 7557c478bd9Sstevel@tonic-gate } 7567c478bd9Sstevel@tonic-gate end_mp = nmp; 7577c478bd9Sstevel@tonic-gate *total += msglen + extra; 7587c478bd9Sstevel@tonic-gate dprint(2, ("sctp_find_fast_rexmit_mblks: " 7597c478bd9Sstevel@tonic-gate "tsn %x\n", sdh->sdh_tsn)); 7607c478bd9Sstevel@tonic-gate } 7617c478bd9Sstevel@tonic-gate } 7627c478bd9Sstevel@tonic-gate } 7637c478bd9Sstevel@tonic-gate /* Clear the flag as there is no more message to be fast rexmitted. */ 7647c478bd9Sstevel@tonic-gate sctp->sctp_chk_fast_rexmit = B_FALSE; 7657c478bd9Sstevel@tonic-gate return (start_mp); 7667c478bd9Sstevel@tonic-gate } 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate /* A debug function just to make sure that a mblk chain is not broken */ 7697c478bd9Sstevel@tonic-gate #ifdef DEBUG 7707c478bd9Sstevel@tonic-gate static boolean_t 7717c478bd9Sstevel@tonic-gate sctp_verify_chain(mblk_t *head, mblk_t *tail) 7727c478bd9Sstevel@tonic-gate { 7737c478bd9Sstevel@tonic-gate mblk_t *mp = head; 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate if (head == NULL || tail == NULL) 7767c478bd9Sstevel@tonic-gate return (B_TRUE); 7777c478bd9Sstevel@tonic-gate while (mp != NULL) { 7787c478bd9Sstevel@tonic-gate if (mp == tail) 7797c478bd9Sstevel@tonic-gate return (B_TRUE); 7807c478bd9Sstevel@tonic-gate mp = mp->b_next; 7817c478bd9Sstevel@tonic-gate } 7827c478bd9Sstevel@tonic-gate return (B_FALSE); 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate #endif 7857c478bd9Sstevel@tonic-gate 7867c478bd9Sstevel@tonic-gate /* 7877c478bd9Sstevel@tonic-gate * Gets the next unsent chunk to transmit. Messages that are abandoned are 7887c478bd9Sstevel@tonic-gate * skipped. A message can be abandoned if it has a non-zero timetolive and 7897c478bd9Sstevel@tonic-gate * transmission has not yet started or if it is a partially reliable 7907c478bd9Sstevel@tonic-gate * message and its time is up (assuming we are PR-SCTP aware). 7917c478bd9Sstevel@tonic-gate * 'cansend' is used to determine if need to try and chunkify messages from 7927c478bd9Sstevel@tonic-gate * the unsent list, if any, and also as an input to sctp_chunkify() if so. 7932dd25cf1SGeorge Shepherd * 7942dd25cf1SGeorge Shepherd * firstseg indicates the space already used, cansend represents remaining 7952dd25cf1SGeorge Shepherd * space in the window, ((sfa_pmss - firstseg) can therefore reasonably 7962dd25cf1SGeorge Shepherd * be used to compute the cansend arg). 7977c478bd9Sstevel@tonic-gate */ 7987c478bd9Sstevel@tonic-gate mblk_t * 7997c478bd9Sstevel@tonic-gate sctp_get_msg_to_send(sctp_t *sctp, mblk_t **mp, mblk_t *meta, int *error, 8007c478bd9Sstevel@tonic-gate int32_t firstseg, uint32_t cansend, sctp_faddr_t *fp) 8017c478bd9Sstevel@tonic-gate { 8027c478bd9Sstevel@tonic-gate mblk_t *mp1; 8037c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *msg_hdr; 8047c478bd9Sstevel@tonic-gate mblk_t *tmp_meta; 8057c478bd9Sstevel@tonic-gate sctp_faddr_t *fp1; 8067c478bd9Sstevel@tonic-gate 8077c478bd9Sstevel@tonic-gate ASSERT(error != NULL && mp != NULL); 8087c478bd9Sstevel@tonic-gate *error = 0; 8097c478bd9Sstevel@tonic-gate 8107c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_current != NULL); 8117c478bd9Sstevel@tonic-gate 8127c478bd9Sstevel@tonic-gate chunkified: 8137c478bd9Sstevel@tonic-gate while (meta != NULL) { 8147c478bd9Sstevel@tonic-gate tmp_meta = meta->b_next; 8157c478bd9Sstevel@tonic-gate msg_hdr = (sctp_msg_hdr_t *)meta->b_rptr; 8167c478bd9Sstevel@tonic-gate mp1 = meta->b_cont; 8177c478bd9Sstevel@tonic-gate if (SCTP_IS_MSG_ABANDONED(meta)) 8187c478bd9Sstevel@tonic-gate goto next_msg; 8197c478bd9Sstevel@tonic-gate if (!SCTP_MSG_TO_BE_ABANDONED(meta, msg_hdr, sctp)) { 8207c478bd9Sstevel@tonic-gate while (mp1 != NULL) { 8217c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_CANSEND(mp1)) { 8227c478bd9Sstevel@tonic-gate *mp = mp1; 8237c478bd9Sstevel@tonic-gate #ifdef DEBUG 8247c478bd9Sstevel@tonic-gate ASSERT(sctp_verify_chain( 8257c478bd9Sstevel@tonic-gate sctp->sctp_xmit_head, meta)); 8267c478bd9Sstevel@tonic-gate #endif 8277c478bd9Sstevel@tonic-gate return (meta); 8287c478bd9Sstevel@tonic-gate } 8297c478bd9Sstevel@tonic-gate mp1 = mp1->b_next; 8307c478bd9Sstevel@tonic-gate } 8317c478bd9Sstevel@tonic-gate goto next_msg; 8327c478bd9Sstevel@tonic-gate } 8337c478bd9Sstevel@tonic-gate /* 8347c478bd9Sstevel@tonic-gate * If we come here and the first chunk is sent, then we 8357c478bd9Sstevel@tonic-gate * we are PR-SCTP aware, in which case if the cumulative 8367c478bd9Sstevel@tonic-gate * TSN has moved upto or beyond the first chunk (which 8377c478bd9Sstevel@tonic-gate * means all the previous messages have been cumulative 8387c478bd9Sstevel@tonic-gate * SACK'd), then we send a Forward TSN with the last 8397c478bd9Sstevel@tonic-gate * chunk that was sent in this message. If we can't send 8407c478bd9Sstevel@tonic-gate * a Forward TSN because previous non-abandoned messages 8417c478bd9Sstevel@tonic-gate * have not been acked then we will defer the Forward TSN 8427c478bd9Sstevel@tonic-gate * to sctp_rexmit() or sctp_cumack(). 8437c478bd9Sstevel@tonic-gate */ 8447c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_ISSENT(mp1)) { 8457c478bd9Sstevel@tonic-gate *error = sctp_check_abandoned_msg(sctp, meta); 8467c478bd9Sstevel@tonic-gate if (*error != 0) { 8477c478bd9Sstevel@tonic-gate #ifdef DEBUG 8487c478bd9Sstevel@tonic-gate ASSERT(sctp_verify_chain(sctp->sctp_xmit_head, 8497c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail)); 8507c478bd9Sstevel@tonic-gate #endif 8517c478bd9Sstevel@tonic-gate return (NULL); 8527c478bd9Sstevel@tonic-gate } 8537c478bd9Sstevel@tonic-gate goto next_msg; 8547c478bd9Sstevel@tonic-gate } 8557c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_prsctpdrop); 8567c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_unsent >= msg_hdr->smh_msglen); 8577c478bd9Sstevel@tonic-gate if (meta->b_prev == NULL) { 8587c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_xmit_head == meta); 8597c478bd9Sstevel@tonic-gate sctp->sctp_xmit_head = tmp_meta; 8607c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_tail == meta) 8617c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail = tmp_meta; 8627c478bd9Sstevel@tonic-gate meta->b_next = NULL; 8637c478bd9Sstevel@tonic-gate if (tmp_meta != NULL) 8647c478bd9Sstevel@tonic-gate tmp_meta->b_prev = NULL; 8657c478bd9Sstevel@tonic-gate } else if (meta->b_next == NULL) { 8667c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_tail == meta) 8677c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail = meta->b_prev; 8687c478bd9Sstevel@tonic-gate meta->b_prev->b_next = NULL; 8697c478bd9Sstevel@tonic-gate meta->b_prev = NULL; 8707c478bd9Sstevel@tonic-gate } else { 8717c478bd9Sstevel@tonic-gate meta->b_prev->b_next = tmp_meta; 8727c478bd9Sstevel@tonic-gate tmp_meta->b_prev = meta->b_prev; 8737c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_tail == meta) 8747c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail = tmp_meta; 8757c478bd9Sstevel@tonic-gate meta->b_prev = NULL; 8767c478bd9Sstevel@tonic-gate meta->b_next = NULL; 8777c478bd9Sstevel@tonic-gate } 8787c478bd9Sstevel@tonic-gate sctp->sctp_unsent -= msg_hdr->smh_msglen; 8797c478bd9Sstevel@tonic-gate /* 8807c478bd9Sstevel@tonic-gate * Update ULP the amount of queued data, which is 8817c478bd9Sstevel@tonic-gate * sent-unack'ed + unsent. 8827c478bd9Sstevel@tonic-gate */ 883*0f1702c5SYu Xiangning if (!SCTP_IS_DETACHED(sctp)) 884*0f1702c5SYu Xiangning SCTP_TXQ_UPDATE(sctp); 8857c478bd9Sstevel@tonic-gate sctp_sendfail_event(sctp, meta, 0, B_TRUE); 8867c478bd9Sstevel@tonic-gate next_msg: 8877c478bd9Sstevel@tonic-gate meta = tmp_meta; 8887c478bd9Sstevel@tonic-gate } 8897c478bd9Sstevel@tonic-gate /* chunkify, if needed */ 8907c478bd9Sstevel@tonic-gate if (cansend > 0 && sctp->sctp_xmit_unsent != NULL) { 8917c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_unsent > 0); 8927c478bd9Sstevel@tonic-gate if (fp == NULL) { 8937c478bd9Sstevel@tonic-gate fp = SCTP_CHUNK_DEST(sctp->sctp_xmit_unsent); 8947c478bd9Sstevel@tonic-gate if (fp == NULL || fp->state != SCTP_FADDRS_ALIVE) 8957c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 8967c478bd9Sstevel@tonic-gate } else { 8977c478bd9Sstevel@tonic-gate /* 8987c478bd9Sstevel@tonic-gate * If user specified destination, try to honor that. 8997c478bd9Sstevel@tonic-gate */ 9007c478bd9Sstevel@tonic-gate fp1 = SCTP_CHUNK_DEST(sctp->sctp_xmit_unsent); 9017c478bd9Sstevel@tonic-gate if (fp1 != NULL && fp1->state == SCTP_FADDRS_ALIVE && 9027c478bd9Sstevel@tonic-gate fp1 != fp) { 9037c478bd9Sstevel@tonic-gate goto chunk_done; 9047c478bd9Sstevel@tonic-gate } 9057c478bd9Sstevel@tonic-gate } 9067c478bd9Sstevel@tonic-gate sctp_chunkify(sctp, fp->sfa_pmss - firstseg, cansend); 9077c478bd9Sstevel@tonic-gate if ((meta = sctp->sctp_xmit_tail) == NULL) 9087c478bd9Sstevel@tonic-gate goto chunk_done; 9097c478bd9Sstevel@tonic-gate /* 9107c478bd9Sstevel@tonic-gate * sctp_chunkify() won't advance sctp_xmit_tail if it adds 9117c478bd9Sstevel@tonic-gate * new chunk(s) to the tail, so we need to skip the 9127c478bd9Sstevel@tonic-gate * sctp_xmit_tail, which would have already been processed. 9137c478bd9Sstevel@tonic-gate * This could happen when there is unacked chunks, but 9147c478bd9Sstevel@tonic-gate * nothing new to send. 9157c478bd9Sstevel@tonic-gate * When sctp_chunkify() is called when the transmit queue 9167c478bd9Sstevel@tonic-gate * is empty then we need to start from sctp_xmit_tail. 9177c478bd9Sstevel@tonic-gate */ 9187c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_ISSENT(sctp->sctp_xmit_tail->b_cont)) { 9197c478bd9Sstevel@tonic-gate #ifdef DEBUG 9207c478bd9Sstevel@tonic-gate mp1 = sctp->sctp_xmit_tail->b_cont; 9217c478bd9Sstevel@tonic-gate while (mp1 != NULL) { 9227c478bd9Sstevel@tonic-gate ASSERT(!SCTP_CHUNK_CANSEND(mp1)); 9237c478bd9Sstevel@tonic-gate mp1 = mp1->b_next; 9247c478bd9Sstevel@tonic-gate } 9257c478bd9Sstevel@tonic-gate #endif 9267c478bd9Sstevel@tonic-gate if ((meta = sctp->sctp_xmit_tail->b_next) == NULL) 9277c478bd9Sstevel@tonic-gate goto chunk_done; 9287c478bd9Sstevel@tonic-gate } 9297c478bd9Sstevel@tonic-gate goto chunkified; 9307c478bd9Sstevel@tonic-gate } 9317c478bd9Sstevel@tonic-gate chunk_done: 9327c478bd9Sstevel@tonic-gate #ifdef DEBUG 9337c478bd9Sstevel@tonic-gate ASSERT(sctp_verify_chain(sctp->sctp_xmit_head, sctp->sctp_xmit_tail)); 9347c478bd9Sstevel@tonic-gate #endif 9357c478bd9Sstevel@tonic-gate return (NULL); 9367c478bd9Sstevel@tonic-gate } 9377c478bd9Sstevel@tonic-gate 9387c478bd9Sstevel@tonic-gate void 9397c478bd9Sstevel@tonic-gate sctp_fast_rexmit(sctp_t *sctp) 9407c478bd9Sstevel@tonic-gate { 9417c478bd9Sstevel@tonic-gate mblk_t *mp, *head; 9427c478bd9Sstevel@tonic-gate int pktlen = 0; 9437c478bd9Sstevel@tonic-gate sctp_faddr_t *fp = NULL; 944f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 9457c478bd9Sstevel@tonic-gate 9467c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_xmit_head != NULL); 9477c478bd9Sstevel@tonic-gate mp = sctp_find_fast_rexmit_mblks(sctp, &pktlen, &fp); 94877c67f2fSkcpoon if (mp == NULL) { 949f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_fr_not_found); 9507c478bd9Sstevel@tonic-gate return; 95177c67f2fSkcpoon } 952df19b344Svi if ((head = sctp_add_proto_hdr(sctp, fp, mp, 0, NULL)) == NULL) { 9537c478bd9Sstevel@tonic-gate freemsg(mp); 954f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_fr_add_hdr); 9557c478bd9Sstevel@tonic-gate return; 9567c478bd9Sstevel@tonic-gate } 9577c478bd9Sstevel@tonic-gate if ((pktlen > fp->sfa_pmss) && fp->isv4) { 9587c478bd9Sstevel@tonic-gate ipha_t *iph = (ipha_t *)head->b_rptr; 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate iph->ipha_fragment_offset_and_flags = 0; 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate sctp_set_iplen(sctp, head); 9647c478bd9Sstevel@tonic-gate sctp_add_sendq(sctp, head); 9657c478bd9Sstevel@tonic-gate sctp->sctp_active = fp->lastactive = lbolt64; 9667c478bd9Sstevel@tonic-gate } 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate void 96912f47623Skcpoon sctp_output(sctp_t *sctp, uint_t num_pkt) 9707c478bd9Sstevel@tonic-gate { 9717c478bd9Sstevel@tonic-gate mblk_t *mp = NULL; 9727c478bd9Sstevel@tonic-gate mblk_t *nmp; 9737c478bd9Sstevel@tonic-gate mblk_t *head; 9747c478bd9Sstevel@tonic-gate mblk_t *meta = sctp->sctp_xmit_tail; 9757c478bd9Sstevel@tonic-gate mblk_t *fill = NULL; 9767c478bd9Sstevel@tonic-gate uint16_t chunklen; 9777c478bd9Sstevel@tonic-gate uint32_t cansend; 9787c478bd9Sstevel@tonic-gate int32_t seglen; 9797c478bd9Sstevel@tonic-gate int32_t xtralen; 9807c478bd9Sstevel@tonic-gate int32_t sacklen; 9817c478bd9Sstevel@tonic-gate int32_t pad = 0; 9827c478bd9Sstevel@tonic-gate int32_t pathmax; 9837c478bd9Sstevel@tonic-gate int extra; 9847c478bd9Sstevel@tonic-gate int64_t now = lbolt64; 9857c478bd9Sstevel@tonic-gate sctp_faddr_t *fp; 9867c478bd9Sstevel@tonic-gate sctp_faddr_t *lfp; 9877c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 9887c478bd9Sstevel@tonic-gate int error; 989df19b344Svi boolean_t notsent = B_TRUE; 99012f47623Skcpoon sctp_stack_t *sctps = sctp->sctp_sctps; 9917c478bd9Sstevel@tonic-gate 9927c478bd9Sstevel@tonic-gate if (sctp->sctp_ftsn == sctp->sctp_lastacked + 1) { 9937c478bd9Sstevel@tonic-gate sacklen = 0; 9947c478bd9Sstevel@tonic-gate } else { 9957c478bd9Sstevel@tonic-gate /* send a SACK chunk */ 9967c478bd9Sstevel@tonic-gate sacklen = sizeof (sctp_chunk_hdr_t) + 9977c478bd9Sstevel@tonic-gate sizeof (sctp_sack_chunk_t) + 9987c478bd9Sstevel@tonic-gate (sizeof (sctp_sack_frag_t) * sctp->sctp_sack_gaps); 9997c478bd9Sstevel@tonic-gate lfp = sctp->sctp_lastdata; 10007c478bd9Sstevel@tonic-gate ASSERT(lfp != NULL); 10017c478bd9Sstevel@tonic-gate if (lfp->state != SCTP_FADDRS_ALIVE) 10027c478bd9Sstevel@tonic-gate lfp = sctp->sctp_current; 10037c478bd9Sstevel@tonic-gate } 10047c478bd9Sstevel@tonic-gate 10057c478bd9Sstevel@tonic-gate cansend = sctp->sctp_frwnd; 10067c478bd9Sstevel@tonic-gate if (sctp->sctp_unsent < cansend) 10077c478bd9Sstevel@tonic-gate cansend = sctp->sctp_unsent; 1008518f8adfSGeorge Shepherd 1009518f8adfSGeorge Shepherd /* 1010518f8adfSGeorge Shepherd * Start persist timer if unable to send or when 1011518f8adfSGeorge Shepherd * trying to send into a zero window. This timer 1012518f8adfSGeorge Shepherd * ensures the blocked send attempt is retried. 1013518f8adfSGeorge Shepherd */ 10147c478bd9Sstevel@tonic-gate if ((cansend < sctp->sctp_current->sfa_pmss / 2) && 1015518f8adfSGeorge Shepherd (sctp->sctp_unacked != 0) && 10167c478bd9Sstevel@tonic-gate (sctp->sctp_unacked < sctp->sctp_current->sfa_pmss) && 1017518f8adfSGeorge Shepherd !sctp->sctp_ndelay || 1018518f8adfSGeorge Shepherd (cansend == 0 && sctp->sctp_unacked == 0 && 1019518f8adfSGeorge Shepherd sctp->sctp_unsent != 0)) { 10207c478bd9Sstevel@tonic-gate head = NULL; 10217c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 10227c478bd9Sstevel@tonic-gate goto unsent_data; 10237c478bd9Sstevel@tonic-gate } 10247c478bd9Sstevel@tonic-gate if (meta != NULL) 10257c478bd9Sstevel@tonic-gate mp = meta->b_cont; 102612f47623Skcpoon while (cansend > 0 && num_pkt-- != 0) { 10277c478bd9Sstevel@tonic-gate pad = 0; 10287c478bd9Sstevel@tonic-gate 10297c478bd9Sstevel@tonic-gate /* 10307c478bd9Sstevel@tonic-gate * Find first segment eligible for transmit. 10317c478bd9Sstevel@tonic-gate */ 10327c478bd9Sstevel@tonic-gate while (mp != NULL) { 10337c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_CANSEND(mp)) 10347c478bd9Sstevel@tonic-gate break; 10357c478bd9Sstevel@tonic-gate mp = mp->b_next; 10367c478bd9Sstevel@tonic-gate } 10377c478bd9Sstevel@tonic-gate if (mp == NULL) { 10387c478bd9Sstevel@tonic-gate meta = sctp_get_msg_to_send(sctp, &mp, 10397c478bd9Sstevel@tonic-gate meta == NULL ? NULL : meta->b_next, &error, sacklen, 10407c478bd9Sstevel@tonic-gate cansend, NULL); 10417c478bd9Sstevel@tonic-gate if (error != 0 || meta == NULL) { 10427c478bd9Sstevel@tonic-gate head = NULL; 10437c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 10447c478bd9Sstevel@tonic-gate goto unsent_data; 10457c478bd9Sstevel@tonic-gate } 10467c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail = meta; 10477c478bd9Sstevel@tonic-gate } 10487c478bd9Sstevel@tonic-gate 10497c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 10507c478bd9Sstevel@tonic-gate seglen = ntohs(sdc->sdh_len); 10517c478bd9Sstevel@tonic-gate xtralen = sizeof (*sdc); 10527c478bd9Sstevel@tonic-gate chunklen = seglen - xtralen; 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate /* 10557c478bd9Sstevel@tonic-gate * Check rwnd. 10567c478bd9Sstevel@tonic-gate */ 10577c478bd9Sstevel@tonic-gate if (chunklen > cansend) { 10587c478bd9Sstevel@tonic-gate head = NULL; 10597c478bd9Sstevel@tonic-gate fp = SCTP_CHUNK_DEST(meta); 10607c478bd9Sstevel@tonic-gate if (fp == NULL || fp->state != SCTP_FADDRS_ALIVE) 10617c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 10627c478bd9Sstevel@tonic-gate goto unsent_data; 10637c478bd9Sstevel@tonic-gate } 10647c478bd9Sstevel@tonic-gate if ((extra = seglen & (SCTP_ALIGN - 1)) != 0) 10657c478bd9Sstevel@tonic-gate extra = SCTP_ALIGN - extra; 10667c478bd9Sstevel@tonic-gate 10677c478bd9Sstevel@tonic-gate /* 10687c478bd9Sstevel@tonic-gate * Pick destination address, and check cwnd. 10697c478bd9Sstevel@tonic-gate */ 10707c478bd9Sstevel@tonic-gate if (sacklen > 0 && (seglen + extra <= lfp->cwnd - lfp->suna) && 10717c478bd9Sstevel@tonic-gate (seglen + sacklen + extra <= lfp->sfa_pmss)) { 10727c478bd9Sstevel@tonic-gate /* 10737c478bd9Sstevel@tonic-gate * Only include SACK chunk if it can be bundled 10747c478bd9Sstevel@tonic-gate * with a data chunk, and sent to sctp_lastdata. 10757c478bd9Sstevel@tonic-gate */ 10767c478bd9Sstevel@tonic-gate pathmax = lfp->cwnd - lfp->suna; 10777c478bd9Sstevel@tonic-gate 10787c478bd9Sstevel@tonic-gate fp = lfp; 10797c478bd9Sstevel@tonic-gate if ((nmp = dupmsg(mp)) == NULL) { 10807c478bd9Sstevel@tonic-gate head = NULL; 10817c478bd9Sstevel@tonic-gate goto unsent_data; 10827c478bd9Sstevel@tonic-gate } 10837c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_FLAGS(nmp); 1084df19b344Svi head = sctp_add_proto_hdr(sctp, fp, nmp, sacklen, 1085df19b344Svi &error); 10867c478bd9Sstevel@tonic-gate if (head == NULL) { 1087df19b344Svi /* 1088df19b344Svi * If none of the source addresses are 1089df19b344Svi * available (i.e error == EHOSTUNREACH), 1090df19b344Svi * pretend we have sent the data. We will 1091df19b344Svi * eventually time out trying to retramsmit 1092df19b344Svi * the data if the interface never comes up. 1093df19b344Svi * If we have already sent some stuff (i.e., 1094df19b344Svi * notsent is B_FALSE) then we are fine, else 1095df19b344Svi * just mark this packet as sent. 1096df19b344Svi */ 1097df19b344Svi if (notsent && error == EHOSTUNREACH) { 1098df19b344Svi SCTP_CHUNK_SENT(sctp, mp, sdc, 1099df19b344Svi fp, chunklen, meta); 1100df19b344Svi } 11017c478bd9Sstevel@tonic-gate freemsg(nmp); 1102f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_output_failed); 11037c478bd9Sstevel@tonic-gate goto unsent_data; 11047c478bd9Sstevel@tonic-gate } 11057c478bd9Sstevel@tonic-gate seglen += sacklen; 11067c478bd9Sstevel@tonic-gate xtralen += sacklen; 11077c478bd9Sstevel@tonic-gate sacklen = 0; 11087c478bd9Sstevel@tonic-gate } else { 11097c478bd9Sstevel@tonic-gate fp = SCTP_CHUNK_DEST(meta); 11107c478bd9Sstevel@tonic-gate if (fp == NULL || fp->state != SCTP_FADDRS_ALIVE) 11117c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 11127c478bd9Sstevel@tonic-gate /* 11137c478bd9Sstevel@tonic-gate * If we haven't sent data to this destination for 11147c478bd9Sstevel@tonic-gate * a while, do slow start again. 11157c478bd9Sstevel@tonic-gate */ 11167c478bd9Sstevel@tonic-gate if (now - fp->lastactive > fp->rto) { 111712f47623Skcpoon SET_CWND(fp, fp->sfa_pmss, 111812f47623Skcpoon sctps->sctps_slow_start_after_idle); 11197c478bd9Sstevel@tonic-gate } 11207c478bd9Sstevel@tonic-gate 11217c478bd9Sstevel@tonic-gate pathmax = fp->cwnd - fp->suna; 11227c478bd9Sstevel@tonic-gate if (seglen + extra > pathmax) { 11237c478bd9Sstevel@tonic-gate head = NULL; 11247c478bd9Sstevel@tonic-gate goto unsent_data; 11257c478bd9Sstevel@tonic-gate } 11267c478bd9Sstevel@tonic-gate if ((nmp = dupmsg(mp)) == NULL) { 11277c478bd9Sstevel@tonic-gate head = NULL; 11287c478bd9Sstevel@tonic-gate goto unsent_data; 11297c478bd9Sstevel@tonic-gate } 11307c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_FLAGS(nmp); 1131df19b344Svi head = sctp_add_proto_hdr(sctp, fp, nmp, 0, &error); 11327c478bd9Sstevel@tonic-gate if (head == NULL) { 1133df19b344Svi /* 1134df19b344Svi * If none of the source addresses are 1135df19b344Svi * available (i.e error == EHOSTUNREACH), 1136df19b344Svi * pretend we have sent the data. We will 1137df19b344Svi * eventually time out trying to retramsmit 1138df19b344Svi * the data if the interface never comes up. 1139df19b344Svi * If we have already sent some stuff (i.e., 1140df19b344Svi * notsent is B_FALSE) then we are fine, else 1141df19b344Svi * just mark this packet as sent. 1142df19b344Svi */ 1143df19b344Svi if (notsent && error == EHOSTUNREACH) { 1144df19b344Svi SCTP_CHUNK_SENT(sctp, mp, sdc, 1145df19b344Svi fp, chunklen, meta); 1146df19b344Svi } 11477c478bd9Sstevel@tonic-gate freemsg(nmp); 1148f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_output_failed); 11497c478bd9Sstevel@tonic-gate goto unsent_data; 11507c478bd9Sstevel@tonic-gate } 11517c478bd9Sstevel@tonic-gate } 115277c67f2fSkcpoon fp->lastactive = now; 11537c478bd9Sstevel@tonic-gate if (pathmax > fp->sfa_pmss) 11547c478bd9Sstevel@tonic-gate pathmax = fp->sfa_pmss; 11557c478bd9Sstevel@tonic-gate SCTP_CHUNK_SENT(sctp, mp, sdc, fp, chunklen, meta); 11567c478bd9Sstevel@tonic-gate mp = mp->b_next; 11577c478bd9Sstevel@tonic-gate 11587c478bd9Sstevel@tonic-gate /* Use this chunk to measure RTT? */ 11597c478bd9Sstevel@tonic-gate if (sctp->sctp_out_time == 0) { 11607c478bd9Sstevel@tonic-gate sctp->sctp_out_time = now; 11617c478bd9Sstevel@tonic-gate sctp->sctp_rtt_tsn = sctp->sctp_ltsn - 1; 116277c67f2fSkcpoon ASSERT(sctp->sctp_rtt_tsn == ntohl(sdc->sdh_tsn)); 11637c478bd9Sstevel@tonic-gate } 11647c478bd9Sstevel@tonic-gate if (extra > 0) { 1165121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 11667c478bd9Sstevel@tonic-gate if (fill != NULL) { 11677c478bd9Sstevel@tonic-gate linkb(head, fill); 11687c478bd9Sstevel@tonic-gate pad = extra; 11697c478bd9Sstevel@tonic-gate seglen += extra; 11707c478bd9Sstevel@tonic-gate } else { 11717c478bd9Sstevel@tonic-gate goto unsent_data; 11727c478bd9Sstevel@tonic-gate } 11737c478bd9Sstevel@tonic-gate } 11747c478bd9Sstevel@tonic-gate /* See if we can bundle more. */ 11757c478bd9Sstevel@tonic-gate while (seglen < pathmax) { 11767c478bd9Sstevel@tonic-gate int32_t new_len; 11777c478bd9Sstevel@tonic-gate int32_t new_xtralen; 11787c478bd9Sstevel@tonic-gate 11797c478bd9Sstevel@tonic-gate while (mp != NULL) { 11807c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_CANSEND(mp)) 11817c478bd9Sstevel@tonic-gate break; 11827c478bd9Sstevel@tonic-gate mp = mp->b_next; 11837c478bd9Sstevel@tonic-gate } 11847c478bd9Sstevel@tonic-gate if (mp == NULL) { 11857c478bd9Sstevel@tonic-gate meta = sctp_get_msg_to_send(sctp, &mp, 11867c478bd9Sstevel@tonic-gate meta->b_next, &error, seglen, 11877c478bd9Sstevel@tonic-gate (seglen - xtralen) >= cansend ? 0 : 11887c478bd9Sstevel@tonic-gate cansend - seglen, fp); 11897c478bd9Sstevel@tonic-gate if (error != 0 || meta == NULL) 11907c478bd9Sstevel@tonic-gate break; 11917c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail = meta; 11927c478bd9Sstevel@tonic-gate } 11937c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 11947c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp) && SCTP_CHUNK_DEST(meta) && 11957c478bd9Sstevel@tonic-gate fp != SCTP_CHUNK_DEST(meta)) { 11967c478bd9Sstevel@tonic-gate break; 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 11997c478bd9Sstevel@tonic-gate chunklen = ntohs(sdc->sdh_len); 12007c478bd9Sstevel@tonic-gate if ((extra = chunklen & (SCTP_ALIGN - 1)) != 0) 12017c478bd9Sstevel@tonic-gate extra = SCTP_ALIGN - extra; 12027c478bd9Sstevel@tonic-gate 12037c478bd9Sstevel@tonic-gate new_len = seglen + chunklen; 12047c478bd9Sstevel@tonic-gate new_xtralen = xtralen + sizeof (*sdc); 12057c478bd9Sstevel@tonic-gate chunklen -= sizeof (*sdc); 12067c478bd9Sstevel@tonic-gate 12077c478bd9Sstevel@tonic-gate if (new_len - new_xtralen > cansend || 12087c478bd9Sstevel@tonic-gate new_len + extra > pathmax) { 12097c478bd9Sstevel@tonic-gate break; 12107c478bd9Sstevel@tonic-gate } 12117c478bd9Sstevel@tonic-gate if ((nmp = dupmsg(mp)) == NULL) 12127c478bd9Sstevel@tonic-gate break; 12137c478bd9Sstevel@tonic-gate if (extra > 0) { 1214121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 12157c478bd9Sstevel@tonic-gate if (fill != NULL) { 12167c478bd9Sstevel@tonic-gate pad += extra; 12177c478bd9Sstevel@tonic-gate new_len += extra; 12187c478bd9Sstevel@tonic-gate linkb(nmp, fill); 12197c478bd9Sstevel@tonic-gate } else { 12207c478bd9Sstevel@tonic-gate freemsg(nmp); 12217c478bd9Sstevel@tonic-gate break; 12227c478bd9Sstevel@tonic-gate } 12237c478bd9Sstevel@tonic-gate } 12247c478bd9Sstevel@tonic-gate seglen = new_len; 12257c478bd9Sstevel@tonic-gate xtralen = new_xtralen; 12267c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_FLAGS(nmp); 12277c478bd9Sstevel@tonic-gate SCTP_CHUNK_SENT(sctp, mp, sdc, fp, chunklen, meta); 12287c478bd9Sstevel@tonic-gate linkb(head, nmp); 12297c478bd9Sstevel@tonic-gate mp = mp->b_next; 12307c478bd9Sstevel@tonic-gate } 12317c478bd9Sstevel@tonic-gate if ((seglen > fp->sfa_pmss) && fp->isv4) { 12327c478bd9Sstevel@tonic-gate ipha_t *iph = (ipha_t *)head->b_rptr; 12337c478bd9Sstevel@tonic-gate 12347c478bd9Sstevel@tonic-gate /* 12357c478bd9Sstevel@tonic-gate * Path MTU is different from what we thought it would 12367c478bd9Sstevel@tonic-gate * be when we created chunks, or IP headers have grown. 12377c478bd9Sstevel@tonic-gate * Need to clear the DF bit. 12387c478bd9Sstevel@tonic-gate */ 12397c478bd9Sstevel@tonic-gate iph->ipha_fragment_offset_and_flags = 0; 12407c478bd9Sstevel@tonic-gate } 12417c478bd9Sstevel@tonic-gate /* xmit segment */ 12427c478bd9Sstevel@tonic-gate ASSERT(cansend >= seglen - pad - xtralen); 12437c478bd9Sstevel@tonic-gate cansend -= (seglen - pad - xtralen); 12447c478bd9Sstevel@tonic-gate dprint(2, ("sctp_output: Sending packet %d bytes, tsn %x " 124545916cd2Sjpk "ssn %d to %p (rwnd %d, cansend %d, lastack_rxd %x)\n", 124645916cd2Sjpk seglen - xtralen, ntohl(sdc->sdh_tsn), 124745916cd2Sjpk ntohs(sdc->sdh_ssn), (void *)fp, sctp->sctp_frwnd, 124845916cd2Sjpk cansend, sctp->sctp_lastack_rxd)); 12497c478bd9Sstevel@tonic-gate sctp_set_iplen(sctp, head); 12507c478bd9Sstevel@tonic-gate sctp_add_sendq(sctp, head); 12517c478bd9Sstevel@tonic-gate /* arm rto timer (if not set) */ 12527c478bd9Sstevel@tonic-gate if (!fp->timer_running) 12537c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->rto); 1254df19b344Svi notsent = B_FALSE; 12557c478bd9Sstevel@tonic-gate } 12567c478bd9Sstevel@tonic-gate sctp->sctp_active = now; 12577c478bd9Sstevel@tonic-gate return; 12587c478bd9Sstevel@tonic-gate unsent_data: 12597c478bd9Sstevel@tonic-gate /* arm persist timer (if rto timer not set) */ 12607c478bd9Sstevel@tonic-gate if (!fp->timer_running) 12617c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->rto); 12627c478bd9Sstevel@tonic-gate if (head != NULL) 12637c478bd9Sstevel@tonic-gate freemsg(head); 12647c478bd9Sstevel@tonic-gate } 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate /* 12677c478bd9Sstevel@tonic-gate * The following two functions initialize and destroy the cache 12687c478bd9Sstevel@tonic-gate * associated with the sets used for PR-SCTP. 12697c478bd9Sstevel@tonic-gate */ 12707c478bd9Sstevel@tonic-gate void 12717c478bd9Sstevel@tonic-gate sctp_ftsn_sets_init(void) 12727c478bd9Sstevel@tonic-gate { 12737c478bd9Sstevel@tonic-gate sctp_kmem_ftsn_set_cache = kmem_cache_create("sctp_ftsn_set_cache", 12747c478bd9Sstevel@tonic-gate sizeof (sctp_ftsn_set_t), 0, NULL, NULL, NULL, NULL, 12757c478bd9Sstevel@tonic-gate NULL, 0); 12767c478bd9Sstevel@tonic-gate } 12777c478bd9Sstevel@tonic-gate 12787c478bd9Sstevel@tonic-gate void 12797c478bd9Sstevel@tonic-gate sctp_ftsn_sets_fini(void) 12807c478bd9Sstevel@tonic-gate { 12817c478bd9Sstevel@tonic-gate kmem_cache_destroy(sctp_kmem_ftsn_set_cache); 12827c478bd9Sstevel@tonic-gate } 12837c478bd9Sstevel@tonic-gate 12847c478bd9Sstevel@tonic-gate 12857c478bd9Sstevel@tonic-gate /* Free PR-SCTP sets */ 12867c478bd9Sstevel@tonic-gate void 12877c478bd9Sstevel@tonic-gate sctp_free_ftsn_set(sctp_ftsn_set_t *s) 12887c478bd9Sstevel@tonic-gate { 12897c478bd9Sstevel@tonic-gate sctp_ftsn_set_t *p; 12907c478bd9Sstevel@tonic-gate 12917c478bd9Sstevel@tonic-gate while (s != NULL) { 12927c478bd9Sstevel@tonic-gate p = s->next; 12937c478bd9Sstevel@tonic-gate s->next = NULL; 12947c478bd9Sstevel@tonic-gate kmem_cache_free(sctp_kmem_ftsn_set_cache, s); 12957c478bd9Sstevel@tonic-gate s = p; 12967c478bd9Sstevel@tonic-gate } 12977c478bd9Sstevel@tonic-gate } 12987c478bd9Sstevel@tonic-gate 12997c478bd9Sstevel@tonic-gate /* 13007c478bd9Sstevel@tonic-gate * Given a message meta block, meta, this routine creates or modifies 13017c478bd9Sstevel@tonic-gate * the set that will be used to generate a Forward TSN chunk. If the 13027c478bd9Sstevel@tonic-gate * entry for stream id, sid, for this message already exists, the 13037c478bd9Sstevel@tonic-gate * sequence number, ssn, is updated if it is greater than the existing 13047c478bd9Sstevel@tonic-gate * one. If an entry for this sid does not exist, one is created if 13057c478bd9Sstevel@tonic-gate * the size does not exceed fp->sfa_pmss. We return false in case 13067c478bd9Sstevel@tonic-gate * or an error. 13077c478bd9Sstevel@tonic-gate */ 13087c478bd9Sstevel@tonic-gate boolean_t 13097c478bd9Sstevel@tonic-gate sctp_add_ftsn_set(sctp_ftsn_set_t **s, sctp_faddr_t *fp, mblk_t *meta, 13107c478bd9Sstevel@tonic-gate uint_t *nsets, uint32_t *slen) 13117c478bd9Sstevel@tonic-gate { 13127c478bd9Sstevel@tonic-gate sctp_ftsn_set_t *p; 13137c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *msg_hdr = (sctp_msg_hdr_t *)meta->b_rptr; 13147c478bd9Sstevel@tonic-gate uint16_t sid = htons(msg_hdr->smh_sid); 13157c478bd9Sstevel@tonic-gate /* msg_hdr->smh_ssn is already in NBO */ 13167c478bd9Sstevel@tonic-gate uint16_t ssn = msg_hdr->smh_ssn; 13177c478bd9Sstevel@tonic-gate 13187c478bd9Sstevel@tonic-gate ASSERT(s != NULL && nsets != NULL); 13197c478bd9Sstevel@tonic-gate ASSERT((*nsets == 0 && *s == NULL) || (*nsets > 0 && *s != NULL)); 13207c478bd9Sstevel@tonic-gate 13217c478bd9Sstevel@tonic-gate if (*s == NULL) { 13227c478bd9Sstevel@tonic-gate ASSERT((*slen + sizeof (uint32_t)) <= fp->sfa_pmss); 13237c478bd9Sstevel@tonic-gate *s = kmem_cache_alloc(sctp_kmem_ftsn_set_cache, KM_NOSLEEP); 13247c478bd9Sstevel@tonic-gate if (*s == NULL) 13257c478bd9Sstevel@tonic-gate return (B_FALSE); 13267c478bd9Sstevel@tonic-gate (*s)->ftsn_entries.ftsn_sid = sid; 13277c478bd9Sstevel@tonic-gate (*s)->ftsn_entries.ftsn_ssn = ssn; 13287c478bd9Sstevel@tonic-gate (*s)->next = NULL; 13297c478bd9Sstevel@tonic-gate *nsets = 1; 13307c478bd9Sstevel@tonic-gate *slen += sizeof (uint32_t); 13317c478bd9Sstevel@tonic-gate return (B_TRUE); 13327c478bd9Sstevel@tonic-gate } 13337c478bd9Sstevel@tonic-gate for (p = *s; p->next != NULL; p = p->next) { 13347c478bd9Sstevel@tonic-gate if (p->ftsn_entries.ftsn_sid == sid) { 13357c478bd9Sstevel@tonic-gate if (SSN_GT(ssn, p->ftsn_entries.ftsn_ssn)) 13367c478bd9Sstevel@tonic-gate p->ftsn_entries.ftsn_ssn = ssn; 13377c478bd9Sstevel@tonic-gate return (B_TRUE); 13387c478bd9Sstevel@tonic-gate } 13397c478bd9Sstevel@tonic-gate } 13407c478bd9Sstevel@tonic-gate /* the last one */ 13417c478bd9Sstevel@tonic-gate if (p->ftsn_entries.ftsn_sid == sid) { 13427c478bd9Sstevel@tonic-gate if (SSN_GT(ssn, p->ftsn_entries.ftsn_ssn)) 13437c478bd9Sstevel@tonic-gate p->ftsn_entries.ftsn_ssn = ssn; 13447c478bd9Sstevel@tonic-gate } else { 13457c478bd9Sstevel@tonic-gate if ((*slen + sizeof (uint32_t)) > fp->sfa_pmss) 13467c478bd9Sstevel@tonic-gate return (B_FALSE); 13477c478bd9Sstevel@tonic-gate p->next = kmem_cache_alloc(sctp_kmem_ftsn_set_cache, 13487c478bd9Sstevel@tonic-gate KM_NOSLEEP); 13497c478bd9Sstevel@tonic-gate if (p->next == NULL) 13507c478bd9Sstevel@tonic-gate return (B_FALSE); 13517c478bd9Sstevel@tonic-gate p = p->next; 13527c478bd9Sstevel@tonic-gate p->ftsn_entries.ftsn_sid = sid; 13537c478bd9Sstevel@tonic-gate p->ftsn_entries.ftsn_ssn = ssn; 13547c478bd9Sstevel@tonic-gate p->next = NULL; 13557c478bd9Sstevel@tonic-gate (*nsets)++; 13567c478bd9Sstevel@tonic-gate *slen += sizeof (uint32_t); 13577c478bd9Sstevel@tonic-gate } 13587c478bd9Sstevel@tonic-gate return (B_TRUE); 13597c478bd9Sstevel@tonic-gate } 13607c478bd9Sstevel@tonic-gate 13617c478bd9Sstevel@tonic-gate /* 13627c478bd9Sstevel@tonic-gate * Given a set of stream id - sequence number pairs, this routing creates 13637c478bd9Sstevel@tonic-gate * a Forward TSN chunk. The cumulative TSN (advanced peer ack point) 13647c478bd9Sstevel@tonic-gate * for the chunk is obtained from sctp->sctp_adv_pap. The caller 13657c478bd9Sstevel@tonic-gate * will add the IP/SCTP header. 13667c478bd9Sstevel@tonic-gate */ 13677c478bd9Sstevel@tonic-gate mblk_t * 13687c478bd9Sstevel@tonic-gate sctp_make_ftsn_chunk(sctp_t *sctp, sctp_faddr_t *fp, sctp_ftsn_set_t *sets, 13697c478bd9Sstevel@tonic-gate uint_t nsets, uint32_t seglen) 13707c478bd9Sstevel@tonic-gate { 13717c478bd9Sstevel@tonic-gate mblk_t *ftsn_mp; 13727c478bd9Sstevel@tonic-gate sctp_chunk_hdr_t *ch_hdr; 13737c478bd9Sstevel@tonic-gate uint32_t *advtsn; 13747c478bd9Sstevel@tonic-gate uint16_t schlen; 13757c478bd9Sstevel@tonic-gate size_t xtralen; 13767c478bd9Sstevel@tonic-gate ftsn_entry_t *ftsn_entry; 1377f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 13787c478bd9Sstevel@tonic-gate 13797c478bd9Sstevel@tonic-gate seglen += sizeof (sctp_chunk_hdr_t); 13807c478bd9Sstevel@tonic-gate if (fp->isv4) 1381f4b3ec61Sdh xtralen = sctp->sctp_hdr_len + sctps->sctps_wroff_xtra; 13827c478bd9Sstevel@tonic-gate else 1383f4b3ec61Sdh xtralen = sctp->sctp_hdr6_len + sctps->sctps_wroff_xtra; 138445916cd2Sjpk ftsn_mp = allocb_cred(xtralen + seglen, CONN_CRED(sctp->sctp_connp)); 13857c478bd9Sstevel@tonic-gate if (ftsn_mp == NULL) 13867c478bd9Sstevel@tonic-gate return (NULL); 13877c478bd9Sstevel@tonic-gate ftsn_mp->b_rptr += xtralen; 13887c478bd9Sstevel@tonic-gate ftsn_mp->b_wptr = ftsn_mp->b_rptr + seglen; 13897c478bd9Sstevel@tonic-gate 13907c478bd9Sstevel@tonic-gate ch_hdr = (sctp_chunk_hdr_t *)ftsn_mp->b_rptr; 13917c478bd9Sstevel@tonic-gate ch_hdr->sch_id = CHUNK_FORWARD_TSN; 13927c478bd9Sstevel@tonic-gate ch_hdr->sch_flags = 0; 13937c478bd9Sstevel@tonic-gate /* 13947c478bd9Sstevel@tonic-gate * The cast here should not be an issue since seglen is 13957c478bd9Sstevel@tonic-gate * the length of the Forward TSN chunk. 13967c478bd9Sstevel@tonic-gate */ 13977c478bd9Sstevel@tonic-gate schlen = (uint16_t)seglen; 13987c478bd9Sstevel@tonic-gate U16_TO_ABE16(schlen, &(ch_hdr->sch_len)); 13997c478bd9Sstevel@tonic-gate 14007c478bd9Sstevel@tonic-gate advtsn = (uint32_t *)(ch_hdr + 1); 14017c478bd9Sstevel@tonic-gate U32_TO_ABE32(sctp->sctp_adv_pap, advtsn); 14027c478bd9Sstevel@tonic-gate ftsn_entry = (ftsn_entry_t *)(advtsn + 1); 14037c478bd9Sstevel@tonic-gate while (nsets > 0) { 14047c478bd9Sstevel@tonic-gate ASSERT((uchar_t *)&ftsn_entry[1] <= ftsn_mp->b_wptr); 14057c478bd9Sstevel@tonic-gate ftsn_entry->ftsn_sid = sets->ftsn_entries.ftsn_sid; 14067c478bd9Sstevel@tonic-gate ftsn_entry->ftsn_ssn = sets->ftsn_entries.ftsn_ssn; 14077c478bd9Sstevel@tonic-gate ftsn_entry++; 14087c478bd9Sstevel@tonic-gate sets = sets->next; 14097c478bd9Sstevel@tonic-gate nsets--; 14107c478bd9Sstevel@tonic-gate } 14117c478bd9Sstevel@tonic-gate return (ftsn_mp); 14127c478bd9Sstevel@tonic-gate } 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate /* 14157c478bd9Sstevel@tonic-gate * Given a starting message, the routine steps through all the 14167c478bd9Sstevel@tonic-gate * messages whose TSN is less than sctp->sctp_adv_pap and creates 14177c478bd9Sstevel@tonic-gate * ftsn sets. The ftsn sets is then used to create an Forward TSN 14187c478bd9Sstevel@tonic-gate * chunk. All the messages, that have chunks that are included in the 14197c478bd9Sstevel@tonic-gate * ftsn sets, are flagged abandonded. If a message is partially sent 14207c478bd9Sstevel@tonic-gate * and is deemed abandoned, all remaining unsent chunks are marked 14217c478bd9Sstevel@tonic-gate * abandoned and are deducted from sctp_unsent. 14227c478bd9Sstevel@tonic-gate */ 14237c478bd9Sstevel@tonic-gate void 14247c478bd9Sstevel@tonic-gate sctp_make_ftsns(sctp_t *sctp, mblk_t *meta, mblk_t *mp, mblk_t **nmp, 14257c478bd9Sstevel@tonic-gate sctp_faddr_t *fp, uint32_t *seglen) 14267c478bd9Sstevel@tonic-gate { 14277c478bd9Sstevel@tonic-gate mblk_t *mp1 = mp; 14287c478bd9Sstevel@tonic-gate mblk_t *mp_head = mp; 14297c478bd9Sstevel@tonic-gate mblk_t *meta_head = meta; 14307c478bd9Sstevel@tonic-gate mblk_t *head; 14317c478bd9Sstevel@tonic-gate sctp_ftsn_set_t *sets = NULL; 14327c478bd9Sstevel@tonic-gate uint_t nsets = 0; 14337c478bd9Sstevel@tonic-gate uint16_t clen; 14347c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 14357c478bd9Sstevel@tonic-gate uint32_t sacklen; 14367c478bd9Sstevel@tonic-gate uint32_t adv_pap = sctp->sctp_adv_pap; 14377c478bd9Sstevel@tonic-gate uint32_t unsent = 0; 14387c478bd9Sstevel@tonic-gate boolean_t ubit; 1439f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 14407c478bd9Sstevel@tonic-gate 14417c478bd9Sstevel@tonic-gate *seglen = sizeof (uint32_t); 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 14447c478bd9Sstevel@tonic-gate while (meta != NULL && 14457c478bd9Sstevel@tonic-gate SEQ_GEQ(sctp->sctp_adv_pap, ntohl(sdc->sdh_tsn))) { 14467c478bd9Sstevel@tonic-gate /* 14477c478bd9Sstevel@tonic-gate * Skip adding FTSN sets for un-ordered messages as they do 14487c478bd9Sstevel@tonic-gate * not have SSNs. 14497c478bd9Sstevel@tonic-gate */ 14507c478bd9Sstevel@tonic-gate ubit = SCTP_DATA_GET_UBIT(sdc); 14517c478bd9Sstevel@tonic-gate if (!ubit && 14527c478bd9Sstevel@tonic-gate !sctp_add_ftsn_set(&sets, fp, meta, &nsets, seglen)) { 14537c478bd9Sstevel@tonic-gate meta = NULL; 14547c478bd9Sstevel@tonic-gate sctp->sctp_adv_pap = adv_pap; 14557c478bd9Sstevel@tonic-gate goto ftsn_done; 14567c478bd9Sstevel@tonic-gate } 14577c478bd9Sstevel@tonic-gate while (mp1 != NULL && SCTP_CHUNK_ISSENT(mp1)) { 14587c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 14597c478bd9Sstevel@tonic-gate adv_pap = ntohl(sdc->sdh_tsn); 14607c478bd9Sstevel@tonic-gate mp1 = mp1->b_next; 14617c478bd9Sstevel@tonic-gate } 14627c478bd9Sstevel@tonic-gate meta = meta->b_next; 14637c478bd9Sstevel@tonic-gate if (meta != NULL) { 14647c478bd9Sstevel@tonic-gate mp1 = meta->b_cont; 14657c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp1)) 14667c478bd9Sstevel@tonic-gate break; 14677c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 14687c478bd9Sstevel@tonic-gate } 14697c478bd9Sstevel@tonic-gate } 14707c478bd9Sstevel@tonic-gate ftsn_done: 14717c478bd9Sstevel@tonic-gate /* 14727c478bd9Sstevel@tonic-gate * Can't compare with sets == NULL, since we don't add any 14737c478bd9Sstevel@tonic-gate * sets for un-ordered messages. 14747c478bd9Sstevel@tonic-gate */ 14757c478bd9Sstevel@tonic-gate if (meta == meta_head) 14767c478bd9Sstevel@tonic-gate return; 14777c478bd9Sstevel@tonic-gate *nmp = sctp_make_ftsn_chunk(sctp, fp, sets, nsets, *seglen); 14787c478bd9Sstevel@tonic-gate sctp_free_ftsn_set(sets); 14797c478bd9Sstevel@tonic-gate if (*nmp == NULL) 14807c478bd9Sstevel@tonic-gate return; 14817c478bd9Sstevel@tonic-gate if (sctp->sctp_ftsn == sctp->sctp_lastacked + 1) { 14827c478bd9Sstevel@tonic-gate sacklen = 0; 14837c478bd9Sstevel@tonic-gate } else { 14847c478bd9Sstevel@tonic-gate sacklen = sizeof (sctp_chunk_hdr_t) + 14857c478bd9Sstevel@tonic-gate sizeof (sctp_sack_chunk_t) + 14867c478bd9Sstevel@tonic-gate (sizeof (sctp_sack_frag_t) * sctp->sctp_sack_gaps); 14877c478bd9Sstevel@tonic-gate if (*seglen + sacklen > sctp->sctp_lastdata->sfa_pmss) { 14887c478bd9Sstevel@tonic-gate /* piggybacked SACK doesn't fit */ 14897c478bd9Sstevel@tonic-gate sacklen = 0; 14907c478bd9Sstevel@tonic-gate } else { 14917c478bd9Sstevel@tonic-gate fp = sctp->sctp_lastdata; 14927c478bd9Sstevel@tonic-gate } 14937c478bd9Sstevel@tonic-gate } 1494df19b344Svi head = sctp_add_proto_hdr(sctp, fp, *nmp, sacklen, NULL); 14957c478bd9Sstevel@tonic-gate if (head == NULL) { 14967c478bd9Sstevel@tonic-gate freemsg(*nmp); 14977c478bd9Sstevel@tonic-gate *nmp = NULL; 1498f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_send_ftsn_failed); 14997c478bd9Sstevel@tonic-gate return; 15007c478bd9Sstevel@tonic-gate } 15017c478bd9Sstevel@tonic-gate *seglen += sacklen; 15027c478bd9Sstevel@tonic-gate *nmp = head; 15037c478bd9Sstevel@tonic-gate 15047c478bd9Sstevel@tonic-gate /* 15057c478bd9Sstevel@tonic-gate * XXXNeed to optimise this, the reason it is done here is so 15067c478bd9Sstevel@tonic-gate * that we don't have to undo in case of failure. 15077c478bd9Sstevel@tonic-gate */ 15087c478bd9Sstevel@tonic-gate mp1 = mp_head; 15097c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 15107c478bd9Sstevel@tonic-gate while (meta_head != NULL && 15117c478bd9Sstevel@tonic-gate SEQ_GEQ(sctp->sctp_adv_pap, ntohl(sdc->sdh_tsn))) { 15127c478bd9Sstevel@tonic-gate if (!SCTP_IS_MSG_ABANDONED(meta_head)) 15137c478bd9Sstevel@tonic-gate SCTP_MSG_SET_ABANDONED(meta_head); 15147c478bd9Sstevel@tonic-gate while (mp1 != NULL && SCTP_CHUNK_ISSENT(mp1)) { 15157c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 15167c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISACKED(mp1)) { 15177c478bd9Sstevel@tonic-gate clen = ntohs(sdc->sdh_len) - sizeof (*sdc); 15187c478bd9Sstevel@tonic-gate SCTP_CHUNK_SENT(sctp, mp1, sdc, fp, clen, 15197c478bd9Sstevel@tonic-gate meta_head); 15207c478bd9Sstevel@tonic-gate } 15217c478bd9Sstevel@tonic-gate mp1 = mp1->b_next; 15227c478bd9Sstevel@tonic-gate } 15237c478bd9Sstevel@tonic-gate while (mp1 != NULL) { 15247c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 15257c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ABANDONED(mp1)) { 15267c478bd9Sstevel@tonic-gate ASSERT(!SCTP_CHUNK_ISSENT(mp1)); 15277c478bd9Sstevel@tonic-gate unsent += ntohs(sdc->sdh_len) - sizeof (*sdc); 15287c478bd9Sstevel@tonic-gate SCTP_ABANDON_CHUNK(mp1); 15297c478bd9Sstevel@tonic-gate } 15307c478bd9Sstevel@tonic-gate mp1 = mp1->b_next; 15317c478bd9Sstevel@tonic-gate } 15327c478bd9Sstevel@tonic-gate meta_head = meta_head->b_next; 15337c478bd9Sstevel@tonic-gate if (meta_head != NULL) { 15347c478bd9Sstevel@tonic-gate mp1 = meta_head->b_cont; 15357c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp1)) 15367c478bd9Sstevel@tonic-gate break; 15377c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 15387c478bd9Sstevel@tonic-gate } 15397c478bd9Sstevel@tonic-gate } 15407c478bd9Sstevel@tonic-gate if (unsent > 0) { 15417c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_unsent >= unsent); 15427c478bd9Sstevel@tonic-gate sctp->sctp_unsent -= unsent; 15437c478bd9Sstevel@tonic-gate /* 15447c478bd9Sstevel@tonic-gate * Update ULP the amount of queued data, which is 15457c478bd9Sstevel@tonic-gate * sent-unack'ed + unsent. 15467c478bd9Sstevel@tonic-gate */ 1547*0f1702c5SYu Xiangning if (!SCTP_IS_DETACHED(sctp)) 1548*0f1702c5SYu Xiangning SCTP_TXQ_UPDATE(sctp); 15497c478bd9Sstevel@tonic-gate } 15507c478bd9Sstevel@tonic-gate } 15517c478bd9Sstevel@tonic-gate 15527c478bd9Sstevel@tonic-gate /* 15537c478bd9Sstevel@tonic-gate * This function steps through messages starting at meta and checks if 15547c478bd9Sstevel@tonic-gate * the message is abandoned. It stops when it hits an unsent chunk or 15557c478bd9Sstevel@tonic-gate * a message that has all its chunk acked. This is the only place 15567c478bd9Sstevel@tonic-gate * where the sctp_adv_pap is moved forward to indicated abandoned 15577c478bd9Sstevel@tonic-gate * messages. 15587c478bd9Sstevel@tonic-gate */ 15597c478bd9Sstevel@tonic-gate void 15607c478bd9Sstevel@tonic-gate sctp_check_adv_ack_pt(sctp_t *sctp, mblk_t *meta, mblk_t *mp) 15617c478bd9Sstevel@tonic-gate { 15627c478bd9Sstevel@tonic-gate uint32_t tsn = sctp->sctp_adv_pap; 15637c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 15647c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *msg_hdr; 15657c478bd9Sstevel@tonic-gate 15667c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 15677c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 15687c478bd9Sstevel@tonic-gate ASSERT(SEQ_GT(ntohl(sdc->sdh_tsn), sctp->sctp_lastack_rxd)); 15697c478bd9Sstevel@tonic-gate msg_hdr = (sctp_msg_hdr_t *)meta->b_rptr; 15707c478bd9Sstevel@tonic-gate if (!SCTP_IS_MSG_ABANDONED(meta) && 15717c478bd9Sstevel@tonic-gate !SCTP_MSG_TO_BE_ABANDONED(meta, msg_hdr, sctp)) { 15727c478bd9Sstevel@tonic-gate return; 15737c478bd9Sstevel@tonic-gate } 15747c478bd9Sstevel@tonic-gate while (meta != NULL) { 15757c478bd9Sstevel@tonic-gate while (mp != NULL && SCTP_CHUNK_ISSENT(mp)) { 15767c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 15777c478bd9Sstevel@tonic-gate tsn = ntohl(sdc->sdh_tsn); 15787c478bd9Sstevel@tonic-gate mp = mp->b_next; 15797c478bd9Sstevel@tonic-gate } 15807c478bd9Sstevel@tonic-gate if (mp != NULL) 15817c478bd9Sstevel@tonic-gate break; 15827c478bd9Sstevel@tonic-gate /* 15837c478bd9Sstevel@tonic-gate * We continue checking for successive messages only if there 15847c478bd9Sstevel@tonic-gate * is a chunk marked for retransmission. Else, we might 15857c478bd9Sstevel@tonic-gate * end up sending FTSN prematurely for chunks that have been 15867c478bd9Sstevel@tonic-gate * sent, but not yet acked. 15877c478bd9Sstevel@tonic-gate */ 15887c478bd9Sstevel@tonic-gate if ((meta = meta->b_next) != NULL) { 15897c478bd9Sstevel@tonic-gate msg_hdr = (sctp_msg_hdr_t *)meta->b_rptr; 15907c478bd9Sstevel@tonic-gate if (!SCTP_IS_MSG_ABANDONED(meta) && 15917c478bd9Sstevel@tonic-gate !SCTP_MSG_TO_BE_ABANDONED(meta, msg_hdr, sctp)) { 15927c478bd9Sstevel@tonic-gate break; 15937c478bd9Sstevel@tonic-gate } 15947c478bd9Sstevel@tonic-gate for (mp = meta->b_cont; mp != NULL; mp = mp->b_next) { 15957c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp)) { 15967c478bd9Sstevel@tonic-gate sctp->sctp_adv_pap = tsn; 15977c478bd9Sstevel@tonic-gate return; 15987c478bd9Sstevel@tonic-gate } 15997c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_WANT_REXMIT(mp)) 16007c478bd9Sstevel@tonic-gate break; 16017c478bd9Sstevel@tonic-gate } 16027c478bd9Sstevel@tonic-gate if (mp == NULL) 16037c478bd9Sstevel@tonic-gate break; 16047c478bd9Sstevel@tonic-gate } 16057c478bd9Sstevel@tonic-gate } 16067c478bd9Sstevel@tonic-gate sctp->sctp_adv_pap = tsn; 16077c478bd9Sstevel@tonic-gate } 16087c478bd9Sstevel@tonic-gate 160977c67f2fSkcpoon 161077c67f2fSkcpoon /* 161177c67f2fSkcpoon * Determine if we should bundle a data chunk with the chunk being 161277c67f2fSkcpoon * retransmitted. We bundle if 161377c67f2fSkcpoon * 161477c67f2fSkcpoon * - the chunk is sent to the same destination and unack'ed. 161577c67f2fSkcpoon * 161677c67f2fSkcpoon * OR 161777c67f2fSkcpoon * 161877c67f2fSkcpoon * - the chunk is unsent, i.e. new data. 161977c67f2fSkcpoon */ 162077c67f2fSkcpoon #define SCTP_CHUNK_RX_CANBUNDLE(mp, fp) \ 162177c67f2fSkcpoon (!SCTP_CHUNK_ABANDONED((mp)) && \ 162277c67f2fSkcpoon ((SCTP_CHUNK_ISSENT((mp)) && (SCTP_CHUNK_DEST(mp) == (fp) && \ 162377c67f2fSkcpoon !SCTP_CHUNK_ISACKED(mp))) || \ 162477c67f2fSkcpoon (((mp)->b_flag & (SCTP_CHUNK_FLAG_REXMIT|SCTP_CHUNK_FLAG_SENT)) != \ 162577c67f2fSkcpoon SCTP_CHUNK_FLAG_SENT))) 162677c67f2fSkcpoon 16277c478bd9Sstevel@tonic-gate /* 16287c478bd9Sstevel@tonic-gate * Retransmit first segment which hasn't been acked with cumtsn or send 16297c478bd9Sstevel@tonic-gate * a Forward TSN chunk, if appropriate. 16307c478bd9Sstevel@tonic-gate */ 16317c478bd9Sstevel@tonic-gate void 16327c478bd9Sstevel@tonic-gate sctp_rexmit(sctp_t *sctp, sctp_faddr_t *oldfp) 16337c478bd9Sstevel@tonic-gate { 16347c478bd9Sstevel@tonic-gate mblk_t *mp; 16357c478bd9Sstevel@tonic-gate mblk_t *nmp = NULL; 16367c478bd9Sstevel@tonic-gate mblk_t *head; 16377c478bd9Sstevel@tonic-gate mblk_t *meta = sctp->sctp_xmit_head; 16387c478bd9Sstevel@tonic-gate mblk_t *fill; 16397c478bd9Sstevel@tonic-gate uint32_t seglen = 0; 16407c478bd9Sstevel@tonic-gate uint32_t sacklen; 16417c478bd9Sstevel@tonic-gate uint16_t chunklen; 16427c478bd9Sstevel@tonic-gate int extra; 16437c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 16447c478bd9Sstevel@tonic-gate sctp_faddr_t *fp; 16457c478bd9Sstevel@tonic-gate uint32_t adv_pap = sctp->sctp_adv_pap; 16467c478bd9Sstevel@tonic-gate boolean_t do_ftsn = B_FALSE; 16477c478bd9Sstevel@tonic-gate boolean_t ftsn_check = B_TRUE; 164877c67f2fSkcpoon uint32_t first_ua_tsn; 164977c67f2fSkcpoon sctp_msg_hdr_t *mhdr; 1650f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 16512dd25cf1SGeorge Shepherd int error; 16527c478bd9Sstevel@tonic-gate 16537c478bd9Sstevel@tonic-gate while (meta != NULL) { 16547c478bd9Sstevel@tonic-gate for (mp = meta->b_cont; mp != NULL; mp = mp->b_next) { 16557c478bd9Sstevel@tonic-gate uint32_t tsn; 16567c478bd9Sstevel@tonic-gate 16577c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp)) 16587c478bd9Sstevel@tonic-gate goto window_probe; 16597c478bd9Sstevel@tonic-gate /* 16607c478bd9Sstevel@tonic-gate * We break in the following cases - 16617c478bd9Sstevel@tonic-gate * 16627c478bd9Sstevel@tonic-gate * if the advanced peer ack point includes the next 16637c478bd9Sstevel@tonic-gate * chunk to be retransmited - possibly the Forward 16647c478bd9Sstevel@tonic-gate * TSN was lost. 16657c478bd9Sstevel@tonic-gate * 16667c478bd9Sstevel@tonic-gate * if we are PRSCTP aware and the next chunk to be 16677c478bd9Sstevel@tonic-gate * retransmitted is now abandoned 16687c478bd9Sstevel@tonic-gate * 16697c478bd9Sstevel@tonic-gate * if the next chunk to be retransmitted is for 16707c478bd9Sstevel@tonic-gate * the dest on which the timer went off. (this 16717c478bd9Sstevel@tonic-gate * message is not abandoned). 16727c478bd9Sstevel@tonic-gate * 16737c478bd9Sstevel@tonic-gate * We check for Forward TSN only for the first 16747c478bd9Sstevel@tonic-gate * eligible chunk to be retransmitted. The reason 16757c478bd9Sstevel@tonic-gate * being if the first eligible chunk is skipped (say 16767c478bd9Sstevel@tonic-gate * it was sent to a destination other than oldfp) 16777c478bd9Sstevel@tonic-gate * then we cannot advance the cum TSN via Forward 16787c478bd9Sstevel@tonic-gate * TSN chunk. 16797c478bd9Sstevel@tonic-gate * 16807c478bd9Sstevel@tonic-gate * Also, ftsn_check is B_TRUE only for the first 16817c478bd9Sstevel@tonic-gate * eligible chunk, it will be B_FALSE for all 16827c478bd9Sstevel@tonic-gate * subsequent candidate messages for retransmission. 16837c478bd9Sstevel@tonic-gate */ 16847c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 16857c478bd9Sstevel@tonic-gate tsn = ntohl(sdc->sdh_tsn); 16867c478bd9Sstevel@tonic-gate if (SEQ_GT(tsn, sctp->sctp_lastack_rxd)) { 16877c478bd9Sstevel@tonic-gate if (sctp->sctp_prsctp_aware && ftsn_check) { 16887c478bd9Sstevel@tonic-gate if (SEQ_GEQ(sctp->sctp_adv_pap, tsn)) { 16897c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_prsctp_aware); 16907c478bd9Sstevel@tonic-gate do_ftsn = B_TRUE; 16917c478bd9Sstevel@tonic-gate goto out; 16927c478bd9Sstevel@tonic-gate } else { 16937c478bd9Sstevel@tonic-gate sctp_check_adv_ack_pt(sctp, 16947c478bd9Sstevel@tonic-gate meta, mp); 16957c478bd9Sstevel@tonic-gate if (SEQ_GT(sctp->sctp_adv_pap, 16967c478bd9Sstevel@tonic-gate adv_pap)) { 16977c478bd9Sstevel@tonic-gate do_ftsn = B_TRUE; 16987c478bd9Sstevel@tonic-gate goto out; 16997c478bd9Sstevel@tonic-gate } 17007c478bd9Sstevel@tonic-gate } 17017c478bd9Sstevel@tonic-gate ftsn_check = B_FALSE; 17027c478bd9Sstevel@tonic-gate } 17037c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_DEST(mp) == oldfp) 17047c478bd9Sstevel@tonic-gate goto out; 17057c478bd9Sstevel@tonic-gate } 17067c478bd9Sstevel@tonic-gate } 17077c478bd9Sstevel@tonic-gate meta = meta->b_next; 17087c478bd9Sstevel@tonic-gate if (meta != NULL && sctp->sctp_prsctp_aware) { 170977c67f2fSkcpoon mhdr = (sctp_msg_hdr_t *)meta->b_rptr; 17107c478bd9Sstevel@tonic-gate 17117c478bd9Sstevel@tonic-gate while (meta != NULL && (SCTP_IS_MSG_ABANDONED(meta) || 17127c478bd9Sstevel@tonic-gate SCTP_MSG_TO_BE_ABANDONED(meta, mhdr, sctp))) { 17137c478bd9Sstevel@tonic-gate meta = meta->b_next; 17147c478bd9Sstevel@tonic-gate } 17157c478bd9Sstevel@tonic-gate } 17167c478bd9Sstevel@tonic-gate } 17177c478bd9Sstevel@tonic-gate window_probe: 17187c478bd9Sstevel@tonic-gate /* 17197c478bd9Sstevel@tonic-gate * Retransmit fired for a destination which didn't have 17207c478bd9Sstevel@tonic-gate * any unacked data pending. 17217c478bd9Sstevel@tonic-gate */ 1722769b977dSvi if (sctp->sctp_unacked == 0 && sctp->sctp_unsent != 0) { 17237c478bd9Sstevel@tonic-gate /* 17247c478bd9Sstevel@tonic-gate * Send a window probe. Inflate frwnd to allow 17257c478bd9Sstevel@tonic-gate * sending one segment. 17267c478bd9Sstevel@tonic-gate */ 1727769b977dSvi if (sctp->sctp_frwnd < (oldfp->sfa_pmss - sizeof (*sdc))) 17287c478bd9Sstevel@tonic-gate sctp->sctp_frwnd = oldfp->sfa_pmss - sizeof (*sdc); 172912f47623Skcpoon 1730769b977dSvi /* next TSN to send */ 1731769b977dSvi sctp->sctp_rxt_nxttsn = sctp->sctp_ltsn; 173212f47623Skcpoon 173312f47623Skcpoon /* 173412f47623Skcpoon * The above sctp_frwnd adjustment is coarse. The "changed" 173512f47623Skcpoon * sctp_frwnd may allow us to send more than 1 packet. So 173612f47623Skcpoon * tell sctp_output() to send only 1 packet. 173712f47623Skcpoon */ 173812f47623Skcpoon sctp_output(sctp, 1); 173912f47623Skcpoon 1740769b977dSvi /* Last sent TSN */ 1741769b977dSvi sctp->sctp_rxt_maxtsn = sctp->sctp_ltsn - 1; 1742769b977dSvi ASSERT(sctp->sctp_rxt_maxtsn >= sctp->sctp_rxt_nxttsn); 1743769b977dSvi sctp->sctp_zero_win_probe = B_TRUE; 1744f4b3ec61Sdh BUMP_MIB(&sctps->sctps_mib, sctpOutWinProbe); 17457c478bd9Sstevel@tonic-gate } 17467c478bd9Sstevel@tonic-gate return; 17477c478bd9Sstevel@tonic-gate out: 1748769b977dSvi /* 174912f47623Skcpoon * After a time out, assume that everything has left the network. So 175012f47623Skcpoon * we can clear rxt_unacked for the original peer address. 175112f47623Skcpoon */ 175212f47623Skcpoon oldfp->rxt_unacked = 0; 175312f47623Skcpoon 175412f47623Skcpoon /* 175512f47623Skcpoon * If we were probing for zero window, don't adjust retransmission 1756769b977dSvi * variables, but the timer is still backed off. 1757769b977dSvi */ 1758769b977dSvi if (sctp->sctp_zero_win_probe) { 1759769b977dSvi mblk_t *pkt; 1760769b977dSvi uint_t pkt_len; 1761769b977dSvi 1762769b977dSvi /* 1763769b977dSvi * Get the Zero Win Probe for retrasmission, sctp_rxt_nxttsn 1764769b977dSvi * and sctp_rxt_maxtsn will specify the ZWP packet. 1765769b977dSvi */ 1766769b977dSvi fp = oldfp; 1767769b977dSvi if (oldfp->state != SCTP_FADDRS_ALIVE) 1768769b977dSvi fp = sctp_rotate_faddr(sctp, oldfp); 1769769b977dSvi pkt = sctp_rexmit_packet(sctp, &meta, &mp, fp, &pkt_len); 1770769b977dSvi if (pkt != NULL) { 1771769b977dSvi ASSERT(pkt_len <= fp->sfa_pmss); 1772769b977dSvi sctp_set_iplen(sctp, pkt); 1773769b977dSvi sctp_add_sendq(sctp, pkt); 1774769b977dSvi } else { 1775f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_ss_rexmit_failed); 1776769b977dSvi } 177712f47623Skcpoon 177812f47623Skcpoon /* 177912f47623Skcpoon * The strikes will be clear by sctp_faddr_alive() when the 178012f47623Skcpoon * other side sends us an ack. 178112f47623Skcpoon */ 1782769b977dSvi oldfp->strikes++; 1783769b977dSvi sctp->sctp_strikes++; 178412f47623Skcpoon 1785769b977dSvi SCTP_CALC_RXT(oldfp, sctp->sctp_rto_max); 1786769b977dSvi if (oldfp != fp && oldfp->suna != 0) 1787769b977dSvi SCTP_FADDR_TIMER_RESTART(sctp, oldfp, fp->rto); 1788769b977dSvi SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->rto); 1789f4b3ec61Sdh BUMP_MIB(&sctps->sctps_mib, sctpOutWinProbe); 1790769b977dSvi return; 1791769b977dSvi } 1792769b977dSvi 17937c478bd9Sstevel@tonic-gate /* 17947c478bd9Sstevel@tonic-gate * Enter slowstart for this destination 17957c478bd9Sstevel@tonic-gate */ 17967c478bd9Sstevel@tonic-gate oldfp->ssthresh = oldfp->cwnd / 2; 17977c478bd9Sstevel@tonic-gate if (oldfp->ssthresh < 2 * oldfp->sfa_pmss) 17987c478bd9Sstevel@tonic-gate oldfp->ssthresh = 2 * oldfp->sfa_pmss; 17997c478bd9Sstevel@tonic-gate oldfp->cwnd = oldfp->sfa_pmss; 18007c478bd9Sstevel@tonic-gate oldfp->pba = 0; 18017c478bd9Sstevel@tonic-gate fp = sctp_rotate_faddr(sctp, oldfp); 18027c478bd9Sstevel@tonic-gate ASSERT(fp != NULL); 18037c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 18047c478bd9Sstevel@tonic-gate 180577c67f2fSkcpoon first_ua_tsn = ntohl(sdc->sdh_tsn); 18067c478bd9Sstevel@tonic-gate if (do_ftsn) { 18077c478bd9Sstevel@tonic-gate sctp_make_ftsns(sctp, meta, mp, &nmp, fp, &seglen); 18087c478bd9Sstevel@tonic-gate if (nmp == NULL) { 18097c478bd9Sstevel@tonic-gate sctp->sctp_adv_pap = adv_pap; 18107c478bd9Sstevel@tonic-gate goto restart_timer; 18117c478bd9Sstevel@tonic-gate } 18127c478bd9Sstevel@tonic-gate head = nmp; 181377c67f2fSkcpoon /* 181477c67f2fSkcpoon * Move to the next unabandoned chunk. XXXCheck if meta will 181577c67f2fSkcpoon * always be marked abandoned. 181677c67f2fSkcpoon */ 181777c67f2fSkcpoon while (meta != NULL && SCTP_IS_MSG_ABANDONED(meta)) 181877c67f2fSkcpoon meta = meta->b_next; 18197c478bd9Sstevel@tonic-gate if (meta != NULL) 182077c67f2fSkcpoon mp = mp->b_cont; 182177c67f2fSkcpoon else 182277c67f2fSkcpoon mp = NULL; 18237c478bd9Sstevel@tonic-gate goto try_bundle; 18247c478bd9Sstevel@tonic-gate } 18257c478bd9Sstevel@tonic-gate seglen = ntohs(sdc->sdh_len); 18267c478bd9Sstevel@tonic-gate chunklen = seglen - sizeof (*sdc); 18277c478bd9Sstevel@tonic-gate if ((extra = seglen & (SCTP_ALIGN - 1)) != 0) 18287c478bd9Sstevel@tonic-gate extra = SCTP_ALIGN - extra; 18297c478bd9Sstevel@tonic-gate 183077c67f2fSkcpoon /* Find out if we need to piggyback SACK. */ 18317c478bd9Sstevel@tonic-gate if (sctp->sctp_ftsn == sctp->sctp_lastacked + 1) { 18327c478bd9Sstevel@tonic-gate sacklen = 0; 18337c478bd9Sstevel@tonic-gate } else { 18347c478bd9Sstevel@tonic-gate sacklen = sizeof (sctp_chunk_hdr_t) + 18357c478bd9Sstevel@tonic-gate sizeof (sctp_sack_chunk_t) + 18367c478bd9Sstevel@tonic-gate (sizeof (sctp_sack_frag_t) * sctp->sctp_sack_gaps); 18377c478bd9Sstevel@tonic-gate if (seglen + sacklen > sctp->sctp_lastdata->sfa_pmss) { 18387c478bd9Sstevel@tonic-gate /* piggybacked SACK doesn't fit */ 18397c478bd9Sstevel@tonic-gate sacklen = 0; 18407c478bd9Sstevel@tonic-gate } else { 184177c67f2fSkcpoon /* 184277c67f2fSkcpoon * OK, we have room to send SACK back. But we 184377c67f2fSkcpoon * should send it back to the last fp where we 184477c67f2fSkcpoon * receive data from, unless sctp_lastdata equals 184577c67f2fSkcpoon * oldfp, then we should probably not send it 184677c67f2fSkcpoon * back to that fp. Also we should check that 184777c67f2fSkcpoon * the fp is alive. 184877c67f2fSkcpoon */ 184977c67f2fSkcpoon if (sctp->sctp_lastdata != oldfp && 185077c67f2fSkcpoon sctp->sctp_lastdata->state == SCTP_FADDRS_ALIVE) { 185177c67f2fSkcpoon fp = sctp->sctp_lastdata; 185277c67f2fSkcpoon } 18537c478bd9Sstevel@tonic-gate } 18547c478bd9Sstevel@tonic-gate } 18557c478bd9Sstevel@tonic-gate 185677c67f2fSkcpoon /* 185777c67f2fSkcpoon * Cancel RTT measurement if the retransmitted TSN is before the 185877c67f2fSkcpoon * TSN used for timimg. 185977c67f2fSkcpoon */ 186077c67f2fSkcpoon if (sctp->sctp_out_time != 0 && 186177c67f2fSkcpoon SEQ_GEQ(sctp->sctp_rtt_tsn, sdc->sdh_tsn)) { 186277c67f2fSkcpoon sctp->sctp_out_time = 0; 186377c67f2fSkcpoon } 186477c67f2fSkcpoon /* Clear the counter as the RTT calculation may be off. */ 186577c67f2fSkcpoon fp->rtt_updates = 0; 186677c67f2fSkcpoon oldfp->rtt_updates = 0; 186777c67f2fSkcpoon 186877c67f2fSkcpoon /* 186977c67f2fSkcpoon * After a timeout, we should change the current faddr so that 187077c67f2fSkcpoon * new chunks will be sent to the alternate address. 187177c67f2fSkcpoon */ 187277c67f2fSkcpoon sctp_set_faddr_current(sctp, fp); 187377c67f2fSkcpoon 18747c478bd9Sstevel@tonic-gate nmp = dupmsg(mp); 18757c478bd9Sstevel@tonic-gate if (nmp == NULL) 18767c478bd9Sstevel@tonic-gate goto restart_timer; 18777c478bd9Sstevel@tonic-gate if (extra > 0) { 1878121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 18797c478bd9Sstevel@tonic-gate if (fill != NULL) { 18807c478bd9Sstevel@tonic-gate linkb(nmp, fill); 18817c478bd9Sstevel@tonic-gate seglen += extra; 18827c478bd9Sstevel@tonic-gate } else { 18837c478bd9Sstevel@tonic-gate freemsg(nmp); 18847c478bd9Sstevel@tonic-gate goto restart_timer; 18857c478bd9Sstevel@tonic-gate } 18867c478bd9Sstevel@tonic-gate } 18877c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_FLAGS(nmp); 1888df19b344Svi head = sctp_add_proto_hdr(sctp, fp, nmp, sacklen, NULL); 18897c478bd9Sstevel@tonic-gate if (head == NULL) { 18907c478bd9Sstevel@tonic-gate freemsg(nmp); 1891f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_rexmit_failed); 18927c478bd9Sstevel@tonic-gate goto restart_timer; 18937c478bd9Sstevel@tonic-gate } 18947c478bd9Sstevel@tonic-gate seglen += sacklen; 18957c478bd9Sstevel@tonic-gate 18967c478bd9Sstevel@tonic-gate SCTP_CHUNK_SENT(sctp, mp, sdc, fp, chunklen, meta); 18977c478bd9Sstevel@tonic-gate 18987c478bd9Sstevel@tonic-gate mp = mp->b_next; 189977c67f2fSkcpoon 19007c478bd9Sstevel@tonic-gate try_bundle: 190112f47623Skcpoon /* We can at least and at most send 1 packet at timeout. */ 19027c478bd9Sstevel@tonic-gate while (seglen < fp->sfa_pmss) { 19037c478bd9Sstevel@tonic-gate int32_t new_len; 19047c478bd9Sstevel@tonic-gate 190577c67f2fSkcpoon /* Go through the list to find more chunks to be bundled. */ 19067c478bd9Sstevel@tonic-gate while (mp != NULL) { 190777c67f2fSkcpoon /* Check if the chunk can be bundled. */ 190877c67f2fSkcpoon if (SCTP_CHUNK_RX_CANBUNDLE(mp, oldfp)) 19097c478bd9Sstevel@tonic-gate break; 19107c478bd9Sstevel@tonic-gate mp = mp->b_next; 19117c478bd9Sstevel@tonic-gate } 191277c67f2fSkcpoon /* Go to the next message. */ 19137c478bd9Sstevel@tonic-gate if (mp == NULL) { 191477c67f2fSkcpoon for (meta = meta->b_next; meta != NULL; 191577c67f2fSkcpoon meta = meta->b_next) { 191677c67f2fSkcpoon mhdr = (sctp_msg_hdr_t *)meta->b_rptr; 191777c67f2fSkcpoon 191877c67f2fSkcpoon if (SCTP_IS_MSG_ABANDONED(meta) || 191977c67f2fSkcpoon SCTP_MSG_TO_BE_ABANDONED(meta, mhdr, 192077c67f2fSkcpoon sctp)) { 192177c67f2fSkcpoon continue; 192277c67f2fSkcpoon } 192377c67f2fSkcpoon 192477c67f2fSkcpoon mp = meta->b_cont; 192577c67f2fSkcpoon goto try_bundle; 192677c67f2fSkcpoon } 19272dd25cf1SGeorge Shepherd /* 19282dd25cf1SGeorge Shepherd * Check if there is a new message which potentially 19292dd25cf1SGeorge Shepherd * could be bundled with this retransmission. 19302dd25cf1SGeorge Shepherd */ 19312dd25cf1SGeorge Shepherd meta = sctp_get_msg_to_send(sctp, &mp, NULL, &error, 19322dd25cf1SGeorge Shepherd seglen, fp->sfa_pmss - seglen, NULL); 19332dd25cf1SGeorge Shepherd if (error != 0 || meta == NULL) { 19342dd25cf1SGeorge Shepherd /* No more chunk to be bundled. */ 19352dd25cf1SGeorge Shepherd break; 19362dd25cf1SGeorge Shepherd } else { 19372dd25cf1SGeorge Shepherd goto try_bundle; 19382dd25cf1SGeorge Shepherd } 19397c478bd9Sstevel@tonic-gate } 194077c67f2fSkcpoon 19417c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 194277c67f2fSkcpoon new_len = ntohs(sdc->sdh_len); 194377c67f2fSkcpoon chunklen = new_len - sizeof (*sdc); 19447c478bd9Sstevel@tonic-gate 194577c67f2fSkcpoon if ((extra = new_len & (SCTP_ALIGN - 1)) != 0) 194677c67f2fSkcpoon extra = SCTP_ALIGN - extra; 194777c67f2fSkcpoon if ((new_len = seglen + new_len + extra) > fp->sfa_pmss) 194877c67f2fSkcpoon break; 194977c67f2fSkcpoon if ((nmp = dupmsg(mp)) == NULL) 195077c67f2fSkcpoon break; 19517c478bd9Sstevel@tonic-gate 195277c67f2fSkcpoon if (extra > 0) { 1953121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 19547c478bd9Sstevel@tonic-gate if (fill != NULL) { 195577c67f2fSkcpoon linkb(nmp, fill); 19567c478bd9Sstevel@tonic-gate } else { 195777c67f2fSkcpoon freemsg(nmp); 19587c478bd9Sstevel@tonic-gate break; 19597c478bd9Sstevel@tonic-gate } 19607c478bd9Sstevel@tonic-gate } 196177c67f2fSkcpoon linkb(head, nmp); 19627c478bd9Sstevel@tonic-gate 19637c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_FLAGS(nmp); 19647c478bd9Sstevel@tonic-gate SCTP_CHUNK_SENT(sctp, mp, sdc, fp, chunklen, meta); 196577c67f2fSkcpoon 196677c67f2fSkcpoon seglen = new_len; 19677c478bd9Sstevel@tonic-gate mp = mp->b_next; 19687c478bd9Sstevel@tonic-gate } 196977c67f2fSkcpoon done_bundle: 19707c478bd9Sstevel@tonic-gate if ((seglen > fp->sfa_pmss) && fp->isv4) { 19717c478bd9Sstevel@tonic-gate ipha_t *iph = (ipha_t *)head->b_rptr; 19727c478bd9Sstevel@tonic-gate 19737c478bd9Sstevel@tonic-gate /* 19747c478bd9Sstevel@tonic-gate * Path MTU is different from path we thought it would 19757c478bd9Sstevel@tonic-gate * be when we created chunks, or IP headers have grown. 19767c478bd9Sstevel@tonic-gate * Need to clear the DF bit. 19777c478bd9Sstevel@tonic-gate */ 19787c478bd9Sstevel@tonic-gate iph->ipha_fragment_offset_and_flags = 0; 19797c478bd9Sstevel@tonic-gate } 198012f47623Skcpoon fp->rxt_unacked += seglen; 198112f47623Skcpoon 19827c478bd9Sstevel@tonic-gate dprint(2, ("sctp_rexmit: Sending packet %d bytes, tsn %x " 19837c478bd9Sstevel@tonic-gate "ssn %d to %p (rwnd %d, lastack_rxd %x)\n", 198445916cd2Sjpk seglen, ntohl(sdc->sdh_tsn), ntohs(sdc->sdh_ssn), 198545916cd2Sjpk (void *)fp, sctp->sctp_frwnd, sctp->sctp_lastack_rxd)); 19867c478bd9Sstevel@tonic-gate 198777c67f2fSkcpoon sctp->sctp_rexmitting = B_TRUE; 198877c67f2fSkcpoon sctp->sctp_rxt_nxttsn = first_ua_tsn; 198977c67f2fSkcpoon sctp->sctp_rxt_maxtsn = sctp->sctp_ltsn - 1; 19907c478bd9Sstevel@tonic-gate sctp_set_iplen(sctp, head); 19917c478bd9Sstevel@tonic-gate sctp_add_sendq(sctp, head); 19927c478bd9Sstevel@tonic-gate 19937c478bd9Sstevel@tonic-gate /* 199477c67f2fSkcpoon * Restart the oldfp timer with exponential backoff and 199577c67f2fSkcpoon * the new fp timer for the retransmitted chunks. 19967c478bd9Sstevel@tonic-gate */ 19977c478bd9Sstevel@tonic-gate restart_timer: 19987c478bd9Sstevel@tonic-gate oldfp->strikes++; 19997c478bd9Sstevel@tonic-gate sctp->sctp_strikes++; 20007c478bd9Sstevel@tonic-gate SCTP_CALC_RXT(oldfp, sctp->sctp_rto_max); 2001c31292eeSkcpoon /* 2002c31292eeSkcpoon * If there is still some data in the oldfp, restart the 2003c31292eeSkcpoon * retransmission timer. If there is no data, the heartbeat will 2004c31292eeSkcpoon * continue to run so it will do its job in checking the reachability 2005c31292eeSkcpoon * of the oldfp. 2006c31292eeSkcpoon */ 2007c31292eeSkcpoon if (oldfp != fp && oldfp->suna != 0) 20087c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, oldfp, oldfp->rto); 200977c67f2fSkcpoon 201077c67f2fSkcpoon /* 201177c67f2fSkcpoon * Should we restart the timer of the new fp? If there is 201277c67f2fSkcpoon * outstanding data to the new fp, the timer should be 201377c67f2fSkcpoon * running already. So restarting it means that the timer 201477c67f2fSkcpoon * will fire later for those outstanding data. But if 201577c67f2fSkcpoon * we don't restart it, the timer will fire too early for the 201677c67f2fSkcpoon * just retransmitted chunks to the new fp. The reason is that we 201777c67f2fSkcpoon * don't keep a timestamp on when a chunk is retransmitted. 201877c67f2fSkcpoon * So when the timer fires, it will just search for the 201977c67f2fSkcpoon * chunk with the earliest TSN sent to new fp. This probably 202077c67f2fSkcpoon * is the chunk we just retransmitted. So for now, let's 202177c67f2fSkcpoon * be conservative and restart the timer of the new fp. 202277c67f2fSkcpoon */ 202377c67f2fSkcpoon SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->rto); 2024c31292eeSkcpoon 2025c31292eeSkcpoon sctp->sctp_active = lbolt64; 20267c478bd9Sstevel@tonic-gate } 20277c478bd9Sstevel@tonic-gate 202877c67f2fSkcpoon /* 202977c67f2fSkcpoon * This function is called by sctp_ss_rexmit() to create a packet 203077c67f2fSkcpoon * to be retransmitted to the given fp. The given meta and mp 203177c67f2fSkcpoon * parameters are respectively the sctp_msg_hdr_t and the mblk of the 203212f47623Skcpoon * first chunk to be retransmitted. This is also called when we want 2033769b977dSvi * to retransmit a zero window probe from sctp_rexmit() or when we 2034769b977dSvi * want to retransmit the zero window probe after the window has 2035769b977dSvi * opened from sctp_got_sack(). 203677c67f2fSkcpoon */ 2037769b977dSvi mblk_t * 203877c67f2fSkcpoon sctp_rexmit_packet(sctp_t *sctp, mblk_t **meta, mblk_t **mp, sctp_faddr_t *fp, 203977c67f2fSkcpoon uint_t *packet_len) 204077c67f2fSkcpoon { 204177c67f2fSkcpoon uint32_t seglen = 0; 204277c67f2fSkcpoon uint16_t chunklen; 204377c67f2fSkcpoon int extra; 204477c67f2fSkcpoon mblk_t *nmp; 204577c67f2fSkcpoon mblk_t *head; 204677c67f2fSkcpoon mblk_t *fill; 204777c67f2fSkcpoon sctp_data_hdr_t *sdc; 204877c67f2fSkcpoon sctp_msg_hdr_t *mhdr; 204977c67f2fSkcpoon 205077c67f2fSkcpoon sdc = (sctp_data_hdr_t *)(*mp)->b_rptr; 205177c67f2fSkcpoon seglen = ntohs(sdc->sdh_len); 205277c67f2fSkcpoon chunklen = seglen - sizeof (*sdc); 205377c67f2fSkcpoon if ((extra = seglen & (SCTP_ALIGN - 1)) != 0) 205477c67f2fSkcpoon extra = SCTP_ALIGN - extra; 205577c67f2fSkcpoon 205677c67f2fSkcpoon nmp = dupmsg(*mp); 205777c67f2fSkcpoon if (nmp == NULL) 205877c67f2fSkcpoon return (NULL); 205977c67f2fSkcpoon if (extra > 0) { 2060121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 206177c67f2fSkcpoon if (fill != NULL) { 206277c67f2fSkcpoon linkb(nmp, fill); 206377c67f2fSkcpoon seglen += extra; 206477c67f2fSkcpoon } else { 206577c67f2fSkcpoon freemsg(nmp); 206677c67f2fSkcpoon return (NULL); 206777c67f2fSkcpoon } 206877c67f2fSkcpoon } 206977c67f2fSkcpoon SCTP_CHUNK_CLEAR_FLAGS(nmp); 207077c67f2fSkcpoon head = sctp_add_proto_hdr(sctp, fp, nmp, 0, NULL); 207177c67f2fSkcpoon if (head == NULL) { 207277c67f2fSkcpoon freemsg(nmp); 207377c67f2fSkcpoon return (NULL); 207477c67f2fSkcpoon } 207577c67f2fSkcpoon SCTP_CHUNK_SENT(sctp, *mp, sdc, fp, chunklen, *meta); 2076769b977dSvi /* 2077769b977dSvi * Don't update the TSN if we are doing a Zero Win Probe. 2078769b977dSvi */ 2079769b977dSvi if (!sctp->sctp_zero_win_probe) 2080769b977dSvi sctp->sctp_rxt_nxttsn = ntohl(sdc->sdh_tsn); 208177c67f2fSkcpoon *mp = (*mp)->b_next; 208277c67f2fSkcpoon 208377c67f2fSkcpoon try_bundle: 208477c67f2fSkcpoon while (seglen < fp->sfa_pmss) { 208577c67f2fSkcpoon int32_t new_len; 208677c67f2fSkcpoon 208777c67f2fSkcpoon /* 208877c67f2fSkcpoon * Go through the list to find more chunks to be bundled. 208977c67f2fSkcpoon * We should only retransmit sent by unack'ed chunks. Since 209077c67f2fSkcpoon * they were sent before, the peer's receive window should 209177c67f2fSkcpoon * be able to receive them. 209277c67f2fSkcpoon */ 209377c67f2fSkcpoon while (*mp != NULL) { 209477c67f2fSkcpoon /* Check if the chunk can be bundled. */ 209577c67f2fSkcpoon if (SCTP_CHUNK_ISSENT(*mp) && !SCTP_CHUNK_ISACKED(*mp)) 209677c67f2fSkcpoon break; 209777c67f2fSkcpoon *mp = (*mp)->b_next; 209877c67f2fSkcpoon } 209977c67f2fSkcpoon /* Go to the next message. */ 210077c67f2fSkcpoon if (*mp == NULL) { 210177c67f2fSkcpoon for (*meta = (*meta)->b_next; *meta != NULL; 210277c67f2fSkcpoon *meta = (*meta)->b_next) { 210377c67f2fSkcpoon mhdr = (sctp_msg_hdr_t *)(*meta)->b_rptr; 210477c67f2fSkcpoon 210577c67f2fSkcpoon if (SCTP_IS_MSG_ABANDONED(*meta) || 210677c67f2fSkcpoon SCTP_MSG_TO_BE_ABANDONED(*meta, mhdr, 210777c67f2fSkcpoon sctp)) { 210877c67f2fSkcpoon continue; 210977c67f2fSkcpoon } 211077c67f2fSkcpoon 211177c67f2fSkcpoon *mp = (*meta)->b_cont; 211277c67f2fSkcpoon goto try_bundle; 211377c67f2fSkcpoon } 211477c67f2fSkcpoon /* No more chunk to be bundled. */ 211577c67f2fSkcpoon break; 211677c67f2fSkcpoon } 211777c67f2fSkcpoon 211877c67f2fSkcpoon sdc = (sctp_data_hdr_t *)(*mp)->b_rptr; 211977c67f2fSkcpoon /* Don't bundle chunks beyond sctp_rxt_maxtsn. */ 212077c67f2fSkcpoon if (SEQ_GT(ntohl(sdc->sdh_tsn), sctp->sctp_rxt_maxtsn)) 212177c67f2fSkcpoon break; 212277c67f2fSkcpoon new_len = ntohs(sdc->sdh_len); 212377c67f2fSkcpoon chunklen = new_len - sizeof (*sdc); 212477c67f2fSkcpoon 212577c67f2fSkcpoon if ((extra = new_len & (SCTP_ALIGN - 1)) != 0) 212677c67f2fSkcpoon extra = SCTP_ALIGN - extra; 212777c67f2fSkcpoon if ((new_len = seglen + new_len + extra) > fp->sfa_pmss) 212877c67f2fSkcpoon break; 212977c67f2fSkcpoon if ((nmp = dupmsg(*mp)) == NULL) 213077c67f2fSkcpoon break; 213177c67f2fSkcpoon 213277c67f2fSkcpoon if (extra > 0) { 2133121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 213477c67f2fSkcpoon if (fill != NULL) { 213577c67f2fSkcpoon linkb(nmp, fill); 213677c67f2fSkcpoon } else { 213777c67f2fSkcpoon freemsg(nmp); 213877c67f2fSkcpoon break; 213977c67f2fSkcpoon } 214077c67f2fSkcpoon } 214177c67f2fSkcpoon linkb(head, nmp); 214277c67f2fSkcpoon 214377c67f2fSkcpoon SCTP_CHUNK_CLEAR_FLAGS(nmp); 214477c67f2fSkcpoon SCTP_CHUNK_SENT(sctp, *mp, sdc, fp, chunklen, *meta); 2145769b977dSvi /* 2146769b977dSvi * Don't update the TSN if we are doing a Zero Win Probe. 2147769b977dSvi */ 2148769b977dSvi if (!sctp->sctp_zero_win_probe) 2149769b977dSvi sctp->sctp_rxt_nxttsn = ntohl(sdc->sdh_tsn); 215077c67f2fSkcpoon 215177c67f2fSkcpoon seglen = new_len; 215277c67f2fSkcpoon *mp = (*mp)->b_next; 215377c67f2fSkcpoon } 215477c67f2fSkcpoon *packet_len = seglen; 215512f47623Skcpoon fp->rxt_unacked += seglen; 215677c67f2fSkcpoon return (head); 215777c67f2fSkcpoon } 215877c67f2fSkcpoon 215977c67f2fSkcpoon /* 216077c67f2fSkcpoon * sctp_ss_rexmit() is called when we get a SACK after a timeout which 216177c67f2fSkcpoon * advances the cum_tsn but the cum_tsn is still less than what we have sent 216277c67f2fSkcpoon * (sctp_rxt_maxtsn) at the time of the timeout. This SACK is a "partial" 216377c67f2fSkcpoon * SACK. We retransmit unacked chunks without having to wait for another 216477c67f2fSkcpoon * timeout. The rationale is that the SACK should not be "partial" if all the 216577c67f2fSkcpoon * lost chunks have been retransmitted. Since the SACK is "partial," 216677c67f2fSkcpoon * the chunks between the cum_tsn and the sctp_rxt_maxtsn should still 216777c67f2fSkcpoon * be missing. It is better for us to retransmit them now instead 216877c67f2fSkcpoon * of waiting for a timeout. 216977c67f2fSkcpoon */ 217077c67f2fSkcpoon void 217177c67f2fSkcpoon sctp_ss_rexmit(sctp_t *sctp) 217277c67f2fSkcpoon { 217377c67f2fSkcpoon mblk_t *meta; 217477c67f2fSkcpoon mblk_t *mp; 217577c67f2fSkcpoon mblk_t *pkt; 217677c67f2fSkcpoon sctp_faddr_t *fp; 217777c67f2fSkcpoon uint_t pkt_len; 217877c67f2fSkcpoon uint32_t tot_wnd; 217977c67f2fSkcpoon sctp_data_hdr_t *sdc; 218077c67f2fSkcpoon int burst; 2181f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 218277c67f2fSkcpoon 2183769b977dSvi ASSERT(!sctp->sctp_zero_win_probe); 2184769b977dSvi 218577c67f2fSkcpoon /* 218677c67f2fSkcpoon * If the last cum ack is smaller than what we have just 218777c67f2fSkcpoon * retransmitted, simply return. 218877c67f2fSkcpoon */ 218977c67f2fSkcpoon if (SEQ_GEQ(sctp->sctp_lastack_rxd, sctp->sctp_rxt_nxttsn)) 219077c67f2fSkcpoon sctp->sctp_rxt_nxttsn = sctp->sctp_lastack_rxd + 1; 219177c67f2fSkcpoon else 219277c67f2fSkcpoon return; 219377c67f2fSkcpoon ASSERT(SEQ_LEQ(sctp->sctp_rxt_nxttsn, sctp->sctp_rxt_maxtsn)); 219477c67f2fSkcpoon 219577c67f2fSkcpoon /* 219677c67f2fSkcpoon * After a timer fires, sctp_current should be set to the new 219777c67f2fSkcpoon * fp where the retransmitted chunks are sent. 219877c67f2fSkcpoon */ 219977c67f2fSkcpoon fp = sctp->sctp_current; 220077c67f2fSkcpoon 220177c67f2fSkcpoon /* 220212f47623Skcpoon * Since we are retransmitting, we only need to use cwnd to determine 220312f47623Skcpoon * how much we can send as we were allowed (by peer's receive window) 220412f47623Skcpoon * to send those retransmitted chunks previously when they are first 220512f47623Skcpoon * sent. If we record how much we have retransmitted but 220612f47623Skcpoon * unacknowledged using rxt_unacked, then the amount we can now send 220712f47623Skcpoon * is equal to cwnd minus rxt_unacked. 220812f47623Skcpoon * 220912f47623Skcpoon * The field rxt_unacked is incremented when we retransmit a packet 221012f47623Skcpoon * and decremented when we got a SACK acknowledging something. And 221112f47623Skcpoon * it is reset when the retransmission timer fires as we assume that 221212f47623Skcpoon * all packets have left the network after a timeout. If this 221312f47623Skcpoon * assumption is not true, it means that after a timeout, we can 221412f47623Skcpoon * get a SACK acknowledging more than rxt_unacked (its value only 221512f47623Skcpoon * contains what is retransmitted when the timer fires). So 221612f47623Skcpoon * rxt_unacked will become very big (it is an unsiged int so going 221712f47623Skcpoon * negative means that the value is huge). This is the reason we 221812f47623Skcpoon * always send at least 1 MSS bytes. 221912f47623Skcpoon * 222012f47623Skcpoon * The reason why we do not have an accurate count is that we 222112f47623Skcpoon * only know how many packets are outstanding (using the TSN numbers). 222212f47623Skcpoon * But we do not know how many bytes those packets contain. To 222312f47623Skcpoon * have an accurate count, we need to walk through the send list. 222412f47623Skcpoon * As it is not really important to have an accurate count during 222512f47623Skcpoon * retransmission, we skip this walk to save some time. This should 222612f47623Skcpoon * not make the retransmission too aggressive to cause congestion. 222777c67f2fSkcpoon */ 222812f47623Skcpoon if (fp->cwnd <= fp->rxt_unacked) 222912f47623Skcpoon tot_wnd = fp->sfa_pmss; 223077c67f2fSkcpoon else 223112f47623Skcpoon tot_wnd = fp->cwnd - fp->rxt_unacked; 223277c67f2fSkcpoon 223377c67f2fSkcpoon /* Find the first unack'ed chunk */ 223477c67f2fSkcpoon for (meta = sctp->sctp_xmit_head; meta != NULL; meta = meta->b_next) { 223577c67f2fSkcpoon sctp_msg_hdr_t *mhdr = (sctp_msg_hdr_t *)meta->b_rptr; 223677c67f2fSkcpoon 223777c67f2fSkcpoon if (SCTP_IS_MSG_ABANDONED(meta) || 223877c67f2fSkcpoon SCTP_MSG_TO_BE_ABANDONED(meta, mhdr, sctp)) { 223977c67f2fSkcpoon continue; 224077c67f2fSkcpoon } 224177c67f2fSkcpoon 224277c67f2fSkcpoon for (mp = meta->b_cont; mp != NULL; mp = mp->b_next) { 224377c67f2fSkcpoon /* Again, this may not be possible */ 224477c67f2fSkcpoon if (!SCTP_CHUNK_ISSENT(mp)) 224577c67f2fSkcpoon return; 224677c67f2fSkcpoon sdc = (sctp_data_hdr_t *)mp->b_rptr; 224777c67f2fSkcpoon if (ntohl(sdc->sdh_tsn) == sctp->sctp_rxt_nxttsn) 224877c67f2fSkcpoon goto found_msg; 224977c67f2fSkcpoon } 225077c67f2fSkcpoon } 225177c67f2fSkcpoon 225277c67f2fSkcpoon /* Everything is abandoned... */ 225377c67f2fSkcpoon return; 225477c67f2fSkcpoon 225577c67f2fSkcpoon found_msg: 225677c67f2fSkcpoon if (!fp->timer_running) 225777c67f2fSkcpoon SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->rto); 225877c67f2fSkcpoon pkt = sctp_rexmit_packet(sctp, &meta, &mp, fp, &pkt_len); 225977c67f2fSkcpoon if (pkt == NULL) { 2260f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_ss_rexmit_failed); 226177c67f2fSkcpoon return; 226277c67f2fSkcpoon } 226377c67f2fSkcpoon if ((pkt_len > fp->sfa_pmss) && fp->isv4) { 226477c67f2fSkcpoon ipha_t *iph = (ipha_t *)pkt->b_rptr; 226577c67f2fSkcpoon 226677c67f2fSkcpoon /* 226777c67f2fSkcpoon * Path MTU is different from path we thought it would 226877c67f2fSkcpoon * be when we created chunks, or IP headers have grown. 226977c67f2fSkcpoon * Need to clear the DF bit. 227077c67f2fSkcpoon */ 227177c67f2fSkcpoon iph->ipha_fragment_offset_and_flags = 0; 227277c67f2fSkcpoon } 227377c67f2fSkcpoon sctp_set_iplen(sctp, pkt); 227477c67f2fSkcpoon sctp_add_sendq(sctp, pkt); 227577c67f2fSkcpoon 227677c67f2fSkcpoon /* Check and see if there is more chunk to be retransmitted. */ 227777c67f2fSkcpoon if (tot_wnd <= pkt_len || tot_wnd - pkt_len < fp->sfa_pmss || 227877c67f2fSkcpoon meta == NULL) 227977c67f2fSkcpoon return; 228077c67f2fSkcpoon if (mp == NULL) 228177c67f2fSkcpoon meta = meta->b_next; 228277c67f2fSkcpoon if (meta == NULL) 228377c67f2fSkcpoon return; 228477c67f2fSkcpoon 228577c67f2fSkcpoon /* Retransmit another packet if the window allows. */ 2286f4b3ec61Sdh for (tot_wnd -= pkt_len, burst = sctps->sctps_maxburst - 1; 228777c67f2fSkcpoon meta != NULL && burst > 0; meta = meta->b_next, burst--) { 228877c67f2fSkcpoon if (mp == NULL) 228977c67f2fSkcpoon mp = meta->b_cont; 229077c67f2fSkcpoon for (; mp != NULL; mp = mp->b_next) { 229177c67f2fSkcpoon /* Again, this may not be possible */ 229277c67f2fSkcpoon if (!SCTP_CHUNK_ISSENT(mp)) 229377c67f2fSkcpoon return; 229477c67f2fSkcpoon if (!SCTP_CHUNK_ISACKED(mp)) 229577c67f2fSkcpoon goto found_msg; 229677c67f2fSkcpoon } 229777c67f2fSkcpoon } 229877c67f2fSkcpoon } 2299