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 /* 23fd7b5aedSGeorge Shepherd * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <sys/types.h> 277c478bd9Sstevel@tonic-gate #include <sys/systm.h> 287c478bd9Sstevel@tonic-gate #include <sys/stream.h> 297c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 307c478bd9Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 317c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 327c478bd9Sstevel@tonic-gate #include <sys/socket.h> 337c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 347c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 357c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 367c478bd9Sstevel@tonic-gate #include <sys/socketvar.h> 377c478bd9Sstevel@tonic-gate #include <inet/common.h> 387c478bd9Sstevel@tonic-gate #include <inet/mi.h> 397c478bd9Sstevel@tonic-gate #include <inet/ip.h> 40bd670b35SErik Nordmark #include <inet/ip_ire.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; 821e109b40SNick Street static mblk_t *sctp_chunkify(sctp_t *, int, int, int); 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate #ifdef DEBUG 857c478bd9Sstevel@tonic-gate static boolean_t sctp_verify_chain(mblk_t *, mblk_t *); 867c478bd9Sstevel@tonic-gate #endif 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate /* 897c478bd9Sstevel@tonic-gate * Called to allocate a header mblk when sending data to SCTP. 907c478bd9Sstevel@tonic-gate * Data will follow in b_cont of this mblk. 917c478bd9Sstevel@tonic-gate */ 927c478bd9Sstevel@tonic-gate mblk_t * 937c478bd9Sstevel@tonic-gate sctp_alloc_hdr(const char *name, int nlen, const char *control, int clen, 947c478bd9Sstevel@tonic-gate int flags) 957c478bd9Sstevel@tonic-gate { 967c478bd9Sstevel@tonic-gate mblk_t *mp; 977c478bd9Sstevel@tonic-gate struct T_unitdata_req *tudr; 987c478bd9Sstevel@tonic-gate size_t size; 997c478bd9Sstevel@tonic-gate int error; 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate size = sizeof (*tudr) + _TPI_ALIGN_TOPT(nlen) + clen; 1027c478bd9Sstevel@tonic-gate size = MAX(size, sizeof (sctp_msg_hdr_t)); 1037c478bd9Sstevel@tonic-gate if (flags & SCTP_CAN_BLOCK) { 1047c478bd9Sstevel@tonic-gate mp = allocb_wait(size, BPRI_MED, 0, &error); 1057c478bd9Sstevel@tonic-gate } else { 1067c478bd9Sstevel@tonic-gate mp = allocb(size, BPRI_MED); 1077c478bd9Sstevel@tonic-gate } 1087c478bd9Sstevel@tonic-gate if (mp) { 1097c478bd9Sstevel@tonic-gate tudr = (struct T_unitdata_req *)mp->b_rptr; 1107c478bd9Sstevel@tonic-gate tudr->PRIM_type = T_UNITDATA_REQ; 1117c478bd9Sstevel@tonic-gate tudr->DEST_length = nlen; 1127c478bd9Sstevel@tonic-gate tudr->DEST_offset = sizeof (*tudr); 1137c478bd9Sstevel@tonic-gate tudr->OPT_length = clen; 1147c478bd9Sstevel@tonic-gate tudr->OPT_offset = (t_scalar_t)(sizeof (*tudr) + 1157c478bd9Sstevel@tonic-gate _TPI_ALIGN_TOPT(nlen)); 1167c478bd9Sstevel@tonic-gate if (nlen > 0) 1177c478bd9Sstevel@tonic-gate bcopy(name, tudr + 1, nlen); 1187c478bd9Sstevel@tonic-gate if (clen > 0) 1197c478bd9Sstevel@tonic-gate bcopy(control, (char *)tudr + tudr->OPT_offset, clen); 1207c478bd9Sstevel@tonic-gate mp->b_wptr += (tudr ->OPT_offset + clen); 1217c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO; 1227c478bd9Sstevel@tonic-gate } 1237c478bd9Sstevel@tonic-gate return (mp); 1247c478bd9Sstevel@tonic-gate } 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate /*ARGSUSED2*/ 1277c478bd9Sstevel@tonic-gate int 1287c478bd9Sstevel@tonic-gate sctp_sendmsg(sctp_t *sctp, mblk_t *mp, int flags) 1297c478bd9Sstevel@tonic-gate { 1307c478bd9Sstevel@tonic-gate sctp_faddr_t *fp = NULL; 1317c478bd9Sstevel@tonic-gate struct T_unitdata_req *tudr; 1327c478bd9Sstevel@tonic-gate int error = 0; 1337c478bd9Sstevel@tonic-gate mblk_t *mproto = mp; 1347c478bd9Sstevel@tonic-gate in6_addr_t *addr; 1357c478bd9Sstevel@tonic-gate in6_addr_t tmpaddr; 1367c478bd9Sstevel@tonic-gate uint16_t sid = sctp->sctp_def_stream; 1377c478bd9Sstevel@tonic-gate uint32_t ppid = sctp->sctp_def_ppid; 1387c478bd9Sstevel@tonic-gate uint32_t context = sctp->sctp_def_context; 1397c478bd9Sstevel@tonic-gate uint16_t msg_flags = sctp->sctp_def_flags; 1407c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *sctp_msg_hdr; 1417c478bd9Sstevel@tonic-gate uint32_t msg_len = 0; 1427c478bd9Sstevel@tonic-gate uint32_t timetolive = sctp->sctp_def_timetolive; 143bd670b35SErik Nordmark conn_t *connp = sctp->sctp_connp; 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate ASSERT(DB_TYPE(mproto) == M_PROTO); 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate mp = mp->b_cont; 1487c478bd9Sstevel@tonic-gate ASSERT(mp == NULL || DB_TYPE(mp) == M_DATA); 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate tudr = (struct T_unitdata_req *)mproto->b_rptr; 1517c478bd9Sstevel@tonic-gate ASSERT(tudr->PRIM_type == T_UNITDATA_REQ); 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate /* Get destination address, if specified */ 1547c478bd9Sstevel@tonic-gate if (tudr->DEST_length > 0) { 1557c478bd9Sstevel@tonic-gate sin_t *sin; 1567c478bd9Sstevel@tonic-gate sin6_t *sin6; 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *) 1597c478bd9Sstevel@tonic-gate (mproto->b_rptr + tudr->DEST_offset); 1607c478bd9Sstevel@tonic-gate switch (sin->sin_family) { 1617c478bd9Sstevel@tonic-gate case AF_INET: 1627c478bd9Sstevel@tonic-gate if (tudr->DEST_length < sizeof (*sin)) { 1637c478bd9Sstevel@tonic-gate return (EINVAL); 1647c478bd9Sstevel@tonic-gate } 1657c478bd9Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, &tmpaddr); 1667c478bd9Sstevel@tonic-gate addr = &tmpaddr; 1677c478bd9Sstevel@tonic-gate break; 1687c478bd9Sstevel@tonic-gate case AF_INET6: 1697c478bd9Sstevel@tonic-gate if (tudr->DEST_length < sizeof (*sin6)) { 1707c478bd9Sstevel@tonic-gate return (EINVAL); 1717c478bd9Sstevel@tonic-gate } 1727c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *) 1737c478bd9Sstevel@tonic-gate (mproto->b_rptr + tudr->DEST_offset); 1747c478bd9Sstevel@tonic-gate addr = &sin6->sin6_addr; 1757c478bd9Sstevel@tonic-gate break; 1767c478bd9Sstevel@tonic-gate default: 1777c478bd9Sstevel@tonic-gate return (EAFNOSUPPORT); 1787c478bd9Sstevel@tonic-gate } 1797c478bd9Sstevel@tonic-gate fp = sctp_lookup_faddr(sctp, addr); 1807c478bd9Sstevel@tonic-gate if (fp == NULL) { 1817c478bd9Sstevel@tonic-gate return (EINVAL); 1827c478bd9Sstevel@tonic-gate } 1837c478bd9Sstevel@tonic-gate } 1847c478bd9Sstevel@tonic-gate /* Ancillary Data? */ 1857c478bd9Sstevel@tonic-gate if (tudr->OPT_length > 0) { 1867c478bd9Sstevel@tonic-gate struct cmsghdr *cmsg; 1877c478bd9Sstevel@tonic-gate char *cend; 1887c478bd9Sstevel@tonic-gate struct sctp_sndrcvinfo *sndrcv; 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate cmsg = (struct cmsghdr *)(mproto->b_rptr + tudr->OPT_offset); 1917c478bd9Sstevel@tonic-gate cend = ((char *)cmsg + tudr->OPT_length); 1927c478bd9Sstevel@tonic-gate ASSERT(cend <= (char *)mproto->b_wptr); 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate for (;;) { 1957c478bd9Sstevel@tonic-gate if ((char *)(cmsg + 1) > cend || 1967c478bd9Sstevel@tonic-gate ((char *)cmsg + cmsg->cmsg_len) > cend) { 1977c478bd9Sstevel@tonic-gate break; 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate if ((cmsg->cmsg_level == IPPROTO_SCTP) && 2007c478bd9Sstevel@tonic-gate (cmsg->cmsg_type == SCTP_SNDRCV)) { 2017c478bd9Sstevel@tonic-gate if (cmsg->cmsg_len < 2027c478bd9Sstevel@tonic-gate (sizeof (*sndrcv) + sizeof (*cmsg))) { 2037c478bd9Sstevel@tonic-gate return (EINVAL); 2047c478bd9Sstevel@tonic-gate } 2057c478bd9Sstevel@tonic-gate sndrcv = (struct sctp_sndrcvinfo *)(cmsg + 1); 2067c478bd9Sstevel@tonic-gate sid = sndrcv->sinfo_stream; 2077c478bd9Sstevel@tonic-gate msg_flags = sndrcv->sinfo_flags; 2087c478bd9Sstevel@tonic-gate ppid = sndrcv->sinfo_ppid; 2097c478bd9Sstevel@tonic-gate context = sndrcv->sinfo_context; 2107c478bd9Sstevel@tonic-gate timetolive = sndrcv->sinfo_timetolive; 2117c478bd9Sstevel@tonic-gate break; 2127c478bd9Sstevel@tonic-gate } 2137c478bd9Sstevel@tonic-gate if (cmsg->cmsg_len > 0) 2147c478bd9Sstevel@tonic-gate cmsg = CMSG_NEXT(cmsg); 2157c478bd9Sstevel@tonic-gate else 2167c478bd9Sstevel@tonic-gate break; 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate } 2197c478bd9Sstevel@tonic-gate if (msg_flags & MSG_ABORT) { 2207c478bd9Sstevel@tonic-gate if (mp && mp->b_cont) { 2217c478bd9Sstevel@tonic-gate mblk_t *pump = msgpullup(mp, -1); 2227c478bd9Sstevel@tonic-gate if (!pump) { 2237c478bd9Sstevel@tonic-gate return (ENOMEM); 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate freemsg(mp); 2267c478bd9Sstevel@tonic-gate mp = pump; 2277c478bd9Sstevel@tonic-gate mproto->b_cont = mp; 2287c478bd9Sstevel@tonic-gate } 2297c478bd9Sstevel@tonic-gate RUN_SCTP(sctp); 230e6f13f86SKacheong Poon sctp_user_abort(sctp, mp); 2317c478bd9Sstevel@tonic-gate freemsg(mproto); 232bd670b35SErik Nordmark goto done2; 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate if (mp == NULL) 2357c478bd9Sstevel@tonic-gate goto done; 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate RUN_SCTP(sctp); 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate /* Reject any new data requests if we are shutting down */ 240b34b8d1aSkcpoon if (sctp->sctp_state > SCTPS_ESTABLISHED || 241b34b8d1aSkcpoon (sctp->sctp_connp->conn_state_flags & CONN_CLOSING)) { 2427c478bd9Sstevel@tonic-gate error = EPIPE; 2437c478bd9Sstevel@tonic-gate goto unlock_done; 2447c478bd9Sstevel@tonic-gate } 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate /* Re-use the mproto to store relevant info. */ 2477c478bd9Sstevel@tonic-gate ASSERT(MBLKSIZE(mproto) >= sizeof (*sctp_msg_hdr)); 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate mproto->b_rptr = mproto->b_datap->db_base; 2507c478bd9Sstevel@tonic-gate mproto->b_wptr = mproto->b_rptr + sizeof (*sctp_msg_hdr); 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate sctp_msg_hdr = (sctp_msg_hdr_t *)mproto->b_rptr; 2537c478bd9Sstevel@tonic-gate bzero(sctp_msg_hdr, sizeof (*sctp_msg_hdr)); 2547c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_context = context; 2557c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_sid = sid; 2567c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_ppid = ppid; 2577c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_flags = msg_flags; 2587c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_ttl = MSEC_TO_TICK(timetolive); 259d3d50737SRafael Vanoni sctp_msg_hdr->smh_tob = ddi_get_lbolt64(); 2607c478bd9Sstevel@tonic-gate for (; mp != NULL; mp = mp->b_cont) 2617c478bd9Sstevel@tonic-gate msg_len += MBLKL(mp); 2627c478bd9Sstevel@tonic-gate sctp_msg_hdr->smh_msglen = msg_len; 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate /* User requested specific destination */ 2657c478bd9Sstevel@tonic-gate SCTP_SET_CHUNK_DEST(mproto, fp); 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate if (sctp->sctp_state >= SCTPS_COOKIE_ECHOED && 2687c478bd9Sstevel@tonic-gate sid >= sctp->sctp_num_ostr) { 2697c478bd9Sstevel@tonic-gate /* Send sendfail event */ 2707c478bd9Sstevel@tonic-gate sctp_sendfail_event(sctp, dupmsg(mproto), SCTP_ERR_BAD_SID, 2717c478bd9Sstevel@tonic-gate B_FALSE); 2727c478bd9Sstevel@tonic-gate error = EINVAL; 2737c478bd9Sstevel@tonic-gate goto unlock_done; 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate /* no data */ 2777c478bd9Sstevel@tonic-gate if (msg_len == 0) { 2787c478bd9Sstevel@tonic-gate sctp_sendfail_event(sctp, dupmsg(mproto), 2797c478bd9Sstevel@tonic-gate SCTP_ERR_NO_USR_DATA, B_FALSE); 2807c478bd9Sstevel@tonic-gate error = EINVAL; 2817c478bd9Sstevel@tonic-gate goto unlock_done; 2827c478bd9Sstevel@tonic-gate } 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate /* Add it to the unsent list */ 2857c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_unsent == NULL) { 2867c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent = sctp->sctp_xmit_unsent_tail = mproto; 2877c478bd9Sstevel@tonic-gate } else { 2887c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent_tail->b_next = mproto; 2897c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent_tail = mproto; 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate sctp->sctp_unsent += msg_len; 2927c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_msgcount); 2930f1702c5SYu Xiangning /* 2940f1702c5SYu Xiangning * Notify sockfs if the tx queue is full. 2950f1702c5SYu Xiangning */ 296bd670b35SErik Nordmark if (SCTP_TXQ_LEN(sctp) >= connp->conn_sndbuf) { 2970f1702c5SYu Xiangning sctp->sctp_txq_full = 1; 2980f1702c5SYu Xiangning sctp->sctp_ulp_xmitted(sctp->sctp_ulpd, B_TRUE); 2990f1702c5SYu Xiangning } 3007c478bd9Sstevel@tonic-gate if (sctp->sctp_state == SCTPS_ESTABLISHED) 30112f47623Skcpoon sctp_output(sctp, UINT_MAX); 302bd670b35SErik Nordmark done2: 3037c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 3047c478bd9Sstevel@tonic-gate return (0); 3057c478bd9Sstevel@tonic-gate unlock_done: 3067c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 3077c478bd9Sstevel@tonic-gate done: 3087c478bd9Sstevel@tonic-gate return (error); 3097c478bd9Sstevel@tonic-gate } 3107c478bd9Sstevel@tonic-gate 3111e109b40SNick Street /* 3121e109b40SNick Street * While there are messages on sctp_xmit_unsent, detach each one. For each: 3131e109b40SNick Street * allocate space for the chunk header, fill in the data chunk, and fill in 3141e109b40SNick Street * the chunk header. Then append it to sctp_xmit_tail. 3151e109b40SNick Street * Return after appending as many bytes as required (bytes_to_send). 3161e109b40SNick Street * We also return if we've appended one or more chunks, and find a subsequent 3171e109b40SNick Street * unsent message is too big to fit in the segment. 3181e109b40SNick Street */ 3191e109b40SNick Street mblk_t * 3201e109b40SNick Street sctp_chunkify(sctp_t *sctp, int mss, int firstseg_len, int bytes_to_send) 3217c478bd9Sstevel@tonic-gate { 3227c478bd9Sstevel@tonic-gate mblk_t *mp; 3237c478bd9Sstevel@tonic-gate mblk_t *chunk_mp; 3247c478bd9Sstevel@tonic-gate mblk_t *chunk_head; 3257c478bd9Sstevel@tonic-gate mblk_t *chunk_hdr; 3267c478bd9Sstevel@tonic-gate mblk_t *chunk_tail = NULL; 3277c478bd9Sstevel@tonic-gate int count; 3287c478bd9Sstevel@tonic-gate int chunksize; 3297c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 3307c478bd9Sstevel@tonic-gate mblk_t *mdblk = sctp->sctp_xmit_unsent; 3317c478bd9Sstevel@tonic-gate sctp_faddr_t *fp; 3327c478bd9Sstevel@tonic-gate sctp_faddr_t *fp1; 3337c478bd9Sstevel@tonic-gate size_t xtralen; 3347c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *msg_hdr; 3351e109b40SNick Street sctp_stack_t *sctps = sctp->sctp_sctps; 3361e109b40SNick Street sctp_msg_hdr_t *next_msg_hdr; 3371e109b40SNick Street size_t nextlen; 3381e109b40SNick Street int remaining_len = mss - firstseg_len; 3391e109b40SNick Street 3401e109b40SNick Street ASSERT(remaining_len >= 0); 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate fp = SCTP_CHUNK_DEST(mdblk); 3437c478bd9Sstevel@tonic-gate if (fp == NULL) 3447c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 345*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp->sf_isv4) 346f4b3ec61Sdh xtralen = sctp->sctp_hdr_len + sctps->sctps_wroff_xtra + 347f4b3ec61Sdh sizeof (*sdc); 3487c478bd9Sstevel@tonic-gate else 349f4b3ec61Sdh xtralen = sctp->sctp_hdr6_len + sctps->sctps_wroff_xtra + 350f4b3ec61Sdh sizeof (*sdc); 3511e109b40SNick Street count = chunksize = remaining_len - sizeof (*sdc); 3527c478bd9Sstevel@tonic-gate nextmsg: 3531e109b40SNick Street next_msg_hdr = (sctp_msg_hdr_t *)sctp->sctp_xmit_unsent->b_rptr; 3541e109b40SNick Street nextlen = next_msg_hdr->smh_msglen; 3551e109b40SNick Street /* 3561e109b40SNick Street * Will the entire next message fit in the current packet ? 3571e109b40SNick Street * if not, leave it on the unsent list. 3581e109b40SNick Street */ 3591e109b40SNick Street if ((firstseg_len != 0) && (nextlen > remaining_len)) 3601e109b40SNick Street return (NULL); 3611e109b40SNick Street 3627c478bd9Sstevel@tonic-gate chunk_mp = mdblk->b_cont; 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate /* 3651e109b40SNick Street * If this partially chunked, we ignore the next one for now and 3661e109b40SNick Street * use the one already present. For the unchunked bits, we use the 3671e109b40SNick Street * length of the last chunk. 3687c478bd9Sstevel@tonic-gate */ 3697c478bd9Sstevel@tonic-gate if (SCTP_IS_MSG_CHUNKED(mdblk)) { 3707c478bd9Sstevel@tonic-gate int chunk_len; 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate ASSERT(chunk_mp->b_next != NULL); 3737c478bd9Sstevel@tonic-gate mdblk->b_cont = chunk_mp->b_next; 3747c478bd9Sstevel@tonic-gate chunk_mp->b_next = NULL; 3757c478bd9Sstevel@tonic-gate SCTP_MSG_CLEAR_CHUNKED(mdblk); 3767c478bd9Sstevel@tonic-gate mp = mdblk->b_cont; 3777c478bd9Sstevel@tonic-gate while (mp->b_next != NULL) 3787c478bd9Sstevel@tonic-gate mp = mp->b_next; 3797c478bd9Sstevel@tonic-gate chunk_len = ntohs(((sctp_data_hdr_t *)mp->b_rptr)->sdh_len); 380*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp->sf_pmss - chunk_len > sizeof (*sdc)) 381*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India count = chunksize = fp->sf_pmss - chunk_len; 3827c478bd9Sstevel@tonic-gate else 383*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India count = chunksize = fp->sf_pmss; 3847c478bd9Sstevel@tonic-gate count = chunksize = count - sizeof (*sdc); 3857c478bd9Sstevel@tonic-gate } else { 3867c478bd9Sstevel@tonic-gate msg_hdr = (sctp_msg_hdr_t *)mdblk->b_rptr; 3877c478bd9Sstevel@tonic-gate if (SCTP_MSG_TO_BE_ABANDONED(mdblk, msg_hdr, sctp)) { 3887c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent = mdblk->b_next; 3897c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_unsent == NULL) 3907c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent_tail = NULL; 3917c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_unsent >= msg_hdr->smh_msglen); 3927c478bd9Sstevel@tonic-gate sctp->sctp_unsent -= msg_hdr->smh_msglen; 3937c478bd9Sstevel@tonic-gate mdblk->b_next = NULL; 3947c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_prsctpdrop); 3957c478bd9Sstevel@tonic-gate /* 3967c478bd9Sstevel@tonic-gate * Update ULP the amount of queued data, which is 3977c478bd9Sstevel@tonic-gate * sent-unack'ed + unsent. 3987c478bd9Sstevel@tonic-gate */ 3990f1702c5SYu Xiangning if (!SCTP_IS_DETACHED(sctp)) 4000f1702c5SYu Xiangning SCTP_TXQ_UPDATE(sctp); 4017c478bd9Sstevel@tonic-gate sctp_sendfail_event(sctp, mdblk, 0, B_FALSE); 4027c478bd9Sstevel@tonic-gate goto try_next; 4037c478bd9Sstevel@tonic-gate } 4047c478bd9Sstevel@tonic-gate mdblk->b_cont = NULL; 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate msg_hdr = (sctp_msg_hdr_t *)mdblk->b_rptr; 4077c478bd9Sstevel@tonic-gate nextchunk: 4087c478bd9Sstevel@tonic-gate chunk_head = chunk_mp; 4097c478bd9Sstevel@tonic-gate chunk_tail = NULL; 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate /* Skip as many mblk's as we need */ 4127c478bd9Sstevel@tonic-gate while (chunk_mp != NULL && ((count - MBLKL(chunk_mp)) >= 0)) { 4137c478bd9Sstevel@tonic-gate count -= MBLKL(chunk_mp); 4147c478bd9Sstevel@tonic-gate chunk_tail = chunk_mp; 4157c478bd9Sstevel@tonic-gate chunk_mp = chunk_mp->b_cont; 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate /* Split the chain, if needed */ 4187c478bd9Sstevel@tonic-gate if (chunk_mp != NULL) { 4197c478bd9Sstevel@tonic-gate if (count > 0) { 4207c478bd9Sstevel@tonic-gate mblk_t *split_mp = dupb(chunk_mp); 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate if (split_mp == NULL) { 4237c478bd9Sstevel@tonic-gate if (mdblk->b_cont == NULL) { 4247c478bd9Sstevel@tonic-gate mdblk->b_cont = chunk_head; 4257c478bd9Sstevel@tonic-gate } else { 4267c478bd9Sstevel@tonic-gate SCTP_MSG_SET_CHUNKED(mdblk); 4277c478bd9Sstevel@tonic-gate ASSERT(chunk_head->b_next == NULL); 4287c478bd9Sstevel@tonic-gate chunk_head->b_next = mdblk->b_cont; 4297c478bd9Sstevel@tonic-gate mdblk->b_cont = chunk_head; 4307c478bd9Sstevel@tonic-gate } 4311e109b40SNick Street return (sctp->sctp_xmit_tail); 4327c478bd9Sstevel@tonic-gate } 4337c478bd9Sstevel@tonic-gate if (chunk_tail != NULL) { 4347c478bd9Sstevel@tonic-gate chunk_tail->b_cont = split_mp; 4357c478bd9Sstevel@tonic-gate chunk_tail = chunk_tail->b_cont; 4367c478bd9Sstevel@tonic-gate } else { 4377c478bd9Sstevel@tonic-gate chunk_head = chunk_tail = split_mp; 4387c478bd9Sstevel@tonic-gate } 4397c478bd9Sstevel@tonic-gate chunk_tail->b_wptr = chunk_tail->b_rptr + count; 4407c478bd9Sstevel@tonic-gate chunk_mp->b_rptr = chunk_tail->b_wptr; 4417c478bd9Sstevel@tonic-gate count = 0; 4427c478bd9Sstevel@tonic-gate } else if (chunk_tail == NULL) { 4437c478bd9Sstevel@tonic-gate goto next; 4447c478bd9Sstevel@tonic-gate } else { 4457c478bd9Sstevel@tonic-gate chunk_tail->b_cont = NULL; 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate } 4487c478bd9Sstevel@tonic-gate /* Alloc chunk hdr, if needed */ 4497c478bd9Sstevel@tonic-gate if (DB_REF(chunk_head) > 1 || 4507c478bd9Sstevel@tonic-gate ((intptr_t)chunk_head->b_rptr) & (SCTP_ALIGN - 1) || 4517c478bd9Sstevel@tonic-gate MBLKHEAD(chunk_head) < sizeof (*sdc)) { 4527c478bd9Sstevel@tonic-gate if ((chunk_hdr = allocb(xtralen, BPRI_MED)) == NULL) { 4537c478bd9Sstevel@tonic-gate if (mdblk->b_cont == NULL) { 4547c478bd9Sstevel@tonic-gate if (chunk_mp != NULL) 4557c478bd9Sstevel@tonic-gate linkb(chunk_head, chunk_mp); 4567c478bd9Sstevel@tonic-gate mdblk->b_cont = chunk_head; 4577c478bd9Sstevel@tonic-gate } else { 4587c478bd9Sstevel@tonic-gate SCTP_MSG_SET_CHUNKED(mdblk); 4597c478bd9Sstevel@tonic-gate if (chunk_mp != NULL) 4607c478bd9Sstevel@tonic-gate linkb(chunk_head, chunk_mp); 4617c478bd9Sstevel@tonic-gate ASSERT(chunk_head->b_next == NULL); 4627c478bd9Sstevel@tonic-gate chunk_head->b_next = mdblk->b_cont; 4637c478bd9Sstevel@tonic-gate mdblk->b_cont = chunk_head; 4647c478bd9Sstevel@tonic-gate } 4651e109b40SNick Street return (sctp->sctp_xmit_tail); 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate chunk_hdr->b_rptr += xtralen - sizeof (*sdc); 4687c478bd9Sstevel@tonic-gate chunk_hdr->b_wptr = chunk_hdr->b_rptr + sizeof (*sdc); 4697c478bd9Sstevel@tonic-gate chunk_hdr->b_cont = chunk_head; 4707c478bd9Sstevel@tonic-gate } else { 4717c478bd9Sstevel@tonic-gate chunk_hdr = chunk_head; 4727c478bd9Sstevel@tonic-gate chunk_hdr->b_rptr -= sizeof (*sdc); 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate ASSERT(chunk_hdr->b_datap->db_ref == 1); 4757c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)chunk_hdr->b_rptr; 4767c478bd9Sstevel@tonic-gate sdc->sdh_id = CHUNK_DATA; 4777c478bd9Sstevel@tonic-gate sdc->sdh_flags = 0; 4787c478bd9Sstevel@tonic-gate sdc->sdh_len = htons(sizeof (*sdc) + chunksize - count); 4797c478bd9Sstevel@tonic-gate ASSERT(sdc->sdh_len); 4807c478bd9Sstevel@tonic-gate sdc->sdh_sid = htons(msg_hdr->smh_sid); 4817c478bd9Sstevel@tonic-gate /* 4827c478bd9Sstevel@tonic-gate * We defer assigning the SSN just before sending the chunk, else 4837c478bd9Sstevel@tonic-gate * if we drop the chunk in sctp_get_msg_to_send(), we would need 4847c478bd9Sstevel@tonic-gate * to send a Forward TSN to let the peer know. Some more comments 4857c478bd9Sstevel@tonic-gate * about this in sctp_impl.h for SCTP_CHUNK_SENT. 4867c478bd9Sstevel@tonic-gate */ 4877c478bd9Sstevel@tonic-gate sdc->sdh_payload_id = msg_hdr->smh_ppid; 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate if (mdblk->b_cont == NULL) { 4907c478bd9Sstevel@tonic-gate mdblk->b_cont = chunk_hdr; 4917c478bd9Sstevel@tonic-gate SCTP_DATA_SET_BBIT(sdc); 4927c478bd9Sstevel@tonic-gate } else { 4937c478bd9Sstevel@tonic-gate mp = mdblk->b_cont; 4947c478bd9Sstevel@tonic-gate while (mp->b_next != NULL) 4957c478bd9Sstevel@tonic-gate mp = mp->b_next; 4967c478bd9Sstevel@tonic-gate mp->b_next = chunk_hdr; 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate bytes_to_send -= (chunksize - count); 5007c478bd9Sstevel@tonic-gate if (chunk_mp != NULL) { 5017c478bd9Sstevel@tonic-gate next: 502*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India count = chunksize = fp->sf_pmss - sizeof (*sdc); 5037c478bd9Sstevel@tonic-gate goto nextchunk; 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate SCTP_DATA_SET_EBIT(sdc); 5067c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent = mdblk->b_next; 5077c478bd9Sstevel@tonic-gate if (mdblk->b_next == NULL) { 5087c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent_tail = NULL; 5097c478bd9Sstevel@tonic-gate } 5107c478bd9Sstevel@tonic-gate mdblk->b_next = NULL; 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_tail == NULL) { 5137c478bd9Sstevel@tonic-gate sctp->sctp_xmit_head = sctp->sctp_xmit_tail = mdblk; 5147c478bd9Sstevel@tonic-gate } else { 5157c478bd9Sstevel@tonic-gate mp = sctp->sctp_xmit_tail; 5167c478bd9Sstevel@tonic-gate while (mp->b_next != NULL) 5177c478bd9Sstevel@tonic-gate mp = mp->b_next; 5187c478bd9Sstevel@tonic-gate mp->b_next = mdblk; 5197c478bd9Sstevel@tonic-gate mdblk->b_prev = mp; 5207c478bd9Sstevel@tonic-gate } 5217c478bd9Sstevel@tonic-gate try_next: 5227c478bd9Sstevel@tonic-gate if (bytes_to_send > 0 && sctp->sctp_xmit_unsent != NULL) { 5237c478bd9Sstevel@tonic-gate mdblk = sctp->sctp_xmit_unsent; 5247c478bd9Sstevel@tonic-gate fp1 = SCTP_CHUNK_DEST(mdblk); 5257c478bd9Sstevel@tonic-gate if (fp1 == NULL) 5267c478bd9Sstevel@tonic-gate fp1 = sctp->sctp_current; 5277c478bd9Sstevel@tonic-gate if (fp == fp1) { 5287c478bd9Sstevel@tonic-gate size_t len = MBLKL(mdblk->b_cont); 5297c478bd9Sstevel@tonic-gate if ((count > 0) && 530*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India ((len > fp->sf_pmss - sizeof (*sdc)) || 531b34b8d1aSkcpoon (len <= count))) { 5327c478bd9Sstevel@tonic-gate count -= sizeof (*sdc); 5337c478bd9Sstevel@tonic-gate count = chunksize = count - (count & 0x3); 5347c478bd9Sstevel@tonic-gate } else { 535*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India count = chunksize = fp->sf_pmss - 5367c478bd9Sstevel@tonic-gate sizeof (*sdc); 5377c478bd9Sstevel@tonic-gate } 5387c478bd9Sstevel@tonic-gate } else { 539*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp1->sf_isv4) 5407c478bd9Sstevel@tonic-gate xtralen = sctp->sctp_hdr_len; 5417c478bd9Sstevel@tonic-gate else 5427c478bd9Sstevel@tonic-gate xtralen = sctp->sctp_hdr6_len; 543f4b3ec61Sdh xtralen += sctps->sctps_wroff_xtra + sizeof (*sdc); 544*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India count = chunksize = fp1->sf_pmss - sizeof (*sdc); 5457c478bd9Sstevel@tonic-gate fp = fp1; 5467c478bd9Sstevel@tonic-gate } 5477c478bd9Sstevel@tonic-gate goto nextmsg; 5487c478bd9Sstevel@tonic-gate } 5491e109b40SNick Street return (sctp->sctp_xmit_tail); 5507c478bd9Sstevel@tonic-gate } 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate void 5537c478bd9Sstevel@tonic-gate sctp_free_msg(mblk_t *ump) 5547c478bd9Sstevel@tonic-gate { 5557c478bd9Sstevel@tonic-gate mblk_t *mp, *nmp; 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate for (mp = ump->b_cont; mp; mp = nmp) { 5587c478bd9Sstevel@tonic-gate nmp = mp->b_next; 5597c478bd9Sstevel@tonic-gate mp->b_next = mp->b_prev = NULL; 5607c478bd9Sstevel@tonic-gate freemsg(mp); 5617c478bd9Sstevel@tonic-gate } 5627c478bd9Sstevel@tonic-gate ASSERT(!ump->b_prev); 5637c478bd9Sstevel@tonic-gate ump->b_next = NULL; 5647c478bd9Sstevel@tonic-gate freeb(ump); 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate mblk_t * 568df19b344Svi sctp_add_proto_hdr(sctp_t *sctp, sctp_faddr_t *fp, mblk_t *mp, int sacklen, 569df19b344Svi int *error) 5707c478bd9Sstevel@tonic-gate { 5717c478bd9Sstevel@tonic-gate int hdrlen; 572bd670b35SErik Nordmark uchar_t *hdr; 573*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India int isv4 = fp->sf_isv4; 574f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 5757c478bd9Sstevel@tonic-gate 576df19b344Svi if (error != NULL) 577df19b344Svi *error = 0; 578df19b344Svi 5797c478bd9Sstevel@tonic-gate if (isv4) { 5807c478bd9Sstevel@tonic-gate hdrlen = sctp->sctp_hdr_len; 5817c478bd9Sstevel@tonic-gate hdr = sctp->sctp_iphc; 5827c478bd9Sstevel@tonic-gate } else { 5837c478bd9Sstevel@tonic-gate hdrlen = sctp->sctp_hdr6_len; 5847c478bd9Sstevel@tonic-gate hdr = sctp->sctp_iphc6; 5857c478bd9Sstevel@tonic-gate } 586df19b344Svi /* 587bd670b35SErik Nordmark * A reject|blackhole could mean that the address is 'down'. Similarly, 588df19b344Svi * it is possible that the address went down, we tried to send an 589*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India * heartbeat and ended up setting fp->sf_saddr as unspec because we 59077c67f2fSkcpoon * didn't have any usable source address. In either case 591bd670b35SErik Nordmark * sctp_get_dest() will try find an IRE, if available, and set 59277c67f2fSkcpoon * the source address, if needed. If we still don't have any 593*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India * usable source address, fp->sf_state will be SCTP_FADDRS_UNREACH and 594df19b344Svi * we return EHOSTUNREACH. 595df19b344Svi */ 596*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India ASSERT(fp->sf_ixa->ixa_ire != NULL); 597*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if ((fp->sf_ixa->ixa_ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE)) || 598*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India SCTP_IS_ADDR_UNSPEC(fp->sf_isv4, fp->sf_saddr)) { 599bd670b35SErik Nordmark sctp_get_dest(sctp, fp); 600*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp->sf_state == SCTP_FADDRS_UNREACH) { 601df19b344Svi if (error != NULL) 602df19b344Svi *error = EHOSTUNREACH; 603df19b344Svi return (NULL); 6047c478bd9Sstevel@tonic-gate } 6057c478bd9Sstevel@tonic-gate } 6067c478bd9Sstevel@tonic-gate /* Copy in IP header. */ 6077c478bd9Sstevel@tonic-gate if ((mp->b_rptr - mp->b_datap->db_base) < 608bd670b35SErik Nordmark (sctps->sctps_wroff_xtra + hdrlen + sacklen) || DB_REF(mp) > 2) { 6097c478bd9Sstevel@tonic-gate mblk_t *nmp; 61077c67f2fSkcpoon 6117c478bd9Sstevel@tonic-gate /* 6127c478bd9Sstevel@tonic-gate * This can happen if IP headers are adjusted after 6137c478bd9Sstevel@tonic-gate * data was moved into chunks, or during retransmission, 6147c478bd9Sstevel@tonic-gate * or things like snoop is running. 6157c478bd9Sstevel@tonic-gate */ 616bd670b35SErik Nordmark nmp = allocb(sctps->sctps_wroff_xtra + hdrlen + sacklen, 617bd670b35SErik Nordmark BPRI_MED); 6187c478bd9Sstevel@tonic-gate if (nmp == NULL) { 619df19b344Svi if (error != NULL) 620df19b344Svi *error = ENOMEM; 6217c478bd9Sstevel@tonic-gate return (NULL); 6227c478bd9Sstevel@tonic-gate } 623f4b3ec61Sdh nmp->b_rptr += sctps->sctps_wroff_xtra; 6247c478bd9Sstevel@tonic-gate nmp->b_wptr = nmp->b_rptr + hdrlen + sacklen; 6257c478bd9Sstevel@tonic-gate nmp->b_cont = mp; 6267c478bd9Sstevel@tonic-gate mp = nmp; 6277c478bd9Sstevel@tonic-gate } else { 6287c478bd9Sstevel@tonic-gate mp->b_rptr -= (hdrlen + sacklen); 6297c478bd9Sstevel@tonic-gate } 6307c478bd9Sstevel@tonic-gate bcopy(hdr, mp->b_rptr, hdrlen); 6317c478bd9Sstevel@tonic-gate if (sacklen) { 6327c478bd9Sstevel@tonic-gate sctp_fill_sack(sctp, mp->b_rptr + hdrlen, sacklen); 6337c478bd9Sstevel@tonic-gate } 6347c478bd9Sstevel@tonic-gate if (fp != sctp->sctp_current) { 6357c478bd9Sstevel@tonic-gate /* change addresses in header */ 6367c478bd9Sstevel@tonic-gate if (isv4) { 6377c478bd9Sstevel@tonic-gate ipha_t *iph = (ipha_t *)mp->b_rptr; 6387c478bd9Sstevel@tonic-gate 639*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India IN6_V4MAPPED_TO_IPADDR(&fp->sf_faddr, iph->ipha_dst); 640*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (!IN6_IS_ADDR_V4MAPPED_ANY(&fp->sf_saddr)) { 641*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India IN6_V4MAPPED_TO_IPADDR(&fp->sf_saddr, 6427c478bd9Sstevel@tonic-gate iph->ipha_src); 6437c478bd9Sstevel@tonic-gate } else if (sctp->sctp_bound_to_all) { 6447c478bd9Sstevel@tonic-gate iph->ipha_src = INADDR_ANY; 6457c478bd9Sstevel@tonic-gate } 6467c478bd9Sstevel@tonic-gate } else { 647bd670b35SErik Nordmark ip6_t *ip6h = (ip6_t *)mp->b_rptr; 648bd670b35SErik Nordmark 649*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India ip6h->ip6_dst = fp->sf_faddr; 650*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (!IN6_IS_ADDR_UNSPECIFIED(&fp->sf_saddr)) { 651*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India ip6h->ip6_src = fp->sf_saddr; 6527c478bd9Sstevel@tonic-gate } else if (sctp->sctp_bound_to_all) { 653bd670b35SErik Nordmark ip6h->ip6_src = ipv6_all_zeros; 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate } 6577c478bd9Sstevel@tonic-gate return (mp); 6587c478bd9Sstevel@tonic-gate } 6597c478bd9Sstevel@tonic-gate 6607c478bd9Sstevel@tonic-gate /* 6617c478bd9Sstevel@tonic-gate * SCTP requires every chunk to be padded so that the total length 6627c478bd9Sstevel@tonic-gate * is a multiple of SCTP_ALIGN. This function returns a mblk with 6637c478bd9Sstevel@tonic-gate * the specified pad length. 6647c478bd9Sstevel@tonic-gate */ 6657c478bd9Sstevel@tonic-gate static mblk_t * 666121e5416Skcpoon sctp_get_padding(sctp_t *sctp, int pad) 6677c478bd9Sstevel@tonic-gate { 6687c478bd9Sstevel@tonic-gate mblk_t *fill; 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate ASSERT(pad < SCTP_ALIGN); 671121e5416Skcpoon ASSERT(sctp->sctp_pad_mp != NULL); 672121e5416Skcpoon if ((fill = dupb(sctp->sctp_pad_mp)) != NULL) { 6737c478bd9Sstevel@tonic-gate fill->b_wptr += pad; 6747c478bd9Sstevel@tonic-gate return (fill); 6757c478bd9Sstevel@tonic-gate } 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate /* 6787c478bd9Sstevel@tonic-gate * The memory saving path of reusing the sctp_pad_mp 6797c478bd9Sstevel@tonic-gate * fails may be because it has been dupb() too 6807c478bd9Sstevel@tonic-gate * many times (DBLK_REFMAX). Use the memory consuming 6817c478bd9Sstevel@tonic-gate * path of allocating the pad mblk. 6827c478bd9Sstevel@tonic-gate */ 6837c478bd9Sstevel@tonic-gate if ((fill = allocb(SCTP_ALIGN, BPRI_MED)) != NULL) { 6847c478bd9Sstevel@tonic-gate /* Zero it out. SCTP_ALIGN is sizeof (int32_t) */ 6857c478bd9Sstevel@tonic-gate *(int32_t *)fill->b_rptr = 0; 6867c478bd9Sstevel@tonic-gate fill->b_wptr += pad; 6877c478bd9Sstevel@tonic-gate } 6887c478bd9Sstevel@tonic-gate return (fill); 6897c478bd9Sstevel@tonic-gate } 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate static mblk_t * 6927c478bd9Sstevel@tonic-gate sctp_find_fast_rexmit_mblks(sctp_t *sctp, int *total, sctp_faddr_t **fp) 6937c478bd9Sstevel@tonic-gate { 6947c478bd9Sstevel@tonic-gate mblk_t *meta; 6957c478bd9Sstevel@tonic-gate mblk_t *start_mp = NULL; 6967c478bd9Sstevel@tonic-gate mblk_t *end_mp = NULL; 6977c478bd9Sstevel@tonic-gate mblk_t *mp, *nmp; 6987c478bd9Sstevel@tonic-gate mblk_t *fill; 6997c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdh; 7007c478bd9Sstevel@tonic-gate int msglen; 7017c478bd9Sstevel@tonic-gate int extra; 7027c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *msg_hdr; 70377c67f2fSkcpoon sctp_faddr_t *old_fp = NULL; 70477c67f2fSkcpoon sctp_faddr_t *chunk_fp; 705f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate for (meta = sctp->sctp_xmit_head; meta != NULL; meta = meta->b_next) { 7087c478bd9Sstevel@tonic-gate msg_hdr = (sctp_msg_hdr_t *)meta->b_rptr; 7097c478bd9Sstevel@tonic-gate if (SCTP_IS_MSG_ABANDONED(meta) || 7107c478bd9Sstevel@tonic-gate SCTP_MSG_TO_BE_ABANDONED(meta, msg_hdr, sctp)) { 7117c478bd9Sstevel@tonic-gate continue; 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate for (mp = meta->b_cont; mp != NULL; mp = mp->b_next) { 7147c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_WANT_REXMIT(mp)) { 7157c478bd9Sstevel@tonic-gate /* 7167c478bd9Sstevel@tonic-gate * Use the same peer address to do fast 71777c67f2fSkcpoon * retransmission. If the original peer 71877c67f2fSkcpoon * address is dead, switch to the current 71977c67f2fSkcpoon * one. Record the old one so that we 72077c67f2fSkcpoon * will pick the chunks sent to the old 72177c67f2fSkcpoon * one for fast retransmission. 7227c478bd9Sstevel@tonic-gate */ 72377c67f2fSkcpoon chunk_fp = SCTP_CHUNK_DEST(mp); 7247c478bd9Sstevel@tonic-gate if (*fp == NULL) { 72577c67f2fSkcpoon *fp = chunk_fp; 726*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if ((*fp)->sf_state != 727*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India SCTP_FADDRS_ALIVE) { 72877c67f2fSkcpoon old_fp = *fp; 7297c478bd9Sstevel@tonic-gate *fp = sctp->sctp_current; 73077c67f2fSkcpoon } 73177c67f2fSkcpoon } else if (old_fp == NULL && *fp != chunk_fp) { 73277c67f2fSkcpoon continue; 73377c67f2fSkcpoon } else if (old_fp != NULL && 73477c67f2fSkcpoon old_fp != chunk_fp) { 7357c478bd9Sstevel@tonic-gate continue; 7367c478bd9Sstevel@tonic-gate } 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate sdh = (sctp_data_hdr_t *)mp->b_rptr; 7397c478bd9Sstevel@tonic-gate msglen = ntohs(sdh->sdh_len); 7407c478bd9Sstevel@tonic-gate if ((extra = msglen & (SCTP_ALIGN - 1)) != 0) { 7417c478bd9Sstevel@tonic-gate extra = SCTP_ALIGN - extra; 7427c478bd9Sstevel@tonic-gate } 7437c478bd9Sstevel@tonic-gate 7447c478bd9Sstevel@tonic-gate /* 7457c478bd9Sstevel@tonic-gate * We still return at least the first message 7467c478bd9Sstevel@tonic-gate * even if that message cannot fit in as 7477c478bd9Sstevel@tonic-gate * PMTU may have changed. 7487c478bd9Sstevel@tonic-gate */ 7497c478bd9Sstevel@tonic-gate if (*total + msglen + extra > 750*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India (*fp)->sf_pmss && start_mp != NULL) { 7517c478bd9Sstevel@tonic-gate return (start_mp); 7527c478bd9Sstevel@tonic-gate } 7537c478bd9Sstevel@tonic-gate if ((nmp = dupmsg(mp)) == NULL) 7547c478bd9Sstevel@tonic-gate return (start_mp); 7557c478bd9Sstevel@tonic-gate if (extra > 0) { 756121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 7577c478bd9Sstevel@tonic-gate if (fill != NULL) { 7587c478bd9Sstevel@tonic-gate linkb(nmp, fill); 7597c478bd9Sstevel@tonic-gate } else { 7607c478bd9Sstevel@tonic-gate return (start_mp); 7617c478bd9Sstevel@tonic-gate } 7627c478bd9Sstevel@tonic-gate } 7635dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpOutFastRetrans); 76477c67f2fSkcpoon BUMP_LOCAL(sctp->sctp_rxtchunks); 7657c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_REXMIT(mp); 7667c478bd9Sstevel@tonic-gate if (start_mp == NULL) { 7677c478bd9Sstevel@tonic-gate start_mp = nmp; 7687c478bd9Sstevel@tonic-gate } else { 7697c478bd9Sstevel@tonic-gate linkb(end_mp, nmp); 7707c478bd9Sstevel@tonic-gate } 7717c478bd9Sstevel@tonic-gate end_mp = nmp; 7727c478bd9Sstevel@tonic-gate *total += msglen + extra; 7737c478bd9Sstevel@tonic-gate dprint(2, ("sctp_find_fast_rexmit_mblks: " 7747c478bd9Sstevel@tonic-gate "tsn %x\n", sdh->sdh_tsn)); 7757c478bd9Sstevel@tonic-gate } 7767c478bd9Sstevel@tonic-gate } 7777c478bd9Sstevel@tonic-gate } 7787c478bd9Sstevel@tonic-gate /* Clear the flag as there is no more message to be fast rexmitted. */ 7797c478bd9Sstevel@tonic-gate sctp->sctp_chk_fast_rexmit = B_FALSE; 7807c478bd9Sstevel@tonic-gate return (start_mp); 7817c478bd9Sstevel@tonic-gate } 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate /* A debug function just to make sure that a mblk chain is not broken */ 7847c478bd9Sstevel@tonic-gate #ifdef DEBUG 7857c478bd9Sstevel@tonic-gate static boolean_t 7867c478bd9Sstevel@tonic-gate sctp_verify_chain(mblk_t *head, mblk_t *tail) 7877c478bd9Sstevel@tonic-gate { 7887c478bd9Sstevel@tonic-gate mblk_t *mp = head; 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate if (head == NULL || tail == NULL) 7917c478bd9Sstevel@tonic-gate return (B_TRUE); 7927c478bd9Sstevel@tonic-gate while (mp != NULL) { 7937c478bd9Sstevel@tonic-gate if (mp == tail) 7947c478bd9Sstevel@tonic-gate return (B_TRUE); 7957c478bd9Sstevel@tonic-gate mp = mp->b_next; 7967c478bd9Sstevel@tonic-gate } 7977c478bd9Sstevel@tonic-gate return (B_FALSE); 7987c478bd9Sstevel@tonic-gate } 7997c478bd9Sstevel@tonic-gate #endif 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate /* 8027c478bd9Sstevel@tonic-gate * Gets the next unsent chunk to transmit. Messages that are abandoned are 8037c478bd9Sstevel@tonic-gate * skipped. A message can be abandoned if it has a non-zero timetolive and 8047c478bd9Sstevel@tonic-gate * transmission has not yet started or if it is a partially reliable 8057c478bd9Sstevel@tonic-gate * message and its time is up (assuming we are PR-SCTP aware). 8061e109b40SNick Street * We only return a chunk if it will fit entirely in the current packet. 8077c478bd9Sstevel@tonic-gate * 'cansend' is used to determine if need to try and chunkify messages from 8087c478bd9Sstevel@tonic-gate * the unsent list, if any, and also as an input to sctp_chunkify() if so. 8092dd25cf1SGeorge Shepherd * 8101e109b40SNick Street * firstseg_len indicates the space already used, cansend represents remaining 811*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India * space in the window, ((sf_pmss - firstseg_len) can therefore reasonably 8122dd25cf1SGeorge Shepherd * be used to compute the cansend arg). 8137c478bd9Sstevel@tonic-gate */ 8147c478bd9Sstevel@tonic-gate mblk_t * 8157c478bd9Sstevel@tonic-gate sctp_get_msg_to_send(sctp_t *sctp, mblk_t **mp, mblk_t *meta, int *error, 8161e109b40SNick Street int32_t firstseg_len, uint32_t cansend, sctp_faddr_t *fp) 8177c478bd9Sstevel@tonic-gate { 8187c478bd9Sstevel@tonic-gate mblk_t *mp1; 8197c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *msg_hdr; 8207c478bd9Sstevel@tonic-gate mblk_t *tmp_meta; 8217c478bd9Sstevel@tonic-gate sctp_faddr_t *fp1; 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate ASSERT(error != NULL && mp != NULL); 8247c478bd9Sstevel@tonic-gate *error = 0; 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_current != NULL); 8277c478bd9Sstevel@tonic-gate 8287c478bd9Sstevel@tonic-gate chunkified: 8297c478bd9Sstevel@tonic-gate while (meta != NULL) { 8307c478bd9Sstevel@tonic-gate tmp_meta = meta->b_next; 8317c478bd9Sstevel@tonic-gate msg_hdr = (sctp_msg_hdr_t *)meta->b_rptr; 8327c478bd9Sstevel@tonic-gate mp1 = meta->b_cont; 8337c478bd9Sstevel@tonic-gate if (SCTP_IS_MSG_ABANDONED(meta)) 8347c478bd9Sstevel@tonic-gate goto next_msg; 8357c478bd9Sstevel@tonic-gate if (!SCTP_MSG_TO_BE_ABANDONED(meta, msg_hdr, sctp)) { 8367c478bd9Sstevel@tonic-gate while (mp1 != NULL) { 8377c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_CANSEND(mp1)) { 8387c478bd9Sstevel@tonic-gate *mp = mp1; 8397c478bd9Sstevel@tonic-gate #ifdef DEBUG 8407c478bd9Sstevel@tonic-gate ASSERT(sctp_verify_chain( 8417c478bd9Sstevel@tonic-gate sctp->sctp_xmit_head, meta)); 8427c478bd9Sstevel@tonic-gate #endif 8437c478bd9Sstevel@tonic-gate return (meta); 8447c478bd9Sstevel@tonic-gate } 8457c478bd9Sstevel@tonic-gate mp1 = mp1->b_next; 8467c478bd9Sstevel@tonic-gate } 8477c478bd9Sstevel@tonic-gate goto next_msg; 8487c478bd9Sstevel@tonic-gate } 8497c478bd9Sstevel@tonic-gate /* 8507c478bd9Sstevel@tonic-gate * If we come here and the first chunk is sent, then we 8517c478bd9Sstevel@tonic-gate * we are PR-SCTP aware, in which case if the cumulative 8527c478bd9Sstevel@tonic-gate * TSN has moved upto or beyond the first chunk (which 8537c478bd9Sstevel@tonic-gate * means all the previous messages have been cumulative 8547c478bd9Sstevel@tonic-gate * SACK'd), then we send a Forward TSN with the last 8557c478bd9Sstevel@tonic-gate * chunk that was sent in this message. If we can't send 8567c478bd9Sstevel@tonic-gate * a Forward TSN because previous non-abandoned messages 8577c478bd9Sstevel@tonic-gate * have not been acked then we will defer the Forward TSN 8587c478bd9Sstevel@tonic-gate * to sctp_rexmit() or sctp_cumack(). 8597c478bd9Sstevel@tonic-gate */ 8607c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_ISSENT(mp1)) { 8617c478bd9Sstevel@tonic-gate *error = sctp_check_abandoned_msg(sctp, meta); 8627c478bd9Sstevel@tonic-gate if (*error != 0) { 8637c478bd9Sstevel@tonic-gate #ifdef DEBUG 8647c478bd9Sstevel@tonic-gate ASSERT(sctp_verify_chain(sctp->sctp_xmit_head, 8657c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail)); 8667c478bd9Sstevel@tonic-gate #endif 8677c478bd9Sstevel@tonic-gate return (NULL); 8687c478bd9Sstevel@tonic-gate } 8697c478bd9Sstevel@tonic-gate goto next_msg; 8707c478bd9Sstevel@tonic-gate } 8717c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_prsctpdrop); 8727c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_unsent >= msg_hdr->smh_msglen); 8737c478bd9Sstevel@tonic-gate if (meta->b_prev == NULL) { 8747c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_xmit_head == meta); 8757c478bd9Sstevel@tonic-gate sctp->sctp_xmit_head = tmp_meta; 8767c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_tail == meta) 8777c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail = tmp_meta; 8787c478bd9Sstevel@tonic-gate meta->b_next = NULL; 8797c478bd9Sstevel@tonic-gate if (tmp_meta != NULL) 8807c478bd9Sstevel@tonic-gate tmp_meta->b_prev = NULL; 8817c478bd9Sstevel@tonic-gate } else if (meta->b_next == NULL) { 8827c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_tail == meta) 8837c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail = meta->b_prev; 8847c478bd9Sstevel@tonic-gate meta->b_prev->b_next = NULL; 8857c478bd9Sstevel@tonic-gate meta->b_prev = NULL; 8867c478bd9Sstevel@tonic-gate } else { 8877c478bd9Sstevel@tonic-gate meta->b_prev->b_next = tmp_meta; 8887c478bd9Sstevel@tonic-gate tmp_meta->b_prev = meta->b_prev; 8897c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_tail == meta) 8907c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail = tmp_meta; 8917c478bd9Sstevel@tonic-gate meta->b_prev = NULL; 8927c478bd9Sstevel@tonic-gate meta->b_next = NULL; 8937c478bd9Sstevel@tonic-gate } 8947c478bd9Sstevel@tonic-gate sctp->sctp_unsent -= msg_hdr->smh_msglen; 8957c478bd9Sstevel@tonic-gate /* 8967c478bd9Sstevel@tonic-gate * Update ULP the amount of queued data, which is 8977c478bd9Sstevel@tonic-gate * sent-unack'ed + unsent. 8987c478bd9Sstevel@tonic-gate */ 8990f1702c5SYu Xiangning if (!SCTP_IS_DETACHED(sctp)) 9000f1702c5SYu Xiangning SCTP_TXQ_UPDATE(sctp); 9017c478bd9Sstevel@tonic-gate sctp_sendfail_event(sctp, meta, 0, B_TRUE); 9027c478bd9Sstevel@tonic-gate next_msg: 9037c478bd9Sstevel@tonic-gate meta = tmp_meta; 9047c478bd9Sstevel@tonic-gate } 9057c478bd9Sstevel@tonic-gate /* chunkify, if needed */ 9067c478bd9Sstevel@tonic-gate if (cansend > 0 && sctp->sctp_xmit_unsent != NULL) { 9077c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_unsent > 0); 9087c478bd9Sstevel@tonic-gate if (fp == NULL) { 9097c478bd9Sstevel@tonic-gate fp = SCTP_CHUNK_DEST(sctp->sctp_xmit_unsent); 910*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp == NULL || fp->sf_state != SCTP_FADDRS_ALIVE) 9117c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 9127c478bd9Sstevel@tonic-gate } else { 9137c478bd9Sstevel@tonic-gate /* 9147c478bd9Sstevel@tonic-gate * If user specified destination, try to honor that. 9157c478bd9Sstevel@tonic-gate */ 9167c478bd9Sstevel@tonic-gate fp1 = SCTP_CHUNK_DEST(sctp->sctp_xmit_unsent); 917*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp1 != NULL && fp1->sf_state == SCTP_FADDRS_ALIVE && 9187c478bd9Sstevel@tonic-gate fp1 != fp) { 9197c478bd9Sstevel@tonic-gate goto chunk_done; 9207c478bd9Sstevel@tonic-gate } 9217c478bd9Sstevel@tonic-gate } 922*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India meta = sctp_chunkify(sctp, fp->sf_pmss, firstseg_len, cansend); 9231e109b40SNick Street if (meta == NULL) 9247c478bd9Sstevel@tonic-gate goto chunk_done; 9257c478bd9Sstevel@tonic-gate /* 9267c478bd9Sstevel@tonic-gate * sctp_chunkify() won't advance sctp_xmit_tail if it adds 9277c478bd9Sstevel@tonic-gate * new chunk(s) to the tail, so we need to skip the 9287c478bd9Sstevel@tonic-gate * sctp_xmit_tail, which would have already been processed. 9297c478bd9Sstevel@tonic-gate * This could happen when there is unacked chunks, but 9307c478bd9Sstevel@tonic-gate * nothing new to send. 9317c478bd9Sstevel@tonic-gate * When sctp_chunkify() is called when the transmit queue 9327c478bd9Sstevel@tonic-gate * is empty then we need to start from sctp_xmit_tail. 9337c478bd9Sstevel@tonic-gate */ 9347c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_ISSENT(sctp->sctp_xmit_tail->b_cont)) { 9357c478bd9Sstevel@tonic-gate #ifdef DEBUG 9367c478bd9Sstevel@tonic-gate mp1 = sctp->sctp_xmit_tail->b_cont; 9377c478bd9Sstevel@tonic-gate while (mp1 != NULL) { 9387c478bd9Sstevel@tonic-gate ASSERT(!SCTP_CHUNK_CANSEND(mp1)); 9397c478bd9Sstevel@tonic-gate mp1 = mp1->b_next; 9407c478bd9Sstevel@tonic-gate } 9417c478bd9Sstevel@tonic-gate #endif 9427c478bd9Sstevel@tonic-gate if ((meta = sctp->sctp_xmit_tail->b_next) == NULL) 9437c478bd9Sstevel@tonic-gate goto chunk_done; 9447c478bd9Sstevel@tonic-gate } 9457c478bd9Sstevel@tonic-gate goto chunkified; 9467c478bd9Sstevel@tonic-gate } 9477c478bd9Sstevel@tonic-gate chunk_done: 9487c478bd9Sstevel@tonic-gate #ifdef DEBUG 9497c478bd9Sstevel@tonic-gate ASSERT(sctp_verify_chain(sctp->sctp_xmit_head, sctp->sctp_xmit_tail)); 9507c478bd9Sstevel@tonic-gate #endif 9517c478bd9Sstevel@tonic-gate return (NULL); 9527c478bd9Sstevel@tonic-gate } 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate void 9557c478bd9Sstevel@tonic-gate sctp_fast_rexmit(sctp_t *sctp) 9567c478bd9Sstevel@tonic-gate { 9577c478bd9Sstevel@tonic-gate mblk_t *mp, *head; 9587c478bd9Sstevel@tonic-gate int pktlen = 0; 9597c478bd9Sstevel@tonic-gate sctp_faddr_t *fp = NULL; 960f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 9617c478bd9Sstevel@tonic-gate 9627c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_xmit_head != NULL); 9637c478bd9Sstevel@tonic-gate mp = sctp_find_fast_rexmit_mblks(sctp, &pktlen, &fp); 96477c67f2fSkcpoon if (mp == NULL) { 965f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_fr_not_found); 9667c478bd9Sstevel@tonic-gate return; 96777c67f2fSkcpoon } 968df19b344Svi if ((head = sctp_add_proto_hdr(sctp, fp, mp, 0, NULL)) == NULL) { 9697c478bd9Sstevel@tonic-gate freemsg(mp); 970f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_fr_add_hdr); 9717c478bd9Sstevel@tonic-gate return; 9727c478bd9Sstevel@tonic-gate } 973*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if ((pktlen > fp->sf_pmss) && fp->sf_isv4) { 9747c478bd9Sstevel@tonic-gate ipha_t *iph = (ipha_t *)head->b_rptr; 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate iph->ipha_fragment_offset_and_flags = 0; 9777c478bd9Sstevel@tonic-gate } 9787c478bd9Sstevel@tonic-gate 979*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp_set_iplen(sctp, head, fp->sf_ixa); 980*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India (void) conn_ip_output(head, fp->sf_ixa); 981bd670b35SErik Nordmark BUMP_LOCAL(sctp->sctp_opkts); 982*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp->sctp_active = fp->sf_lastactive = ddi_get_lbolt64(); 9837c478bd9Sstevel@tonic-gate } 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate void 98612f47623Skcpoon sctp_output(sctp_t *sctp, uint_t num_pkt) 9877c478bd9Sstevel@tonic-gate { 9887c478bd9Sstevel@tonic-gate mblk_t *mp = NULL; 9897c478bd9Sstevel@tonic-gate mblk_t *nmp; 9907c478bd9Sstevel@tonic-gate mblk_t *head; 9917c478bd9Sstevel@tonic-gate mblk_t *meta = sctp->sctp_xmit_tail; 9927c478bd9Sstevel@tonic-gate mblk_t *fill = NULL; 9937c478bd9Sstevel@tonic-gate uint16_t chunklen; 9947c478bd9Sstevel@tonic-gate uint32_t cansend; 9957c478bd9Sstevel@tonic-gate int32_t seglen; 9967c478bd9Sstevel@tonic-gate int32_t xtralen; 9977c478bd9Sstevel@tonic-gate int32_t sacklen; 9987c478bd9Sstevel@tonic-gate int32_t pad = 0; 9997c478bd9Sstevel@tonic-gate int32_t pathmax; 10007c478bd9Sstevel@tonic-gate int extra; 10015dd46ab5SKacheong Poon int64_t now = LBOLT_FASTPATH64; 10027c478bd9Sstevel@tonic-gate sctp_faddr_t *fp; 10037c478bd9Sstevel@tonic-gate sctp_faddr_t *lfp; 10047c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 10057c478bd9Sstevel@tonic-gate int error; 1006df19b344Svi boolean_t notsent = B_TRUE; 100712f47623Skcpoon sctp_stack_t *sctps = sctp->sctp_sctps; 1008481845d8SGeorge Shepherd uint32_t tsn; 10097c478bd9Sstevel@tonic-gate 10107c478bd9Sstevel@tonic-gate if (sctp->sctp_ftsn == sctp->sctp_lastacked + 1) { 10117c478bd9Sstevel@tonic-gate sacklen = 0; 10127c478bd9Sstevel@tonic-gate } else { 10137c478bd9Sstevel@tonic-gate /* send a SACK chunk */ 10147c478bd9Sstevel@tonic-gate sacklen = sizeof (sctp_chunk_hdr_t) + 10157c478bd9Sstevel@tonic-gate sizeof (sctp_sack_chunk_t) + 10167c478bd9Sstevel@tonic-gate (sizeof (sctp_sack_frag_t) * sctp->sctp_sack_gaps); 10177c478bd9Sstevel@tonic-gate lfp = sctp->sctp_lastdata; 10187c478bd9Sstevel@tonic-gate ASSERT(lfp != NULL); 1019*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (lfp->sf_state != SCTP_FADDRS_ALIVE) 10207c478bd9Sstevel@tonic-gate lfp = sctp->sctp_current; 10217c478bd9Sstevel@tonic-gate } 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate cansend = sctp->sctp_frwnd; 10247c478bd9Sstevel@tonic-gate if (sctp->sctp_unsent < cansend) 10257c478bd9Sstevel@tonic-gate cansend = sctp->sctp_unsent; 1026518f8adfSGeorge Shepherd 1027518f8adfSGeorge Shepherd /* 1028518f8adfSGeorge Shepherd * Start persist timer if unable to send or when 1029518f8adfSGeorge Shepherd * trying to send into a zero window. This timer 1030518f8adfSGeorge Shepherd * ensures the blocked send attempt is retried. 1031518f8adfSGeorge Shepherd */ 1032*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if ((cansend < sctp->sctp_current->sf_pmss / 2) && 1033518f8adfSGeorge Shepherd (sctp->sctp_unacked != 0) && 1034*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India (sctp->sctp_unacked < sctp->sctp_current->sf_pmss) && 1035518f8adfSGeorge Shepherd !sctp->sctp_ndelay || 1036518f8adfSGeorge Shepherd (cansend == 0 && sctp->sctp_unacked == 0 && 1037518f8adfSGeorge Shepherd sctp->sctp_unsent != 0)) { 10387c478bd9Sstevel@tonic-gate head = NULL; 10397c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 10407c478bd9Sstevel@tonic-gate goto unsent_data; 10417c478bd9Sstevel@tonic-gate } 10427c478bd9Sstevel@tonic-gate if (meta != NULL) 10437c478bd9Sstevel@tonic-gate mp = meta->b_cont; 104412f47623Skcpoon while (cansend > 0 && num_pkt-- != 0) { 10457c478bd9Sstevel@tonic-gate pad = 0; 10467c478bd9Sstevel@tonic-gate 10477c478bd9Sstevel@tonic-gate /* 10487c478bd9Sstevel@tonic-gate * Find first segment eligible for transmit. 10497c478bd9Sstevel@tonic-gate */ 10507c478bd9Sstevel@tonic-gate while (mp != NULL) { 10517c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_CANSEND(mp)) 10527c478bd9Sstevel@tonic-gate break; 10537c478bd9Sstevel@tonic-gate mp = mp->b_next; 10547c478bd9Sstevel@tonic-gate } 10557c478bd9Sstevel@tonic-gate if (mp == NULL) { 10567c478bd9Sstevel@tonic-gate meta = sctp_get_msg_to_send(sctp, &mp, 10577c478bd9Sstevel@tonic-gate meta == NULL ? NULL : meta->b_next, &error, sacklen, 10587c478bd9Sstevel@tonic-gate cansend, NULL); 10597c478bd9Sstevel@tonic-gate if (error != 0 || meta == NULL) { 10607c478bd9Sstevel@tonic-gate head = NULL; 10617c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 10627c478bd9Sstevel@tonic-gate goto unsent_data; 10637c478bd9Sstevel@tonic-gate } 10647c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail = meta; 10657c478bd9Sstevel@tonic-gate } 10667c478bd9Sstevel@tonic-gate 10677c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 10687c478bd9Sstevel@tonic-gate seglen = ntohs(sdc->sdh_len); 10697c478bd9Sstevel@tonic-gate xtralen = sizeof (*sdc); 10707c478bd9Sstevel@tonic-gate chunklen = seglen - xtralen; 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate /* 10737c478bd9Sstevel@tonic-gate * Check rwnd. 10747c478bd9Sstevel@tonic-gate */ 10757c478bd9Sstevel@tonic-gate if (chunklen > cansend) { 10767c478bd9Sstevel@tonic-gate head = NULL; 10777c478bd9Sstevel@tonic-gate fp = SCTP_CHUNK_DEST(meta); 1078*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp == NULL || fp->sf_state != SCTP_FADDRS_ALIVE) 10797c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 10807c478bd9Sstevel@tonic-gate goto unsent_data; 10817c478bd9Sstevel@tonic-gate } 10827c478bd9Sstevel@tonic-gate if ((extra = seglen & (SCTP_ALIGN - 1)) != 0) 10837c478bd9Sstevel@tonic-gate extra = SCTP_ALIGN - extra; 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate /* 10867c478bd9Sstevel@tonic-gate * Pick destination address, and check cwnd. 10877c478bd9Sstevel@tonic-gate */ 1088*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (sacklen > 0 && (seglen + extra <= lfp->sf_cwnd - 1089*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India lfp->sf_suna) && 1090*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India (seglen + sacklen + extra <= lfp->sf_pmss)) { 10917c478bd9Sstevel@tonic-gate /* 10927c478bd9Sstevel@tonic-gate * Only include SACK chunk if it can be bundled 10937c478bd9Sstevel@tonic-gate * with a data chunk, and sent to sctp_lastdata. 10947c478bd9Sstevel@tonic-gate */ 1095*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India pathmax = lfp->sf_cwnd - lfp->sf_suna; 10967c478bd9Sstevel@tonic-gate 10977c478bd9Sstevel@tonic-gate fp = lfp; 10987c478bd9Sstevel@tonic-gate if ((nmp = dupmsg(mp)) == NULL) { 10997c478bd9Sstevel@tonic-gate head = NULL; 11007c478bd9Sstevel@tonic-gate goto unsent_data; 11017c478bd9Sstevel@tonic-gate } 11027c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_FLAGS(nmp); 1103df19b344Svi head = sctp_add_proto_hdr(sctp, fp, nmp, sacklen, 1104df19b344Svi &error); 11057c478bd9Sstevel@tonic-gate if (head == NULL) { 1106df19b344Svi /* 1107df19b344Svi * If none of the source addresses are 1108df19b344Svi * available (i.e error == EHOSTUNREACH), 1109df19b344Svi * pretend we have sent the data. We will 1110df19b344Svi * eventually time out trying to retramsmit 1111df19b344Svi * the data if the interface never comes up. 1112df19b344Svi * If we have already sent some stuff (i.e., 1113df19b344Svi * notsent is B_FALSE) then we are fine, else 1114df19b344Svi * just mark this packet as sent. 1115df19b344Svi */ 1116df19b344Svi if (notsent && error == EHOSTUNREACH) { 1117df19b344Svi SCTP_CHUNK_SENT(sctp, mp, sdc, 1118df19b344Svi fp, chunklen, meta); 1119df19b344Svi } 11207c478bd9Sstevel@tonic-gate freemsg(nmp); 1121f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_output_failed); 11227c478bd9Sstevel@tonic-gate goto unsent_data; 11237c478bd9Sstevel@tonic-gate } 11247c478bd9Sstevel@tonic-gate seglen += sacklen; 11257c478bd9Sstevel@tonic-gate xtralen += sacklen; 11267c478bd9Sstevel@tonic-gate sacklen = 0; 11277c478bd9Sstevel@tonic-gate } else { 11287c478bd9Sstevel@tonic-gate fp = SCTP_CHUNK_DEST(meta); 1129*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp == NULL || fp->sf_state != SCTP_FADDRS_ALIVE) 11307c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 11317c478bd9Sstevel@tonic-gate /* 11327c478bd9Sstevel@tonic-gate * If we haven't sent data to this destination for 11337c478bd9Sstevel@tonic-gate * a while, do slow start again. 11347c478bd9Sstevel@tonic-gate */ 1135*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (now - fp->sf_lastactive > fp->sf_rto) { 1136*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India SET_CWND(fp, fp->sf_pmss, 113712f47623Skcpoon sctps->sctps_slow_start_after_idle); 11387c478bd9Sstevel@tonic-gate } 11397c478bd9Sstevel@tonic-gate 1140*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India pathmax = fp->sf_cwnd - fp->sf_suna; 11417c478bd9Sstevel@tonic-gate if (seglen + extra > pathmax) { 11427c478bd9Sstevel@tonic-gate head = NULL; 11437c478bd9Sstevel@tonic-gate goto unsent_data; 11447c478bd9Sstevel@tonic-gate } 11457c478bd9Sstevel@tonic-gate if ((nmp = dupmsg(mp)) == NULL) { 11467c478bd9Sstevel@tonic-gate head = NULL; 11477c478bd9Sstevel@tonic-gate goto unsent_data; 11487c478bd9Sstevel@tonic-gate } 11497c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_FLAGS(nmp); 1150df19b344Svi head = sctp_add_proto_hdr(sctp, fp, nmp, 0, &error); 11517c478bd9Sstevel@tonic-gate if (head == NULL) { 1152df19b344Svi /* 1153df19b344Svi * If none of the source addresses are 1154df19b344Svi * available (i.e error == EHOSTUNREACH), 1155df19b344Svi * pretend we have sent the data. We will 1156df19b344Svi * eventually time out trying to retramsmit 1157df19b344Svi * the data if the interface never comes up. 1158df19b344Svi * If we have already sent some stuff (i.e., 1159df19b344Svi * notsent is B_FALSE) then we are fine, else 1160df19b344Svi * just mark this packet as sent. 1161df19b344Svi */ 1162df19b344Svi if (notsent && error == EHOSTUNREACH) { 1163df19b344Svi SCTP_CHUNK_SENT(sctp, mp, sdc, 1164df19b344Svi fp, chunklen, meta); 1165df19b344Svi } 11667c478bd9Sstevel@tonic-gate freemsg(nmp); 1167f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_output_failed); 11687c478bd9Sstevel@tonic-gate goto unsent_data; 11697c478bd9Sstevel@tonic-gate } 11707c478bd9Sstevel@tonic-gate } 1171*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_lastactive = now; 1172*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (pathmax > fp->sf_pmss) 1173*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India pathmax = fp->sf_pmss; 11747c478bd9Sstevel@tonic-gate SCTP_CHUNK_SENT(sctp, mp, sdc, fp, chunklen, meta); 11757c478bd9Sstevel@tonic-gate mp = mp->b_next; 11767c478bd9Sstevel@tonic-gate 1177481845d8SGeorge Shepherd /* 1178481845d8SGeorge Shepherd * Use this chunk to measure RTT? 1179481845d8SGeorge Shepherd * Must not be a retransmision of an earlier chunk, 1180481845d8SGeorge Shepherd * ensure the tsn is current. 1181481845d8SGeorge Shepherd */ 1182481845d8SGeorge Shepherd tsn = ntohl(sdc->sdh_tsn); 1183481845d8SGeorge Shepherd if (sctp->sctp_out_time == 0 && tsn == (sctp->sctp_ltsn - 1)) { 11847c478bd9Sstevel@tonic-gate sctp->sctp_out_time = now; 1185481845d8SGeorge Shepherd sctp->sctp_rtt_tsn = tsn; 11867c478bd9Sstevel@tonic-gate } 11877c478bd9Sstevel@tonic-gate if (extra > 0) { 1188121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 11897c478bd9Sstevel@tonic-gate if (fill != NULL) { 11907c478bd9Sstevel@tonic-gate linkb(head, fill); 11917c478bd9Sstevel@tonic-gate pad = extra; 11927c478bd9Sstevel@tonic-gate seglen += extra; 11937c478bd9Sstevel@tonic-gate } else { 11947c478bd9Sstevel@tonic-gate goto unsent_data; 11957c478bd9Sstevel@tonic-gate } 11967c478bd9Sstevel@tonic-gate } 11971e109b40SNick Street /* 11981e109b40SNick Street * Bundle chunks. We linkb() the chunks together to send 11991e109b40SNick Street * downstream in a single packet. 12001e109b40SNick Street * Partial chunks MUST NOT be bundled with full chunks, so we 12011e109b40SNick Street * rely on sctp_get_msg_to_send() to only return messages that 12021e109b40SNick Street * will fit entirely in the current packet. 12031e109b40SNick Street */ 12047c478bd9Sstevel@tonic-gate while (seglen < pathmax) { 12057c478bd9Sstevel@tonic-gate int32_t new_len; 12067c478bd9Sstevel@tonic-gate int32_t new_xtralen; 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate while (mp != NULL) { 12097c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_CANSEND(mp)) 12107c478bd9Sstevel@tonic-gate break; 12117c478bd9Sstevel@tonic-gate mp = mp->b_next; 12127c478bd9Sstevel@tonic-gate } 12137c478bd9Sstevel@tonic-gate if (mp == NULL) { 12147c478bd9Sstevel@tonic-gate meta = sctp_get_msg_to_send(sctp, &mp, 12157c478bd9Sstevel@tonic-gate meta->b_next, &error, seglen, 12167c478bd9Sstevel@tonic-gate (seglen - xtralen) >= cansend ? 0 : 12177c478bd9Sstevel@tonic-gate cansend - seglen, fp); 12181e109b40SNick Street if (error != 0) 12191e109b40SNick Street break; 12201e109b40SNick Street /* If no more eligible chunks, cease bundling */ 12211e109b40SNick Street if (meta == NULL) 12227c478bd9Sstevel@tonic-gate break; 12237c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail = meta; 12247c478bd9Sstevel@tonic-gate } 12257c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 12267c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp) && SCTP_CHUNK_DEST(meta) && 12277c478bd9Sstevel@tonic-gate fp != SCTP_CHUNK_DEST(meta)) { 12287c478bd9Sstevel@tonic-gate break; 12297c478bd9Sstevel@tonic-gate } 12307c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 12317c478bd9Sstevel@tonic-gate chunklen = ntohs(sdc->sdh_len); 12327c478bd9Sstevel@tonic-gate if ((extra = chunklen & (SCTP_ALIGN - 1)) != 0) 12337c478bd9Sstevel@tonic-gate extra = SCTP_ALIGN - extra; 12347c478bd9Sstevel@tonic-gate 12357c478bd9Sstevel@tonic-gate new_len = seglen + chunklen; 12367c478bd9Sstevel@tonic-gate new_xtralen = xtralen + sizeof (*sdc); 12377c478bd9Sstevel@tonic-gate chunklen -= sizeof (*sdc); 12387c478bd9Sstevel@tonic-gate 12397c478bd9Sstevel@tonic-gate if (new_len - new_xtralen > cansend || 12407c478bd9Sstevel@tonic-gate new_len + extra > pathmax) { 12417c478bd9Sstevel@tonic-gate break; 12427c478bd9Sstevel@tonic-gate } 12437c478bd9Sstevel@tonic-gate if ((nmp = dupmsg(mp)) == NULL) 12447c478bd9Sstevel@tonic-gate break; 12457c478bd9Sstevel@tonic-gate if (extra > 0) { 1246121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 12477c478bd9Sstevel@tonic-gate if (fill != NULL) { 12487c478bd9Sstevel@tonic-gate pad += extra; 12497c478bd9Sstevel@tonic-gate new_len += extra; 12507c478bd9Sstevel@tonic-gate linkb(nmp, fill); 12517c478bd9Sstevel@tonic-gate } else { 12527c478bd9Sstevel@tonic-gate freemsg(nmp); 12537c478bd9Sstevel@tonic-gate break; 12547c478bd9Sstevel@tonic-gate } 12557c478bd9Sstevel@tonic-gate } 12567c478bd9Sstevel@tonic-gate seglen = new_len; 12577c478bd9Sstevel@tonic-gate xtralen = new_xtralen; 12587c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_FLAGS(nmp); 12597c478bd9Sstevel@tonic-gate SCTP_CHUNK_SENT(sctp, mp, sdc, fp, chunklen, meta); 12607c478bd9Sstevel@tonic-gate linkb(head, nmp); 12617c478bd9Sstevel@tonic-gate mp = mp->b_next; 12627c478bd9Sstevel@tonic-gate } 1263*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if ((seglen > fp->sf_pmss) && fp->sf_isv4) { 12647c478bd9Sstevel@tonic-gate ipha_t *iph = (ipha_t *)head->b_rptr; 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate /* 12677c478bd9Sstevel@tonic-gate * Path MTU is different from what we thought it would 12687c478bd9Sstevel@tonic-gate * be when we created chunks, or IP headers have grown. 12697c478bd9Sstevel@tonic-gate * Need to clear the DF bit. 12707c478bd9Sstevel@tonic-gate */ 12717c478bd9Sstevel@tonic-gate iph->ipha_fragment_offset_and_flags = 0; 12727c478bd9Sstevel@tonic-gate } 12737c478bd9Sstevel@tonic-gate /* xmit segment */ 12747c478bd9Sstevel@tonic-gate ASSERT(cansend >= seglen - pad - xtralen); 12757c478bd9Sstevel@tonic-gate cansend -= (seglen - pad - xtralen); 12767c478bd9Sstevel@tonic-gate dprint(2, ("sctp_output: Sending packet %d bytes, tsn %x " 127745916cd2Sjpk "ssn %d to %p (rwnd %d, cansend %d, lastack_rxd %x)\n", 127845916cd2Sjpk seglen - xtralen, ntohl(sdc->sdh_tsn), 127945916cd2Sjpk ntohs(sdc->sdh_ssn), (void *)fp, sctp->sctp_frwnd, 128045916cd2Sjpk cansend, sctp->sctp_lastack_rxd)); 1281*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp_set_iplen(sctp, head, fp->sf_ixa); 1282*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India (void) conn_ip_output(head, fp->sf_ixa); 1283bd670b35SErik Nordmark BUMP_LOCAL(sctp->sctp_opkts); 12847c478bd9Sstevel@tonic-gate /* arm rto timer (if not set) */ 1285*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (!fp->sf_timer_running) 1286*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->sf_rto); 1287df19b344Svi notsent = B_FALSE; 12887c478bd9Sstevel@tonic-gate } 12897c478bd9Sstevel@tonic-gate sctp->sctp_active = now; 12907c478bd9Sstevel@tonic-gate return; 12917c478bd9Sstevel@tonic-gate unsent_data: 12927c478bd9Sstevel@tonic-gate /* arm persist timer (if rto timer not set) */ 1293*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (!fp->sf_timer_running) 1294*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->sf_rto); 12957c478bd9Sstevel@tonic-gate if (head != NULL) 12967c478bd9Sstevel@tonic-gate freemsg(head); 12977c478bd9Sstevel@tonic-gate } 12987c478bd9Sstevel@tonic-gate 12997c478bd9Sstevel@tonic-gate /* 13007c478bd9Sstevel@tonic-gate * The following two functions initialize and destroy the cache 13017c478bd9Sstevel@tonic-gate * associated with the sets used for PR-SCTP. 13027c478bd9Sstevel@tonic-gate */ 13037c478bd9Sstevel@tonic-gate void 13047c478bd9Sstevel@tonic-gate sctp_ftsn_sets_init(void) 13057c478bd9Sstevel@tonic-gate { 13067c478bd9Sstevel@tonic-gate sctp_kmem_ftsn_set_cache = kmem_cache_create("sctp_ftsn_set_cache", 13077c478bd9Sstevel@tonic-gate sizeof (sctp_ftsn_set_t), 0, NULL, NULL, NULL, NULL, 13087c478bd9Sstevel@tonic-gate NULL, 0); 13097c478bd9Sstevel@tonic-gate } 13107c478bd9Sstevel@tonic-gate 13117c478bd9Sstevel@tonic-gate void 13127c478bd9Sstevel@tonic-gate sctp_ftsn_sets_fini(void) 13137c478bd9Sstevel@tonic-gate { 13147c478bd9Sstevel@tonic-gate kmem_cache_destroy(sctp_kmem_ftsn_set_cache); 13157c478bd9Sstevel@tonic-gate } 13167c478bd9Sstevel@tonic-gate 13177c478bd9Sstevel@tonic-gate 13187c478bd9Sstevel@tonic-gate /* Free PR-SCTP sets */ 13197c478bd9Sstevel@tonic-gate void 13207c478bd9Sstevel@tonic-gate sctp_free_ftsn_set(sctp_ftsn_set_t *s) 13217c478bd9Sstevel@tonic-gate { 13227c478bd9Sstevel@tonic-gate sctp_ftsn_set_t *p; 13237c478bd9Sstevel@tonic-gate 13247c478bd9Sstevel@tonic-gate while (s != NULL) { 13257c478bd9Sstevel@tonic-gate p = s->next; 13267c478bd9Sstevel@tonic-gate s->next = NULL; 13277c478bd9Sstevel@tonic-gate kmem_cache_free(sctp_kmem_ftsn_set_cache, s); 13287c478bd9Sstevel@tonic-gate s = p; 13297c478bd9Sstevel@tonic-gate } 13307c478bd9Sstevel@tonic-gate } 13317c478bd9Sstevel@tonic-gate 13327c478bd9Sstevel@tonic-gate /* 13337c478bd9Sstevel@tonic-gate * Given a message meta block, meta, this routine creates or modifies 13347c478bd9Sstevel@tonic-gate * the set that will be used to generate a Forward TSN chunk. If the 13357c478bd9Sstevel@tonic-gate * entry for stream id, sid, for this message already exists, the 13367c478bd9Sstevel@tonic-gate * sequence number, ssn, is updated if it is greater than the existing 13377c478bd9Sstevel@tonic-gate * one. If an entry for this sid does not exist, one is created if 1338*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India * the size does not exceed fp->sf_pmss. We return false in case 13397c478bd9Sstevel@tonic-gate * or an error. 13407c478bd9Sstevel@tonic-gate */ 13417c478bd9Sstevel@tonic-gate boolean_t 13427c478bd9Sstevel@tonic-gate sctp_add_ftsn_set(sctp_ftsn_set_t **s, sctp_faddr_t *fp, mblk_t *meta, 13437c478bd9Sstevel@tonic-gate uint_t *nsets, uint32_t *slen) 13447c478bd9Sstevel@tonic-gate { 13457c478bd9Sstevel@tonic-gate sctp_ftsn_set_t *p; 13467c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *msg_hdr = (sctp_msg_hdr_t *)meta->b_rptr; 13477c478bd9Sstevel@tonic-gate uint16_t sid = htons(msg_hdr->smh_sid); 13487c478bd9Sstevel@tonic-gate /* msg_hdr->smh_ssn is already in NBO */ 13497c478bd9Sstevel@tonic-gate uint16_t ssn = msg_hdr->smh_ssn; 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate ASSERT(s != NULL && nsets != NULL); 13527c478bd9Sstevel@tonic-gate ASSERT((*nsets == 0 && *s == NULL) || (*nsets > 0 && *s != NULL)); 13537c478bd9Sstevel@tonic-gate 13547c478bd9Sstevel@tonic-gate if (*s == NULL) { 1355*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India ASSERT((*slen + sizeof (uint32_t)) <= fp->sf_pmss); 13567c478bd9Sstevel@tonic-gate *s = kmem_cache_alloc(sctp_kmem_ftsn_set_cache, KM_NOSLEEP); 13577c478bd9Sstevel@tonic-gate if (*s == NULL) 13587c478bd9Sstevel@tonic-gate return (B_FALSE); 13597c478bd9Sstevel@tonic-gate (*s)->ftsn_entries.ftsn_sid = sid; 13607c478bd9Sstevel@tonic-gate (*s)->ftsn_entries.ftsn_ssn = ssn; 13617c478bd9Sstevel@tonic-gate (*s)->next = NULL; 13627c478bd9Sstevel@tonic-gate *nsets = 1; 13637c478bd9Sstevel@tonic-gate *slen += sizeof (uint32_t); 13647c478bd9Sstevel@tonic-gate return (B_TRUE); 13657c478bd9Sstevel@tonic-gate } 13667c478bd9Sstevel@tonic-gate for (p = *s; p->next != NULL; p = p->next) { 13677c478bd9Sstevel@tonic-gate if (p->ftsn_entries.ftsn_sid == sid) { 13687c478bd9Sstevel@tonic-gate if (SSN_GT(ssn, p->ftsn_entries.ftsn_ssn)) 13697c478bd9Sstevel@tonic-gate p->ftsn_entries.ftsn_ssn = ssn; 13707c478bd9Sstevel@tonic-gate return (B_TRUE); 13717c478bd9Sstevel@tonic-gate } 13727c478bd9Sstevel@tonic-gate } 13737c478bd9Sstevel@tonic-gate /* the last one */ 13747c478bd9Sstevel@tonic-gate if (p->ftsn_entries.ftsn_sid == sid) { 13757c478bd9Sstevel@tonic-gate if (SSN_GT(ssn, p->ftsn_entries.ftsn_ssn)) 13767c478bd9Sstevel@tonic-gate p->ftsn_entries.ftsn_ssn = ssn; 13777c478bd9Sstevel@tonic-gate } else { 1378*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if ((*slen + sizeof (uint32_t)) > fp->sf_pmss) 13797c478bd9Sstevel@tonic-gate return (B_FALSE); 13807c478bd9Sstevel@tonic-gate p->next = kmem_cache_alloc(sctp_kmem_ftsn_set_cache, 13817c478bd9Sstevel@tonic-gate KM_NOSLEEP); 13827c478bd9Sstevel@tonic-gate if (p->next == NULL) 13837c478bd9Sstevel@tonic-gate return (B_FALSE); 13847c478bd9Sstevel@tonic-gate p = p->next; 13857c478bd9Sstevel@tonic-gate p->ftsn_entries.ftsn_sid = sid; 13867c478bd9Sstevel@tonic-gate p->ftsn_entries.ftsn_ssn = ssn; 13877c478bd9Sstevel@tonic-gate p->next = NULL; 13887c478bd9Sstevel@tonic-gate (*nsets)++; 13897c478bd9Sstevel@tonic-gate *slen += sizeof (uint32_t); 13907c478bd9Sstevel@tonic-gate } 13917c478bd9Sstevel@tonic-gate return (B_TRUE); 13927c478bd9Sstevel@tonic-gate } 13937c478bd9Sstevel@tonic-gate 13947c478bd9Sstevel@tonic-gate /* 13957c478bd9Sstevel@tonic-gate * Given a set of stream id - sequence number pairs, this routing creates 13967c478bd9Sstevel@tonic-gate * a Forward TSN chunk. The cumulative TSN (advanced peer ack point) 13977c478bd9Sstevel@tonic-gate * for the chunk is obtained from sctp->sctp_adv_pap. The caller 13987c478bd9Sstevel@tonic-gate * will add the IP/SCTP header. 13997c478bd9Sstevel@tonic-gate */ 14007c478bd9Sstevel@tonic-gate mblk_t * 14017c478bd9Sstevel@tonic-gate sctp_make_ftsn_chunk(sctp_t *sctp, sctp_faddr_t *fp, sctp_ftsn_set_t *sets, 14027c478bd9Sstevel@tonic-gate uint_t nsets, uint32_t seglen) 14037c478bd9Sstevel@tonic-gate { 14047c478bd9Sstevel@tonic-gate mblk_t *ftsn_mp; 14057c478bd9Sstevel@tonic-gate sctp_chunk_hdr_t *ch_hdr; 14067c478bd9Sstevel@tonic-gate uint32_t *advtsn; 14077c478bd9Sstevel@tonic-gate uint16_t schlen; 14087c478bd9Sstevel@tonic-gate size_t xtralen; 14097c478bd9Sstevel@tonic-gate ftsn_entry_t *ftsn_entry; 1410f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 14117c478bd9Sstevel@tonic-gate 14127c478bd9Sstevel@tonic-gate seglen += sizeof (sctp_chunk_hdr_t); 1413*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp->sf_isv4) 1414f4b3ec61Sdh xtralen = sctp->sctp_hdr_len + sctps->sctps_wroff_xtra; 14157c478bd9Sstevel@tonic-gate else 1416f4b3ec61Sdh xtralen = sctp->sctp_hdr6_len + sctps->sctps_wroff_xtra; 1417bd670b35SErik Nordmark ftsn_mp = allocb(xtralen + seglen, BPRI_MED); 14187c478bd9Sstevel@tonic-gate if (ftsn_mp == NULL) 14197c478bd9Sstevel@tonic-gate return (NULL); 14207c478bd9Sstevel@tonic-gate ftsn_mp->b_rptr += xtralen; 14217c478bd9Sstevel@tonic-gate ftsn_mp->b_wptr = ftsn_mp->b_rptr + seglen; 14227c478bd9Sstevel@tonic-gate 14237c478bd9Sstevel@tonic-gate ch_hdr = (sctp_chunk_hdr_t *)ftsn_mp->b_rptr; 14247c478bd9Sstevel@tonic-gate ch_hdr->sch_id = CHUNK_FORWARD_TSN; 14257c478bd9Sstevel@tonic-gate ch_hdr->sch_flags = 0; 14267c478bd9Sstevel@tonic-gate /* 14277c478bd9Sstevel@tonic-gate * The cast here should not be an issue since seglen is 14287c478bd9Sstevel@tonic-gate * the length of the Forward TSN chunk. 14297c478bd9Sstevel@tonic-gate */ 14307c478bd9Sstevel@tonic-gate schlen = (uint16_t)seglen; 14317c478bd9Sstevel@tonic-gate U16_TO_ABE16(schlen, &(ch_hdr->sch_len)); 14327c478bd9Sstevel@tonic-gate 14337c478bd9Sstevel@tonic-gate advtsn = (uint32_t *)(ch_hdr + 1); 14347c478bd9Sstevel@tonic-gate U32_TO_ABE32(sctp->sctp_adv_pap, advtsn); 14357c478bd9Sstevel@tonic-gate ftsn_entry = (ftsn_entry_t *)(advtsn + 1); 14367c478bd9Sstevel@tonic-gate while (nsets > 0) { 14377c478bd9Sstevel@tonic-gate ASSERT((uchar_t *)&ftsn_entry[1] <= ftsn_mp->b_wptr); 14387c478bd9Sstevel@tonic-gate ftsn_entry->ftsn_sid = sets->ftsn_entries.ftsn_sid; 14397c478bd9Sstevel@tonic-gate ftsn_entry->ftsn_ssn = sets->ftsn_entries.ftsn_ssn; 14407c478bd9Sstevel@tonic-gate ftsn_entry++; 14417c478bd9Sstevel@tonic-gate sets = sets->next; 14427c478bd9Sstevel@tonic-gate nsets--; 14437c478bd9Sstevel@tonic-gate } 14447c478bd9Sstevel@tonic-gate return (ftsn_mp); 14457c478bd9Sstevel@tonic-gate } 14467c478bd9Sstevel@tonic-gate 14477c478bd9Sstevel@tonic-gate /* 14487c478bd9Sstevel@tonic-gate * Given a starting message, the routine steps through all the 14497c478bd9Sstevel@tonic-gate * messages whose TSN is less than sctp->sctp_adv_pap and creates 14507c478bd9Sstevel@tonic-gate * ftsn sets. The ftsn sets is then used to create an Forward TSN 14517c478bd9Sstevel@tonic-gate * chunk. All the messages, that have chunks that are included in the 14527c478bd9Sstevel@tonic-gate * ftsn sets, are flagged abandonded. If a message is partially sent 14537c478bd9Sstevel@tonic-gate * and is deemed abandoned, all remaining unsent chunks are marked 14547c478bd9Sstevel@tonic-gate * abandoned and are deducted from sctp_unsent. 14557c478bd9Sstevel@tonic-gate */ 14567c478bd9Sstevel@tonic-gate void 14577c478bd9Sstevel@tonic-gate sctp_make_ftsns(sctp_t *sctp, mblk_t *meta, mblk_t *mp, mblk_t **nmp, 14587c478bd9Sstevel@tonic-gate sctp_faddr_t *fp, uint32_t *seglen) 14597c478bd9Sstevel@tonic-gate { 14607c478bd9Sstevel@tonic-gate mblk_t *mp1 = mp; 14617c478bd9Sstevel@tonic-gate mblk_t *mp_head = mp; 14627c478bd9Sstevel@tonic-gate mblk_t *meta_head = meta; 14637c478bd9Sstevel@tonic-gate mblk_t *head; 14647c478bd9Sstevel@tonic-gate sctp_ftsn_set_t *sets = NULL; 14657c478bd9Sstevel@tonic-gate uint_t nsets = 0; 14667c478bd9Sstevel@tonic-gate uint16_t clen; 14677c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 14687c478bd9Sstevel@tonic-gate uint32_t sacklen; 14697c478bd9Sstevel@tonic-gate uint32_t adv_pap = sctp->sctp_adv_pap; 14707c478bd9Sstevel@tonic-gate uint32_t unsent = 0; 14717c478bd9Sstevel@tonic-gate boolean_t ubit; 1472f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate *seglen = sizeof (uint32_t); 14757c478bd9Sstevel@tonic-gate 14767c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 14777c478bd9Sstevel@tonic-gate while (meta != NULL && 14787c478bd9Sstevel@tonic-gate SEQ_GEQ(sctp->sctp_adv_pap, ntohl(sdc->sdh_tsn))) { 14797c478bd9Sstevel@tonic-gate /* 14807c478bd9Sstevel@tonic-gate * Skip adding FTSN sets for un-ordered messages as they do 14817c478bd9Sstevel@tonic-gate * not have SSNs. 14827c478bd9Sstevel@tonic-gate */ 14837c478bd9Sstevel@tonic-gate ubit = SCTP_DATA_GET_UBIT(sdc); 14847c478bd9Sstevel@tonic-gate if (!ubit && 14857c478bd9Sstevel@tonic-gate !sctp_add_ftsn_set(&sets, fp, meta, &nsets, seglen)) { 14867c478bd9Sstevel@tonic-gate meta = NULL; 14877c478bd9Sstevel@tonic-gate sctp->sctp_adv_pap = adv_pap; 14887c478bd9Sstevel@tonic-gate goto ftsn_done; 14897c478bd9Sstevel@tonic-gate } 14907c478bd9Sstevel@tonic-gate while (mp1 != NULL && SCTP_CHUNK_ISSENT(mp1)) { 14917c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 14927c478bd9Sstevel@tonic-gate adv_pap = ntohl(sdc->sdh_tsn); 14937c478bd9Sstevel@tonic-gate mp1 = mp1->b_next; 14947c478bd9Sstevel@tonic-gate } 14957c478bd9Sstevel@tonic-gate meta = meta->b_next; 14967c478bd9Sstevel@tonic-gate if (meta != NULL) { 14977c478bd9Sstevel@tonic-gate mp1 = meta->b_cont; 14987c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp1)) 14997c478bd9Sstevel@tonic-gate break; 15007c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 15017c478bd9Sstevel@tonic-gate } 15027c478bd9Sstevel@tonic-gate } 15037c478bd9Sstevel@tonic-gate ftsn_done: 15047c478bd9Sstevel@tonic-gate /* 15057c478bd9Sstevel@tonic-gate * Can't compare with sets == NULL, since we don't add any 15067c478bd9Sstevel@tonic-gate * sets for un-ordered messages. 15077c478bd9Sstevel@tonic-gate */ 15087c478bd9Sstevel@tonic-gate if (meta == meta_head) 15097c478bd9Sstevel@tonic-gate return; 15107c478bd9Sstevel@tonic-gate *nmp = sctp_make_ftsn_chunk(sctp, fp, sets, nsets, *seglen); 15117c478bd9Sstevel@tonic-gate sctp_free_ftsn_set(sets); 15127c478bd9Sstevel@tonic-gate if (*nmp == NULL) 15137c478bd9Sstevel@tonic-gate return; 15147c478bd9Sstevel@tonic-gate if (sctp->sctp_ftsn == sctp->sctp_lastacked + 1) { 15157c478bd9Sstevel@tonic-gate sacklen = 0; 15167c478bd9Sstevel@tonic-gate } else { 15177c478bd9Sstevel@tonic-gate sacklen = sizeof (sctp_chunk_hdr_t) + 15187c478bd9Sstevel@tonic-gate sizeof (sctp_sack_chunk_t) + 15197c478bd9Sstevel@tonic-gate (sizeof (sctp_sack_frag_t) * sctp->sctp_sack_gaps); 1520*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (*seglen + sacklen > sctp->sctp_lastdata->sf_pmss) { 15217c478bd9Sstevel@tonic-gate /* piggybacked SACK doesn't fit */ 15227c478bd9Sstevel@tonic-gate sacklen = 0; 15237c478bd9Sstevel@tonic-gate } else { 15247c478bd9Sstevel@tonic-gate fp = sctp->sctp_lastdata; 15257c478bd9Sstevel@tonic-gate } 15267c478bd9Sstevel@tonic-gate } 1527df19b344Svi head = sctp_add_proto_hdr(sctp, fp, *nmp, sacklen, NULL); 15287c478bd9Sstevel@tonic-gate if (head == NULL) { 15297c478bd9Sstevel@tonic-gate freemsg(*nmp); 15307c478bd9Sstevel@tonic-gate *nmp = NULL; 1531f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_send_ftsn_failed); 15327c478bd9Sstevel@tonic-gate return; 15337c478bd9Sstevel@tonic-gate } 15347c478bd9Sstevel@tonic-gate *seglen += sacklen; 15357c478bd9Sstevel@tonic-gate *nmp = head; 15367c478bd9Sstevel@tonic-gate 15377c478bd9Sstevel@tonic-gate /* 15387c478bd9Sstevel@tonic-gate * XXXNeed to optimise this, the reason it is done here is so 15397c478bd9Sstevel@tonic-gate * that we don't have to undo in case of failure. 15407c478bd9Sstevel@tonic-gate */ 15417c478bd9Sstevel@tonic-gate mp1 = mp_head; 15427c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 15437c478bd9Sstevel@tonic-gate while (meta_head != NULL && 15447c478bd9Sstevel@tonic-gate SEQ_GEQ(sctp->sctp_adv_pap, ntohl(sdc->sdh_tsn))) { 15457c478bd9Sstevel@tonic-gate if (!SCTP_IS_MSG_ABANDONED(meta_head)) 15467c478bd9Sstevel@tonic-gate SCTP_MSG_SET_ABANDONED(meta_head); 15477c478bd9Sstevel@tonic-gate while (mp1 != NULL && SCTP_CHUNK_ISSENT(mp1)) { 15487c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 15497c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISACKED(mp1)) { 15507c478bd9Sstevel@tonic-gate clen = ntohs(sdc->sdh_len) - sizeof (*sdc); 15517c478bd9Sstevel@tonic-gate SCTP_CHUNK_SENT(sctp, mp1, sdc, fp, clen, 15527c478bd9Sstevel@tonic-gate meta_head); 15537c478bd9Sstevel@tonic-gate } 15547c478bd9Sstevel@tonic-gate mp1 = mp1->b_next; 15557c478bd9Sstevel@tonic-gate } 15567c478bd9Sstevel@tonic-gate while (mp1 != NULL) { 15577c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 15587c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ABANDONED(mp1)) { 15597c478bd9Sstevel@tonic-gate ASSERT(!SCTP_CHUNK_ISSENT(mp1)); 15607c478bd9Sstevel@tonic-gate unsent += ntohs(sdc->sdh_len) - sizeof (*sdc); 15617c478bd9Sstevel@tonic-gate SCTP_ABANDON_CHUNK(mp1); 15627c478bd9Sstevel@tonic-gate } 15637c478bd9Sstevel@tonic-gate mp1 = mp1->b_next; 15647c478bd9Sstevel@tonic-gate } 15657c478bd9Sstevel@tonic-gate meta_head = meta_head->b_next; 15667c478bd9Sstevel@tonic-gate if (meta_head != NULL) { 15677c478bd9Sstevel@tonic-gate mp1 = meta_head->b_cont; 15687c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp1)) 15697c478bd9Sstevel@tonic-gate break; 15707c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp1->b_rptr; 15717c478bd9Sstevel@tonic-gate } 15727c478bd9Sstevel@tonic-gate } 15737c478bd9Sstevel@tonic-gate if (unsent > 0) { 15747c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_unsent >= unsent); 15757c478bd9Sstevel@tonic-gate sctp->sctp_unsent -= unsent; 15767c478bd9Sstevel@tonic-gate /* 15777c478bd9Sstevel@tonic-gate * Update ULP the amount of queued data, which is 15787c478bd9Sstevel@tonic-gate * sent-unack'ed + unsent. 15797c478bd9Sstevel@tonic-gate */ 15800f1702c5SYu Xiangning if (!SCTP_IS_DETACHED(sctp)) 15810f1702c5SYu Xiangning SCTP_TXQ_UPDATE(sctp); 15827c478bd9Sstevel@tonic-gate } 15837c478bd9Sstevel@tonic-gate } 15847c478bd9Sstevel@tonic-gate 15857c478bd9Sstevel@tonic-gate /* 15867c478bd9Sstevel@tonic-gate * This function steps through messages starting at meta and checks if 15877c478bd9Sstevel@tonic-gate * the message is abandoned. It stops when it hits an unsent chunk or 15887c478bd9Sstevel@tonic-gate * a message that has all its chunk acked. This is the only place 15897c478bd9Sstevel@tonic-gate * where the sctp_adv_pap is moved forward to indicated abandoned 15907c478bd9Sstevel@tonic-gate * messages. 15917c478bd9Sstevel@tonic-gate */ 15927c478bd9Sstevel@tonic-gate void 15937c478bd9Sstevel@tonic-gate sctp_check_adv_ack_pt(sctp_t *sctp, mblk_t *meta, mblk_t *mp) 15947c478bd9Sstevel@tonic-gate { 15957c478bd9Sstevel@tonic-gate uint32_t tsn = sctp->sctp_adv_pap; 15967c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 15977c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *msg_hdr; 15987c478bd9Sstevel@tonic-gate 15997c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 16007c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 16017c478bd9Sstevel@tonic-gate ASSERT(SEQ_GT(ntohl(sdc->sdh_tsn), sctp->sctp_lastack_rxd)); 16027c478bd9Sstevel@tonic-gate msg_hdr = (sctp_msg_hdr_t *)meta->b_rptr; 16037c478bd9Sstevel@tonic-gate if (!SCTP_IS_MSG_ABANDONED(meta) && 16047c478bd9Sstevel@tonic-gate !SCTP_MSG_TO_BE_ABANDONED(meta, msg_hdr, sctp)) { 16057c478bd9Sstevel@tonic-gate return; 16067c478bd9Sstevel@tonic-gate } 16077c478bd9Sstevel@tonic-gate while (meta != NULL) { 16087c478bd9Sstevel@tonic-gate while (mp != NULL && SCTP_CHUNK_ISSENT(mp)) { 16097c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 16107c478bd9Sstevel@tonic-gate tsn = ntohl(sdc->sdh_tsn); 16117c478bd9Sstevel@tonic-gate mp = mp->b_next; 16127c478bd9Sstevel@tonic-gate } 16137c478bd9Sstevel@tonic-gate if (mp != NULL) 16147c478bd9Sstevel@tonic-gate break; 16157c478bd9Sstevel@tonic-gate /* 16167c478bd9Sstevel@tonic-gate * We continue checking for successive messages only if there 16177c478bd9Sstevel@tonic-gate * is a chunk marked for retransmission. Else, we might 16187c478bd9Sstevel@tonic-gate * end up sending FTSN prematurely for chunks that have been 16197c478bd9Sstevel@tonic-gate * sent, but not yet acked. 16207c478bd9Sstevel@tonic-gate */ 16217c478bd9Sstevel@tonic-gate if ((meta = meta->b_next) != NULL) { 16227c478bd9Sstevel@tonic-gate msg_hdr = (sctp_msg_hdr_t *)meta->b_rptr; 16237c478bd9Sstevel@tonic-gate if (!SCTP_IS_MSG_ABANDONED(meta) && 16247c478bd9Sstevel@tonic-gate !SCTP_MSG_TO_BE_ABANDONED(meta, msg_hdr, sctp)) { 16257c478bd9Sstevel@tonic-gate break; 16267c478bd9Sstevel@tonic-gate } 16277c478bd9Sstevel@tonic-gate for (mp = meta->b_cont; mp != NULL; mp = mp->b_next) { 16287c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp)) { 16297c478bd9Sstevel@tonic-gate sctp->sctp_adv_pap = tsn; 16307c478bd9Sstevel@tonic-gate return; 16317c478bd9Sstevel@tonic-gate } 16327c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_WANT_REXMIT(mp)) 16337c478bd9Sstevel@tonic-gate break; 16347c478bd9Sstevel@tonic-gate } 16357c478bd9Sstevel@tonic-gate if (mp == NULL) 16367c478bd9Sstevel@tonic-gate break; 16377c478bd9Sstevel@tonic-gate } 16387c478bd9Sstevel@tonic-gate } 16397c478bd9Sstevel@tonic-gate sctp->sctp_adv_pap = tsn; 16407c478bd9Sstevel@tonic-gate } 16417c478bd9Sstevel@tonic-gate 164277c67f2fSkcpoon 164377c67f2fSkcpoon /* 164477c67f2fSkcpoon * Determine if we should bundle a data chunk with the chunk being 164577c67f2fSkcpoon * retransmitted. We bundle if 164677c67f2fSkcpoon * 164777c67f2fSkcpoon * - the chunk is sent to the same destination and unack'ed. 164877c67f2fSkcpoon * 164977c67f2fSkcpoon * OR 165077c67f2fSkcpoon * 165177c67f2fSkcpoon * - the chunk is unsent, i.e. new data. 165277c67f2fSkcpoon */ 165377c67f2fSkcpoon #define SCTP_CHUNK_RX_CANBUNDLE(mp, fp) \ 165477c67f2fSkcpoon (!SCTP_CHUNK_ABANDONED((mp)) && \ 165577c67f2fSkcpoon ((SCTP_CHUNK_ISSENT((mp)) && (SCTP_CHUNK_DEST(mp) == (fp) && \ 165677c67f2fSkcpoon !SCTP_CHUNK_ISACKED(mp))) || \ 165777c67f2fSkcpoon (((mp)->b_flag & (SCTP_CHUNK_FLAG_REXMIT|SCTP_CHUNK_FLAG_SENT)) != \ 165877c67f2fSkcpoon SCTP_CHUNK_FLAG_SENT))) 165977c67f2fSkcpoon 16607c478bd9Sstevel@tonic-gate /* 16617c478bd9Sstevel@tonic-gate * Retransmit first segment which hasn't been acked with cumtsn or send 16627c478bd9Sstevel@tonic-gate * a Forward TSN chunk, if appropriate. 16637c478bd9Sstevel@tonic-gate */ 16647c478bd9Sstevel@tonic-gate void 16657c478bd9Sstevel@tonic-gate sctp_rexmit(sctp_t *sctp, sctp_faddr_t *oldfp) 16667c478bd9Sstevel@tonic-gate { 16677c478bd9Sstevel@tonic-gate mblk_t *mp; 16687c478bd9Sstevel@tonic-gate mblk_t *nmp = NULL; 16697c478bd9Sstevel@tonic-gate mblk_t *head; 16707c478bd9Sstevel@tonic-gate mblk_t *meta = sctp->sctp_xmit_head; 16717c478bd9Sstevel@tonic-gate mblk_t *fill; 16727c478bd9Sstevel@tonic-gate uint32_t seglen = 0; 16737c478bd9Sstevel@tonic-gate uint32_t sacklen; 16747c478bd9Sstevel@tonic-gate uint16_t chunklen; 16757c478bd9Sstevel@tonic-gate int extra; 16767c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 16777c478bd9Sstevel@tonic-gate sctp_faddr_t *fp; 16787c478bd9Sstevel@tonic-gate uint32_t adv_pap = sctp->sctp_adv_pap; 16797c478bd9Sstevel@tonic-gate boolean_t do_ftsn = B_FALSE; 16807c478bd9Sstevel@tonic-gate boolean_t ftsn_check = B_TRUE; 168177c67f2fSkcpoon uint32_t first_ua_tsn; 168277c67f2fSkcpoon sctp_msg_hdr_t *mhdr; 1683f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 16842dd25cf1SGeorge Shepherd int error; 16857c478bd9Sstevel@tonic-gate 16867c478bd9Sstevel@tonic-gate while (meta != NULL) { 16877c478bd9Sstevel@tonic-gate for (mp = meta->b_cont; mp != NULL; mp = mp->b_next) { 16887c478bd9Sstevel@tonic-gate uint32_t tsn; 16897c478bd9Sstevel@tonic-gate 16907c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp)) 16917c478bd9Sstevel@tonic-gate goto window_probe; 16927c478bd9Sstevel@tonic-gate /* 16937c478bd9Sstevel@tonic-gate * We break in the following cases - 16947c478bd9Sstevel@tonic-gate * 16957c478bd9Sstevel@tonic-gate * if the advanced peer ack point includes the next 16967c478bd9Sstevel@tonic-gate * chunk to be retransmited - possibly the Forward 16977c478bd9Sstevel@tonic-gate * TSN was lost. 16987c478bd9Sstevel@tonic-gate * 16997c478bd9Sstevel@tonic-gate * if we are PRSCTP aware and the next chunk to be 17007c478bd9Sstevel@tonic-gate * retransmitted is now abandoned 17017c478bd9Sstevel@tonic-gate * 17027c478bd9Sstevel@tonic-gate * if the next chunk to be retransmitted is for 17037c478bd9Sstevel@tonic-gate * the dest on which the timer went off. (this 17047c478bd9Sstevel@tonic-gate * message is not abandoned). 17057c478bd9Sstevel@tonic-gate * 17067c478bd9Sstevel@tonic-gate * We check for Forward TSN only for the first 17077c478bd9Sstevel@tonic-gate * eligible chunk to be retransmitted. The reason 17087c478bd9Sstevel@tonic-gate * being if the first eligible chunk is skipped (say 17097c478bd9Sstevel@tonic-gate * it was sent to a destination other than oldfp) 17107c478bd9Sstevel@tonic-gate * then we cannot advance the cum TSN via Forward 17117c478bd9Sstevel@tonic-gate * TSN chunk. 17127c478bd9Sstevel@tonic-gate * 17137c478bd9Sstevel@tonic-gate * Also, ftsn_check is B_TRUE only for the first 17147c478bd9Sstevel@tonic-gate * eligible chunk, it will be B_FALSE for all 17157c478bd9Sstevel@tonic-gate * subsequent candidate messages for retransmission. 17167c478bd9Sstevel@tonic-gate */ 17177c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 17187c478bd9Sstevel@tonic-gate tsn = ntohl(sdc->sdh_tsn); 17197c478bd9Sstevel@tonic-gate if (SEQ_GT(tsn, sctp->sctp_lastack_rxd)) { 17207c478bd9Sstevel@tonic-gate if (sctp->sctp_prsctp_aware && ftsn_check) { 17217c478bd9Sstevel@tonic-gate if (SEQ_GEQ(sctp->sctp_adv_pap, tsn)) { 17227c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_prsctp_aware); 17237c478bd9Sstevel@tonic-gate do_ftsn = B_TRUE; 17247c478bd9Sstevel@tonic-gate goto out; 17257c478bd9Sstevel@tonic-gate } else { 17267c478bd9Sstevel@tonic-gate sctp_check_adv_ack_pt(sctp, 17277c478bd9Sstevel@tonic-gate meta, mp); 17287c478bd9Sstevel@tonic-gate if (SEQ_GT(sctp->sctp_adv_pap, 17297c478bd9Sstevel@tonic-gate adv_pap)) { 17307c478bd9Sstevel@tonic-gate do_ftsn = B_TRUE; 17317c478bd9Sstevel@tonic-gate goto out; 17327c478bd9Sstevel@tonic-gate } 17337c478bd9Sstevel@tonic-gate } 17347c478bd9Sstevel@tonic-gate ftsn_check = B_FALSE; 17357c478bd9Sstevel@tonic-gate } 17367c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_DEST(mp) == oldfp) 17377c478bd9Sstevel@tonic-gate goto out; 17387c478bd9Sstevel@tonic-gate } 17397c478bd9Sstevel@tonic-gate } 17407c478bd9Sstevel@tonic-gate meta = meta->b_next; 17417c478bd9Sstevel@tonic-gate if (meta != NULL && sctp->sctp_prsctp_aware) { 174277c67f2fSkcpoon mhdr = (sctp_msg_hdr_t *)meta->b_rptr; 17437c478bd9Sstevel@tonic-gate 17447c478bd9Sstevel@tonic-gate while (meta != NULL && (SCTP_IS_MSG_ABANDONED(meta) || 17457c478bd9Sstevel@tonic-gate SCTP_MSG_TO_BE_ABANDONED(meta, mhdr, sctp))) { 17467c478bd9Sstevel@tonic-gate meta = meta->b_next; 17477c478bd9Sstevel@tonic-gate } 17487c478bd9Sstevel@tonic-gate } 17497c478bd9Sstevel@tonic-gate } 17507c478bd9Sstevel@tonic-gate window_probe: 17517c478bd9Sstevel@tonic-gate /* 17527c478bd9Sstevel@tonic-gate * Retransmit fired for a destination which didn't have 17537c478bd9Sstevel@tonic-gate * any unacked data pending. 17547c478bd9Sstevel@tonic-gate */ 1755769b977dSvi if (sctp->sctp_unacked == 0 && sctp->sctp_unsent != 0) { 17567c478bd9Sstevel@tonic-gate /* 17577c478bd9Sstevel@tonic-gate * Send a window probe. Inflate frwnd to allow 17587c478bd9Sstevel@tonic-gate * sending one segment. 17597c478bd9Sstevel@tonic-gate */ 1760*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (sctp->sctp_frwnd < (oldfp->sf_pmss - sizeof (*sdc))) 1761*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp->sctp_frwnd = oldfp->sf_pmss - sizeof (*sdc); 176212f47623Skcpoon 1763769b977dSvi /* next TSN to send */ 1764769b977dSvi sctp->sctp_rxt_nxttsn = sctp->sctp_ltsn; 176512f47623Skcpoon 176612f47623Skcpoon /* 176712f47623Skcpoon * The above sctp_frwnd adjustment is coarse. The "changed" 176812f47623Skcpoon * sctp_frwnd may allow us to send more than 1 packet. So 176912f47623Skcpoon * tell sctp_output() to send only 1 packet. 177012f47623Skcpoon */ 177112f47623Skcpoon sctp_output(sctp, 1); 177212f47623Skcpoon 1773769b977dSvi /* Last sent TSN */ 1774769b977dSvi sctp->sctp_rxt_maxtsn = sctp->sctp_ltsn - 1; 1775769b977dSvi ASSERT(sctp->sctp_rxt_maxtsn >= sctp->sctp_rxt_nxttsn); 1776769b977dSvi sctp->sctp_zero_win_probe = B_TRUE; 17775dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpOutWinProbe); 17787c478bd9Sstevel@tonic-gate } 17797c478bd9Sstevel@tonic-gate return; 17807c478bd9Sstevel@tonic-gate out: 1781769b977dSvi /* 178212f47623Skcpoon * After a time out, assume that everything has left the network. So 178312f47623Skcpoon * we can clear rxt_unacked for the original peer address. 178412f47623Skcpoon */ 1785*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India oldfp->sf_rxt_unacked = 0; 178612f47623Skcpoon 178712f47623Skcpoon /* 178812f47623Skcpoon * If we were probing for zero window, don't adjust retransmission 1789769b977dSvi * variables, but the timer is still backed off. 1790769b977dSvi */ 1791769b977dSvi if (sctp->sctp_zero_win_probe) { 1792769b977dSvi mblk_t *pkt; 1793769b977dSvi uint_t pkt_len; 1794769b977dSvi 1795769b977dSvi /* 1796769b977dSvi * Get the Zero Win Probe for retrasmission, sctp_rxt_nxttsn 1797769b977dSvi * and sctp_rxt_maxtsn will specify the ZWP packet. 1798769b977dSvi */ 1799769b977dSvi fp = oldfp; 1800*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (oldfp->sf_state != SCTP_FADDRS_ALIVE) 1801769b977dSvi fp = sctp_rotate_faddr(sctp, oldfp); 1802769b977dSvi pkt = sctp_rexmit_packet(sctp, &meta, &mp, fp, &pkt_len); 1803769b977dSvi if (pkt != NULL) { 1804*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India ASSERT(pkt_len <= fp->sf_pmss); 1805*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp_set_iplen(sctp, pkt, fp->sf_ixa); 1806*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India (void) conn_ip_output(pkt, fp->sf_ixa); 1807bd670b35SErik Nordmark BUMP_LOCAL(sctp->sctp_opkts); 1808769b977dSvi } else { 1809f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_ss_rexmit_failed); 1810769b977dSvi } 181112f47623Skcpoon 181212f47623Skcpoon /* 181312f47623Skcpoon * The strikes will be clear by sctp_faddr_alive() when the 181412f47623Skcpoon * other side sends us an ack. 181512f47623Skcpoon */ 1816*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India oldfp->sf_strikes++; 1817769b977dSvi sctp->sctp_strikes++; 181812f47623Skcpoon 1819fd7b5aedSGeorge Shepherd SCTP_CALC_RXT(sctp, oldfp, sctp->sctp_rto_max); 1820*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (oldfp != fp && oldfp->sf_suna != 0) 1821*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India SCTP_FADDR_TIMER_RESTART(sctp, oldfp, fp->sf_rto); 1822*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->sf_rto); 18235dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpOutWinProbe); 1824769b977dSvi return; 1825769b977dSvi } 1826769b977dSvi 18277c478bd9Sstevel@tonic-gate /* 18287c478bd9Sstevel@tonic-gate * Enter slowstart for this destination 18297c478bd9Sstevel@tonic-gate */ 1830*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India oldfp->sf_ssthresh = oldfp->sf_cwnd / 2; 1831*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (oldfp->sf_ssthresh < 2 * oldfp->sf_pmss) 1832*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India oldfp->sf_ssthresh = 2 * oldfp->sf_pmss; 1833*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India oldfp->sf_cwnd = oldfp->sf_pmss; 1834*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India oldfp->sf_pba = 0; 18357c478bd9Sstevel@tonic-gate fp = sctp_rotate_faddr(sctp, oldfp); 18367c478bd9Sstevel@tonic-gate ASSERT(fp != NULL); 18377c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 18387c478bd9Sstevel@tonic-gate 183977c67f2fSkcpoon first_ua_tsn = ntohl(sdc->sdh_tsn); 18407c478bd9Sstevel@tonic-gate if (do_ftsn) { 18417c478bd9Sstevel@tonic-gate sctp_make_ftsns(sctp, meta, mp, &nmp, fp, &seglen); 18427c478bd9Sstevel@tonic-gate if (nmp == NULL) { 18437c478bd9Sstevel@tonic-gate sctp->sctp_adv_pap = adv_pap; 18447c478bd9Sstevel@tonic-gate goto restart_timer; 18457c478bd9Sstevel@tonic-gate } 18467c478bd9Sstevel@tonic-gate head = nmp; 184777c67f2fSkcpoon /* 184877c67f2fSkcpoon * Move to the next unabandoned chunk. XXXCheck if meta will 184977c67f2fSkcpoon * always be marked abandoned. 185077c67f2fSkcpoon */ 185177c67f2fSkcpoon while (meta != NULL && SCTP_IS_MSG_ABANDONED(meta)) 185277c67f2fSkcpoon meta = meta->b_next; 18537c478bd9Sstevel@tonic-gate if (meta != NULL) 185477c67f2fSkcpoon mp = mp->b_cont; 185577c67f2fSkcpoon else 185677c67f2fSkcpoon mp = NULL; 18577c478bd9Sstevel@tonic-gate goto try_bundle; 18587c478bd9Sstevel@tonic-gate } 18597c478bd9Sstevel@tonic-gate seglen = ntohs(sdc->sdh_len); 18607c478bd9Sstevel@tonic-gate chunklen = seglen - sizeof (*sdc); 18617c478bd9Sstevel@tonic-gate if ((extra = seglen & (SCTP_ALIGN - 1)) != 0) 18627c478bd9Sstevel@tonic-gate extra = SCTP_ALIGN - extra; 18637c478bd9Sstevel@tonic-gate 186477c67f2fSkcpoon /* Find out if we need to piggyback SACK. */ 18657c478bd9Sstevel@tonic-gate if (sctp->sctp_ftsn == sctp->sctp_lastacked + 1) { 18667c478bd9Sstevel@tonic-gate sacklen = 0; 18677c478bd9Sstevel@tonic-gate } else { 18687c478bd9Sstevel@tonic-gate sacklen = sizeof (sctp_chunk_hdr_t) + 18697c478bd9Sstevel@tonic-gate sizeof (sctp_sack_chunk_t) + 18707c478bd9Sstevel@tonic-gate (sizeof (sctp_sack_frag_t) * sctp->sctp_sack_gaps); 1871*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (seglen + sacklen > sctp->sctp_lastdata->sf_pmss) { 18727c478bd9Sstevel@tonic-gate /* piggybacked SACK doesn't fit */ 18737c478bd9Sstevel@tonic-gate sacklen = 0; 18747c478bd9Sstevel@tonic-gate } else { 187577c67f2fSkcpoon /* 187677c67f2fSkcpoon * OK, we have room to send SACK back. But we 187777c67f2fSkcpoon * should send it back to the last fp where we 187877c67f2fSkcpoon * receive data from, unless sctp_lastdata equals 187977c67f2fSkcpoon * oldfp, then we should probably not send it 188077c67f2fSkcpoon * back to that fp. Also we should check that 188177c67f2fSkcpoon * the fp is alive. 188277c67f2fSkcpoon */ 188377c67f2fSkcpoon if (sctp->sctp_lastdata != oldfp && 1884*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp->sctp_lastdata->sf_state == 1885*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India SCTP_FADDRS_ALIVE) { 188677c67f2fSkcpoon fp = sctp->sctp_lastdata; 188777c67f2fSkcpoon } 18887c478bd9Sstevel@tonic-gate } 18897c478bd9Sstevel@tonic-gate } 18907c478bd9Sstevel@tonic-gate 189177c67f2fSkcpoon /* 189277c67f2fSkcpoon * Cancel RTT measurement if the retransmitted TSN is before the 189377c67f2fSkcpoon * TSN used for timimg. 189477c67f2fSkcpoon */ 189577c67f2fSkcpoon if (sctp->sctp_out_time != 0 && 189677c67f2fSkcpoon SEQ_GEQ(sctp->sctp_rtt_tsn, sdc->sdh_tsn)) { 189777c67f2fSkcpoon sctp->sctp_out_time = 0; 189877c67f2fSkcpoon } 189977c67f2fSkcpoon /* Clear the counter as the RTT calculation may be off. */ 1900*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_rtt_updates = 0; 1901*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India oldfp->sf_rtt_updates = 0; 190277c67f2fSkcpoon 190377c67f2fSkcpoon /* 190477c67f2fSkcpoon * After a timeout, we should change the current faddr so that 190577c67f2fSkcpoon * new chunks will be sent to the alternate address. 190677c67f2fSkcpoon */ 190777c67f2fSkcpoon sctp_set_faddr_current(sctp, fp); 190877c67f2fSkcpoon 19097c478bd9Sstevel@tonic-gate nmp = dupmsg(mp); 19107c478bd9Sstevel@tonic-gate if (nmp == NULL) 19117c478bd9Sstevel@tonic-gate goto restart_timer; 19127c478bd9Sstevel@tonic-gate if (extra > 0) { 1913121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 19147c478bd9Sstevel@tonic-gate if (fill != NULL) { 19157c478bd9Sstevel@tonic-gate linkb(nmp, fill); 19167c478bd9Sstevel@tonic-gate seglen += extra; 19177c478bd9Sstevel@tonic-gate } else { 19187c478bd9Sstevel@tonic-gate freemsg(nmp); 19197c478bd9Sstevel@tonic-gate goto restart_timer; 19207c478bd9Sstevel@tonic-gate } 19217c478bd9Sstevel@tonic-gate } 19227c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_FLAGS(nmp); 1923df19b344Svi head = sctp_add_proto_hdr(sctp, fp, nmp, sacklen, NULL); 19247c478bd9Sstevel@tonic-gate if (head == NULL) { 19257c478bd9Sstevel@tonic-gate freemsg(nmp); 1926f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_rexmit_failed); 19277c478bd9Sstevel@tonic-gate goto restart_timer; 19287c478bd9Sstevel@tonic-gate } 19297c478bd9Sstevel@tonic-gate seglen += sacklen; 19307c478bd9Sstevel@tonic-gate 19317c478bd9Sstevel@tonic-gate SCTP_CHUNK_SENT(sctp, mp, sdc, fp, chunklen, meta); 19327c478bd9Sstevel@tonic-gate 19337c478bd9Sstevel@tonic-gate mp = mp->b_next; 193477c67f2fSkcpoon 19357c478bd9Sstevel@tonic-gate try_bundle: 193612f47623Skcpoon /* We can at least and at most send 1 packet at timeout. */ 1937*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India while (seglen < fp->sf_pmss) { 19387c478bd9Sstevel@tonic-gate int32_t new_len; 19397c478bd9Sstevel@tonic-gate 194077c67f2fSkcpoon /* Go through the list to find more chunks to be bundled. */ 19417c478bd9Sstevel@tonic-gate while (mp != NULL) { 194277c67f2fSkcpoon /* Check if the chunk can be bundled. */ 194377c67f2fSkcpoon if (SCTP_CHUNK_RX_CANBUNDLE(mp, oldfp)) 19447c478bd9Sstevel@tonic-gate break; 19457c478bd9Sstevel@tonic-gate mp = mp->b_next; 19467c478bd9Sstevel@tonic-gate } 194777c67f2fSkcpoon /* Go to the next message. */ 19487c478bd9Sstevel@tonic-gate if (mp == NULL) { 194977c67f2fSkcpoon for (meta = meta->b_next; meta != NULL; 195077c67f2fSkcpoon meta = meta->b_next) { 195177c67f2fSkcpoon mhdr = (sctp_msg_hdr_t *)meta->b_rptr; 195277c67f2fSkcpoon 195377c67f2fSkcpoon if (SCTP_IS_MSG_ABANDONED(meta) || 195477c67f2fSkcpoon SCTP_MSG_TO_BE_ABANDONED(meta, mhdr, 195577c67f2fSkcpoon sctp)) { 195677c67f2fSkcpoon continue; 195777c67f2fSkcpoon } 195877c67f2fSkcpoon 195977c67f2fSkcpoon mp = meta->b_cont; 196077c67f2fSkcpoon goto try_bundle; 196177c67f2fSkcpoon } 19622dd25cf1SGeorge Shepherd /* 19632dd25cf1SGeorge Shepherd * Check if there is a new message which potentially 19642dd25cf1SGeorge Shepherd * could be bundled with this retransmission. 19652dd25cf1SGeorge Shepherd */ 19662dd25cf1SGeorge Shepherd meta = sctp_get_msg_to_send(sctp, &mp, NULL, &error, 1967*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India seglen, fp->sf_pmss - seglen, NULL); 19682dd25cf1SGeorge Shepherd if (error != 0 || meta == NULL) { 19692dd25cf1SGeorge Shepherd /* No more chunk to be bundled. */ 19702dd25cf1SGeorge Shepherd break; 19712dd25cf1SGeorge Shepherd } else { 19722dd25cf1SGeorge Shepherd goto try_bundle; 19732dd25cf1SGeorge Shepherd } 19747c478bd9Sstevel@tonic-gate } 197577c67f2fSkcpoon 19767c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 197777c67f2fSkcpoon new_len = ntohs(sdc->sdh_len); 197877c67f2fSkcpoon chunklen = new_len - sizeof (*sdc); 19797c478bd9Sstevel@tonic-gate 198077c67f2fSkcpoon if ((extra = new_len & (SCTP_ALIGN - 1)) != 0) 198177c67f2fSkcpoon extra = SCTP_ALIGN - extra; 1982*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if ((new_len = seglen + new_len + extra) > fp->sf_pmss) 198377c67f2fSkcpoon break; 198477c67f2fSkcpoon if ((nmp = dupmsg(mp)) == NULL) 198577c67f2fSkcpoon break; 19867c478bd9Sstevel@tonic-gate 198777c67f2fSkcpoon if (extra > 0) { 1988121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 19897c478bd9Sstevel@tonic-gate if (fill != NULL) { 199077c67f2fSkcpoon linkb(nmp, fill); 19917c478bd9Sstevel@tonic-gate } else { 199277c67f2fSkcpoon freemsg(nmp); 19937c478bd9Sstevel@tonic-gate break; 19947c478bd9Sstevel@tonic-gate } 19957c478bd9Sstevel@tonic-gate } 199677c67f2fSkcpoon linkb(head, nmp); 19977c478bd9Sstevel@tonic-gate 19987c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_FLAGS(nmp); 19997c478bd9Sstevel@tonic-gate SCTP_CHUNK_SENT(sctp, mp, sdc, fp, chunklen, meta); 200077c67f2fSkcpoon 200177c67f2fSkcpoon seglen = new_len; 20027c478bd9Sstevel@tonic-gate mp = mp->b_next; 20037c478bd9Sstevel@tonic-gate } 200477c67f2fSkcpoon done_bundle: 2005*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if ((seglen > fp->sf_pmss) && fp->sf_isv4) { 20067c478bd9Sstevel@tonic-gate ipha_t *iph = (ipha_t *)head->b_rptr; 20077c478bd9Sstevel@tonic-gate 20087c478bd9Sstevel@tonic-gate /* 20097c478bd9Sstevel@tonic-gate * Path MTU is different from path we thought it would 20107c478bd9Sstevel@tonic-gate * be when we created chunks, or IP headers have grown. 20117c478bd9Sstevel@tonic-gate * Need to clear the DF bit. 20127c478bd9Sstevel@tonic-gate */ 20137c478bd9Sstevel@tonic-gate iph->ipha_fragment_offset_and_flags = 0; 20147c478bd9Sstevel@tonic-gate } 2015*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_rxt_unacked += seglen; 201612f47623Skcpoon 20177c478bd9Sstevel@tonic-gate dprint(2, ("sctp_rexmit: Sending packet %d bytes, tsn %x " 20187c478bd9Sstevel@tonic-gate "ssn %d to %p (rwnd %d, lastack_rxd %x)\n", 201945916cd2Sjpk seglen, ntohl(sdc->sdh_tsn), ntohs(sdc->sdh_ssn), 202045916cd2Sjpk (void *)fp, sctp->sctp_frwnd, sctp->sctp_lastack_rxd)); 20217c478bd9Sstevel@tonic-gate 202277c67f2fSkcpoon sctp->sctp_rexmitting = B_TRUE; 202377c67f2fSkcpoon sctp->sctp_rxt_nxttsn = first_ua_tsn; 202477c67f2fSkcpoon sctp->sctp_rxt_maxtsn = sctp->sctp_ltsn - 1; 2025*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp_set_iplen(sctp, head, fp->sf_ixa); 2026*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India (void) conn_ip_output(head, fp->sf_ixa); 2027bd670b35SErik Nordmark BUMP_LOCAL(sctp->sctp_opkts); 20287c478bd9Sstevel@tonic-gate 20297c478bd9Sstevel@tonic-gate /* 203077c67f2fSkcpoon * Restart the oldfp timer with exponential backoff and 203177c67f2fSkcpoon * the new fp timer for the retransmitted chunks. 20327c478bd9Sstevel@tonic-gate */ 20337c478bd9Sstevel@tonic-gate restart_timer: 2034*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India oldfp->sf_strikes++; 20357c478bd9Sstevel@tonic-gate sctp->sctp_strikes++; 2036fd7b5aedSGeorge Shepherd SCTP_CALC_RXT(sctp, oldfp, sctp->sctp_rto_max); 2037c31292eeSkcpoon /* 2038c31292eeSkcpoon * If there is still some data in the oldfp, restart the 2039c31292eeSkcpoon * retransmission timer. If there is no data, the heartbeat will 2040c31292eeSkcpoon * continue to run so it will do its job in checking the reachability 2041c31292eeSkcpoon * of the oldfp. 2042c31292eeSkcpoon */ 2043*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (oldfp != fp && oldfp->sf_suna != 0) 2044*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India SCTP_FADDR_TIMER_RESTART(sctp, oldfp, oldfp->sf_rto); 204577c67f2fSkcpoon 204677c67f2fSkcpoon /* 204777c67f2fSkcpoon * Should we restart the timer of the new fp? If there is 204877c67f2fSkcpoon * outstanding data to the new fp, the timer should be 204977c67f2fSkcpoon * running already. So restarting it means that the timer 205077c67f2fSkcpoon * will fire later for those outstanding data. But if 205177c67f2fSkcpoon * we don't restart it, the timer will fire too early for the 205277c67f2fSkcpoon * just retransmitted chunks to the new fp. The reason is that we 205377c67f2fSkcpoon * don't keep a timestamp on when a chunk is retransmitted. 205477c67f2fSkcpoon * So when the timer fires, it will just search for the 205577c67f2fSkcpoon * chunk with the earliest TSN sent to new fp. This probably 205677c67f2fSkcpoon * is the chunk we just retransmitted. So for now, let's 205777c67f2fSkcpoon * be conservative and restart the timer of the new fp. 205877c67f2fSkcpoon */ 2059*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->sf_rto); 2060c31292eeSkcpoon 2061d3d50737SRafael Vanoni sctp->sctp_active = ddi_get_lbolt64(); 20627c478bd9Sstevel@tonic-gate } 20637c478bd9Sstevel@tonic-gate 206477c67f2fSkcpoon /* 206577c67f2fSkcpoon * This function is called by sctp_ss_rexmit() to create a packet 206677c67f2fSkcpoon * to be retransmitted to the given fp. The given meta and mp 206777c67f2fSkcpoon * parameters are respectively the sctp_msg_hdr_t and the mblk of the 206812f47623Skcpoon * first chunk to be retransmitted. This is also called when we want 2069769b977dSvi * to retransmit a zero window probe from sctp_rexmit() or when we 2070769b977dSvi * want to retransmit the zero window probe after the window has 2071769b977dSvi * opened from sctp_got_sack(). 207277c67f2fSkcpoon */ 2073769b977dSvi mblk_t * 207477c67f2fSkcpoon sctp_rexmit_packet(sctp_t *sctp, mblk_t **meta, mblk_t **mp, sctp_faddr_t *fp, 207577c67f2fSkcpoon uint_t *packet_len) 207677c67f2fSkcpoon { 207777c67f2fSkcpoon uint32_t seglen = 0; 207877c67f2fSkcpoon uint16_t chunklen; 207977c67f2fSkcpoon int extra; 208077c67f2fSkcpoon mblk_t *nmp; 208177c67f2fSkcpoon mblk_t *head; 208277c67f2fSkcpoon mblk_t *fill; 208377c67f2fSkcpoon sctp_data_hdr_t *sdc; 208477c67f2fSkcpoon sctp_msg_hdr_t *mhdr; 208577c67f2fSkcpoon 208677c67f2fSkcpoon sdc = (sctp_data_hdr_t *)(*mp)->b_rptr; 208777c67f2fSkcpoon seglen = ntohs(sdc->sdh_len); 208877c67f2fSkcpoon chunklen = seglen - sizeof (*sdc); 208977c67f2fSkcpoon if ((extra = seglen & (SCTP_ALIGN - 1)) != 0) 209077c67f2fSkcpoon extra = SCTP_ALIGN - extra; 209177c67f2fSkcpoon 209277c67f2fSkcpoon nmp = dupmsg(*mp); 209377c67f2fSkcpoon if (nmp == NULL) 209477c67f2fSkcpoon return (NULL); 209577c67f2fSkcpoon if (extra > 0) { 2096121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 209777c67f2fSkcpoon if (fill != NULL) { 209877c67f2fSkcpoon linkb(nmp, fill); 209977c67f2fSkcpoon seglen += extra; 210077c67f2fSkcpoon } else { 210177c67f2fSkcpoon freemsg(nmp); 210277c67f2fSkcpoon return (NULL); 210377c67f2fSkcpoon } 210477c67f2fSkcpoon } 210577c67f2fSkcpoon SCTP_CHUNK_CLEAR_FLAGS(nmp); 210677c67f2fSkcpoon head = sctp_add_proto_hdr(sctp, fp, nmp, 0, NULL); 210777c67f2fSkcpoon if (head == NULL) { 210877c67f2fSkcpoon freemsg(nmp); 210977c67f2fSkcpoon return (NULL); 211077c67f2fSkcpoon } 211177c67f2fSkcpoon SCTP_CHUNK_SENT(sctp, *mp, sdc, fp, chunklen, *meta); 2112769b977dSvi /* 2113769b977dSvi * Don't update the TSN if we are doing a Zero Win Probe. 2114769b977dSvi */ 2115769b977dSvi if (!sctp->sctp_zero_win_probe) 2116769b977dSvi sctp->sctp_rxt_nxttsn = ntohl(sdc->sdh_tsn); 211777c67f2fSkcpoon *mp = (*mp)->b_next; 211877c67f2fSkcpoon 211977c67f2fSkcpoon try_bundle: 2120*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India while (seglen < fp->sf_pmss) { 212177c67f2fSkcpoon int32_t new_len; 212277c67f2fSkcpoon 212377c67f2fSkcpoon /* 212477c67f2fSkcpoon * Go through the list to find more chunks to be bundled. 212577c67f2fSkcpoon * We should only retransmit sent by unack'ed chunks. Since 212677c67f2fSkcpoon * they were sent before, the peer's receive window should 212777c67f2fSkcpoon * be able to receive them. 212877c67f2fSkcpoon */ 212977c67f2fSkcpoon while (*mp != NULL) { 213077c67f2fSkcpoon /* Check if the chunk can be bundled. */ 213177c67f2fSkcpoon if (SCTP_CHUNK_ISSENT(*mp) && !SCTP_CHUNK_ISACKED(*mp)) 213277c67f2fSkcpoon break; 213377c67f2fSkcpoon *mp = (*mp)->b_next; 213477c67f2fSkcpoon } 213577c67f2fSkcpoon /* Go to the next message. */ 213677c67f2fSkcpoon if (*mp == NULL) { 213777c67f2fSkcpoon for (*meta = (*meta)->b_next; *meta != NULL; 213877c67f2fSkcpoon *meta = (*meta)->b_next) { 213977c67f2fSkcpoon mhdr = (sctp_msg_hdr_t *)(*meta)->b_rptr; 214077c67f2fSkcpoon 214177c67f2fSkcpoon if (SCTP_IS_MSG_ABANDONED(*meta) || 214277c67f2fSkcpoon SCTP_MSG_TO_BE_ABANDONED(*meta, mhdr, 214377c67f2fSkcpoon sctp)) { 214477c67f2fSkcpoon continue; 214577c67f2fSkcpoon } 214677c67f2fSkcpoon 214777c67f2fSkcpoon *mp = (*meta)->b_cont; 214877c67f2fSkcpoon goto try_bundle; 214977c67f2fSkcpoon } 215077c67f2fSkcpoon /* No more chunk to be bundled. */ 215177c67f2fSkcpoon break; 215277c67f2fSkcpoon } 215377c67f2fSkcpoon 215477c67f2fSkcpoon sdc = (sctp_data_hdr_t *)(*mp)->b_rptr; 215577c67f2fSkcpoon /* Don't bundle chunks beyond sctp_rxt_maxtsn. */ 215677c67f2fSkcpoon if (SEQ_GT(ntohl(sdc->sdh_tsn), sctp->sctp_rxt_maxtsn)) 215777c67f2fSkcpoon break; 215877c67f2fSkcpoon new_len = ntohs(sdc->sdh_len); 215977c67f2fSkcpoon chunklen = new_len - sizeof (*sdc); 216077c67f2fSkcpoon 216177c67f2fSkcpoon if ((extra = new_len & (SCTP_ALIGN - 1)) != 0) 216277c67f2fSkcpoon extra = SCTP_ALIGN - extra; 2163*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if ((new_len = seglen + new_len + extra) > fp->sf_pmss) 216477c67f2fSkcpoon break; 216577c67f2fSkcpoon if ((nmp = dupmsg(*mp)) == NULL) 216677c67f2fSkcpoon break; 216777c67f2fSkcpoon 216877c67f2fSkcpoon if (extra > 0) { 2169121e5416Skcpoon fill = sctp_get_padding(sctp, extra); 217077c67f2fSkcpoon if (fill != NULL) { 217177c67f2fSkcpoon linkb(nmp, fill); 217277c67f2fSkcpoon } else { 217377c67f2fSkcpoon freemsg(nmp); 217477c67f2fSkcpoon break; 217577c67f2fSkcpoon } 217677c67f2fSkcpoon } 217777c67f2fSkcpoon linkb(head, nmp); 217877c67f2fSkcpoon 217977c67f2fSkcpoon SCTP_CHUNK_CLEAR_FLAGS(nmp); 218077c67f2fSkcpoon SCTP_CHUNK_SENT(sctp, *mp, sdc, fp, chunklen, *meta); 2181769b977dSvi /* 2182769b977dSvi * Don't update the TSN if we are doing a Zero Win Probe. 2183769b977dSvi */ 2184769b977dSvi if (!sctp->sctp_zero_win_probe) 2185769b977dSvi sctp->sctp_rxt_nxttsn = ntohl(sdc->sdh_tsn); 218677c67f2fSkcpoon 218777c67f2fSkcpoon seglen = new_len; 218877c67f2fSkcpoon *mp = (*mp)->b_next; 218977c67f2fSkcpoon } 219077c67f2fSkcpoon *packet_len = seglen; 2191*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_rxt_unacked += seglen; 219277c67f2fSkcpoon return (head); 219377c67f2fSkcpoon } 219477c67f2fSkcpoon 219577c67f2fSkcpoon /* 219677c67f2fSkcpoon * sctp_ss_rexmit() is called when we get a SACK after a timeout which 219777c67f2fSkcpoon * advances the cum_tsn but the cum_tsn is still less than what we have sent 219877c67f2fSkcpoon * (sctp_rxt_maxtsn) at the time of the timeout. This SACK is a "partial" 219977c67f2fSkcpoon * SACK. We retransmit unacked chunks without having to wait for another 220077c67f2fSkcpoon * timeout. The rationale is that the SACK should not be "partial" if all the 220177c67f2fSkcpoon * lost chunks have been retransmitted. Since the SACK is "partial," 220277c67f2fSkcpoon * the chunks between the cum_tsn and the sctp_rxt_maxtsn should still 220377c67f2fSkcpoon * be missing. It is better for us to retransmit them now instead 220477c67f2fSkcpoon * of waiting for a timeout. 220577c67f2fSkcpoon */ 220677c67f2fSkcpoon void 220777c67f2fSkcpoon sctp_ss_rexmit(sctp_t *sctp) 220877c67f2fSkcpoon { 220977c67f2fSkcpoon mblk_t *meta; 221077c67f2fSkcpoon mblk_t *mp; 221177c67f2fSkcpoon mblk_t *pkt; 221277c67f2fSkcpoon sctp_faddr_t *fp; 221377c67f2fSkcpoon uint_t pkt_len; 221477c67f2fSkcpoon uint32_t tot_wnd; 221577c67f2fSkcpoon sctp_data_hdr_t *sdc; 221677c67f2fSkcpoon int burst; 2217f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 221877c67f2fSkcpoon 2219769b977dSvi ASSERT(!sctp->sctp_zero_win_probe); 2220769b977dSvi 222177c67f2fSkcpoon /* 222277c67f2fSkcpoon * If the last cum ack is smaller than what we have just 222377c67f2fSkcpoon * retransmitted, simply return. 222477c67f2fSkcpoon */ 222577c67f2fSkcpoon if (SEQ_GEQ(sctp->sctp_lastack_rxd, sctp->sctp_rxt_nxttsn)) 222677c67f2fSkcpoon sctp->sctp_rxt_nxttsn = sctp->sctp_lastack_rxd + 1; 222777c67f2fSkcpoon else 222877c67f2fSkcpoon return; 222977c67f2fSkcpoon ASSERT(SEQ_LEQ(sctp->sctp_rxt_nxttsn, sctp->sctp_rxt_maxtsn)); 223077c67f2fSkcpoon 223177c67f2fSkcpoon /* 223277c67f2fSkcpoon * After a timer fires, sctp_current should be set to the new 223377c67f2fSkcpoon * fp where the retransmitted chunks are sent. 223477c67f2fSkcpoon */ 223577c67f2fSkcpoon fp = sctp->sctp_current; 223677c67f2fSkcpoon 223777c67f2fSkcpoon /* 223812f47623Skcpoon * Since we are retransmitting, we only need to use cwnd to determine 223912f47623Skcpoon * how much we can send as we were allowed (by peer's receive window) 224012f47623Skcpoon * to send those retransmitted chunks previously when they are first 224112f47623Skcpoon * sent. If we record how much we have retransmitted but 224212f47623Skcpoon * unacknowledged using rxt_unacked, then the amount we can now send 224312f47623Skcpoon * is equal to cwnd minus rxt_unacked. 224412f47623Skcpoon * 224512f47623Skcpoon * The field rxt_unacked is incremented when we retransmit a packet 224612f47623Skcpoon * and decremented when we got a SACK acknowledging something. And 224712f47623Skcpoon * it is reset when the retransmission timer fires as we assume that 224812f47623Skcpoon * all packets have left the network after a timeout. If this 224912f47623Skcpoon * assumption is not true, it means that after a timeout, we can 225012f47623Skcpoon * get a SACK acknowledging more than rxt_unacked (its value only 225112f47623Skcpoon * contains what is retransmitted when the timer fires). So 225212f47623Skcpoon * rxt_unacked will become very big (it is an unsiged int so going 225312f47623Skcpoon * negative means that the value is huge). This is the reason we 225412f47623Skcpoon * always send at least 1 MSS bytes. 225512f47623Skcpoon * 225612f47623Skcpoon * The reason why we do not have an accurate count is that we 225712f47623Skcpoon * only know how many packets are outstanding (using the TSN numbers). 225812f47623Skcpoon * But we do not know how many bytes those packets contain. To 225912f47623Skcpoon * have an accurate count, we need to walk through the send list. 226012f47623Skcpoon * As it is not really important to have an accurate count during 226112f47623Skcpoon * retransmission, we skip this walk to save some time. This should 226212f47623Skcpoon * not make the retransmission too aggressive to cause congestion. 226377c67f2fSkcpoon */ 2264*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp->sf_cwnd <= fp->sf_rxt_unacked) 2265*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India tot_wnd = fp->sf_pmss; 226677c67f2fSkcpoon else 2267*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India tot_wnd = fp->sf_cwnd - fp->sf_rxt_unacked; 226877c67f2fSkcpoon 226977c67f2fSkcpoon /* Find the first unack'ed chunk */ 227077c67f2fSkcpoon for (meta = sctp->sctp_xmit_head; meta != NULL; meta = meta->b_next) { 227177c67f2fSkcpoon sctp_msg_hdr_t *mhdr = (sctp_msg_hdr_t *)meta->b_rptr; 227277c67f2fSkcpoon 227377c67f2fSkcpoon if (SCTP_IS_MSG_ABANDONED(meta) || 227477c67f2fSkcpoon SCTP_MSG_TO_BE_ABANDONED(meta, mhdr, sctp)) { 227577c67f2fSkcpoon continue; 227677c67f2fSkcpoon } 227777c67f2fSkcpoon 227877c67f2fSkcpoon for (mp = meta->b_cont; mp != NULL; mp = mp->b_next) { 227977c67f2fSkcpoon /* Again, this may not be possible */ 228077c67f2fSkcpoon if (!SCTP_CHUNK_ISSENT(mp)) 228177c67f2fSkcpoon return; 228277c67f2fSkcpoon sdc = (sctp_data_hdr_t *)mp->b_rptr; 228377c67f2fSkcpoon if (ntohl(sdc->sdh_tsn) == sctp->sctp_rxt_nxttsn) 228477c67f2fSkcpoon goto found_msg; 228577c67f2fSkcpoon } 228677c67f2fSkcpoon } 228777c67f2fSkcpoon 228877c67f2fSkcpoon /* Everything is abandoned... */ 228977c67f2fSkcpoon return; 229077c67f2fSkcpoon 229177c67f2fSkcpoon found_msg: 2292*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (!fp->sf_timer_running) 2293*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->sf_rto); 229477c67f2fSkcpoon pkt = sctp_rexmit_packet(sctp, &meta, &mp, fp, &pkt_len); 229577c67f2fSkcpoon if (pkt == NULL) { 2296f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_ss_rexmit_failed); 229777c67f2fSkcpoon return; 229877c67f2fSkcpoon } 2299*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if ((pkt_len > fp->sf_pmss) && fp->sf_isv4) { 230077c67f2fSkcpoon ipha_t *iph = (ipha_t *)pkt->b_rptr; 230177c67f2fSkcpoon 230277c67f2fSkcpoon /* 230377c67f2fSkcpoon * Path MTU is different from path we thought it would 230477c67f2fSkcpoon * be when we created chunks, or IP headers have grown. 230577c67f2fSkcpoon * Need to clear the DF bit. 230677c67f2fSkcpoon */ 230777c67f2fSkcpoon iph->ipha_fragment_offset_and_flags = 0; 230877c67f2fSkcpoon } 2309*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp_set_iplen(sctp, pkt, fp->sf_ixa); 2310*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India (void) conn_ip_output(pkt, fp->sf_ixa); 2311bd670b35SErik Nordmark BUMP_LOCAL(sctp->sctp_opkts); 231277c67f2fSkcpoon 231377c67f2fSkcpoon /* Check and see if there is more chunk to be retransmitted. */ 2314*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (tot_wnd <= pkt_len || tot_wnd - pkt_len < fp->sf_pmss || 231577c67f2fSkcpoon meta == NULL) 231677c67f2fSkcpoon return; 231777c67f2fSkcpoon if (mp == NULL) 231877c67f2fSkcpoon meta = meta->b_next; 231977c67f2fSkcpoon if (meta == NULL) 232077c67f2fSkcpoon return; 232177c67f2fSkcpoon 232277c67f2fSkcpoon /* Retransmit another packet if the window allows. */ 2323f4b3ec61Sdh for (tot_wnd -= pkt_len, burst = sctps->sctps_maxburst - 1; 232477c67f2fSkcpoon meta != NULL && burst > 0; meta = meta->b_next, burst--) { 232577c67f2fSkcpoon if (mp == NULL) 232677c67f2fSkcpoon mp = meta->b_cont; 232777c67f2fSkcpoon for (; mp != NULL; mp = mp->b_next) { 232877c67f2fSkcpoon /* Again, this may not be possible */ 232977c67f2fSkcpoon if (!SCTP_CHUNK_ISSENT(mp)) 233077c67f2fSkcpoon return; 233177c67f2fSkcpoon if (!SCTP_CHUNK_ISACKED(mp)) 233277c67f2fSkcpoon goto found_msg; 233377c67f2fSkcpoon } 233477c67f2fSkcpoon } 233577c67f2fSkcpoon } 2336