1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/types.h> 30*0Sstevel@tonic-gate #include <sys/systm.h> 31*0Sstevel@tonic-gate #include <sys/stream.h> 32*0Sstevel@tonic-gate #include <sys/cmn_err.h> 33*0Sstevel@tonic-gate #include <sys/kmem.h> 34*0Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 35*0Sstevel@tonic-gate #include <sys/tihdr.h> 36*0Sstevel@tonic-gate #include <sys/socket.h> 37*0Sstevel@tonic-gate #include <sys/strsun.h> 38*0Sstevel@tonic-gate #include <sys/strsubr.h> 39*0Sstevel@tonic-gate 40*0Sstevel@tonic-gate #include <netinet/in.h> 41*0Sstevel@tonic-gate #include <netinet/ip6.h> 42*0Sstevel@tonic-gate #include <netinet/tcp_seq.h> 43*0Sstevel@tonic-gate #include <netinet/sctp.h> 44*0Sstevel@tonic-gate 45*0Sstevel@tonic-gate #include <inet/common.h> 46*0Sstevel@tonic-gate #include <inet/ip.h> 47*0Sstevel@tonic-gate #include <inet/ip6.h> 48*0Sstevel@tonic-gate #include <inet/mib2.h> 49*0Sstevel@tonic-gate #include <inet/ipclassifier.h> 50*0Sstevel@tonic-gate #include <inet/ipp_common.h> 51*0Sstevel@tonic-gate #include <inet/ipsec_impl.h> 52*0Sstevel@tonic-gate #include <inet/sctp_ip.h> 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate #include "sctp_impl.h" 55*0Sstevel@tonic-gate #include "sctp_asconf.h" 56*0Sstevel@tonic-gate #include "sctp_addr.h" 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate static struct kmem_cache *sctp_kmem_set_cache; 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate /* 61*0Sstevel@tonic-gate * PR-SCTP comments. 62*0Sstevel@tonic-gate * 63*0Sstevel@tonic-gate * When we get a valid Forward TSN chunk, we check the fragment list for this 64*0Sstevel@tonic-gate * SSN and preceeding SSNs free all them. Further, if this Forward TSN causes 65*0Sstevel@tonic-gate * the next expected SSN to be present in the stream queue, we deliver any 66*0Sstevel@tonic-gate * such stranded messages upstream. We also update the SACK info. appropriately. 67*0Sstevel@tonic-gate * When checking for advancing the cumulative ack (in sctp_cumack()) we must 68*0Sstevel@tonic-gate * check for abandoned chunks and messages. While traversing the tramsmit 69*0Sstevel@tonic-gate * list if we come across an abandoned chunk, we can skip the message (i.e. 70*0Sstevel@tonic-gate * take it out of the (re)transmit list) since this message, and hence this 71*0Sstevel@tonic-gate * chunk, has been marked abandoned by sctp_rexmit(). If we come across an 72*0Sstevel@tonic-gate * unsent chunk for a message this now abandoned we need to check if a 73*0Sstevel@tonic-gate * Forward TSN needs to be sent, this could be a case where we deferred sending 74*0Sstevel@tonic-gate * a Forward TSN in sctp_get_msg_to_send(). Further, after processing a 75*0Sstevel@tonic-gate * SACK we check if the Advanced peer ack point can be moved ahead, i.e. 76*0Sstevel@tonic-gate * if we can send a Forward TSN via sctp_check_abandoned_data(). 77*0Sstevel@tonic-gate */ 78*0Sstevel@tonic-gate void 79*0Sstevel@tonic-gate sctp_free_set(sctp_set_t *s) 80*0Sstevel@tonic-gate { 81*0Sstevel@tonic-gate sctp_set_t *p; 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate while (s) { 84*0Sstevel@tonic-gate p = s->next; 85*0Sstevel@tonic-gate kmem_cache_free(sctp_kmem_set_cache, s); 86*0Sstevel@tonic-gate s = p; 87*0Sstevel@tonic-gate } 88*0Sstevel@tonic-gate } 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate static void 91*0Sstevel@tonic-gate sctp_ack_add(sctp_set_t **head, uint32_t tsn, int *num) 92*0Sstevel@tonic-gate { 93*0Sstevel@tonic-gate sctp_set_t *p, *t; 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate if (head == NULL || num == NULL) 96*0Sstevel@tonic-gate return; 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate ASSERT(*num >= 0); 99*0Sstevel@tonic-gate ASSERT((*num == 0 && *head == NULL) || (*num > 0 && *head != NULL)); 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate if (*head == NULL) { 102*0Sstevel@tonic-gate *head = kmem_cache_alloc(sctp_kmem_set_cache, KM_NOSLEEP); 103*0Sstevel@tonic-gate if (*head == NULL) 104*0Sstevel@tonic-gate return; 105*0Sstevel@tonic-gate (*head)->prev = (*head)->next = NULL; 106*0Sstevel@tonic-gate (*head)->begin = tsn; 107*0Sstevel@tonic-gate (*head)->end = tsn; 108*0Sstevel@tonic-gate *num = 1; 109*0Sstevel@tonic-gate return; 110*0Sstevel@tonic-gate } 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gate ASSERT((*head)->prev == NULL); 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate /* 115*0Sstevel@tonic-gate * Handle this special case here so we don't have to check 116*0Sstevel@tonic-gate * for it each time in the loop. 117*0Sstevel@tonic-gate */ 118*0Sstevel@tonic-gate if (SEQ_LT(tsn + 1, (*head)->begin)) { 119*0Sstevel@tonic-gate /* add a new set, and move the head pointer */ 120*0Sstevel@tonic-gate t = kmem_cache_alloc(sctp_kmem_set_cache, KM_NOSLEEP); 121*0Sstevel@tonic-gate if (t == NULL) 122*0Sstevel@tonic-gate return; 123*0Sstevel@tonic-gate t->next = *head; 124*0Sstevel@tonic-gate t->prev = NULL; 125*0Sstevel@tonic-gate (*head)->prev = t; 126*0Sstevel@tonic-gate t->begin = tsn; 127*0Sstevel@tonic-gate t->end = tsn; 128*0Sstevel@tonic-gate (*num)++; 129*0Sstevel@tonic-gate *head = t; 130*0Sstevel@tonic-gate return; 131*0Sstevel@tonic-gate } 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate /* 134*0Sstevel@tonic-gate * We need to handle the following cases, where p points to 135*0Sstevel@tonic-gate * the current set (as we walk through the loop): 136*0Sstevel@tonic-gate * 137*0Sstevel@tonic-gate * 1. tsn is entirely less than p; create a new set before p. 138*0Sstevel@tonic-gate * 2. tsn borders p from less; coalesce p with tsn. 139*0Sstevel@tonic-gate * 3. tsn is withing p; do nothing. 140*0Sstevel@tonic-gate * 4. tsn borders p from greater; coalesce p with tsn. 141*0Sstevel@tonic-gate * 4a. p may now border p->next from less; if so, coalesce those 142*0Sstevel@tonic-gate * two sets. 143*0Sstevel@tonic-gate * 5. tsn is entirely greater then all sets; add a new set at 144*0Sstevel@tonic-gate * the end. 145*0Sstevel@tonic-gate */ 146*0Sstevel@tonic-gate for (p = *head; ; p = p->next) { 147*0Sstevel@tonic-gate if (SEQ_LT(tsn + 1, p->begin)) { 148*0Sstevel@tonic-gate /* 1: add a new set before p. */ 149*0Sstevel@tonic-gate t = kmem_cache_alloc(sctp_kmem_set_cache, KM_NOSLEEP); 150*0Sstevel@tonic-gate if (t == NULL) 151*0Sstevel@tonic-gate return; 152*0Sstevel@tonic-gate t->next = p; 153*0Sstevel@tonic-gate t->prev = NULL; 154*0Sstevel@tonic-gate t->begin = tsn; 155*0Sstevel@tonic-gate t->end = tsn; 156*0Sstevel@tonic-gate if (p->prev) { 157*0Sstevel@tonic-gate t->prev = p->prev; 158*0Sstevel@tonic-gate p->prev->next = t; 159*0Sstevel@tonic-gate } 160*0Sstevel@tonic-gate p->prev = t; 161*0Sstevel@tonic-gate (*num)++; 162*0Sstevel@tonic-gate return; 163*0Sstevel@tonic-gate } 164*0Sstevel@tonic-gate 165*0Sstevel@tonic-gate if ((tsn + 1) == p->begin) { 166*0Sstevel@tonic-gate /* 2: adjust p->begin */ 167*0Sstevel@tonic-gate p->begin = tsn; 168*0Sstevel@tonic-gate return; 169*0Sstevel@tonic-gate } 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate if (SEQ_GEQ(tsn, p->begin) && SEQ_LEQ(tsn, p->end)) { 172*0Sstevel@tonic-gate /* 3; do nothing */ 173*0Sstevel@tonic-gate return; 174*0Sstevel@tonic-gate } 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate if ((p->end + 1) == tsn) { 177*0Sstevel@tonic-gate /* 4; adjust p->end */ 178*0Sstevel@tonic-gate p->end = tsn; 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate if (p->next != NULL && (tsn + 1) == p->next->begin) { 181*0Sstevel@tonic-gate /* 4a: coalesce p and p->next */ 182*0Sstevel@tonic-gate t = p->next; 183*0Sstevel@tonic-gate p->end = t->end; 184*0Sstevel@tonic-gate p->next = t->next; 185*0Sstevel@tonic-gate if (t->next != NULL) 186*0Sstevel@tonic-gate t->next->prev = p; 187*0Sstevel@tonic-gate kmem_cache_free(sctp_kmem_set_cache, t); 188*0Sstevel@tonic-gate (*num)--; 189*0Sstevel@tonic-gate } 190*0Sstevel@tonic-gate return; 191*0Sstevel@tonic-gate } 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gate if (p->next == NULL) { 194*0Sstevel@tonic-gate /* 5: add new set at the end */ 195*0Sstevel@tonic-gate t = kmem_cache_alloc(sctp_kmem_set_cache, KM_NOSLEEP); 196*0Sstevel@tonic-gate if (t == NULL) 197*0Sstevel@tonic-gate return; 198*0Sstevel@tonic-gate t->next = NULL; 199*0Sstevel@tonic-gate t->prev = p; 200*0Sstevel@tonic-gate t->begin = tsn; 201*0Sstevel@tonic-gate t->end = tsn; 202*0Sstevel@tonic-gate p->next = t; 203*0Sstevel@tonic-gate (*num)++; 204*0Sstevel@tonic-gate return; 205*0Sstevel@tonic-gate } 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate if (SEQ_GT(tsn, p->end + 1)) 208*0Sstevel@tonic-gate continue; 209*0Sstevel@tonic-gate } 210*0Sstevel@tonic-gate } 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate static void 213*0Sstevel@tonic-gate sctp_ack_rem(sctp_set_t **head, uint32_t end, int *num) 214*0Sstevel@tonic-gate { 215*0Sstevel@tonic-gate sctp_set_t *p, *t; 216*0Sstevel@tonic-gate 217*0Sstevel@tonic-gate if (head == NULL || *head == NULL || num == NULL) 218*0Sstevel@tonic-gate return; 219*0Sstevel@tonic-gate 220*0Sstevel@tonic-gate /* Nothing to remove */ 221*0Sstevel@tonic-gate if (SEQ_LT(end, (*head)->begin)) 222*0Sstevel@tonic-gate return; 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate /* Find out where to start removing sets */ 225*0Sstevel@tonic-gate for (p = *head; p->next; p = p->next) { 226*0Sstevel@tonic-gate if (SEQ_LEQ(end, p->end)) 227*0Sstevel@tonic-gate break; 228*0Sstevel@tonic-gate } 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate if (SEQ_LT(end, p->end) && SEQ_GEQ(end, p->begin)) { 231*0Sstevel@tonic-gate /* adjust p */ 232*0Sstevel@tonic-gate p->begin = end + 1; 233*0Sstevel@tonic-gate /* all done */ 234*0Sstevel@tonic-gate if (p == *head) 235*0Sstevel@tonic-gate return; 236*0Sstevel@tonic-gate } else if (SEQ_GEQ(end, p->end)) { 237*0Sstevel@tonic-gate /* remove this set too */ 238*0Sstevel@tonic-gate p = p->next; 239*0Sstevel@tonic-gate } 240*0Sstevel@tonic-gate 241*0Sstevel@tonic-gate /* unlink everything before this set */ 242*0Sstevel@tonic-gate t = *head; 243*0Sstevel@tonic-gate *head = p; 244*0Sstevel@tonic-gate if (p != NULL && p->prev != NULL) { 245*0Sstevel@tonic-gate p->prev->next = NULL; 246*0Sstevel@tonic-gate p->prev = NULL; 247*0Sstevel@tonic-gate } 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate sctp_free_set(t); 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate /* recount the number of sets */ 252*0Sstevel@tonic-gate *num = 0; 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate for (p = *head; p != NULL; p = p->next) 255*0Sstevel@tonic-gate (*num)++; 256*0Sstevel@tonic-gate } 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate void 259*0Sstevel@tonic-gate sctp_sets_init() 260*0Sstevel@tonic-gate { 261*0Sstevel@tonic-gate sctp_kmem_set_cache = kmem_cache_create("sctp_set_cache", 262*0Sstevel@tonic-gate sizeof (sctp_set_t), 0, NULL, NULL, NULL, NULL, 263*0Sstevel@tonic-gate NULL, 0); 264*0Sstevel@tonic-gate } 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate void 267*0Sstevel@tonic-gate sctp_sets_fini() 268*0Sstevel@tonic-gate { 269*0Sstevel@tonic-gate kmem_cache_destroy(sctp_kmem_set_cache); 270*0Sstevel@tonic-gate } 271*0Sstevel@tonic-gate 272*0Sstevel@tonic-gate sctp_chunk_hdr_t * 273*0Sstevel@tonic-gate sctp_first_chunk(uchar_t *rptr, ssize_t remaining) 274*0Sstevel@tonic-gate { 275*0Sstevel@tonic-gate sctp_chunk_hdr_t *ch; 276*0Sstevel@tonic-gate uint16_t ch_len; 277*0Sstevel@tonic-gate 278*0Sstevel@tonic-gate if (remaining < sizeof (*ch)) { 279*0Sstevel@tonic-gate return (NULL); 280*0Sstevel@tonic-gate } 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate ch = (sctp_chunk_hdr_t *)rptr; 283*0Sstevel@tonic-gate ch_len = ntohs(ch->sch_len); 284*0Sstevel@tonic-gate 285*0Sstevel@tonic-gate if (ch_len < sizeof (*ch) || remaining < ch_len) { 286*0Sstevel@tonic-gate return (NULL); 287*0Sstevel@tonic-gate } 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate return (ch); 290*0Sstevel@tonic-gate } 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate sctp_chunk_hdr_t * 293*0Sstevel@tonic-gate sctp_next_chunk(sctp_chunk_hdr_t *ch, ssize_t *remaining) 294*0Sstevel@tonic-gate { 295*0Sstevel@tonic-gate int pad; 296*0Sstevel@tonic-gate uint16_t ch_len; 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate if (!ch) { 299*0Sstevel@tonic-gate return (NULL); 300*0Sstevel@tonic-gate } 301*0Sstevel@tonic-gate 302*0Sstevel@tonic-gate ch_len = ntohs(ch->sch_len); 303*0Sstevel@tonic-gate 304*0Sstevel@tonic-gate if ((pad = ch_len & (SCTP_ALIGN - 1)) != 0) { 305*0Sstevel@tonic-gate pad = SCTP_ALIGN - pad; 306*0Sstevel@tonic-gate } 307*0Sstevel@tonic-gate 308*0Sstevel@tonic-gate *remaining -= (ch_len + pad); 309*0Sstevel@tonic-gate ch = (sctp_chunk_hdr_t *)((char *)ch + ch_len + pad); 310*0Sstevel@tonic-gate 311*0Sstevel@tonic-gate return (sctp_first_chunk((uchar_t *)ch, *remaining)); 312*0Sstevel@tonic-gate } 313*0Sstevel@tonic-gate 314*0Sstevel@tonic-gate /* 315*0Sstevel@tonic-gate * Attach ancillary data to a received SCTP segments. 316*0Sstevel@tonic-gate * If the source address (fp) is not the primary, send up a 317*0Sstevel@tonic-gate * unitdata_ind so recvfrom() can populate the msg_name field. 318*0Sstevel@tonic-gate * If ancillary data is also requested, we append it to the 319*0Sstevel@tonic-gate * unitdata_req. Otherwise, we just send up an optdata_ind. 320*0Sstevel@tonic-gate */ 321*0Sstevel@tonic-gate static int 322*0Sstevel@tonic-gate sctp_input_add_ancillary(sctp_t *sctp, mblk_t **mp, sctp_data_hdr_t *dcp, 323*0Sstevel@tonic-gate sctp_faddr_t *fp, ip6_pkt_t *ipp) 324*0Sstevel@tonic-gate { 325*0Sstevel@tonic-gate struct T_unitdata_ind *tudi; 326*0Sstevel@tonic-gate int optlen; 327*0Sstevel@tonic-gate int hdrlen; 328*0Sstevel@tonic-gate uchar_t *optptr; 329*0Sstevel@tonic-gate struct cmsghdr *cmsg; 330*0Sstevel@tonic-gate mblk_t *mp1; 331*0Sstevel@tonic-gate struct sockaddr_in6 sin_buf[1]; 332*0Sstevel@tonic-gate struct sockaddr_in6 *sin6; 333*0Sstevel@tonic-gate struct sockaddr_in *sin4; 334*0Sstevel@tonic-gate uint_t addflag = 0; 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate sin4 = NULL; 337*0Sstevel@tonic-gate sin6 = NULL; 338*0Sstevel@tonic-gate 339*0Sstevel@tonic-gate optlen = hdrlen = 0; 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate /* Figure out address size */ 342*0Sstevel@tonic-gate if (sctp->sctp_ipversion == IPV4_VERSION) { 343*0Sstevel@tonic-gate sin4 = (struct sockaddr_in *)sin_buf; 344*0Sstevel@tonic-gate sin4->sin_family = AF_INET; 345*0Sstevel@tonic-gate sin4->sin_port = sctp->sctp_fport; 346*0Sstevel@tonic-gate IN6_V4MAPPED_TO_IPADDR(&fp->faddr, sin4->sin_addr.s_addr); 347*0Sstevel@tonic-gate hdrlen = sizeof (*tudi) + sizeof (*sin4); 348*0Sstevel@tonic-gate } else { 349*0Sstevel@tonic-gate sin6 = sin_buf; 350*0Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 351*0Sstevel@tonic-gate sin6->sin6_port = sctp->sctp_fport; 352*0Sstevel@tonic-gate sin6->sin6_addr = fp->faddr; 353*0Sstevel@tonic-gate hdrlen = sizeof (*tudi) + sizeof (*sin6); 354*0Sstevel@tonic-gate } 355*0Sstevel@tonic-gate 356*0Sstevel@tonic-gate /* If app asked to receive send / recv info */ 357*0Sstevel@tonic-gate if (sctp->sctp_recvsndrcvinfo) { 358*0Sstevel@tonic-gate optlen += sizeof (*cmsg) + sizeof (struct sctp_sndrcvinfo); 359*0Sstevel@tonic-gate if (hdrlen == 0) 360*0Sstevel@tonic-gate hdrlen = sizeof (struct T_optdata_ind); 361*0Sstevel@tonic-gate } 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate if (sctp->sctp_ipv6_recvancillary == 0) 364*0Sstevel@tonic-gate goto noancillary; 365*0Sstevel@tonic-gate 366*0Sstevel@tonic-gate if ((ipp->ipp_fields & IPPF_IFINDEX) && 367*0Sstevel@tonic-gate ipp->ipp_ifindex != sctp->sctp_recvifindex && 368*0Sstevel@tonic-gate (sctp->sctp_ipv6_recvancillary & SCTP_IPV6_RECVPKTINFO)) { 369*0Sstevel@tonic-gate optlen += sizeof (*cmsg) + sizeof (struct in6_pktinfo); 370*0Sstevel@tonic-gate if (hdrlen == 0) 371*0Sstevel@tonic-gate hdrlen = sizeof (struct T_unitdata_ind); 372*0Sstevel@tonic-gate addflag |= SCTP_IPV6_RECVPKTINFO; 373*0Sstevel@tonic-gate } 374*0Sstevel@tonic-gate /* If app asked for hoplimit and it has changed ... */ 375*0Sstevel@tonic-gate if ((ipp->ipp_fields & IPPF_HOPLIMIT) && 376*0Sstevel@tonic-gate ipp->ipp_hoplimit != sctp->sctp_recvhops && 377*0Sstevel@tonic-gate (sctp->sctp_ipv6_recvancillary & SCTP_IPV6_RECVHOPLIMIT)) { 378*0Sstevel@tonic-gate optlen += sizeof (*cmsg) + sizeof (uint_t); 379*0Sstevel@tonic-gate if (hdrlen == 0) 380*0Sstevel@tonic-gate hdrlen = sizeof (struct T_unitdata_ind); 381*0Sstevel@tonic-gate addflag |= SCTP_IPV6_RECVHOPLIMIT; 382*0Sstevel@tonic-gate } 383*0Sstevel@tonic-gate /* If app asked for hopbyhop headers and it has changed ... */ 384*0Sstevel@tonic-gate if ((sctp->sctp_ipv6_recvancillary & SCTP_IPV6_RECVHOPOPTS) && 385*0Sstevel@tonic-gate sctp_cmpbuf(sctp->sctp_hopopts, sctp->sctp_hopoptslen, 386*0Sstevel@tonic-gate (ipp->ipp_fields & IPPF_HOPOPTS), 387*0Sstevel@tonic-gate ipp->ipp_hopopts, ipp->ipp_hopoptslen)) { 388*0Sstevel@tonic-gate optlen += sizeof (*cmsg) + ipp->ipp_hopoptslen; 389*0Sstevel@tonic-gate if (hdrlen == 0) 390*0Sstevel@tonic-gate hdrlen = sizeof (struct T_unitdata_ind); 391*0Sstevel@tonic-gate addflag |= SCTP_IPV6_RECVHOPOPTS; 392*0Sstevel@tonic-gate if (!sctp_allocbuf((void **)&sctp->sctp_hopopts, 393*0Sstevel@tonic-gate &sctp->sctp_hopoptslen, 394*0Sstevel@tonic-gate (ipp->ipp_fields & IPPF_HOPOPTS), 395*0Sstevel@tonic-gate ipp->ipp_hopopts, ipp->ipp_hopoptslen)) 396*0Sstevel@tonic-gate return (-1); 397*0Sstevel@tonic-gate } 398*0Sstevel@tonic-gate /* If app asked for dst headers before routing headers ... */ 399*0Sstevel@tonic-gate if ((sctp->sctp_ipv6_recvancillary & SCTP_IPV6_RECVRTDSTOPTS) && 400*0Sstevel@tonic-gate sctp_cmpbuf(sctp->sctp_rtdstopts, sctp->sctp_rtdstoptslen, 401*0Sstevel@tonic-gate (ipp->ipp_fields & IPPF_RTDSTOPTS), 402*0Sstevel@tonic-gate ipp->ipp_rtdstopts, ipp->ipp_rtdstoptslen)) { 403*0Sstevel@tonic-gate optlen += sizeof (*cmsg) + ipp->ipp_rtdstoptslen; 404*0Sstevel@tonic-gate if (hdrlen == 0) 405*0Sstevel@tonic-gate hdrlen = sizeof (struct T_unitdata_ind); 406*0Sstevel@tonic-gate addflag |= SCTP_IPV6_RECVRTDSTOPTS; 407*0Sstevel@tonic-gate if (!sctp_allocbuf((void **)&sctp->sctp_rtdstopts, 408*0Sstevel@tonic-gate &sctp->sctp_rtdstoptslen, 409*0Sstevel@tonic-gate (ipp->ipp_fields & IPPF_RTDSTOPTS), 410*0Sstevel@tonic-gate ipp->ipp_rtdstopts, ipp->ipp_rtdstoptslen)) 411*0Sstevel@tonic-gate return (-1); 412*0Sstevel@tonic-gate } 413*0Sstevel@tonic-gate /* If app asked for routing headers and it has changed ... */ 414*0Sstevel@tonic-gate if (sctp->sctp_ipv6_recvancillary & SCTP_IPV6_RECVRTHDR) { 415*0Sstevel@tonic-gate if (sctp_cmpbuf(sctp->sctp_rthdr, sctp->sctp_rthdrlen, 416*0Sstevel@tonic-gate (ipp->ipp_fields & IPPF_RTHDR), 417*0Sstevel@tonic-gate ipp->ipp_rthdr, ipp->ipp_rthdrlen)) { 418*0Sstevel@tonic-gate optlen += sizeof (*cmsg) + ipp->ipp_rthdrlen; 419*0Sstevel@tonic-gate if (hdrlen == 0) 420*0Sstevel@tonic-gate hdrlen = sizeof (struct T_unitdata_ind); 421*0Sstevel@tonic-gate addflag |= SCTP_IPV6_RECVRTHDR; 422*0Sstevel@tonic-gate if (!sctp_allocbuf((void **)&sctp->sctp_rthdr, 423*0Sstevel@tonic-gate &sctp->sctp_rthdrlen, 424*0Sstevel@tonic-gate (ipp->ipp_fields & IPPF_RTHDR), 425*0Sstevel@tonic-gate ipp->ipp_rthdr, ipp->ipp_rthdrlen)) 426*0Sstevel@tonic-gate return (-1); 427*0Sstevel@tonic-gate } 428*0Sstevel@tonic-gate } 429*0Sstevel@tonic-gate /* If app asked for dest headers and it has changed ... */ 430*0Sstevel@tonic-gate if ((sctp->sctp_ipv6_recvancillary & SCTP_IPV6_RECVDSTOPTS) && 431*0Sstevel@tonic-gate sctp_cmpbuf(sctp->sctp_dstopts, sctp->sctp_dstoptslen, 432*0Sstevel@tonic-gate (ipp->ipp_fields & IPPF_DSTOPTS), 433*0Sstevel@tonic-gate ipp->ipp_dstopts, ipp->ipp_dstoptslen)) { 434*0Sstevel@tonic-gate optlen += sizeof (*cmsg) + ipp->ipp_dstoptslen; 435*0Sstevel@tonic-gate if (hdrlen == 0) 436*0Sstevel@tonic-gate hdrlen = sizeof (struct T_unitdata_ind); 437*0Sstevel@tonic-gate addflag |= SCTP_IPV6_RECVDSTOPTS; 438*0Sstevel@tonic-gate if (!sctp_allocbuf((void **)&sctp->sctp_dstopts, 439*0Sstevel@tonic-gate &sctp->sctp_dstoptslen, 440*0Sstevel@tonic-gate (ipp->ipp_fields & IPPF_DSTOPTS), 441*0Sstevel@tonic-gate ipp->ipp_dstopts, ipp->ipp_dstoptslen)) 442*0Sstevel@tonic-gate return (-1); 443*0Sstevel@tonic-gate } 444*0Sstevel@tonic-gate noancillary: 445*0Sstevel@tonic-gate /* Nothing to add */ 446*0Sstevel@tonic-gate if (hdrlen == 0) 447*0Sstevel@tonic-gate return (-1); 448*0Sstevel@tonic-gate 449*0Sstevel@tonic-gate mp1 = allocb(hdrlen + optlen + sizeof (void *), BPRI_MED); 450*0Sstevel@tonic-gate if (mp1 == NULL) 451*0Sstevel@tonic-gate return (-1); 452*0Sstevel@tonic-gate mp1->b_cont = *mp; 453*0Sstevel@tonic-gate *mp = mp1; 454*0Sstevel@tonic-gate mp1->b_rptr += sizeof (void *); /* pointer worth of padding */ 455*0Sstevel@tonic-gate mp1->b_wptr = mp1->b_rptr + hdrlen + optlen; 456*0Sstevel@tonic-gate DB_TYPE(mp1) = M_PROTO; 457*0Sstevel@tonic-gate tudi = (struct T_unitdata_ind *)mp1->b_rptr; 458*0Sstevel@tonic-gate tudi->PRIM_type = T_UNITDATA_IND; 459*0Sstevel@tonic-gate tudi->SRC_length = sin4 ? sizeof (*sin4) : sizeof (*sin6); 460*0Sstevel@tonic-gate tudi->SRC_offset = sizeof (*tudi); 461*0Sstevel@tonic-gate tudi->OPT_offset = sizeof (*tudi) + tudi->SRC_length; 462*0Sstevel@tonic-gate tudi->OPT_length = optlen; 463*0Sstevel@tonic-gate if (sin4) { 464*0Sstevel@tonic-gate bcopy(sin4, tudi + 1, sizeof (*sin4)); 465*0Sstevel@tonic-gate } else { 466*0Sstevel@tonic-gate bcopy(sin6, tudi + 1, sizeof (*sin6)); 467*0Sstevel@tonic-gate } 468*0Sstevel@tonic-gate optptr = (uchar_t *)tudi + tudi->OPT_offset; 469*0Sstevel@tonic-gate 470*0Sstevel@tonic-gate if (sctp->sctp_recvsndrcvinfo) { 471*0Sstevel@tonic-gate /* XXX need backout method if memory allocation fails. */ 472*0Sstevel@tonic-gate struct sctp_sndrcvinfo *sri; 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate cmsg = (struct cmsghdr *)optptr; 475*0Sstevel@tonic-gate cmsg->cmsg_level = IPPROTO_SCTP; 476*0Sstevel@tonic-gate cmsg->cmsg_type = SCTP_SNDRCV; 477*0Sstevel@tonic-gate cmsg->cmsg_len = sizeof (*cmsg) + sizeof (*sri); 478*0Sstevel@tonic-gate optptr += sizeof (*cmsg); 479*0Sstevel@tonic-gate 480*0Sstevel@tonic-gate sri = (struct sctp_sndrcvinfo *)(cmsg + 1); 481*0Sstevel@tonic-gate ASSERT(OK_32PTR(sri)); 482*0Sstevel@tonic-gate sri->sinfo_stream = ntohs(dcp->sdh_sid); 483*0Sstevel@tonic-gate sri->sinfo_ssn = ntohs(dcp->sdh_ssn); 484*0Sstevel@tonic-gate if (SCTP_DATA_GET_UBIT(dcp)) { 485*0Sstevel@tonic-gate sri->sinfo_flags = MSG_UNORDERED; 486*0Sstevel@tonic-gate } else { 487*0Sstevel@tonic-gate sri->sinfo_flags = 0; 488*0Sstevel@tonic-gate } 489*0Sstevel@tonic-gate sri->sinfo_ppid = dcp->sdh_payload_id; 490*0Sstevel@tonic-gate sri->sinfo_context = 0; 491*0Sstevel@tonic-gate sri->sinfo_timetolive = 0; 492*0Sstevel@tonic-gate sri->sinfo_tsn = ntohl(dcp->sdh_tsn); 493*0Sstevel@tonic-gate sri->sinfo_cumtsn = sctp->sctp_ftsn; 494*0Sstevel@tonic-gate sri->sinfo_assoc_id = 0; 495*0Sstevel@tonic-gate 496*0Sstevel@tonic-gate optptr += sizeof (*sri); 497*0Sstevel@tonic-gate } 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate /* 500*0Sstevel@tonic-gate * If app asked for pktinfo and the index has changed ... 501*0Sstevel@tonic-gate * Note that the local address never changes for the connection. 502*0Sstevel@tonic-gate */ 503*0Sstevel@tonic-gate if (addflag & SCTP_IPV6_RECVPKTINFO) { 504*0Sstevel@tonic-gate struct in6_pktinfo *pkti; 505*0Sstevel@tonic-gate 506*0Sstevel@tonic-gate cmsg = (struct cmsghdr *)optptr; 507*0Sstevel@tonic-gate cmsg->cmsg_level = IPPROTO_IPV6; 508*0Sstevel@tonic-gate cmsg->cmsg_type = IPV6_PKTINFO; 509*0Sstevel@tonic-gate cmsg->cmsg_len = sizeof (*cmsg) + sizeof (*pkti); 510*0Sstevel@tonic-gate optptr += sizeof (*cmsg); 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate pkti = (struct in6_pktinfo *)optptr; 513*0Sstevel@tonic-gate if (sctp->sctp_ipversion == IPV6_VERSION) 514*0Sstevel@tonic-gate pkti->ipi6_addr = sctp->sctp_ip6h->ip6_src; 515*0Sstevel@tonic-gate else 516*0Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(sctp->sctp_ipha->ipha_src, 517*0Sstevel@tonic-gate &pkti->ipi6_addr); 518*0Sstevel@tonic-gate pkti->ipi6_ifindex = ipp->ipp_ifindex; 519*0Sstevel@tonic-gate optptr += sizeof (*pkti); 520*0Sstevel@tonic-gate ASSERT(OK_32PTR(optptr)); 521*0Sstevel@tonic-gate /* Save as "last" value */ 522*0Sstevel@tonic-gate sctp->sctp_recvifindex = ipp->ipp_ifindex; 523*0Sstevel@tonic-gate } 524*0Sstevel@tonic-gate /* If app asked for hoplimit and it has changed ... */ 525*0Sstevel@tonic-gate if (addflag & SCTP_IPV6_RECVHOPLIMIT) { 526*0Sstevel@tonic-gate cmsg = (struct cmsghdr *)optptr; 527*0Sstevel@tonic-gate cmsg->cmsg_level = IPPROTO_IPV6; 528*0Sstevel@tonic-gate cmsg->cmsg_type = IPV6_HOPLIMIT; 529*0Sstevel@tonic-gate cmsg->cmsg_len = sizeof (*cmsg) + sizeof (uint_t); 530*0Sstevel@tonic-gate optptr += sizeof (*cmsg); 531*0Sstevel@tonic-gate 532*0Sstevel@tonic-gate *(uint_t *)optptr = ipp->ipp_hoplimit; 533*0Sstevel@tonic-gate optptr += sizeof (uint_t); 534*0Sstevel@tonic-gate ASSERT(OK_32PTR(optptr)); 535*0Sstevel@tonic-gate /* Save as "last" value */ 536*0Sstevel@tonic-gate sctp->sctp_recvhops = ipp->ipp_hoplimit; 537*0Sstevel@tonic-gate } 538*0Sstevel@tonic-gate if (addflag & SCTP_IPV6_RECVHOPOPTS) { 539*0Sstevel@tonic-gate cmsg = (struct cmsghdr *)optptr; 540*0Sstevel@tonic-gate cmsg->cmsg_level = IPPROTO_IPV6; 541*0Sstevel@tonic-gate cmsg->cmsg_type = IPV6_HOPOPTS; 542*0Sstevel@tonic-gate cmsg->cmsg_len = sizeof (*cmsg) + ipp->ipp_hopoptslen; 543*0Sstevel@tonic-gate optptr += sizeof (*cmsg); 544*0Sstevel@tonic-gate 545*0Sstevel@tonic-gate bcopy(ipp->ipp_hopopts, optptr, ipp->ipp_hopoptslen); 546*0Sstevel@tonic-gate optptr += ipp->ipp_hopoptslen; 547*0Sstevel@tonic-gate ASSERT(OK_32PTR(optptr)); 548*0Sstevel@tonic-gate /* Save as last value */ 549*0Sstevel@tonic-gate sctp_savebuf((void **)&sctp->sctp_hopopts, 550*0Sstevel@tonic-gate &sctp->sctp_hopoptslen, 551*0Sstevel@tonic-gate (ipp->ipp_fields & IPPF_HOPOPTS), 552*0Sstevel@tonic-gate ipp->ipp_hopopts, ipp->ipp_hopoptslen); 553*0Sstevel@tonic-gate } 554*0Sstevel@tonic-gate if (addflag & SCTP_IPV6_RECVRTDSTOPTS) { 555*0Sstevel@tonic-gate cmsg = (struct cmsghdr *)optptr; 556*0Sstevel@tonic-gate cmsg->cmsg_level = IPPROTO_IPV6; 557*0Sstevel@tonic-gate cmsg->cmsg_type = IPV6_RTHDRDSTOPTS; 558*0Sstevel@tonic-gate cmsg->cmsg_len = sizeof (*cmsg) + ipp->ipp_rtdstoptslen; 559*0Sstevel@tonic-gate optptr += sizeof (*cmsg); 560*0Sstevel@tonic-gate 561*0Sstevel@tonic-gate bcopy(ipp->ipp_rtdstopts, optptr, ipp->ipp_rtdstoptslen); 562*0Sstevel@tonic-gate optptr += ipp->ipp_rtdstoptslen; 563*0Sstevel@tonic-gate ASSERT(OK_32PTR(optptr)); 564*0Sstevel@tonic-gate /* Save as last value */ 565*0Sstevel@tonic-gate sctp_savebuf((void **)&sctp->sctp_rtdstopts, 566*0Sstevel@tonic-gate &sctp->sctp_rtdstoptslen, 567*0Sstevel@tonic-gate (ipp->ipp_fields & IPPF_RTDSTOPTS), 568*0Sstevel@tonic-gate ipp->ipp_rtdstopts, ipp->ipp_rtdstoptslen); 569*0Sstevel@tonic-gate } 570*0Sstevel@tonic-gate if (addflag & SCTP_IPV6_RECVRTHDR) { 571*0Sstevel@tonic-gate cmsg = (struct cmsghdr *)optptr; 572*0Sstevel@tonic-gate cmsg->cmsg_level = IPPROTO_IPV6; 573*0Sstevel@tonic-gate cmsg->cmsg_type = IPV6_RTHDR; 574*0Sstevel@tonic-gate cmsg->cmsg_len = sizeof (*cmsg) + ipp->ipp_rthdrlen; 575*0Sstevel@tonic-gate optptr += sizeof (*cmsg); 576*0Sstevel@tonic-gate 577*0Sstevel@tonic-gate bcopy(ipp->ipp_rthdr, optptr, ipp->ipp_rthdrlen); 578*0Sstevel@tonic-gate optptr += ipp->ipp_rthdrlen; 579*0Sstevel@tonic-gate ASSERT(OK_32PTR(optptr)); 580*0Sstevel@tonic-gate /* Save as last value */ 581*0Sstevel@tonic-gate sctp_savebuf((void **)&sctp->sctp_rthdr, 582*0Sstevel@tonic-gate &sctp->sctp_rthdrlen, 583*0Sstevel@tonic-gate (ipp->ipp_fields & IPPF_RTHDR), 584*0Sstevel@tonic-gate ipp->ipp_rthdr, ipp->ipp_rthdrlen); 585*0Sstevel@tonic-gate } 586*0Sstevel@tonic-gate if (addflag & SCTP_IPV6_RECVDSTOPTS) { 587*0Sstevel@tonic-gate cmsg = (struct cmsghdr *)optptr; 588*0Sstevel@tonic-gate cmsg->cmsg_level = IPPROTO_IPV6; 589*0Sstevel@tonic-gate cmsg->cmsg_type = IPV6_DSTOPTS; 590*0Sstevel@tonic-gate cmsg->cmsg_len = sizeof (*cmsg) + ipp->ipp_dstoptslen; 591*0Sstevel@tonic-gate optptr += sizeof (*cmsg); 592*0Sstevel@tonic-gate 593*0Sstevel@tonic-gate bcopy(ipp->ipp_dstopts, optptr, ipp->ipp_dstoptslen); 594*0Sstevel@tonic-gate optptr += ipp->ipp_dstoptslen; 595*0Sstevel@tonic-gate ASSERT(OK_32PTR(optptr)); 596*0Sstevel@tonic-gate /* Save as last value */ 597*0Sstevel@tonic-gate sctp_savebuf((void **)&sctp->sctp_dstopts, 598*0Sstevel@tonic-gate &sctp->sctp_dstoptslen, 599*0Sstevel@tonic-gate (ipp->ipp_fields & IPPF_DSTOPTS), 600*0Sstevel@tonic-gate ipp->ipp_dstopts, ipp->ipp_dstoptslen); 601*0Sstevel@tonic-gate } 602*0Sstevel@tonic-gate 603*0Sstevel@tonic-gate ASSERT(optptr == mp1->b_wptr); 604*0Sstevel@tonic-gate 605*0Sstevel@tonic-gate return (0); 606*0Sstevel@tonic-gate } 607*0Sstevel@tonic-gate 608*0Sstevel@tonic-gate void 609*0Sstevel@tonic-gate sctp_free_reass(sctp_instr_t *sip) 610*0Sstevel@tonic-gate { 611*0Sstevel@tonic-gate mblk_t *mp, *mpnext, *mctl; 612*0Sstevel@tonic-gate 613*0Sstevel@tonic-gate for (mp = sip->istr_reass; mp != NULL; mp = mpnext) { 614*0Sstevel@tonic-gate mpnext = mp->b_next; 615*0Sstevel@tonic-gate mp->b_next = NULL; 616*0Sstevel@tonic-gate mp->b_prev = NULL; 617*0Sstevel@tonic-gate if (DB_TYPE(mp) == M_CTL) { 618*0Sstevel@tonic-gate mctl = mp; 619*0Sstevel@tonic-gate ASSERT(mp->b_cont != NULL); 620*0Sstevel@tonic-gate mp = mp->b_cont; 621*0Sstevel@tonic-gate mctl->b_cont = NULL; 622*0Sstevel@tonic-gate freeb(mctl); 623*0Sstevel@tonic-gate } 624*0Sstevel@tonic-gate freemsg(mp); 625*0Sstevel@tonic-gate } 626*0Sstevel@tonic-gate } 627*0Sstevel@tonic-gate 628*0Sstevel@tonic-gate /* 629*0Sstevel@tonic-gate * If the series of data fragments of which dmp is a part is successfully 630*0Sstevel@tonic-gate * reassembled, the first mblk in the series is returned. dc is adjusted 631*0Sstevel@tonic-gate * to point at the data chunk in the lead mblk, and b_rptr also points to 632*0Sstevel@tonic-gate * the data chunk; the following mblk's b_rptr's point at the actual payload. 633*0Sstevel@tonic-gate * 634*0Sstevel@tonic-gate * If the series is not yet reassembled, NULL is returned. dc is not changed. 635*0Sstevel@tonic-gate * XXX should probably move this up into the state machine. 636*0Sstevel@tonic-gate */ 637*0Sstevel@tonic-gate 638*0Sstevel@tonic-gate /* Fragment list for un-ordered messages. Partial delivery is not supported */ 639*0Sstevel@tonic-gate static mblk_t * 640*0Sstevel@tonic-gate sctp_uodata_frag(sctp_t *sctp, mblk_t *dmp, sctp_data_hdr_t **dc) 641*0Sstevel@tonic-gate { 642*0Sstevel@tonic-gate mblk_t *hmp; 643*0Sstevel@tonic-gate mblk_t *begin = NULL; 644*0Sstevel@tonic-gate mblk_t *end = NULL; 645*0Sstevel@tonic-gate sctp_data_hdr_t *qdc; 646*0Sstevel@tonic-gate uint32_t ntsn; 647*0Sstevel@tonic-gate uint32_t tsn = ntohl((*dc)->sdh_tsn); 648*0Sstevel@tonic-gate #ifdef DEBUG 649*0Sstevel@tonic-gate mblk_t *mp1; 650*0Sstevel@tonic-gate #endif 651*0Sstevel@tonic-gate 652*0Sstevel@tonic-gate /* First frag. */ 653*0Sstevel@tonic-gate if (sctp->sctp_uo_frags == NULL) { 654*0Sstevel@tonic-gate sctp->sctp_uo_frags = dmp; 655*0Sstevel@tonic-gate return (NULL); 656*0Sstevel@tonic-gate } 657*0Sstevel@tonic-gate hmp = sctp->sctp_uo_frags; 658*0Sstevel@tonic-gate /* 659*0Sstevel@tonic-gate * Insert the segment according to the TSN, fragmented unordered 660*0Sstevel@tonic-gate * chunks are sequenced by TSN. 661*0Sstevel@tonic-gate */ 662*0Sstevel@tonic-gate while (hmp != NULL) { 663*0Sstevel@tonic-gate qdc = (sctp_data_hdr_t *)hmp->b_rptr; 664*0Sstevel@tonic-gate ntsn = ntohl(qdc->sdh_tsn); 665*0Sstevel@tonic-gate if (SEQ_GT(ntsn, tsn)) { 666*0Sstevel@tonic-gate if (hmp->b_prev == NULL) { 667*0Sstevel@tonic-gate dmp->b_next = hmp; 668*0Sstevel@tonic-gate hmp->b_prev = dmp; 669*0Sstevel@tonic-gate sctp->sctp_uo_frags = dmp; 670*0Sstevel@tonic-gate } else { 671*0Sstevel@tonic-gate dmp->b_next = hmp; 672*0Sstevel@tonic-gate dmp->b_prev = hmp->b_prev; 673*0Sstevel@tonic-gate hmp->b_prev->b_next = dmp; 674*0Sstevel@tonic-gate hmp->b_prev = dmp; 675*0Sstevel@tonic-gate } 676*0Sstevel@tonic-gate break; 677*0Sstevel@tonic-gate } 678*0Sstevel@tonic-gate if (hmp->b_next == NULL) { 679*0Sstevel@tonic-gate hmp->b_next = dmp; 680*0Sstevel@tonic-gate dmp->b_prev = hmp; 681*0Sstevel@tonic-gate break; 682*0Sstevel@tonic-gate } 683*0Sstevel@tonic-gate hmp = hmp->b_next; 684*0Sstevel@tonic-gate } 685*0Sstevel@tonic-gate /* check if we completed a msg */ 686*0Sstevel@tonic-gate if (SCTP_DATA_GET_BBIT(*dc)) { 687*0Sstevel@tonic-gate begin = dmp; 688*0Sstevel@tonic-gate } else if (SCTP_DATA_GET_EBIT(*dc)) { 689*0Sstevel@tonic-gate end = dmp; 690*0Sstevel@tonic-gate } 691*0Sstevel@tonic-gate /* 692*0Sstevel@tonic-gate * We walk consecutive TSNs backwards till we get a seg. with 693*0Sstevel@tonic-gate * the B bit 694*0Sstevel@tonic-gate */ 695*0Sstevel@tonic-gate if (begin == NULL) { 696*0Sstevel@tonic-gate for (hmp = dmp->b_prev; hmp != NULL; hmp = hmp->b_prev) { 697*0Sstevel@tonic-gate qdc = (sctp_data_hdr_t *)hmp->b_rptr; 698*0Sstevel@tonic-gate ntsn = ntohl(qdc->sdh_tsn); 699*0Sstevel@tonic-gate if ((int32_t)(tsn - ntsn) > 1) { 700*0Sstevel@tonic-gate return (NULL); 701*0Sstevel@tonic-gate } 702*0Sstevel@tonic-gate if (SCTP_DATA_GET_BBIT(qdc)) { 703*0Sstevel@tonic-gate begin = hmp; 704*0Sstevel@tonic-gate break; 705*0Sstevel@tonic-gate } 706*0Sstevel@tonic-gate tsn = ntsn; 707*0Sstevel@tonic-gate } 708*0Sstevel@tonic-gate } 709*0Sstevel@tonic-gate tsn = ntohl((*dc)->sdh_tsn); 710*0Sstevel@tonic-gate /* 711*0Sstevel@tonic-gate * We walk consecutive TSNs till we get a seg. with the E bit 712*0Sstevel@tonic-gate */ 713*0Sstevel@tonic-gate if (end == NULL) { 714*0Sstevel@tonic-gate for (hmp = dmp->b_next; hmp != NULL; hmp = hmp->b_next) { 715*0Sstevel@tonic-gate qdc = (sctp_data_hdr_t *)hmp->b_rptr; 716*0Sstevel@tonic-gate ntsn = ntohl(qdc->sdh_tsn); 717*0Sstevel@tonic-gate if ((int32_t)(ntsn - tsn) > 1) { 718*0Sstevel@tonic-gate return (NULL); 719*0Sstevel@tonic-gate } 720*0Sstevel@tonic-gate if (SCTP_DATA_GET_EBIT(qdc)) { 721*0Sstevel@tonic-gate end = hmp; 722*0Sstevel@tonic-gate break; 723*0Sstevel@tonic-gate } 724*0Sstevel@tonic-gate tsn = ntsn; 725*0Sstevel@tonic-gate } 726*0Sstevel@tonic-gate } 727*0Sstevel@tonic-gate if (begin == NULL || end == NULL) { 728*0Sstevel@tonic-gate return (NULL); 729*0Sstevel@tonic-gate } 730*0Sstevel@tonic-gate /* Got one!, Remove the msg from the list */ 731*0Sstevel@tonic-gate if (sctp->sctp_uo_frags == begin) { 732*0Sstevel@tonic-gate ASSERT(begin->b_prev == NULL); 733*0Sstevel@tonic-gate sctp->sctp_uo_frags = end->b_next; 734*0Sstevel@tonic-gate if (end->b_next != NULL) 735*0Sstevel@tonic-gate end->b_next->b_prev = NULL; 736*0Sstevel@tonic-gate } else { 737*0Sstevel@tonic-gate begin->b_prev->b_next = end->b_next; 738*0Sstevel@tonic-gate if (end->b_next != NULL) 739*0Sstevel@tonic-gate end->b_next->b_prev = begin->b_prev; 740*0Sstevel@tonic-gate } 741*0Sstevel@tonic-gate begin->b_prev = NULL; 742*0Sstevel@tonic-gate end->b_next = NULL; 743*0Sstevel@tonic-gate 744*0Sstevel@tonic-gate /* 745*0Sstevel@tonic-gate * Null out b_next and b_prev and chain using b_cont. 746*0Sstevel@tonic-gate */ 747*0Sstevel@tonic-gate dmp = end = begin; 748*0Sstevel@tonic-gate hmp = begin->b_next; 749*0Sstevel@tonic-gate *dc = (sctp_data_hdr_t *)begin->b_rptr; 750*0Sstevel@tonic-gate begin->b_next = NULL; 751*0Sstevel@tonic-gate while (hmp != NULL) { 752*0Sstevel@tonic-gate qdc = (sctp_data_hdr_t *)hmp->b_rptr; 753*0Sstevel@tonic-gate hmp->b_rptr = (uchar_t *)(qdc + 1); 754*0Sstevel@tonic-gate end = hmp->b_next; 755*0Sstevel@tonic-gate dmp->b_cont = hmp; 756*0Sstevel@tonic-gate dmp = hmp; 757*0Sstevel@tonic-gate 758*0Sstevel@tonic-gate if (end != NULL) 759*0Sstevel@tonic-gate hmp->b_next = NULL; 760*0Sstevel@tonic-gate hmp->b_prev = NULL; 761*0Sstevel@tonic-gate hmp = end; 762*0Sstevel@tonic-gate } 763*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_reassmsgs); 764*0Sstevel@tonic-gate #ifdef DEBUG 765*0Sstevel@tonic-gate mp1 = begin; 766*0Sstevel@tonic-gate while (mp1 != NULL) { 767*0Sstevel@tonic-gate ASSERT(mp1->b_next == NULL); 768*0Sstevel@tonic-gate ASSERT(mp1->b_prev == NULL); 769*0Sstevel@tonic-gate mp1 = mp1->b_cont; 770*0Sstevel@tonic-gate } 771*0Sstevel@tonic-gate #endif 772*0Sstevel@tonic-gate return (begin); 773*0Sstevel@tonic-gate } 774*0Sstevel@tonic-gate /* 775*0Sstevel@tonic-gate * Fragment list for ordered messages. 776*0Sstevel@tonic-gate * If no error occures, error is set to 0. If we run out of memory, error 777*0Sstevel@tonic-gate * is set to 1. If the peer commits a fatal error (like using different 778*0Sstevel@tonic-gate * sequence numbers for the same data fragment series), the association is 779*0Sstevel@tonic-gate * aborted and error is set to 2. 780*0Sstevel@tonic-gate */ 781*0Sstevel@tonic-gate static mblk_t * 782*0Sstevel@tonic-gate sctp_data_frag(sctp_t *sctp, mblk_t *dmp, sctp_data_hdr_t **dc, int *error, 783*0Sstevel@tonic-gate sctp_instr_t *sip, int trypartial, int *tpfinished) 784*0Sstevel@tonic-gate { 785*0Sstevel@tonic-gate mblk_t *hmp; 786*0Sstevel@tonic-gate mblk_t *pmp; 787*0Sstevel@tonic-gate mblk_t *qmp; 788*0Sstevel@tonic-gate mblk_t *mp; 789*0Sstevel@tonic-gate mblk_t *prev; 790*0Sstevel@tonic-gate mblk_t *prevprev; 791*0Sstevel@tonic-gate mblk_t *first_mp; 792*0Sstevel@tonic-gate sctp_reass_t *srp; 793*0Sstevel@tonic-gate sctp_data_hdr_t *qdc; 794*0Sstevel@tonic-gate sctp_data_hdr_t *bdc; 795*0Sstevel@tonic-gate sctp_data_hdr_t *edc; 796*0Sstevel@tonic-gate uint32_t tsn; 797*0Sstevel@tonic-gate 798*0Sstevel@tonic-gate /* 799*0Sstevel@tonic-gate * We can overwrite the Link Layer + IP header here, I suppose. 800*0Sstevel@tonic-gate * The M_CTL does not leave this function. We need to check 801*0Sstevel@tonic-gate * DB_REF(dmp) before using DB_BASE(dmp), since there could be 802*0Sstevel@tonic-gate * two fragments for different ssns in the same mblk. 803*0Sstevel@tonic-gate */ 804*0Sstevel@tonic-gate #define SCTP_NEW_REASS(nmp, dmp, srp, seterror) \ 805*0Sstevel@tonic-gate if ((DB_REF(dmp) == 2) && (MBLKHEAD(dmp) >= \ 806*0Sstevel@tonic-gate (sizeof (*(srp)) + sizeof (sctp_hdr_t)))) { \ 807*0Sstevel@tonic-gate (nmp) = (dmp); \ 808*0Sstevel@tonic-gate } else { \ 809*0Sstevel@tonic-gate (nmp) = allocb(sizeof (*(srp)), BPRI_MED); \ 810*0Sstevel@tonic-gate if ((nmp) == NULL) { \ 811*0Sstevel@tonic-gate switch (seterror) { \ 812*0Sstevel@tonic-gate case B_TRUE: \ 813*0Sstevel@tonic-gate *error = 1; \ 814*0Sstevel@tonic-gate break; \ 815*0Sstevel@tonic-gate } \ 816*0Sstevel@tonic-gate return (NULL); \ 817*0Sstevel@tonic-gate } \ 818*0Sstevel@tonic-gate DB_TYPE(nmp) = M_CTL; \ 819*0Sstevel@tonic-gate (nmp)->b_cont = dmp; \ 820*0Sstevel@tonic-gate } \ 821*0Sstevel@tonic-gate (srp) = (sctp_reass_t *)DB_BASE(nmp); 822*0Sstevel@tonic-gate 823*0Sstevel@tonic-gate *error = 0; 824*0Sstevel@tonic-gate 825*0Sstevel@tonic-gate /* find the reassembly queue for this data chunk */ 826*0Sstevel@tonic-gate hmp = qmp = sip->istr_reass; 827*0Sstevel@tonic-gate for (; hmp != NULL; hmp = hmp->b_next) { 828*0Sstevel@tonic-gate srp = (sctp_reass_t *)DB_BASE(hmp); 829*0Sstevel@tonic-gate if (ntohs((*dc)->sdh_ssn) == srp->ssn) 830*0Sstevel@tonic-gate goto foundit; 831*0Sstevel@tonic-gate else if (SSN_GT(srp->ssn, ntohs((*dc)->sdh_ssn))) 832*0Sstevel@tonic-gate break; 833*0Sstevel@tonic-gate qmp = hmp; 834*0Sstevel@tonic-gate } 835*0Sstevel@tonic-gate 836*0Sstevel@tonic-gate SCTP_NEW_REASS(pmp, dmp, srp, B_TRUE); 837*0Sstevel@tonic-gate srp->ssn = ntohs((*dc)->sdh_ssn); 838*0Sstevel@tonic-gate srp->needed = 0; 839*0Sstevel@tonic-gate srp->got = 1; 840*0Sstevel@tonic-gate srp->tail = dmp; 841*0Sstevel@tonic-gate srp->partial_delivered = B_FALSE; 842*0Sstevel@tonic-gate 843*0Sstevel@tonic-gate if (hmp != NULL) { 844*0Sstevel@tonic-gate if (sip->istr_reass == hmp) { 845*0Sstevel@tonic-gate sip->istr_reass = pmp; 846*0Sstevel@tonic-gate pmp->b_next = hmp; 847*0Sstevel@tonic-gate pmp->b_prev = NULL; 848*0Sstevel@tonic-gate hmp->b_prev = pmp; 849*0Sstevel@tonic-gate } else { 850*0Sstevel@tonic-gate qmp->b_next = pmp; 851*0Sstevel@tonic-gate pmp->b_prev = qmp; 852*0Sstevel@tonic-gate pmp->b_next = hmp; 853*0Sstevel@tonic-gate hmp->b_prev = pmp; 854*0Sstevel@tonic-gate } 855*0Sstevel@tonic-gate } else { 856*0Sstevel@tonic-gate /* make a new reass head and stick it on the end */ 857*0Sstevel@tonic-gate if (sip->istr_reass == NULL) { 858*0Sstevel@tonic-gate sip->istr_reass = pmp; 859*0Sstevel@tonic-gate pmp->b_prev = NULL; 860*0Sstevel@tonic-gate } else { 861*0Sstevel@tonic-gate qmp->b_next = pmp; 862*0Sstevel@tonic-gate pmp->b_prev = qmp; 863*0Sstevel@tonic-gate } 864*0Sstevel@tonic-gate pmp->b_next = NULL; 865*0Sstevel@tonic-gate } 866*0Sstevel@tonic-gate return (NULL); 867*0Sstevel@tonic-gate foundit: 868*0Sstevel@tonic-gate /* 869*0Sstevel@tonic-gate * else already have a reassembly queue. Insert the new data chunk 870*0Sstevel@tonic-gate * in the reassemble queue. Try the tail first, on the assumption 871*0Sstevel@tonic-gate * that the fragments are coming in in order. 872*0Sstevel@tonic-gate */ 873*0Sstevel@tonic-gate 874*0Sstevel@tonic-gate qmp = srp->tail; 875*0Sstevel@tonic-gate qdc = (sctp_data_hdr_t *)qmp->b_rptr; 876*0Sstevel@tonic-gate ASSERT(qmp->b_cont == NULL); 877*0Sstevel@tonic-gate 878*0Sstevel@tonic-gate /* XXXIs it fine to do this just here? */ 879*0Sstevel@tonic-gate if ((*dc)->sdh_sid != qdc->sdh_sid) { 880*0Sstevel@tonic-gate /* our peer is fatally confused; XXX abort the assc */ 881*0Sstevel@tonic-gate *error = 2; 882*0Sstevel@tonic-gate return (NULL); 883*0Sstevel@tonic-gate } 884*0Sstevel@tonic-gate if (SEQ_GT(ntohl((*dc)->sdh_tsn), ntohl(qdc->sdh_tsn))) { 885*0Sstevel@tonic-gate qmp->b_cont = dmp; 886*0Sstevel@tonic-gate srp->tail = dmp; 887*0Sstevel@tonic-gate dmp->b_cont = NULL; 888*0Sstevel@tonic-gate goto inserted; 889*0Sstevel@tonic-gate } 890*0Sstevel@tonic-gate 891*0Sstevel@tonic-gate /* Next check for insertion at the beginning */ 892*0Sstevel@tonic-gate qmp = (DB_TYPE(hmp) == M_DATA) ? hmp : hmp->b_cont; 893*0Sstevel@tonic-gate qdc = (sctp_data_hdr_t *)qmp->b_rptr; 894*0Sstevel@tonic-gate if (SEQ_LT(ntohl((*dc)->sdh_tsn), ntohl(qdc->sdh_tsn))) { 895*0Sstevel@tonic-gate if (DB_TYPE(hmp) == M_DATA) { 896*0Sstevel@tonic-gate sctp_reass_t *srp1 = srp; 897*0Sstevel@tonic-gate 898*0Sstevel@tonic-gate SCTP_NEW_REASS(pmp, dmp, srp, B_TRUE); 899*0Sstevel@tonic-gate ASSERT(pmp->b_prev == NULL && pmp->b_next == NULL); 900*0Sstevel@tonic-gate if (sip->istr_reass == hmp) { 901*0Sstevel@tonic-gate sip->istr_reass = pmp; 902*0Sstevel@tonic-gate if (hmp->b_next != NULL) { 903*0Sstevel@tonic-gate hmp->b_next->b_prev = pmp; 904*0Sstevel@tonic-gate pmp->b_next = hmp->b_next; 905*0Sstevel@tonic-gate } 906*0Sstevel@tonic-gate } else { 907*0Sstevel@tonic-gate hmp->b_prev->b_next = pmp; 908*0Sstevel@tonic-gate pmp->b_prev = hmp->b_prev; 909*0Sstevel@tonic-gate if (hmp->b_next != NULL) { 910*0Sstevel@tonic-gate hmp->b_next->b_prev = pmp; 911*0Sstevel@tonic-gate pmp->b_next = hmp->b_next; 912*0Sstevel@tonic-gate } 913*0Sstevel@tonic-gate } 914*0Sstevel@tonic-gate srp->ssn = srp1->ssn; 915*0Sstevel@tonic-gate srp->needed = srp1->needed; 916*0Sstevel@tonic-gate srp->got = srp1->got; 917*0Sstevel@tonic-gate srp->tail = srp1->tail; 918*0Sstevel@tonic-gate srp->partial_delivered = srp1->partial_delivered; 919*0Sstevel@tonic-gate hmp->b_next = hmp->b_prev = NULL; 920*0Sstevel@tonic-gate dmp->b_cont = hmp; 921*0Sstevel@tonic-gate hmp = pmp; 922*0Sstevel@tonic-gate } else { 923*0Sstevel@tonic-gate ASSERT(DB_TYPE(hmp) == M_CTL); 924*0Sstevel@tonic-gate dmp->b_cont = qmp; 925*0Sstevel@tonic-gate hmp->b_cont = dmp; 926*0Sstevel@tonic-gate } 927*0Sstevel@tonic-gate goto inserted; 928*0Sstevel@tonic-gate } 929*0Sstevel@tonic-gate 930*0Sstevel@tonic-gate /* Insert somewhere in the middle */ 931*0Sstevel@tonic-gate for (;;) { 932*0Sstevel@tonic-gate /* Tail check above should have caught this */ 933*0Sstevel@tonic-gate ASSERT(qmp->b_cont != NULL); 934*0Sstevel@tonic-gate 935*0Sstevel@tonic-gate qdc = (sctp_data_hdr_t *)qmp->b_cont->b_rptr; 936*0Sstevel@tonic-gate if (SEQ_LT(ntohl((*dc)->sdh_tsn), ntohl(qdc->sdh_tsn))) { 937*0Sstevel@tonic-gate /* insert here */ 938*0Sstevel@tonic-gate dmp->b_cont = qmp->b_cont; 939*0Sstevel@tonic-gate qmp->b_cont = dmp; 940*0Sstevel@tonic-gate break; 941*0Sstevel@tonic-gate } 942*0Sstevel@tonic-gate qmp = qmp->b_cont; 943*0Sstevel@tonic-gate } 944*0Sstevel@tonic-gate 945*0Sstevel@tonic-gate inserted: 946*0Sstevel@tonic-gate (srp->got)++; 947*0Sstevel@tonic-gate first_mp = (DB_TYPE(hmp) == M_DATA) ? hmp : hmp->b_cont; 948*0Sstevel@tonic-gate if (srp->needed == 0) { 949*0Sstevel@tonic-gate /* check if we have the first and last fragments */ 950*0Sstevel@tonic-gate bdc = (sctp_data_hdr_t *)first_mp->b_rptr; 951*0Sstevel@tonic-gate edc = (sctp_data_hdr_t *)srp->tail->b_rptr; 952*0Sstevel@tonic-gate 953*0Sstevel@tonic-gate /* calculate how many fragments are needed, if possible */ 954*0Sstevel@tonic-gate if (SCTP_DATA_GET_BBIT(bdc) && SCTP_DATA_GET_EBIT(edc)) 955*0Sstevel@tonic-gate srp->needed = ntohl(edc->sdh_tsn) - 956*0Sstevel@tonic-gate ntohl(bdc->sdh_tsn) + 1; 957*0Sstevel@tonic-gate } 958*0Sstevel@tonic-gate 959*0Sstevel@tonic-gate if (srp->needed != srp->got) { 960*0Sstevel@tonic-gate if (!trypartial) 961*0Sstevel@tonic-gate return (NULL); 962*0Sstevel@tonic-gate /* 963*0Sstevel@tonic-gate * Try partial delivery. We need a consecutive run of 964*0Sstevel@tonic-gate * at least two chunks, starting from the first chunk 965*0Sstevel@tonic-gate * (which may have been the last + 1 chunk from a 966*0Sstevel@tonic-gate * previous partial delivery). 967*0Sstevel@tonic-gate */ 968*0Sstevel@tonic-gate dprint(4, ("trypartial: got=%d, needed=%d\n", 969*0Sstevel@tonic-gate (int)(srp->got), (int)(srp->needed))); 970*0Sstevel@tonic-gate mp = first_mp; 971*0Sstevel@tonic-gate if (mp->b_cont == NULL) { 972*0Sstevel@tonic-gate /* need at least two chunks */ 973*0Sstevel@tonic-gate dprint(4, ("trypartial: only 1 chunk\n")); 974*0Sstevel@tonic-gate return (NULL); 975*0Sstevel@tonic-gate } 976*0Sstevel@tonic-gate 977*0Sstevel@tonic-gate qdc = (sctp_data_hdr_t *)mp->b_rptr; 978*0Sstevel@tonic-gate if (!SCTP_DATA_GET_BBIT(qdc)) { 979*0Sstevel@tonic-gate /* don't have first chunk; can't do it. */ 980*0Sstevel@tonic-gate dprint(4, ("trypartial: no beginning\n")); 981*0Sstevel@tonic-gate return (NULL); 982*0Sstevel@tonic-gate } 983*0Sstevel@tonic-gate 984*0Sstevel@tonic-gate tsn = ntohl(qdc->sdh_tsn) + 1; 985*0Sstevel@tonic-gate 986*0Sstevel@tonic-gate /* 987*0Sstevel@tonic-gate * This loop has two exit conditions: the 988*0Sstevel@tonic-gate * end of received chunks has been reached, or 989*0Sstevel@tonic-gate * there is a break in the sequence. We want 990*0Sstevel@tonic-gate * to chop the reassembly list as follows (the 991*0Sstevel@tonic-gate * numbers are TSNs): 992*0Sstevel@tonic-gate * 10 -> 11 -> | 12 (end of chunks) 993*0Sstevel@tonic-gate * 10 -> 11 -> | 12 -> 14 (break in sequence) 994*0Sstevel@tonic-gate */ 995*0Sstevel@tonic-gate prevprev = prev = mp; 996*0Sstevel@tonic-gate mp = mp->b_cont; 997*0Sstevel@tonic-gate while (mp != NULL) { 998*0Sstevel@tonic-gate qdc = (sctp_data_hdr_t *)mp->b_rptr; 999*0Sstevel@tonic-gate if (ntohl(qdc->sdh_tsn) != tsn) { 1000*0Sstevel@tonic-gate /* 1001*0Sstevel@tonic-gate * break in sequence. 1002*0Sstevel@tonic-gate * 1st and 2nd chunks are not sequntial. 1003*0Sstevel@tonic-gate */ 1004*0Sstevel@tonic-gate if (mp == first_mp->b_cont) 1005*0Sstevel@tonic-gate return (NULL); 1006*0Sstevel@tonic-gate /* Back up mp and prev */ 1007*0Sstevel@tonic-gate mp = prev; 1008*0Sstevel@tonic-gate prev = prevprev; 1009*0Sstevel@tonic-gate break; 1010*0Sstevel@tonic-gate } 1011*0Sstevel@tonic-gate 1012*0Sstevel@tonic-gate /* end of sequence */ 1013*0Sstevel@tonic-gate if (mp->b_cont == NULL) 1014*0Sstevel@tonic-gate break; 1015*0Sstevel@tonic-gate 1016*0Sstevel@tonic-gate prevprev = prev; 1017*0Sstevel@tonic-gate prev = mp; 1018*0Sstevel@tonic-gate mp = mp->b_cont; 1019*0Sstevel@tonic-gate tsn++; 1020*0Sstevel@tonic-gate } 1021*0Sstevel@tonic-gate if (DB_TYPE(hmp) == M_DATA) { 1022*0Sstevel@tonic-gate sctp_reass_t *srp1 = srp; 1023*0Sstevel@tonic-gate 1024*0Sstevel@tonic-gate SCTP_NEW_REASS(pmp, mp, srp, B_FALSE); 1025*0Sstevel@tonic-gate ASSERT(pmp->b_prev == NULL && pmp->b_next == NULL); 1026*0Sstevel@tonic-gate if (sip->istr_reass == hmp) { 1027*0Sstevel@tonic-gate sip->istr_reass = pmp; 1028*0Sstevel@tonic-gate if (hmp->b_next != NULL) { 1029*0Sstevel@tonic-gate hmp->b_next->b_prev = pmp; 1030*0Sstevel@tonic-gate pmp->b_next = hmp->b_next; 1031*0Sstevel@tonic-gate } 1032*0Sstevel@tonic-gate } else { 1033*0Sstevel@tonic-gate hmp->b_prev->b_next = pmp; 1034*0Sstevel@tonic-gate pmp->b_prev = hmp->b_prev; 1035*0Sstevel@tonic-gate if (hmp->b_next != NULL) { 1036*0Sstevel@tonic-gate hmp->b_next->b_prev = pmp; 1037*0Sstevel@tonic-gate pmp->b_next = hmp->b_next; 1038*0Sstevel@tonic-gate } 1039*0Sstevel@tonic-gate } 1040*0Sstevel@tonic-gate srp->ssn = srp1->ssn; 1041*0Sstevel@tonic-gate srp->needed = srp1->needed; 1042*0Sstevel@tonic-gate srp->got = srp1->got; 1043*0Sstevel@tonic-gate srp->tail = srp1->tail; 1044*0Sstevel@tonic-gate hmp->b_next = hmp->b_prev = NULL; 1045*0Sstevel@tonic-gate dmp = hmp; 1046*0Sstevel@tonic-gate hmp = pmp; 1047*0Sstevel@tonic-gate } else { 1048*0Sstevel@tonic-gate ASSERT(DB_TYPE(hmp) == M_CTL); 1049*0Sstevel@tonic-gate dmp = hmp->b_cont; 1050*0Sstevel@tonic-gate hmp->b_cont = mp; 1051*0Sstevel@tonic-gate } 1052*0Sstevel@tonic-gate /* 1053*0Sstevel@tonic-gate * mp now points at the last chunk in the sequence, 1054*0Sstevel@tonic-gate * and prev points to mp's previous in the list. 1055*0Sstevel@tonic-gate * We chop the list at prev, and convert mp into the 1056*0Sstevel@tonic-gate * new list head by setting the B bit. Subsequence 1057*0Sstevel@tonic-gate * fragment deliveries will follow the normal reassembly 1058*0Sstevel@tonic-gate * path. 1059*0Sstevel@tonic-gate */ 1060*0Sstevel@tonic-gate prev->b_cont = NULL; 1061*0Sstevel@tonic-gate bdc = (sctp_data_hdr_t *)mp->b_rptr; 1062*0Sstevel@tonic-gate SCTP_DATA_SET_BBIT(bdc); 1063*0Sstevel@tonic-gate *tpfinished = 0; 1064*0Sstevel@tonic-gate srp->partial_delivered = B_TRUE; 1065*0Sstevel@tonic-gate 1066*0Sstevel@tonic-gate dprint(4, ("trypartial: got some, got=%d, needed=%d\n", 1067*0Sstevel@tonic-gate (int)(srp->got), (int)(srp->needed))); 1068*0Sstevel@tonic-gate goto fixup; 1069*0Sstevel@tonic-gate } 1070*0Sstevel@tonic-gate 1071*0Sstevel@tonic-gate /* 1072*0Sstevel@tonic-gate * else reassembly done; prepare the data for delivery. 1073*0Sstevel@tonic-gate * First unlink hmp from the ssn list. 1074*0Sstevel@tonic-gate */ 1075*0Sstevel@tonic-gate if (sip->istr_reass == hmp) { 1076*0Sstevel@tonic-gate sip->istr_reass = hmp->b_next; 1077*0Sstevel@tonic-gate if (hmp->b_next) { 1078*0Sstevel@tonic-gate hmp->b_next->b_prev = NULL; 1079*0Sstevel@tonic-gate } 1080*0Sstevel@tonic-gate } else { 1081*0Sstevel@tonic-gate ASSERT(hmp->b_prev != NULL); 1082*0Sstevel@tonic-gate hmp->b_prev->b_next = hmp->b_next; 1083*0Sstevel@tonic-gate if (hmp->b_next) { 1084*0Sstevel@tonic-gate hmp->b_next->b_prev = hmp->b_prev; 1085*0Sstevel@tonic-gate } 1086*0Sstevel@tonic-gate } 1087*0Sstevel@tonic-gate 1088*0Sstevel@tonic-gate /* 1089*0Sstevel@tonic-gate * Using b_prev and b_next was a little sinful, but OK since 1090*0Sstevel@tonic-gate * this mblk is never put*'d. However, freeb() will still 1091*0Sstevel@tonic-gate * ASSERT that they are unused, so we need to NULL them out now. 1092*0Sstevel@tonic-gate */ 1093*0Sstevel@tonic-gate hmp->b_next = NULL; 1094*0Sstevel@tonic-gate hmp->b_prev = NULL; 1095*0Sstevel@tonic-gate dmp = hmp; 1096*0Sstevel@tonic-gate if (DB_TYPE(hmp) == M_CTL) { 1097*0Sstevel@tonic-gate dmp = dmp->b_cont; 1098*0Sstevel@tonic-gate hmp->b_cont = NULL; 1099*0Sstevel@tonic-gate freeb(hmp); 1100*0Sstevel@tonic-gate } 1101*0Sstevel@tonic-gate *tpfinished = 1; 1102*0Sstevel@tonic-gate 1103*0Sstevel@tonic-gate fixup: 1104*0Sstevel@tonic-gate /* 1105*0Sstevel@tonic-gate * Adjust all mblk's except the lead so their rptr's point to the 1106*0Sstevel@tonic-gate * payload. sctp_data_chunk() will need to process the lead's 1107*0Sstevel@tonic-gate * data chunk section, so leave it's rptr pointing at the data chunk. 1108*0Sstevel@tonic-gate */ 1109*0Sstevel@tonic-gate *dc = (sctp_data_hdr_t *)dmp->b_rptr; 1110*0Sstevel@tonic-gate if (trypartial && !(*tpfinished)) { 1111*0Sstevel@tonic-gate (srp->got)--; 1112*0Sstevel@tonic-gate ASSERT(srp->got != 0); 1113*0Sstevel@tonic-gate if (srp->needed != 0) { 1114*0Sstevel@tonic-gate (srp->needed)--; 1115*0Sstevel@tonic-gate ASSERT(srp->needed != 0); 1116*0Sstevel@tonic-gate } 1117*0Sstevel@tonic-gate } 1118*0Sstevel@tonic-gate for (qmp = dmp->b_cont; qmp; qmp = qmp->b_cont) { 1119*0Sstevel@tonic-gate qdc = (sctp_data_hdr_t *)qmp->b_rptr; 1120*0Sstevel@tonic-gate qmp->b_rptr = (uchar_t *)(qdc + 1); 1121*0Sstevel@tonic-gate 1122*0Sstevel@tonic-gate /* 1123*0Sstevel@tonic-gate * If in partial delivery, deduct the balance from got 1124*0Sstevel@tonic-gate * and needed here, now that we know we are actually 1125*0Sstevel@tonic-gate * delivering these data. 1126*0Sstevel@tonic-gate */ 1127*0Sstevel@tonic-gate if (trypartial && !(*tpfinished)) { 1128*0Sstevel@tonic-gate (srp->got)--; 1129*0Sstevel@tonic-gate ASSERT(srp->got != 0); 1130*0Sstevel@tonic-gate if (srp->needed != 0) { 1131*0Sstevel@tonic-gate (srp->needed)--; 1132*0Sstevel@tonic-gate ASSERT(srp->needed != 0); 1133*0Sstevel@tonic-gate } 1134*0Sstevel@tonic-gate } 1135*0Sstevel@tonic-gate } 1136*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_reassmsgs); 1137*0Sstevel@tonic-gate 1138*0Sstevel@tonic-gate return (dmp); 1139*0Sstevel@tonic-gate } 1140*0Sstevel@tonic-gate 1141*0Sstevel@tonic-gate static void 1142*0Sstevel@tonic-gate sctp_add_dup(uint32_t tsn, mblk_t **dups) 1143*0Sstevel@tonic-gate { 1144*0Sstevel@tonic-gate mblk_t *mp; 1145*0Sstevel@tonic-gate size_t bsize = SCTP_DUP_MBLK_SZ * sizeof (tsn); 1146*0Sstevel@tonic-gate 1147*0Sstevel@tonic-gate if (dups == NULL) { 1148*0Sstevel@tonic-gate return; 1149*0Sstevel@tonic-gate } 1150*0Sstevel@tonic-gate 1151*0Sstevel@tonic-gate /* first time? */ 1152*0Sstevel@tonic-gate if (*dups == NULL) { 1153*0Sstevel@tonic-gate *dups = allocb(bsize, BPRI_MED); 1154*0Sstevel@tonic-gate if (*dups == NULL) { 1155*0Sstevel@tonic-gate return; 1156*0Sstevel@tonic-gate } 1157*0Sstevel@tonic-gate } 1158*0Sstevel@tonic-gate 1159*0Sstevel@tonic-gate mp = *dups; 1160*0Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) >= bsize) { 1161*0Sstevel@tonic-gate /* maximum reached */ 1162*0Sstevel@tonic-gate return; 1163*0Sstevel@tonic-gate } 1164*0Sstevel@tonic-gate 1165*0Sstevel@tonic-gate /* add the duplicate tsn */ 1166*0Sstevel@tonic-gate bcopy(&tsn, mp->b_wptr, sizeof (tsn)); 1167*0Sstevel@tonic-gate mp->b_wptr += sizeof (tsn); 1168*0Sstevel@tonic-gate ASSERT((mp->b_wptr - mp->b_rptr) <= bsize); 1169*0Sstevel@tonic-gate } 1170*0Sstevel@tonic-gate 1171*0Sstevel@tonic-gate static void 1172*0Sstevel@tonic-gate sctp_data_chunk(sctp_t *sctp, sctp_chunk_hdr_t *ch, mblk_t *mp, mblk_t **dups, 1173*0Sstevel@tonic-gate sctp_faddr_t *fp, ip6_pkt_t *ipp) 1174*0Sstevel@tonic-gate { 1175*0Sstevel@tonic-gate sctp_data_hdr_t *dc; 1176*0Sstevel@tonic-gate mblk_t *dmp, *pmp; 1177*0Sstevel@tonic-gate mblk_t *errmp; 1178*0Sstevel@tonic-gate sctp_instr_t *instr; 1179*0Sstevel@tonic-gate int ubit; 1180*0Sstevel@tonic-gate int isfrag; 1181*0Sstevel@tonic-gate uint16_t ssn; 1182*0Sstevel@tonic-gate uint32_t oftsn; 1183*0Sstevel@tonic-gate boolean_t can_deliver = B_TRUE; 1184*0Sstevel@tonic-gate uint32_t tsn; 1185*0Sstevel@tonic-gate int dlen; 1186*0Sstevel@tonic-gate int trypartial = 0; 1187*0Sstevel@tonic-gate int tpfinished = 1; 1188*0Sstevel@tonic-gate int32_t new_rwnd; 1189*0Sstevel@tonic-gate 1190*0Sstevel@tonic-gate /* The following are used multiple times, so we inline them */ 1191*0Sstevel@tonic-gate #define SCTP_ACK_IT(sctp, tsn) \ 1192*0Sstevel@tonic-gate if (tsn == sctp->sctp_ftsn) { \ 1193*0Sstevel@tonic-gate dprint(2, ("data_chunk: acking next %x\n", tsn)); \ 1194*0Sstevel@tonic-gate (sctp->sctp_ftsn)++; \ 1195*0Sstevel@tonic-gate } else if (SEQ_GT(tsn, sctp->sctp_ftsn)) { \ 1196*0Sstevel@tonic-gate /* Got a gap; record it */ \ 1197*0Sstevel@tonic-gate dprint(2, ("data_chunk: acking gap %x\n", tsn)); \ 1198*0Sstevel@tonic-gate sctp_ack_add(&sctp->sctp_sack_info, \ 1199*0Sstevel@tonic-gate tsn, \ 1200*0Sstevel@tonic-gate &sctp->sctp_sack_gaps); \ 1201*0Sstevel@tonic-gate sctp->sctp_force_sack = 1; \ 1202*0Sstevel@tonic-gate } 1203*0Sstevel@tonic-gate 1204*0Sstevel@tonic-gate errmp = NULL; 1205*0Sstevel@tonic-gate dmp = NULL; 1206*0Sstevel@tonic-gate 1207*0Sstevel@tonic-gate dc = (sctp_data_hdr_t *)ch; 1208*0Sstevel@tonic-gate tsn = ntohl(dc->sdh_tsn); 1209*0Sstevel@tonic-gate 1210*0Sstevel@tonic-gate dprint(3, ("sctp_data_chunk: mp=%p tsn=%x\n", mp, tsn)); 1211*0Sstevel@tonic-gate 1212*0Sstevel@tonic-gate /* Check for duplicates */ 1213*0Sstevel@tonic-gate if (SEQ_LT(tsn, sctp->sctp_ftsn)) { 1214*0Sstevel@tonic-gate dprint(4, ("sctp_data_chunk: dropping duplicate\n")); 1215*0Sstevel@tonic-gate sctp->sctp_force_sack = 1; 1216*0Sstevel@tonic-gate sctp_add_dup(dc->sdh_tsn, dups); 1217*0Sstevel@tonic-gate return; 1218*0Sstevel@tonic-gate } 1219*0Sstevel@tonic-gate 1220*0Sstevel@tonic-gate if (sctp->sctp_sack_info != NULL) { 1221*0Sstevel@tonic-gate sctp_set_t *sp; 1222*0Sstevel@tonic-gate 1223*0Sstevel@tonic-gate for (sp = sctp->sctp_sack_info; sp; sp = sp->next) { 1224*0Sstevel@tonic-gate if (SEQ_GEQ(tsn, sp->begin) && SEQ_LEQ(tsn, sp->end)) { 1225*0Sstevel@tonic-gate dprint(4, 1226*0Sstevel@tonic-gate ("sctp_data_chunk: dropping dup > cumtsn\n")); 1227*0Sstevel@tonic-gate sctp->sctp_force_sack = 1; 1228*0Sstevel@tonic-gate sctp_add_dup(dc->sdh_tsn, dups); 1229*0Sstevel@tonic-gate return; 1230*0Sstevel@tonic-gate } 1231*0Sstevel@tonic-gate } 1232*0Sstevel@tonic-gate } 1233*0Sstevel@tonic-gate 1234*0Sstevel@tonic-gate /* We cannot deliver anything up now but we still need to handle it. */ 1235*0Sstevel@tonic-gate if (SCTP_IS_DETACHED(sctp)) { 1236*0Sstevel@tonic-gate BUMP_MIB(&sctp_mib, sctpInClosed); 1237*0Sstevel@tonic-gate can_deliver = B_FALSE; 1238*0Sstevel@tonic-gate } 1239*0Sstevel@tonic-gate 1240*0Sstevel@tonic-gate dlen = ntohs(dc->sdh_len) - sizeof (*dc); 1241*0Sstevel@tonic-gate 1242*0Sstevel@tonic-gate /* Check for buffer space */ 1243*0Sstevel@tonic-gate if (sctp->sctp_rwnd - sctp->sctp_rxqueued < dlen) { 1244*0Sstevel@tonic-gate /* Drop and SACK, but don't advance the cumulative TSN. */ 1245*0Sstevel@tonic-gate sctp->sctp_force_sack = 1; 1246*0Sstevel@tonic-gate dprint(0, ("sctp_data_chunk: exceed rwnd %d rxqueued %d " 1247*0Sstevel@tonic-gate "ssn %d tsn %x\n", sctp->sctp_rwnd, 1248*0Sstevel@tonic-gate sctp->sctp_rxqueued, dc->sdh_ssn, ntohl(dc->sdh_tsn))); 1249*0Sstevel@tonic-gate return; 1250*0Sstevel@tonic-gate } 1251*0Sstevel@tonic-gate 1252*0Sstevel@tonic-gate if (ntohs(dc->sdh_sid) >= sctp->sctp_num_istr) { 1253*0Sstevel@tonic-gate uint16_t inval_parm[2]; 1254*0Sstevel@tonic-gate 1255*0Sstevel@tonic-gate inval_parm[0] = dc->sdh_sid; 1256*0Sstevel@tonic-gate /* RESERVED to be ignored at the receiving end */ 1257*0Sstevel@tonic-gate inval_parm[1] = 0; 1258*0Sstevel@tonic-gate /* ack and drop it */ 1259*0Sstevel@tonic-gate errmp = sctp_make_err(sctp, SCTP_ERR_BAD_SID, 1260*0Sstevel@tonic-gate (char *)inval_parm, sizeof (inval_parm)); 1261*0Sstevel@tonic-gate SCTP_ACK_IT(sctp, tsn); 1262*0Sstevel@tonic-gate if (errmp != NULL) 1263*0Sstevel@tonic-gate sctp_send_err(sctp, errmp, NULL); 1264*0Sstevel@tonic-gate return; 1265*0Sstevel@tonic-gate } 1266*0Sstevel@tonic-gate 1267*0Sstevel@tonic-gate ubit = SCTP_DATA_GET_UBIT(dc); 1268*0Sstevel@tonic-gate ASSERT(sctp->sctp_instr != NULL); 1269*0Sstevel@tonic-gate instr = &sctp->sctp_instr[ntohs(dc->sdh_sid)]; 1270*0Sstevel@tonic-gate /* Initialize the stream, if not yet used */ 1271*0Sstevel@tonic-gate if (instr->sctp == NULL) 1272*0Sstevel@tonic-gate instr->sctp = sctp; 1273*0Sstevel@tonic-gate /* 1274*0Sstevel@tonic-gate * If we are getting low on buffers set trypartial to try 1275*0Sstevel@tonic-gate * a partial delivery if we are reassembling a fragmented 1276*0Sstevel@tonic-gate * message. Only do this if we can immediately deliver the 1277*0Sstevel@tonic-gate * partially assembled message, and only partially deliver 1278*0Sstevel@tonic-gate * one message at a time (i.e. messages cannot be intermixed 1279*0Sstevel@tonic-gate * arriving at the upper layer). A simple way to enforce 1280*0Sstevel@tonic-gate * this is to only try partial delivery if this TSN is 1281*0Sstevel@tonic-gate * the next expected TSN. Partial Delivery not supported 1282*0Sstevel@tonic-gate * for un-ordered message. 1283*0Sstevel@tonic-gate */ 1284*0Sstevel@tonic-gate isfrag = !(SCTP_DATA_GET_BBIT(dc) && SCTP_DATA_GET_EBIT(dc)); 1285*0Sstevel@tonic-gate ssn = ntohs(dc->sdh_ssn); 1286*0Sstevel@tonic-gate if ((sctp->sctp_rwnd - sctp->sctp_rxqueued < SCTP_RECV_LOWATER) && 1287*0Sstevel@tonic-gate !ubit && isfrag && (tsn == sctp->sctp_ftsn)) { 1288*0Sstevel@tonic-gate trypartial = 1; 1289*0Sstevel@tonic-gate } 1290*0Sstevel@tonic-gate 1291*0Sstevel@tonic-gate dmp = dupb(mp); 1292*0Sstevel@tonic-gate if (dmp == NULL) { 1293*0Sstevel@tonic-gate /* drop it and don't ack it, causing the peer to retransmit */ 1294*0Sstevel@tonic-gate return; 1295*0Sstevel@tonic-gate } 1296*0Sstevel@tonic-gate dmp->b_wptr = (uchar_t *)ch + ntohs(ch->sch_len); 1297*0Sstevel@tonic-gate 1298*0Sstevel@tonic-gate sctp->sctp_rxqueued += dlen; 1299*0Sstevel@tonic-gate 1300*0Sstevel@tonic-gate oftsn = sctp->sctp_ftsn; 1301*0Sstevel@tonic-gate 1302*0Sstevel@tonic-gate if (isfrag) { 1303*0Sstevel@tonic-gate int error = 0; 1304*0Sstevel@tonic-gate 1305*0Sstevel@tonic-gate /* fragmented data chunk */ 1306*0Sstevel@tonic-gate dmp->b_rptr = (uchar_t *)dc; 1307*0Sstevel@tonic-gate if (ubit) { 1308*0Sstevel@tonic-gate dmp = sctp_uodata_frag(sctp, dmp, &dc); 1309*0Sstevel@tonic-gate #if DEBUG 1310*0Sstevel@tonic-gate if (dmp != NULL) { 1311*0Sstevel@tonic-gate ASSERT(instr == 1312*0Sstevel@tonic-gate &sctp->sctp_instr[ntohs(dc->sdh_sid)]); 1313*0Sstevel@tonic-gate } 1314*0Sstevel@tonic-gate #endif 1315*0Sstevel@tonic-gate } else { 1316*0Sstevel@tonic-gate dmp = sctp_data_frag(sctp, dmp, &dc, &error, instr, 1317*0Sstevel@tonic-gate trypartial, &tpfinished); 1318*0Sstevel@tonic-gate } 1319*0Sstevel@tonic-gate if (error != 0) { 1320*0Sstevel@tonic-gate sctp->sctp_rxqueued -= dlen; 1321*0Sstevel@tonic-gate if (error == 1) { 1322*0Sstevel@tonic-gate /* 1323*0Sstevel@tonic-gate * out of memory; don't ack it so 1324*0Sstevel@tonic-gate * the peer retransmits 1325*0Sstevel@tonic-gate */ 1326*0Sstevel@tonic-gate return; 1327*0Sstevel@tonic-gate } else if (error == 2) { 1328*0Sstevel@tonic-gate /* 1329*0Sstevel@tonic-gate * fatal error (i.e. peer used different 1330*0Sstevel@tonic-gate * ssn's for same fragmented data) -- 1331*0Sstevel@tonic-gate * the association has been aborted. 1332*0Sstevel@tonic-gate * XXX need to return errval so state 1333*0Sstevel@tonic-gate * machine can also abort processing. 1334*0Sstevel@tonic-gate */ 1335*0Sstevel@tonic-gate dprint(0, ("error 2: must not happen!\n")); 1336*0Sstevel@tonic-gate return; 1337*0Sstevel@tonic-gate } 1338*0Sstevel@tonic-gate } 1339*0Sstevel@tonic-gate 1340*0Sstevel@tonic-gate if (dmp == NULL) { 1341*0Sstevel@tonic-gate /* 1342*0Sstevel@tonic-gate * Can't process this data now, but the cumulative 1343*0Sstevel@tonic-gate * TSN may be advanced, so do the checks at done. 1344*0Sstevel@tonic-gate */ 1345*0Sstevel@tonic-gate SCTP_ACK_IT(sctp, tsn); 1346*0Sstevel@tonic-gate goto done; 1347*0Sstevel@tonic-gate } 1348*0Sstevel@tonic-gate } 1349*0Sstevel@tonic-gate 1350*0Sstevel@tonic-gate if (!ubit && !trypartial && ssn != instr->nextseq) { 1351*0Sstevel@tonic-gate /* Adjust rptr to point at the data chunk for compares */ 1352*0Sstevel@tonic-gate dmp->b_rptr = (uchar_t *)dc; 1353*0Sstevel@tonic-gate 1354*0Sstevel@tonic-gate dprint(2, 1355*0Sstevel@tonic-gate ("data_chunk: inserted %x in pq (ssn %d expected %d)\n", 1356*0Sstevel@tonic-gate ntohl(dc->sdh_tsn), (int)(ssn), (int)(instr->nextseq))); 1357*0Sstevel@tonic-gate 1358*0Sstevel@tonic-gate if (instr->istr_msgs == NULL) { 1359*0Sstevel@tonic-gate instr->istr_msgs = dmp; 1360*0Sstevel@tonic-gate ASSERT(dmp->b_prev == NULL && dmp->b_next == NULL); 1361*0Sstevel@tonic-gate } else { 1362*0Sstevel@tonic-gate mblk_t *imblk = instr->istr_msgs; 1363*0Sstevel@tonic-gate sctp_data_hdr_t *idc; 1364*0Sstevel@tonic-gate 1365*0Sstevel@tonic-gate /* 1366*0Sstevel@tonic-gate * XXXNeed to take sequence wraps into account, 1367*0Sstevel@tonic-gate * ... and a more efficient insertion algo. 1368*0Sstevel@tonic-gate */ 1369*0Sstevel@tonic-gate for (;;) { 1370*0Sstevel@tonic-gate idc = (sctp_data_hdr_t *)imblk->b_rptr; 1371*0Sstevel@tonic-gate if (SSN_GT(ntohs(idc->sdh_ssn), 1372*0Sstevel@tonic-gate ntohs(dc->sdh_ssn))) { 1373*0Sstevel@tonic-gate if (instr->istr_msgs == imblk) { 1374*0Sstevel@tonic-gate instr->istr_msgs = dmp; 1375*0Sstevel@tonic-gate dmp->b_next = imblk; 1376*0Sstevel@tonic-gate imblk->b_prev = dmp; 1377*0Sstevel@tonic-gate } else { 1378*0Sstevel@tonic-gate ASSERT(imblk->b_prev != NULL); 1379*0Sstevel@tonic-gate imblk->b_prev->b_next = dmp; 1380*0Sstevel@tonic-gate dmp->b_prev = imblk->b_prev; 1381*0Sstevel@tonic-gate imblk->b_prev = dmp; 1382*0Sstevel@tonic-gate dmp->b_next = imblk; 1383*0Sstevel@tonic-gate } 1384*0Sstevel@tonic-gate break; 1385*0Sstevel@tonic-gate } 1386*0Sstevel@tonic-gate if (imblk->b_next == NULL) { 1387*0Sstevel@tonic-gate imblk->b_next = dmp; 1388*0Sstevel@tonic-gate dmp->b_prev = imblk; 1389*0Sstevel@tonic-gate break; 1390*0Sstevel@tonic-gate } 1391*0Sstevel@tonic-gate imblk = imblk->b_next; 1392*0Sstevel@tonic-gate } 1393*0Sstevel@tonic-gate } 1394*0Sstevel@tonic-gate (instr->istr_nmsgs)++; 1395*0Sstevel@tonic-gate (sctp->sctp_istr_nmsgs)++; 1396*0Sstevel@tonic-gate SCTP_ACK_IT(sctp, tsn); 1397*0Sstevel@tonic-gate return; 1398*0Sstevel@tonic-gate } 1399*0Sstevel@tonic-gate 1400*0Sstevel@tonic-gate /* 1401*0Sstevel@tonic-gate * Else we can deliver the data directly. Recalculate 1402*0Sstevel@tonic-gate * dlen now since we may have reassembled data. 1403*0Sstevel@tonic-gate */ 1404*0Sstevel@tonic-gate dlen = dmp->b_wptr - (uchar_t *)dc - sizeof (*dc); 1405*0Sstevel@tonic-gate for (pmp = dmp->b_cont; pmp != NULL; pmp = pmp->b_cont) 1406*0Sstevel@tonic-gate dlen += pmp->b_wptr - pmp->b_rptr; 1407*0Sstevel@tonic-gate ASSERT(sctp->sctp_rxqueued >= dlen); 1408*0Sstevel@tonic-gate ASSERT(sctp->sctp_rwnd >= dlen); 1409*0Sstevel@tonic-gate 1410*0Sstevel@tonic-gate /* Deliver the message. */ 1411*0Sstevel@tonic-gate sctp->sctp_rxqueued -= dlen; 1412*0Sstevel@tonic-gate 1413*0Sstevel@tonic-gate if (can_deliver) { 1414*0Sstevel@tonic-gate dmp->b_rptr = (uchar_t *)(dc + 1); 1415*0Sstevel@tonic-gate if (sctp_input_add_ancillary(sctp, &dmp, dc, fp, ipp) == 0) { 1416*0Sstevel@tonic-gate dprint(1, ("sctp_data_chunk: delivering %lu bytes\n", 1417*0Sstevel@tonic-gate msgdsize(dmp))); 1418*0Sstevel@tonic-gate sctp->sctp_rwnd -= dlen; 1419*0Sstevel@tonic-gate new_rwnd = sctp->sctp_ulp_recv(sctp->sctp_ulpd, dmp, 1420*0Sstevel@tonic-gate tpfinished ? 0 : SCTP_PARTIAL_DATA); 1421*0Sstevel@tonic-gate if (new_rwnd > sctp->sctp_rwnd) { 1422*0Sstevel@tonic-gate sctp->sctp_rwnd = new_rwnd; 1423*0Sstevel@tonic-gate } 1424*0Sstevel@tonic-gate SCTP_ACK_IT(sctp, tsn); 1425*0Sstevel@tonic-gate } else { 1426*0Sstevel@tonic-gate /* Just free the message if we don't have memory. */ 1427*0Sstevel@tonic-gate freemsg(dmp); 1428*0Sstevel@tonic-gate return; 1429*0Sstevel@tonic-gate } 1430*0Sstevel@tonic-gate } else { 1431*0Sstevel@tonic-gate /* About to free the data */ 1432*0Sstevel@tonic-gate freemsg(dmp); 1433*0Sstevel@tonic-gate SCTP_ACK_IT(sctp, tsn); 1434*0Sstevel@tonic-gate } 1435*0Sstevel@tonic-gate 1436*0Sstevel@tonic-gate /* 1437*0Sstevel@tonic-gate * data, now enqueued, may already have been processed and free'd 1438*0Sstevel@tonic-gate * by the ULP (or we may have just freed it above, if we could not 1439*0Sstevel@tonic-gate * deliver it), so we must not reference it (this is why we kept 1440*0Sstevel@tonic-gate * the ssn and ubit above). 1441*0Sstevel@tonic-gate */ 1442*0Sstevel@tonic-gate if (ubit != 0) { 1443*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_iudchunks); 1444*0Sstevel@tonic-gate goto done; 1445*0Sstevel@tonic-gate } 1446*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_idchunks); 1447*0Sstevel@tonic-gate 1448*0Sstevel@tonic-gate /* 1449*0Sstevel@tonic-gate * If there was a partial delivery and it has not finished, 1450*0Sstevel@tonic-gate * don't pull anything from the pqueues. 1451*0Sstevel@tonic-gate */ 1452*0Sstevel@tonic-gate if (!tpfinished) { 1453*0Sstevel@tonic-gate goto done; 1454*0Sstevel@tonic-gate } 1455*0Sstevel@tonic-gate 1456*0Sstevel@tonic-gate instr->nextseq = ssn + 1; 1457*0Sstevel@tonic-gate /* Deliver any successive data chunks in the instr queue */ 1458*0Sstevel@tonic-gate while (instr->istr_nmsgs > 0) { 1459*0Sstevel@tonic-gate dmp = (mblk_t *)instr->istr_msgs; 1460*0Sstevel@tonic-gate dc = (sctp_data_hdr_t *)dmp->b_rptr; 1461*0Sstevel@tonic-gate ssn = ntohs(dc->sdh_ssn); 1462*0Sstevel@tonic-gate /* Gap in the sequence */ 1463*0Sstevel@tonic-gate if (ssn != instr->nextseq) 1464*0Sstevel@tonic-gate break; 1465*0Sstevel@tonic-gate 1466*0Sstevel@tonic-gate /* Else deliver the data */ 1467*0Sstevel@tonic-gate (instr->istr_nmsgs)--; 1468*0Sstevel@tonic-gate (instr->nextseq)++; 1469*0Sstevel@tonic-gate (sctp->sctp_istr_nmsgs)--; 1470*0Sstevel@tonic-gate 1471*0Sstevel@tonic-gate instr->istr_msgs = instr->istr_msgs->b_next; 1472*0Sstevel@tonic-gate if (instr->istr_msgs != NULL) 1473*0Sstevel@tonic-gate instr->istr_msgs->b_prev = NULL; 1474*0Sstevel@tonic-gate dmp->b_next = dmp->b_prev = NULL; 1475*0Sstevel@tonic-gate 1476*0Sstevel@tonic-gate dprint(2, ("data_chunk: pulling %x from pq (ssn %d)\n", 1477*0Sstevel@tonic-gate ntohl(dc->sdh_tsn), (int)ssn)); 1478*0Sstevel@tonic-gate 1479*0Sstevel@tonic-gate /* 1480*0Sstevel@tonic-gate * If this chunk was reassembled, each b_cont represents 1481*0Sstevel@tonic-gate * another TSN; advance ftsn now. 1482*0Sstevel@tonic-gate */ 1483*0Sstevel@tonic-gate dlen = dmp->b_wptr - dmp->b_rptr - sizeof (*dc); 1484*0Sstevel@tonic-gate for (pmp = dmp->b_cont; pmp; pmp = pmp->b_cont) 1485*0Sstevel@tonic-gate dlen += pmp->b_wptr - pmp->b_rptr; 1486*0Sstevel@tonic-gate 1487*0Sstevel@tonic-gate ASSERT(sctp->sctp_rxqueued >= dlen); 1488*0Sstevel@tonic-gate ASSERT(sctp->sctp_rwnd >= dlen); 1489*0Sstevel@tonic-gate 1490*0Sstevel@tonic-gate sctp->sctp_rxqueued -= dlen; 1491*0Sstevel@tonic-gate if (can_deliver) { 1492*0Sstevel@tonic-gate dmp->b_rptr = (uchar_t *)(dc + 1); 1493*0Sstevel@tonic-gate if (sctp_input_add_ancillary(sctp, &dmp, dc, fp, 1494*0Sstevel@tonic-gate ipp) == 0) { 1495*0Sstevel@tonic-gate dprint(1, ("sctp_data_chunk: delivering %lu " 1496*0Sstevel@tonic-gate "bytes\n", msgdsize(dmp))); 1497*0Sstevel@tonic-gate sctp->sctp_rwnd -= dlen; 1498*0Sstevel@tonic-gate new_rwnd = sctp->sctp_ulp_recv(sctp->sctp_ulpd, 1499*0Sstevel@tonic-gate dmp, tpfinished ? 0 : SCTP_PARTIAL_DATA); 1500*0Sstevel@tonic-gate if (new_rwnd > sctp->sctp_rwnd) { 1501*0Sstevel@tonic-gate sctp->sctp_rwnd = new_rwnd; 1502*0Sstevel@tonic-gate } 1503*0Sstevel@tonic-gate SCTP_ACK_IT(sctp, tsn); 1504*0Sstevel@tonic-gate } else { 1505*0Sstevel@tonic-gate freemsg(dmp); 1506*0Sstevel@tonic-gate return; 1507*0Sstevel@tonic-gate } 1508*0Sstevel@tonic-gate } else { 1509*0Sstevel@tonic-gate /* About to free the data */ 1510*0Sstevel@tonic-gate freemsg(dmp); 1511*0Sstevel@tonic-gate SCTP_ACK_IT(sctp, tsn); 1512*0Sstevel@tonic-gate } 1513*0Sstevel@tonic-gate } 1514*0Sstevel@tonic-gate 1515*0Sstevel@tonic-gate done: 1516*0Sstevel@tonic-gate 1517*0Sstevel@tonic-gate /* 1518*0Sstevel@tonic-gate * If there are gap reports pending, check if advancing 1519*0Sstevel@tonic-gate * the ftsn here closes a gap. If so, we can advance 1520*0Sstevel@tonic-gate * ftsn to the end of the set. 1521*0Sstevel@tonic-gate */ 1522*0Sstevel@tonic-gate if (sctp->sctp_sack_info != NULL && 1523*0Sstevel@tonic-gate sctp->sctp_ftsn == sctp->sctp_sack_info->begin) { 1524*0Sstevel@tonic-gate sctp->sctp_ftsn = sctp->sctp_sack_info->end + 1; 1525*0Sstevel@tonic-gate } 1526*0Sstevel@tonic-gate /* 1527*0Sstevel@tonic-gate * If ftsn has moved forward, maybe we can remove gap reports. 1528*0Sstevel@tonic-gate * NB: dmp may now be NULL, so don't dereference it here. 1529*0Sstevel@tonic-gate */ 1530*0Sstevel@tonic-gate if (oftsn != sctp->sctp_ftsn && sctp->sctp_sack_info != NULL) { 1531*0Sstevel@tonic-gate sctp_ack_rem(&sctp->sctp_sack_info, sctp->sctp_ftsn - 1, 1532*0Sstevel@tonic-gate &sctp->sctp_sack_gaps); 1533*0Sstevel@tonic-gate dprint(2, ("data_chunk: removed acks before %x (num=%d)\n", 1534*0Sstevel@tonic-gate sctp->sctp_ftsn - 1, sctp->sctp_sack_gaps)); 1535*0Sstevel@tonic-gate } 1536*0Sstevel@tonic-gate 1537*0Sstevel@tonic-gate #ifdef DEBUG 1538*0Sstevel@tonic-gate if (sctp->sctp_sack_info != NULL) { 1539*0Sstevel@tonic-gate ASSERT(sctp->sctp_ftsn != sctp->sctp_sack_info->begin); 1540*0Sstevel@tonic-gate } 1541*0Sstevel@tonic-gate #endif 1542*0Sstevel@tonic-gate 1543*0Sstevel@tonic-gate #undef SCTP_ACK_IT 1544*0Sstevel@tonic-gate } 1545*0Sstevel@tonic-gate 1546*0Sstevel@tonic-gate void 1547*0Sstevel@tonic-gate sctp_fill_sack(sctp_t *sctp, unsigned char *dst, int sacklen) 1548*0Sstevel@tonic-gate { 1549*0Sstevel@tonic-gate sctp_chunk_hdr_t *sch; 1550*0Sstevel@tonic-gate sctp_sack_chunk_t *sc; 1551*0Sstevel@tonic-gate sctp_sack_frag_t *sf; 1552*0Sstevel@tonic-gate uint16_t num_gaps = sctp->sctp_sack_gaps; 1553*0Sstevel@tonic-gate sctp_set_t *sp; 1554*0Sstevel@tonic-gate 1555*0Sstevel@tonic-gate /* Chunk hdr */ 1556*0Sstevel@tonic-gate sch = (sctp_chunk_hdr_t *)dst; 1557*0Sstevel@tonic-gate sch->sch_id = CHUNK_SACK; 1558*0Sstevel@tonic-gate sch->sch_flags = 0; 1559*0Sstevel@tonic-gate sch->sch_len = htons(sacklen); 1560*0Sstevel@tonic-gate 1561*0Sstevel@tonic-gate /* SACK chunk */ 1562*0Sstevel@tonic-gate sctp->sctp_lastacked = sctp->sctp_ftsn - 1; 1563*0Sstevel@tonic-gate 1564*0Sstevel@tonic-gate sc = (sctp_sack_chunk_t *)(sch + 1); 1565*0Sstevel@tonic-gate sc->ssc_cumtsn = htonl(sctp->sctp_lastacked); 1566*0Sstevel@tonic-gate if (sctp->sctp_rxqueued < sctp->sctp_rwnd) { 1567*0Sstevel@tonic-gate sc->ssc_a_rwnd = htonl(sctp->sctp_rwnd - sctp->sctp_rxqueued); 1568*0Sstevel@tonic-gate } else { 1569*0Sstevel@tonic-gate sc->ssc_a_rwnd = 0; 1570*0Sstevel@tonic-gate } 1571*0Sstevel@tonic-gate sc->ssc_numfrags = htons(num_gaps); 1572*0Sstevel@tonic-gate sc->ssc_numdups = 0; 1573*0Sstevel@tonic-gate 1574*0Sstevel@tonic-gate /* lay in gap reports */ 1575*0Sstevel@tonic-gate sf = (sctp_sack_frag_t *)(sc + 1); 1576*0Sstevel@tonic-gate for (sp = sctp->sctp_sack_info; sp; sp = sp->next) { 1577*0Sstevel@tonic-gate uint16_t offset; 1578*0Sstevel@tonic-gate 1579*0Sstevel@tonic-gate /* start */ 1580*0Sstevel@tonic-gate if (sp->begin > sctp->sctp_lastacked) { 1581*0Sstevel@tonic-gate offset = (uint16_t)(sp->begin - sctp->sctp_lastacked); 1582*0Sstevel@tonic-gate } else { 1583*0Sstevel@tonic-gate /* sequence number wrap */ 1584*0Sstevel@tonic-gate offset = (uint16_t)(UINT32_MAX - sctp->sctp_lastacked + 1585*0Sstevel@tonic-gate sp->begin); 1586*0Sstevel@tonic-gate } 1587*0Sstevel@tonic-gate sf->ssf_start = htons(offset); 1588*0Sstevel@tonic-gate 1589*0Sstevel@tonic-gate /* end */ 1590*0Sstevel@tonic-gate if (sp->end >= sp->begin) { 1591*0Sstevel@tonic-gate offset += (uint16_t)(sp->end - sp->begin); 1592*0Sstevel@tonic-gate } else { 1593*0Sstevel@tonic-gate /* sequence number wrap */ 1594*0Sstevel@tonic-gate offset += (uint16_t)(UINT32_MAX - sp->begin + sp->end); 1595*0Sstevel@tonic-gate } 1596*0Sstevel@tonic-gate sf->ssf_end = htons(offset); 1597*0Sstevel@tonic-gate 1598*0Sstevel@tonic-gate sf++; 1599*0Sstevel@tonic-gate /* This is just for debugging (a la the following assertion) */ 1600*0Sstevel@tonic-gate num_gaps--; 1601*0Sstevel@tonic-gate } 1602*0Sstevel@tonic-gate 1603*0Sstevel@tonic-gate ASSERT(num_gaps == 0); 1604*0Sstevel@tonic-gate 1605*0Sstevel@tonic-gate /* If the SACK timer is running, stop it */ 1606*0Sstevel@tonic-gate if (sctp->sctp_ack_timer_running) { 1607*0Sstevel@tonic-gate sctp_timer_stop(sctp->sctp_ack_mp); 1608*0Sstevel@tonic-gate sctp->sctp_ack_timer_running = B_FALSE; 1609*0Sstevel@tonic-gate } 1610*0Sstevel@tonic-gate 1611*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_obchunks); 1612*0Sstevel@tonic-gate } 1613*0Sstevel@tonic-gate 1614*0Sstevel@tonic-gate mblk_t * 1615*0Sstevel@tonic-gate sctp_make_sack(sctp_t *sctp, sctp_faddr_t *sendto, mblk_t *dups) 1616*0Sstevel@tonic-gate { 1617*0Sstevel@tonic-gate mblk_t *smp; 1618*0Sstevel@tonic-gate size_t slen; 1619*0Sstevel@tonic-gate sctp_chunk_hdr_t *sch; 1620*0Sstevel@tonic-gate sctp_sack_chunk_t *sc; 1621*0Sstevel@tonic-gate 1622*0Sstevel@tonic-gate if (sctp->sctp_force_sack) { 1623*0Sstevel@tonic-gate sctp->sctp_force_sack = 0; 1624*0Sstevel@tonic-gate goto checks_done; 1625*0Sstevel@tonic-gate } 1626*0Sstevel@tonic-gate 1627*0Sstevel@tonic-gate if (sctp->sctp_state == SCTPS_ESTABLISHED) { 1628*0Sstevel@tonic-gate if (sctp->sctp_sack_toggle < 2) { 1629*0Sstevel@tonic-gate /* no need to SACK right now */ 1630*0Sstevel@tonic-gate dprint(2, ("sctp_make_sack: %p no sack (toggle)\n", 1631*0Sstevel@tonic-gate sctp)); 1632*0Sstevel@tonic-gate return (NULL); 1633*0Sstevel@tonic-gate } else if (sctp->sctp_sack_toggle >= 2) { 1634*0Sstevel@tonic-gate sctp->sctp_sack_toggle = 0; 1635*0Sstevel@tonic-gate } 1636*0Sstevel@tonic-gate } 1637*0Sstevel@tonic-gate 1638*0Sstevel@tonic-gate if (sctp->sctp_ftsn == sctp->sctp_lastacked + 1) { 1639*0Sstevel@tonic-gate dprint(2, ("sctp_make_sack: %p no sack (already)\n", sctp)); 1640*0Sstevel@tonic-gate return (NULL); 1641*0Sstevel@tonic-gate } 1642*0Sstevel@tonic-gate 1643*0Sstevel@tonic-gate checks_done: 1644*0Sstevel@tonic-gate dprint(2, ("sctp_make_sack: acking %x\n", sctp->sctp_ftsn - 1)); 1645*0Sstevel@tonic-gate 1646*0Sstevel@tonic-gate slen = sizeof (*sch) + sizeof (*sc) + 1647*0Sstevel@tonic-gate (sizeof (sctp_sack_frag_t) * sctp->sctp_sack_gaps); 1648*0Sstevel@tonic-gate smp = sctp_make_mp(sctp, sendto, slen); 1649*0Sstevel@tonic-gate if (smp == NULL) { 1650*0Sstevel@tonic-gate return (NULL); 1651*0Sstevel@tonic-gate } 1652*0Sstevel@tonic-gate sch = (sctp_chunk_hdr_t *)smp->b_wptr; 1653*0Sstevel@tonic-gate 1654*0Sstevel@tonic-gate sctp_fill_sack(sctp, smp->b_wptr, slen); 1655*0Sstevel@tonic-gate smp->b_wptr += slen; 1656*0Sstevel@tonic-gate if (dups) { 1657*0Sstevel@tonic-gate sc = (sctp_sack_chunk_t *)(sch + 1); 1658*0Sstevel@tonic-gate sc->ssc_numdups = htons((dups->b_wptr - dups->b_rptr) 1659*0Sstevel@tonic-gate / sizeof (uint32_t)); 1660*0Sstevel@tonic-gate sch->sch_len = htons(slen + (dups->b_wptr - dups->b_rptr)); 1661*0Sstevel@tonic-gate smp->b_cont = dups; 1662*0Sstevel@tonic-gate } 1663*0Sstevel@tonic-gate 1664*0Sstevel@tonic-gate return (smp); 1665*0Sstevel@tonic-gate } 1666*0Sstevel@tonic-gate 1667*0Sstevel@tonic-gate void 1668*0Sstevel@tonic-gate sctp_sack(sctp_t *sctp, mblk_t *dups) 1669*0Sstevel@tonic-gate { 1670*0Sstevel@tonic-gate mblk_t *smp; 1671*0Sstevel@tonic-gate 1672*0Sstevel@tonic-gate /* If we are shutting down, let send_shutdown() bundle the SACK */ 1673*0Sstevel@tonic-gate if (sctp->sctp_state == SCTPS_SHUTDOWN_SENT) { 1674*0Sstevel@tonic-gate sctp_send_shutdown(sctp, 0); 1675*0Sstevel@tonic-gate } 1676*0Sstevel@tonic-gate 1677*0Sstevel@tonic-gate ASSERT(sctp->sctp_lastdata != NULL); 1678*0Sstevel@tonic-gate 1679*0Sstevel@tonic-gate if ((smp = sctp_make_sack(sctp, sctp->sctp_lastdata, dups)) == NULL) { 1680*0Sstevel@tonic-gate /* The caller of sctp_sack() will not free the dups mblk. */ 1681*0Sstevel@tonic-gate if (dups != NULL) 1682*0Sstevel@tonic-gate freeb(dups); 1683*0Sstevel@tonic-gate return; 1684*0Sstevel@tonic-gate } 1685*0Sstevel@tonic-gate 1686*0Sstevel@tonic-gate sctp_set_iplen(sctp, smp); 1687*0Sstevel@tonic-gate 1688*0Sstevel@tonic-gate dprint(2, ("sctp_sack: sending to %p %x:%x:%x:%x\n", 1689*0Sstevel@tonic-gate sctp->sctp_lastdata, SCTP_PRINTADDR(sctp->sctp_lastdata->faddr))); 1690*0Sstevel@tonic-gate 1691*0Sstevel@tonic-gate sctp->sctp_active = lbolt64; 1692*0Sstevel@tonic-gate 1693*0Sstevel@tonic-gate BUMP_MIB(&sctp_mib, sctpOutAck); 1694*0Sstevel@tonic-gate sctp_add_sendq(sctp, smp); 1695*0Sstevel@tonic-gate } 1696*0Sstevel@tonic-gate 1697*0Sstevel@tonic-gate /* 1698*0Sstevel@tonic-gate * This is called if we have a message that was partially sent and is 1699*0Sstevel@tonic-gate * abandoned. The cum TSN will be the last chunk sent for this message, 1700*0Sstevel@tonic-gate * subsequent chunks will be marked ABANDONED. We send a Forward TSN 1701*0Sstevel@tonic-gate * chunk in this case with the TSN of the last sent chunk so that the 1702*0Sstevel@tonic-gate * peer can clean up its fragment list for this message. This message 1703*0Sstevel@tonic-gate * will be removed from the transmit list when the peer sends a SACK 1704*0Sstevel@tonic-gate * back. 1705*0Sstevel@tonic-gate */ 1706*0Sstevel@tonic-gate int 1707*0Sstevel@tonic-gate sctp_check_abandoned_msg(sctp_t *sctp, mblk_t *meta) 1708*0Sstevel@tonic-gate { 1709*0Sstevel@tonic-gate sctp_data_hdr_t *dh; 1710*0Sstevel@tonic-gate mblk_t *nmp; 1711*0Sstevel@tonic-gate mblk_t *head; 1712*0Sstevel@tonic-gate int32_t unsent = 0; 1713*0Sstevel@tonic-gate mblk_t *mp1 = meta->b_cont; 1714*0Sstevel@tonic-gate uint32_t adv_pap = sctp->sctp_adv_pap; 1715*0Sstevel@tonic-gate sctp_faddr_t *fp = sctp->sctp_current; 1716*0Sstevel@tonic-gate 1717*0Sstevel@tonic-gate dh = (sctp_data_hdr_t *)mp1->b_rptr; 1718*0Sstevel@tonic-gate if (SEQ_GEQ(sctp->sctp_lastack_rxd, ntohl(dh->sdh_tsn))) { 1719*0Sstevel@tonic-gate sctp_ftsn_set_t *sets = NULL; 1720*0Sstevel@tonic-gate uint_t nsets = 0; 1721*0Sstevel@tonic-gate uint32_t seglen = sizeof (uint32_t); 1722*0Sstevel@tonic-gate boolean_t ubit = SCTP_DATA_GET_UBIT(dh); 1723*0Sstevel@tonic-gate 1724*0Sstevel@tonic-gate while (mp1->b_next != NULL && SCTP_CHUNK_ISSENT(mp1->b_next)) 1725*0Sstevel@tonic-gate mp1 = mp1->b_next; 1726*0Sstevel@tonic-gate dh = (sctp_data_hdr_t *)mp1->b_rptr; 1727*0Sstevel@tonic-gate sctp->sctp_adv_pap = ntohl(dh->sdh_tsn); 1728*0Sstevel@tonic-gate if (!ubit && 1729*0Sstevel@tonic-gate !sctp_add_ftsn_set(&sets, fp, meta, &nsets, &seglen)) { 1730*0Sstevel@tonic-gate sctp->sctp_adv_pap = adv_pap; 1731*0Sstevel@tonic-gate return (ENOMEM); 1732*0Sstevel@tonic-gate } 1733*0Sstevel@tonic-gate nmp = sctp_make_ftsn_chunk(sctp, fp, sets, nsets, seglen); 1734*0Sstevel@tonic-gate sctp_free_ftsn_set(sets); 1735*0Sstevel@tonic-gate if (nmp == NULL) { 1736*0Sstevel@tonic-gate sctp->sctp_adv_pap = adv_pap; 1737*0Sstevel@tonic-gate return (ENOMEM); 1738*0Sstevel@tonic-gate } 1739*0Sstevel@tonic-gate head = sctp_add_proto_hdr(sctp, fp, nmp, 0); 1740*0Sstevel@tonic-gate if (head == NULL) { 1741*0Sstevel@tonic-gate sctp->sctp_adv_pap = adv_pap; 1742*0Sstevel@tonic-gate freemsg(nmp); 1743*0Sstevel@tonic-gate return (ENOMEM); 1744*0Sstevel@tonic-gate } 1745*0Sstevel@tonic-gate SCTP_MSG_SET_ABANDONED(meta); 1746*0Sstevel@tonic-gate sctp_set_iplen(sctp, head); 1747*0Sstevel@tonic-gate sctp_add_sendq(sctp, head); 1748*0Sstevel@tonic-gate if (!fp->timer_running) 1749*0Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->rto); 1750*0Sstevel@tonic-gate mp1 = mp1->b_next; 1751*0Sstevel@tonic-gate while (mp1 != NULL) { 1752*0Sstevel@tonic-gate ASSERT(!SCTP_CHUNK_ISSENT(mp1)); 1753*0Sstevel@tonic-gate ASSERT(!SCTP_CHUNK_ABANDONED(mp1)); 1754*0Sstevel@tonic-gate SCTP_ABANDON_CHUNK(mp1); 1755*0Sstevel@tonic-gate dh = (sctp_data_hdr_t *)mp1->b_rptr; 1756*0Sstevel@tonic-gate unsent += ntohs(dh->sdh_len) - sizeof (*dh); 1757*0Sstevel@tonic-gate mp1 = mp1->b_next; 1758*0Sstevel@tonic-gate } 1759*0Sstevel@tonic-gate ASSERT(sctp->sctp_unsent >= unsent); 1760*0Sstevel@tonic-gate sctp->sctp_unsent -= unsent; 1761*0Sstevel@tonic-gate /* 1762*0Sstevel@tonic-gate * Update ULP the amount of queued data, which is 1763*0Sstevel@tonic-gate * sent-unack'ed + unsent. 1764*0Sstevel@tonic-gate */ 1765*0Sstevel@tonic-gate if (!SCTP_IS_DETACHED(sctp)) { 1766*0Sstevel@tonic-gate sctp->sctp_ulp_xmitted(sctp->sctp_ulpd, 1767*0Sstevel@tonic-gate sctp->sctp_unacked + sctp->sctp_unsent); 1768*0Sstevel@tonic-gate } 1769*0Sstevel@tonic-gate return (0); 1770*0Sstevel@tonic-gate } 1771*0Sstevel@tonic-gate return (-1); 1772*0Sstevel@tonic-gate } 1773*0Sstevel@tonic-gate 1774*0Sstevel@tonic-gate uint32_t 1775*0Sstevel@tonic-gate sctp_cumack(sctp_t *sctp, uint32_t tsn, mblk_t **first_unacked) 1776*0Sstevel@tonic-gate { 1777*0Sstevel@tonic-gate mblk_t *ump, *nump, *mp = NULL; 1778*0Sstevel@tonic-gate uint16_t chunklen; 1779*0Sstevel@tonic-gate uint32_t xtsn; 1780*0Sstevel@tonic-gate sctp_faddr_t *fp; 1781*0Sstevel@tonic-gate sctp_data_hdr_t *sdc; 1782*0Sstevel@tonic-gate uint32_t cumack_forward = 0; 1783*0Sstevel@tonic-gate sctp_msg_hdr_t *mhdr; 1784*0Sstevel@tonic-gate 1785*0Sstevel@tonic-gate ump = sctp->sctp_xmit_head; 1786*0Sstevel@tonic-gate 1787*0Sstevel@tonic-gate /* 1788*0Sstevel@tonic-gate * Free messages only when they're completely acked. 1789*0Sstevel@tonic-gate */ 1790*0Sstevel@tonic-gate while (ump != NULL) { 1791*0Sstevel@tonic-gate mhdr = (sctp_msg_hdr_t *)ump->b_rptr; 1792*0Sstevel@tonic-gate for (mp = ump->b_cont; mp != NULL; mp = mp->b_next) { 1793*0Sstevel@tonic-gate if (SCTP_CHUNK_ABANDONED(mp)) { 1794*0Sstevel@tonic-gate ASSERT(SCTP_IS_MSG_ABANDONED(ump)); 1795*0Sstevel@tonic-gate mp = NULL; 1796*0Sstevel@tonic-gate break; 1797*0Sstevel@tonic-gate } 1798*0Sstevel@tonic-gate /* 1799*0Sstevel@tonic-gate * We check for abandoned message if we are PR-SCTP 1800*0Sstevel@tonic-gate * aware, if this is not the first chunk in the 1801*0Sstevel@tonic-gate * message (b_cont) and if the message is marked 1802*0Sstevel@tonic-gate * abandoned. 1803*0Sstevel@tonic-gate */ 1804*0Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp)) { 1805*0Sstevel@tonic-gate if (sctp->sctp_prsctp_aware && 1806*0Sstevel@tonic-gate mp != ump->b_cont && 1807*0Sstevel@tonic-gate (SCTP_IS_MSG_ABANDONED(ump) || 1808*0Sstevel@tonic-gate SCTP_MSG_TO_BE_ABANDONED(ump, mhdr, 1809*0Sstevel@tonic-gate sctp))) { 1810*0Sstevel@tonic-gate (void) sctp_check_abandoned_msg(sctp, 1811*0Sstevel@tonic-gate ump); 1812*0Sstevel@tonic-gate } 1813*0Sstevel@tonic-gate goto cum_ack_done; 1814*0Sstevel@tonic-gate } 1815*0Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 1816*0Sstevel@tonic-gate xtsn = ntohl(sdc->sdh_tsn); 1817*0Sstevel@tonic-gate if (SEQ_GEQ(sctp->sctp_lastack_rxd, xtsn)) 1818*0Sstevel@tonic-gate continue; 1819*0Sstevel@tonic-gate if (SEQ_GEQ(tsn, xtsn)) { 1820*0Sstevel@tonic-gate fp = SCTP_CHUNK_DEST(mp); 1821*0Sstevel@tonic-gate chunklen = ntohs(sdc->sdh_len); 1822*0Sstevel@tonic-gate 1823*0Sstevel@tonic-gate if (sctp->sctp_out_time != 0 && 1824*0Sstevel@tonic-gate xtsn == sctp->sctp_rtt_tsn) { 1825*0Sstevel@tonic-gate /* Got a new RTT measurement */ 1826*0Sstevel@tonic-gate sctp_update_rtt(sctp, fp, 1827*0Sstevel@tonic-gate lbolt64 - sctp->sctp_out_time); 1828*0Sstevel@tonic-gate sctp->sctp_out_time = 0; 1829*0Sstevel@tonic-gate } 1830*0Sstevel@tonic-gate if (SCTP_CHUNK_ISACKED(mp)) 1831*0Sstevel@tonic-gate continue; 1832*0Sstevel@tonic-gate SCTP_CHUNK_ACKED(mp); 1833*0Sstevel@tonic-gate ASSERT(fp->suna >= chunklen); 1834*0Sstevel@tonic-gate fp->suna -= chunklen; 1835*0Sstevel@tonic-gate fp->acked += chunklen; 1836*0Sstevel@tonic-gate cumack_forward += chunklen; 1837*0Sstevel@tonic-gate ASSERT(sctp->sctp_unacked >= 1838*0Sstevel@tonic-gate (chunklen - sizeof (*sdc))); 1839*0Sstevel@tonic-gate sctp->sctp_unacked -= 1840*0Sstevel@tonic-gate (chunklen - sizeof (*sdc)); 1841*0Sstevel@tonic-gate if (fp->suna == 0) { 1842*0Sstevel@tonic-gate /* all outstanding data acked */ 1843*0Sstevel@tonic-gate fp->pba = 0; 1844*0Sstevel@tonic-gate SCTP_FADDR_TIMER_STOP(fp); 1845*0Sstevel@tonic-gate } else { 1846*0Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, fp, 1847*0Sstevel@tonic-gate fp->rto); 1848*0Sstevel@tonic-gate } 1849*0Sstevel@tonic-gate } else { 1850*0Sstevel@tonic-gate goto cum_ack_done; 1851*0Sstevel@tonic-gate } 1852*0Sstevel@tonic-gate } 1853*0Sstevel@tonic-gate nump = ump->b_next; 1854*0Sstevel@tonic-gate if (nump != NULL) 1855*0Sstevel@tonic-gate nump->b_prev = NULL; 1856*0Sstevel@tonic-gate if (ump == sctp->sctp_xmit_tail) 1857*0Sstevel@tonic-gate sctp->sctp_xmit_tail = nump; 1858*0Sstevel@tonic-gate if (SCTP_IS_MSG_ABANDONED(ump)) { 1859*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_prsctpdrop); 1860*0Sstevel@tonic-gate ump->b_next = NULL; 1861*0Sstevel@tonic-gate sctp_sendfail_event(sctp, ump, 0, B_TRUE); 1862*0Sstevel@tonic-gate } else { 1863*0Sstevel@tonic-gate sctp_free_msg(ump); 1864*0Sstevel@tonic-gate } 1865*0Sstevel@tonic-gate sctp->sctp_xmit_head = ump = nump; 1866*0Sstevel@tonic-gate } 1867*0Sstevel@tonic-gate cum_ack_done: 1868*0Sstevel@tonic-gate *first_unacked = mp; 1869*0Sstevel@tonic-gate if (cumack_forward > 0) { 1870*0Sstevel@tonic-gate BUMP_MIB(&sctp_mib, sctpInAck); 1871*0Sstevel@tonic-gate if (SEQ_GT(sctp->sctp_lastack_rxd, sctp->sctp_recovery_tsn)) { 1872*0Sstevel@tonic-gate sctp->sctp_recovery_tsn = sctp->sctp_lastack_rxd; 1873*0Sstevel@tonic-gate } 1874*0Sstevel@tonic-gate 1875*0Sstevel@tonic-gate /* 1876*0Sstevel@tonic-gate * Update ULP the amount of queued data, which is 1877*0Sstevel@tonic-gate * sent-unack'ed + unsent. 1878*0Sstevel@tonic-gate */ 1879*0Sstevel@tonic-gate if (!SCTP_IS_DETACHED(sctp)) { 1880*0Sstevel@tonic-gate sctp->sctp_ulp_xmitted(sctp->sctp_ulpd, 1881*0Sstevel@tonic-gate sctp->sctp_unacked + sctp->sctp_unsent); 1882*0Sstevel@tonic-gate } 1883*0Sstevel@tonic-gate 1884*0Sstevel@tonic-gate /* Time to send a shutdown? */ 1885*0Sstevel@tonic-gate if (sctp->sctp_state == SCTPS_SHUTDOWN_PENDING) { 1886*0Sstevel@tonic-gate sctp_send_shutdown(sctp, 0); 1887*0Sstevel@tonic-gate } 1888*0Sstevel@tonic-gate sctp->sctp_xmit_unacked = mp; 1889*0Sstevel@tonic-gate } else { 1890*0Sstevel@tonic-gate /* dup ack */ 1891*0Sstevel@tonic-gate BUMP_MIB(&sctp_mib, sctpInDupAck); 1892*0Sstevel@tonic-gate } 1893*0Sstevel@tonic-gate sctp->sctp_lastack_rxd = tsn; 1894*0Sstevel@tonic-gate if (SEQ_LT(sctp->sctp_adv_pap, sctp->sctp_lastack_rxd)) 1895*0Sstevel@tonic-gate sctp->sctp_adv_pap = sctp->sctp_lastack_rxd; 1896*0Sstevel@tonic-gate ASSERT(sctp->sctp_xmit_head || sctp->sctp_unacked == 0); 1897*0Sstevel@tonic-gate 1898*0Sstevel@tonic-gate return (cumack_forward); 1899*0Sstevel@tonic-gate } 1900*0Sstevel@tonic-gate 1901*0Sstevel@tonic-gate static int 1902*0Sstevel@tonic-gate sctp_set_frwnd(sctp_t *sctp, uint32_t frwnd) 1903*0Sstevel@tonic-gate { 1904*0Sstevel@tonic-gate uint32_t orwnd; 1905*0Sstevel@tonic-gate 1906*0Sstevel@tonic-gate if (sctp->sctp_unacked > frwnd) { 1907*0Sstevel@tonic-gate sctp->sctp_frwnd = 0; 1908*0Sstevel@tonic-gate return (0); 1909*0Sstevel@tonic-gate } 1910*0Sstevel@tonic-gate orwnd = sctp->sctp_frwnd; 1911*0Sstevel@tonic-gate sctp->sctp_frwnd = frwnd - sctp->sctp_unacked; 1912*0Sstevel@tonic-gate if (orwnd < sctp->sctp_frwnd) { 1913*0Sstevel@tonic-gate return (1); 1914*0Sstevel@tonic-gate } else { 1915*0Sstevel@tonic-gate return (0); 1916*0Sstevel@tonic-gate } 1917*0Sstevel@tonic-gate } 1918*0Sstevel@tonic-gate 1919*0Sstevel@tonic-gate /* 1920*0Sstevel@tonic-gate * For un-ordered messages. 1921*0Sstevel@tonic-gate * Walk the sctp->sctp_uo_frag list and remove any fragments with TSN 1922*0Sstevel@tonic-gate * less than/equal to ftsn. Fragments for un-ordered messages are 1923*0Sstevel@tonic-gate * strictly in sequence (w.r.t TSN). 1924*0Sstevel@tonic-gate */ 1925*0Sstevel@tonic-gate static int 1926*0Sstevel@tonic-gate sctp_ftsn_check_uo_frag(sctp_t *sctp, uint32_t ftsn) 1927*0Sstevel@tonic-gate { 1928*0Sstevel@tonic-gate mblk_t *hmp; 1929*0Sstevel@tonic-gate mblk_t *hmp_next; 1930*0Sstevel@tonic-gate sctp_data_hdr_t *dc; 1931*0Sstevel@tonic-gate int dlen = 0; 1932*0Sstevel@tonic-gate 1933*0Sstevel@tonic-gate hmp = sctp->sctp_uo_frags; 1934*0Sstevel@tonic-gate while (hmp != NULL) { 1935*0Sstevel@tonic-gate hmp_next = hmp->b_next; 1936*0Sstevel@tonic-gate dc = (sctp_data_hdr_t *)hmp->b_rptr; 1937*0Sstevel@tonic-gate if (SEQ_GT(ntohl(dc->sdh_tsn), ftsn)) 1938*0Sstevel@tonic-gate return (dlen); 1939*0Sstevel@tonic-gate sctp->sctp_uo_frags = hmp_next; 1940*0Sstevel@tonic-gate if (hmp_next != NULL) 1941*0Sstevel@tonic-gate hmp_next->b_prev = NULL; 1942*0Sstevel@tonic-gate hmp->b_next = NULL; 1943*0Sstevel@tonic-gate dlen += ntohs(dc->sdh_len) - sizeof (*dc); 1944*0Sstevel@tonic-gate freeb(hmp); 1945*0Sstevel@tonic-gate hmp = hmp_next; 1946*0Sstevel@tonic-gate } 1947*0Sstevel@tonic-gate return (dlen); 1948*0Sstevel@tonic-gate } 1949*0Sstevel@tonic-gate 1950*0Sstevel@tonic-gate /* 1951*0Sstevel@tonic-gate * For ordered messages. 1952*0Sstevel@tonic-gate * Check for existing fragments for an sid-ssn pair reported as abandoned, 1953*0Sstevel@tonic-gate * hence will not receive, in the Forward TSN. If there are fragments, then 1954*0Sstevel@tonic-gate * we just nuke them. If and when Partial Delivery API is supported, we 1955*0Sstevel@tonic-gate * would need to send a notification to the upper layer about this. 1956*0Sstevel@tonic-gate */ 1957*0Sstevel@tonic-gate static int 1958*0Sstevel@tonic-gate sctp_ftsn_check_frag(sctp_t *sctp, uint16_t ssn, sctp_instr_t *sip) 1959*0Sstevel@tonic-gate { 1960*0Sstevel@tonic-gate sctp_reass_t *srp; 1961*0Sstevel@tonic-gate mblk_t *hmp; 1962*0Sstevel@tonic-gate mblk_t *dmp; 1963*0Sstevel@tonic-gate mblk_t *hmp_next; 1964*0Sstevel@tonic-gate sctp_data_hdr_t *dc; 1965*0Sstevel@tonic-gate int dlen = 0; 1966*0Sstevel@tonic-gate 1967*0Sstevel@tonic-gate hmp = sip->istr_reass; 1968*0Sstevel@tonic-gate while (hmp != NULL) { 1969*0Sstevel@tonic-gate hmp_next = hmp->b_next; 1970*0Sstevel@tonic-gate srp = (sctp_reass_t *)DB_BASE(hmp); 1971*0Sstevel@tonic-gate if (SSN_GT(srp->ssn, ssn)) 1972*0Sstevel@tonic-gate return (dlen); 1973*0Sstevel@tonic-gate /* 1974*0Sstevel@tonic-gate * If we had sent part of this message up, send a partial 1975*0Sstevel@tonic-gate * delivery event. Since this is ordered delivery, we should 1976*0Sstevel@tonic-gate * have sent partial message only for the next in sequence, 1977*0Sstevel@tonic-gate * hence the ASSERT. See comments in sctp_data_chunk() for 1978*0Sstevel@tonic-gate * trypartial. 1979*0Sstevel@tonic-gate */ 1980*0Sstevel@tonic-gate if (srp->partial_delivered) { 1981*0Sstevel@tonic-gate ASSERT(sip->nextseq == srp->ssn); 1982*0Sstevel@tonic-gate sctp_partial_delivery_event(sctp); 1983*0Sstevel@tonic-gate } 1984*0Sstevel@tonic-gate /* Take it out of the reass queue */ 1985*0Sstevel@tonic-gate sip->istr_reass = hmp_next; 1986*0Sstevel@tonic-gate if (hmp_next != NULL) 1987*0Sstevel@tonic-gate hmp_next->b_prev = NULL; 1988*0Sstevel@tonic-gate hmp->b_next = NULL; 1989*0Sstevel@tonic-gate ASSERT(hmp->b_prev == NULL); 1990*0Sstevel@tonic-gate dmp = hmp; 1991*0Sstevel@tonic-gate if (DB_TYPE(hmp) == M_CTL) { 1992*0Sstevel@tonic-gate dmp = hmp->b_cont; 1993*0Sstevel@tonic-gate hmp->b_cont = NULL; 1994*0Sstevel@tonic-gate freeb(hmp); 1995*0Sstevel@tonic-gate hmp = dmp; 1996*0Sstevel@tonic-gate } 1997*0Sstevel@tonic-gate while (dmp != NULL) { 1998*0Sstevel@tonic-gate dc = (sctp_data_hdr_t *)dmp->b_rptr; 1999*0Sstevel@tonic-gate dlen += ntohs(dc->sdh_len) - sizeof (*dc); 2000*0Sstevel@tonic-gate dmp = dmp->b_cont; 2001*0Sstevel@tonic-gate } 2002*0Sstevel@tonic-gate freemsg(hmp); 2003*0Sstevel@tonic-gate hmp = hmp_next; 2004*0Sstevel@tonic-gate } 2005*0Sstevel@tonic-gate return (dlen); 2006*0Sstevel@tonic-gate } 2007*0Sstevel@tonic-gate 2008*0Sstevel@tonic-gate /* 2009*0Sstevel@tonic-gate * Update sctp_ftsn to the cumulative TSN from the Forward TSN chunk. Remove 2010*0Sstevel@tonic-gate * any SACK gaps less than the newly updated sctp_ftsn. Walk through the 2011*0Sstevel@tonic-gate * sid-ssn pair in the Forward TSN and for each, clean the fragment list 2012*0Sstevel@tonic-gate * for this pair, if needed, and check if we can deliver subsequent 2013*0Sstevel@tonic-gate * messages, if any, from the instream queue (that were waiting for this 2014*0Sstevel@tonic-gate * sid-ssn message to show up). Once we are done try to update the SACK 2015*0Sstevel@tonic-gate * info. We could get a duplicate Forward TSN, in which case just send 2016*0Sstevel@tonic-gate * a SACK. If any of the sid values in the the Forward TSN is invalid, 2017*0Sstevel@tonic-gate * send back an "Invalid Stream Identifier" error and continue processing 2018*0Sstevel@tonic-gate * the rest. 2019*0Sstevel@tonic-gate */ 2020*0Sstevel@tonic-gate static void 2021*0Sstevel@tonic-gate sctp_process_forward_tsn(sctp_t *sctp, sctp_chunk_hdr_t *ch, sctp_faddr_t *fp, 2022*0Sstevel@tonic-gate ip6_pkt_t *ipp) 2023*0Sstevel@tonic-gate { 2024*0Sstevel@tonic-gate uint32_t *ftsn = (uint32_t *)(ch + 1); 2025*0Sstevel@tonic-gate ftsn_entry_t *ftsn_entry; 2026*0Sstevel@tonic-gate sctp_instr_t *instr; 2027*0Sstevel@tonic-gate boolean_t can_deliver = B_TRUE; 2028*0Sstevel@tonic-gate size_t dlen; 2029*0Sstevel@tonic-gate int flen; 2030*0Sstevel@tonic-gate mblk_t *dmp; 2031*0Sstevel@tonic-gate mblk_t *pmp; 2032*0Sstevel@tonic-gate sctp_data_hdr_t *dc; 2033*0Sstevel@tonic-gate ssize_t remaining; 2034*0Sstevel@tonic-gate 2035*0Sstevel@tonic-gate *ftsn = ntohl(*ftsn); 2036*0Sstevel@tonic-gate remaining = ntohs(ch->sch_len) - sizeof (*ch) - sizeof (*ftsn); 2037*0Sstevel@tonic-gate 2038*0Sstevel@tonic-gate if (SCTP_IS_DETACHED(sctp)) { 2039*0Sstevel@tonic-gate BUMP_MIB(&sctp_mib, sctpInClosed); 2040*0Sstevel@tonic-gate can_deliver = B_FALSE; 2041*0Sstevel@tonic-gate } 2042*0Sstevel@tonic-gate /* 2043*0Sstevel@tonic-gate * un-ordered messages don't have SID-SSN pair entries, we check 2044*0Sstevel@tonic-gate * for any fragments (for un-ordered message) to be discarded using 2045*0Sstevel@tonic-gate * the cumulative FTSN. 2046*0Sstevel@tonic-gate */ 2047*0Sstevel@tonic-gate flen = sctp_ftsn_check_uo_frag(sctp, *ftsn); 2048*0Sstevel@tonic-gate if (flen > 0) { 2049*0Sstevel@tonic-gate ASSERT(sctp->sctp_rxqueued >= flen); 2050*0Sstevel@tonic-gate sctp->sctp_rxqueued -= flen; 2051*0Sstevel@tonic-gate } 2052*0Sstevel@tonic-gate ftsn_entry = (ftsn_entry_t *)(ftsn + 1); 2053*0Sstevel@tonic-gate while (remaining >= sizeof (*ftsn_entry)) { 2054*0Sstevel@tonic-gate ftsn_entry->ftsn_sid = ntohs(ftsn_entry->ftsn_sid); 2055*0Sstevel@tonic-gate ftsn_entry->ftsn_ssn = ntohs(ftsn_entry->ftsn_ssn); 2056*0Sstevel@tonic-gate if (ftsn_entry->ftsn_sid >= sctp->sctp_num_istr) { 2057*0Sstevel@tonic-gate uint16_t inval_parm[2]; 2058*0Sstevel@tonic-gate mblk_t *errmp; 2059*0Sstevel@tonic-gate 2060*0Sstevel@tonic-gate inval_parm[0] = htons(ftsn_entry->ftsn_sid); 2061*0Sstevel@tonic-gate /* RESERVED to be ignored at the receiving end */ 2062*0Sstevel@tonic-gate inval_parm[1] = 0; 2063*0Sstevel@tonic-gate errmp = sctp_make_err(sctp, SCTP_ERR_BAD_SID, 2064*0Sstevel@tonic-gate (char *)inval_parm, sizeof (inval_parm)); 2065*0Sstevel@tonic-gate if (errmp != NULL) 2066*0Sstevel@tonic-gate sctp_send_err(sctp, errmp, NULL); 2067*0Sstevel@tonic-gate ftsn_entry++; 2068*0Sstevel@tonic-gate remaining -= sizeof (*ftsn_entry); 2069*0Sstevel@tonic-gate continue; 2070*0Sstevel@tonic-gate } 2071*0Sstevel@tonic-gate instr = &sctp->sctp_instr[ftsn_entry->ftsn_sid]; 2072*0Sstevel@tonic-gate flen = sctp_ftsn_check_frag(sctp, ftsn_entry->ftsn_ssn, instr); 2073*0Sstevel@tonic-gate /* Indicates frags were nuked, update rxqueued */ 2074*0Sstevel@tonic-gate if (flen > 0) { 2075*0Sstevel@tonic-gate ASSERT(sctp->sctp_rxqueued >= flen); 2076*0Sstevel@tonic-gate sctp->sctp_rxqueued -= flen; 2077*0Sstevel@tonic-gate } 2078*0Sstevel@tonic-gate /* 2079*0Sstevel@tonic-gate * It is possible to receive an FTSN chunk with SSN smaller 2080*0Sstevel@tonic-gate * than then nextseq if this chunk is a retransmission because 2081*0Sstevel@tonic-gate * of incomplete processing when it was first processed. 2082*0Sstevel@tonic-gate */ 2083*0Sstevel@tonic-gate if (SSN_GE(ftsn_entry->ftsn_ssn, instr->nextseq)) 2084*0Sstevel@tonic-gate instr->nextseq = ftsn_entry->ftsn_ssn + 1; 2085*0Sstevel@tonic-gate while (instr->istr_nmsgs > 0) { 2086*0Sstevel@tonic-gate mblk_t *next; 2087*0Sstevel@tonic-gate 2088*0Sstevel@tonic-gate dmp = (mblk_t *)instr->istr_msgs; 2089*0Sstevel@tonic-gate dc = (sctp_data_hdr_t *)dmp->b_rptr; 2090*0Sstevel@tonic-gate if (ntohs(dc->sdh_ssn) != instr->nextseq) 2091*0Sstevel@tonic-gate break; 2092*0Sstevel@tonic-gate 2093*0Sstevel@tonic-gate next = dmp->b_next; 2094*0Sstevel@tonic-gate dlen = dmp->b_wptr - dmp->b_rptr - sizeof (*dc); 2095*0Sstevel@tonic-gate for (pmp = dmp->b_cont; pmp != NULL; 2096*0Sstevel@tonic-gate pmp = pmp->b_cont) { 2097*0Sstevel@tonic-gate dlen += pmp->b_wptr - pmp->b_rptr; 2098*0Sstevel@tonic-gate } 2099*0Sstevel@tonic-gate if (can_deliver) { 2100*0Sstevel@tonic-gate int32_t nrwnd; 2101*0Sstevel@tonic-gate 2102*0Sstevel@tonic-gate dmp->b_rptr = (uchar_t *)(dc + 1); 2103*0Sstevel@tonic-gate dmp->b_next = NULL; 2104*0Sstevel@tonic-gate ASSERT(dmp->b_prev == NULL); 2105*0Sstevel@tonic-gate if (sctp_input_add_ancillary(sctp, 2106*0Sstevel@tonic-gate &dmp, dc, fp, ipp) == 0) { 2107*0Sstevel@tonic-gate sctp->sctp_rxqueued -= dlen; 2108*0Sstevel@tonic-gate sctp->sctp_rwnd -= dlen; 2109*0Sstevel@tonic-gate nrwnd = sctp->sctp_ulp_recv( 2110*0Sstevel@tonic-gate sctp->sctp_ulpd, dmp, 0); 2111*0Sstevel@tonic-gate if (nrwnd > sctp->sctp_rwnd) 2112*0Sstevel@tonic-gate sctp->sctp_rwnd = nrwnd; 2113*0Sstevel@tonic-gate } else { 2114*0Sstevel@tonic-gate /* 2115*0Sstevel@tonic-gate * We will resume processing when 2116*0Sstevel@tonic-gate * the FTSN chunk is re-xmitted. 2117*0Sstevel@tonic-gate */ 2118*0Sstevel@tonic-gate dmp->b_rptr = (uchar_t *)dc; 2119*0Sstevel@tonic-gate dmp->b_next = next; 2120*0Sstevel@tonic-gate dprint(0, 2121*0Sstevel@tonic-gate ("FTSN dequeuing %u failed\n", 2122*0Sstevel@tonic-gate ntohs(dc->sdh_ssn))); 2123*0Sstevel@tonic-gate return; 2124*0Sstevel@tonic-gate } 2125*0Sstevel@tonic-gate } else { 2126*0Sstevel@tonic-gate sctp->sctp_rxqueued -= dlen; 2127*0Sstevel@tonic-gate ASSERT(dmp->b_prev == NULL); 2128*0Sstevel@tonic-gate dmp->b_next = NULL; 2129*0Sstevel@tonic-gate freemsg(dmp); 2130*0Sstevel@tonic-gate } 2131*0Sstevel@tonic-gate instr->istr_nmsgs--; 2132*0Sstevel@tonic-gate instr->nextseq++; 2133*0Sstevel@tonic-gate sctp->sctp_istr_nmsgs--; 2134*0Sstevel@tonic-gate if (next != NULL) 2135*0Sstevel@tonic-gate next->b_prev = NULL; 2136*0Sstevel@tonic-gate instr->istr_msgs = next; 2137*0Sstevel@tonic-gate } 2138*0Sstevel@tonic-gate ftsn_entry++; 2139*0Sstevel@tonic-gate remaining -= sizeof (*ftsn_entry); 2140*0Sstevel@tonic-gate } 2141*0Sstevel@tonic-gate /* Duplicate FTSN */ 2142*0Sstevel@tonic-gate if (*ftsn <= (sctp->sctp_ftsn - 1)) { 2143*0Sstevel@tonic-gate sctp->sctp_force_sack = 1; 2144*0Sstevel@tonic-gate return; 2145*0Sstevel@tonic-gate } 2146*0Sstevel@tonic-gate /* Advance cum TSN to that reported in the Forward TSN chunk */ 2147*0Sstevel@tonic-gate sctp->sctp_ftsn = *ftsn + 1; 2148*0Sstevel@tonic-gate 2149*0Sstevel@tonic-gate /* Remove all the SACK gaps before the new cum TSN */ 2150*0Sstevel@tonic-gate if (sctp->sctp_sack_info != NULL) { 2151*0Sstevel@tonic-gate sctp_ack_rem(&sctp->sctp_sack_info, sctp->sctp_ftsn - 1, 2152*0Sstevel@tonic-gate &sctp->sctp_sack_gaps); 2153*0Sstevel@tonic-gate } 2154*0Sstevel@tonic-gate /* 2155*0Sstevel@tonic-gate * If there are gap reports pending, check if advancing 2156*0Sstevel@tonic-gate * the ftsn here closes a gap. If so, we can advance 2157*0Sstevel@tonic-gate * ftsn to the end of the set. 2158*0Sstevel@tonic-gate * If ftsn has moved forward, maybe we can remove gap reports. 2159*0Sstevel@tonic-gate */ 2160*0Sstevel@tonic-gate if (sctp->sctp_sack_info != NULL && 2161*0Sstevel@tonic-gate sctp->sctp_ftsn == sctp->sctp_sack_info->begin) { 2162*0Sstevel@tonic-gate sctp->sctp_ftsn = sctp->sctp_sack_info->end + 1; 2163*0Sstevel@tonic-gate sctp_ack_rem(&sctp->sctp_sack_info, sctp->sctp_ftsn - 1, 2164*0Sstevel@tonic-gate &sctp->sctp_sack_gaps); 2165*0Sstevel@tonic-gate } 2166*0Sstevel@tonic-gate } 2167*0Sstevel@tonic-gate 2168*0Sstevel@tonic-gate /* 2169*0Sstevel@tonic-gate * When we have processed a SACK we check to see if we can advance the 2170*0Sstevel@tonic-gate * cumulative TSN if there are abandoned chunks immediately following 2171*0Sstevel@tonic-gate * the updated cumulative TSN. If there are, we attempt to send a 2172*0Sstevel@tonic-gate * Forward TSN chunk. 2173*0Sstevel@tonic-gate */ 2174*0Sstevel@tonic-gate static void 2175*0Sstevel@tonic-gate sctp_check_abandoned_data(sctp_t *sctp, sctp_faddr_t *fp) 2176*0Sstevel@tonic-gate { 2177*0Sstevel@tonic-gate mblk_t *meta = sctp->sctp_xmit_head; 2178*0Sstevel@tonic-gate mblk_t *mp; 2179*0Sstevel@tonic-gate mblk_t *nmp; 2180*0Sstevel@tonic-gate uint32_t seglen; 2181*0Sstevel@tonic-gate uint32_t adv_pap = sctp->sctp_adv_pap; 2182*0Sstevel@tonic-gate 2183*0Sstevel@tonic-gate /* 2184*0Sstevel@tonic-gate * We only check in the first meta since otherwise we can't 2185*0Sstevel@tonic-gate * advance the cumulative ack point. We just look for chunks 2186*0Sstevel@tonic-gate * marked for retransmission, else we might prematurely 2187*0Sstevel@tonic-gate * send an FTSN for a sent, but unacked, chunk. 2188*0Sstevel@tonic-gate */ 2189*0Sstevel@tonic-gate for (mp = meta->b_cont; mp != NULL; mp = mp->b_next) { 2190*0Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp)) 2191*0Sstevel@tonic-gate return; 2192*0Sstevel@tonic-gate if (SCTP_CHUNK_WANT_REXMIT(mp)) 2193*0Sstevel@tonic-gate break; 2194*0Sstevel@tonic-gate } 2195*0Sstevel@tonic-gate if (mp == NULL) 2196*0Sstevel@tonic-gate return; 2197*0Sstevel@tonic-gate sctp_check_adv_ack_pt(sctp, meta, mp); 2198*0Sstevel@tonic-gate if (SEQ_GT(sctp->sctp_adv_pap, adv_pap)) { 2199*0Sstevel@tonic-gate sctp_make_ftsns(sctp, meta, mp, &nmp, fp, &seglen); 2200*0Sstevel@tonic-gate if (nmp == NULL) { 2201*0Sstevel@tonic-gate sctp->sctp_adv_pap = adv_pap; 2202*0Sstevel@tonic-gate if (!fp->timer_running) 2203*0Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->rto); 2204*0Sstevel@tonic-gate return; 2205*0Sstevel@tonic-gate } 2206*0Sstevel@tonic-gate sctp_set_iplen(sctp, nmp); 2207*0Sstevel@tonic-gate sctp_add_sendq(sctp, nmp); 2208*0Sstevel@tonic-gate if (!fp->timer_running) 2209*0Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->rto); 2210*0Sstevel@tonic-gate } 2211*0Sstevel@tonic-gate } 2212*0Sstevel@tonic-gate 2213*0Sstevel@tonic-gate static int 2214*0Sstevel@tonic-gate sctp_got_sack(sctp_t *sctp, sctp_chunk_hdr_t *sch) 2215*0Sstevel@tonic-gate { 2216*0Sstevel@tonic-gate sctp_sack_chunk_t *sc; 2217*0Sstevel@tonic-gate sctp_data_hdr_t *sdc; 2218*0Sstevel@tonic-gate sctp_sack_frag_t *ssf; 2219*0Sstevel@tonic-gate mblk_t *ump; 2220*0Sstevel@tonic-gate mblk_t *mp; 2221*0Sstevel@tonic-gate uint32_t tsn; 2222*0Sstevel@tonic-gate uint32_t xtsn; 2223*0Sstevel@tonic-gate uint32_t gapstart; 2224*0Sstevel@tonic-gate uint32_t gapend; 2225*0Sstevel@tonic-gate uint32_t acked = 0; 2226*0Sstevel@tonic-gate uint16_t chunklen; 2227*0Sstevel@tonic-gate sctp_faddr_t *fp; 2228*0Sstevel@tonic-gate int num_gaps; 2229*0Sstevel@tonic-gate int trysend = 0; 2230*0Sstevel@tonic-gate int i; 2231*0Sstevel@tonic-gate boolean_t fast_recovery = B_FALSE; 2232*0Sstevel@tonic-gate boolean_t cumack_forward = B_FALSE; 2233*0Sstevel@tonic-gate boolean_t fwd_tsn = B_FALSE; 2234*0Sstevel@tonic-gate 2235*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 2236*0Sstevel@tonic-gate chunklen = ntohs(sch->sch_len); 2237*0Sstevel@tonic-gate if (chunklen < (sizeof (*sch) + sizeof (*sc))) 2238*0Sstevel@tonic-gate return (0); 2239*0Sstevel@tonic-gate 2240*0Sstevel@tonic-gate sc = (sctp_sack_chunk_t *)(sch + 1); 2241*0Sstevel@tonic-gate tsn = ntohl(sc->ssc_cumtsn); 2242*0Sstevel@tonic-gate 2243*0Sstevel@tonic-gate dprint(2, ("got sack tsn %x -> %x\n", sctp->sctp_lastack_rxd, tsn)); 2244*0Sstevel@tonic-gate 2245*0Sstevel@tonic-gate /* out of order */ 2246*0Sstevel@tonic-gate if (SEQ_LT(tsn, sctp->sctp_lastack_rxd)) 2247*0Sstevel@tonic-gate return (0); 2248*0Sstevel@tonic-gate 2249*0Sstevel@tonic-gate if (SEQ_GT(tsn, sctp->sctp_ltsn - 1)) { 2250*0Sstevel@tonic-gate BUMP_MIB(&sctp_mib, sctpInAckUnsent); 2251*0Sstevel@tonic-gate /* funky; don't go beyond our own last assigned TSN */ 2252*0Sstevel@tonic-gate tsn = sctp->sctp_ltsn - 1; 2253*0Sstevel@tonic-gate } 2254*0Sstevel@tonic-gate 2255*0Sstevel@tonic-gate /* 2256*0Sstevel@tonic-gate * Cwnd only done when not in fast recovery mode. 2257*0Sstevel@tonic-gate */ 2258*0Sstevel@tonic-gate if (SEQ_LT(sctp->sctp_lastack_rxd, sctp->sctp_recovery_tsn)) 2259*0Sstevel@tonic-gate fast_recovery = B_TRUE; 2260*0Sstevel@tonic-gate 2261*0Sstevel@tonic-gate /* 2262*0Sstevel@tonic-gate * .. and if the cum TSN is not moving ahead on account Forward TSN 2263*0Sstevel@tonic-gate */ 2264*0Sstevel@tonic-gate if (SEQ_LT(sctp->sctp_lastack_rxd, sctp->sctp_adv_pap)) 2265*0Sstevel@tonic-gate fwd_tsn = B_TRUE; 2266*0Sstevel@tonic-gate 2267*0Sstevel@tonic-gate if (tsn == sctp->sctp_lastack_rxd && 2268*0Sstevel@tonic-gate (sctp->sctp_xmit_unacked == NULL || 2269*0Sstevel@tonic-gate !SCTP_CHUNK_ABANDONED(sctp->sctp_xmit_unacked))) { 2270*0Sstevel@tonic-gate if (sctp->sctp_xmit_unacked != NULL) 2271*0Sstevel@tonic-gate mp = sctp->sctp_xmit_unacked; 2272*0Sstevel@tonic-gate else if (sctp->sctp_xmit_head != NULL) 2273*0Sstevel@tonic-gate mp = sctp->sctp_xmit_head->b_cont; 2274*0Sstevel@tonic-gate else 2275*0Sstevel@tonic-gate mp = NULL; 2276*0Sstevel@tonic-gate BUMP_MIB(&sctp_mib, sctpInDupAck); 2277*0Sstevel@tonic-gate } else { 2278*0Sstevel@tonic-gate acked = sctp_cumack(sctp, tsn, &mp); 2279*0Sstevel@tonic-gate sctp->sctp_xmit_unacked = mp; 2280*0Sstevel@tonic-gate if (acked > 0) { 2281*0Sstevel@tonic-gate trysend = 1; 2282*0Sstevel@tonic-gate cumack_forward = B_TRUE; 2283*0Sstevel@tonic-gate if (fwd_tsn && SEQ_GEQ(sctp->sctp_lastack_rxd, 2284*0Sstevel@tonic-gate sctp->sctp_adv_pap)) { 2285*0Sstevel@tonic-gate cumack_forward = B_FALSE; 2286*0Sstevel@tonic-gate } 2287*0Sstevel@tonic-gate } 2288*0Sstevel@tonic-gate } 2289*0Sstevel@tonic-gate num_gaps = ntohs(sc->ssc_numfrags); 2290*0Sstevel@tonic-gate if (num_gaps == 0 || mp == NULL || !SCTP_CHUNK_ISSENT(mp) || 2291*0Sstevel@tonic-gate chunklen < (sizeof (*sch) + sizeof (*sc) + 2292*0Sstevel@tonic-gate num_gaps * sizeof (*ssf))) { 2293*0Sstevel@tonic-gate goto ret; 2294*0Sstevel@tonic-gate } 2295*0Sstevel@tonic-gate 2296*0Sstevel@tonic-gate ump = sctp->sctp_xmit_head; 2297*0Sstevel@tonic-gate 2298*0Sstevel@tonic-gate /* 2299*0Sstevel@tonic-gate * Go through SACK gaps. They are ordered based on start TSN. 2300*0Sstevel@tonic-gate */ 2301*0Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 2302*0Sstevel@tonic-gate xtsn = ntohl(sdc->sdh_tsn); 2303*0Sstevel@tonic-gate ASSERT(xtsn == tsn + 1); 2304*0Sstevel@tonic-gate 2305*0Sstevel@tonic-gate ssf = (sctp_sack_frag_t *)(sc + 1); 2306*0Sstevel@tonic-gate for (i = 0; i < num_gaps; i++) { 2307*0Sstevel@tonic-gate gapstart = tsn + ntohs(ssf->ssf_start); 2308*0Sstevel@tonic-gate gapend = tsn + ntohs(ssf->ssf_end); 2309*0Sstevel@tonic-gate 2310*0Sstevel@tonic-gate while (xtsn != gapstart) { 2311*0Sstevel@tonic-gate SCTP_CHUNK_SET_SACKCNT(mp, SCTP_CHUNK_SACKCNT(mp) + 1); 2312*0Sstevel@tonic-gate if (SCTP_CHUNK_SACKCNT(mp) == sctp_fast_rxt_thresh) { 2313*0Sstevel@tonic-gate SCTP_CHUNK_REXMIT(mp); 2314*0Sstevel@tonic-gate sctp->sctp_chk_fast_rexmit = B_TRUE; 2315*0Sstevel@tonic-gate trysend = 1; 2316*0Sstevel@tonic-gate if (!fast_recovery) { 2317*0Sstevel@tonic-gate /* 2318*0Sstevel@tonic-gate * Entering fast recovery. 2319*0Sstevel@tonic-gate */ 2320*0Sstevel@tonic-gate fp = SCTP_CHUNK_DEST(mp); 2321*0Sstevel@tonic-gate fp->ssthresh = fp->cwnd / 2; 2322*0Sstevel@tonic-gate if (fp->ssthresh < 2 * fp->sfa_pmss) { 2323*0Sstevel@tonic-gate fp->ssthresh = 2324*0Sstevel@tonic-gate 2 * fp->sfa_pmss; 2325*0Sstevel@tonic-gate } 2326*0Sstevel@tonic-gate fp->cwnd = fp->ssthresh; 2327*0Sstevel@tonic-gate fp->pba = 0; 2328*0Sstevel@tonic-gate sctp->sctp_recovery_tsn = 2329*0Sstevel@tonic-gate sctp->sctp_ltsn - 1; 2330*0Sstevel@tonic-gate fast_recovery = B_TRUE; 2331*0Sstevel@tonic-gate } 2332*0Sstevel@tonic-gate } 2333*0Sstevel@tonic-gate 2334*0Sstevel@tonic-gate /* 2335*0Sstevel@tonic-gate * Peer may have reneged on this chunk, so un-sack 2336*0Sstevel@tonic-gate * it now. If the peer did renege, we need to 2337*0Sstevel@tonic-gate * readjust unacked. 2338*0Sstevel@tonic-gate */ 2339*0Sstevel@tonic-gate if (SCTP_CHUNK_ISACKED(mp)) { 2340*0Sstevel@tonic-gate chunklen = ntohs(sdc->sdh_len); 2341*0Sstevel@tonic-gate fp = SCTP_CHUNK_DEST(mp); 2342*0Sstevel@tonic-gate fp->suna += chunklen; 2343*0Sstevel@tonic-gate sctp->sctp_unacked += chunklen - sizeof (*sdc); 2344*0Sstevel@tonic-gate SCTP_CHUNK_CLEAR_ACKED(mp); 2345*0Sstevel@tonic-gate if (!fp->timer_running) { 2346*0Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, fp, 2347*0Sstevel@tonic-gate fp->rto); 2348*0Sstevel@tonic-gate } 2349*0Sstevel@tonic-gate } 2350*0Sstevel@tonic-gate 2351*0Sstevel@tonic-gate mp = mp->b_next; 2352*0Sstevel@tonic-gate if (mp == NULL) { 2353*0Sstevel@tonic-gate ump = ump->b_next; 2354*0Sstevel@tonic-gate if (ump == NULL) { 2355*0Sstevel@tonic-gate goto ret; 2356*0Sstevel@tonic-gate } 2357*0Sstevel@tonic-gate mp = ump->b_cont; 2358*0Sstevel@tonic-gate } 2359*0Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp)) { 2360*0Sstevel@tonic-gate goto ret; 2361*0Sstevel@tonic-gate } 2362*0Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 2363*0Sstevel@tonic-gate xtsn = ntohl(sdc->sdh_tsn); 2364*0Sstevel@tonic-gate } 2365*0Sstevel@tonic-gate while (SEQ_LEQ(xtsn, gapend)) { 2366*0Sstevel@tonic-gate /* 2367*0Sstevel@tonic-gate * SACKed 2368*0Sstevel@tonic-gate */ 2369*0Sstevel@tonic-gate SCTP_CHUNK_SET_SACKCNT(mp, 0); 2370*0Sstevel@tonic-gate if (!SCTP_CHUNK_ISACKED(mp)) { 2371*0Sstevel@tonic-gate SCTP_CHUNK_ACKED(mp); 2372*0Sstevel@tonic-gate 2373*0Sstevel@tonic-gate fp = SCTP_CHUNK_DEST(mp); 2374*0Sstevel@tonic-gate chunklen = ntohs(sdc->sdh_len); 2375*0Sstevel@tonic-gate ASSERT(fp->suna >= chunklen); 2376*0Sstevel@tonic-gate fp->suna -= chunklen; 2377*0Sstevel@tonic-gate if (fp->suna == 0) { 2378*0Sstevel@tonic-gate /* All outstanding data acked. */ 2379*0Sstevel@tonic-gate fp->pba = 0; 2380*0Sstevel@tonic-gate SCTP_FADDR_TIMER_STOP(fp); 2381*0Sstevel@tonic-gate } 2382*0Sstevel@tonic-gate fp->acked += chunklen; 2383*0Sstevel@tonic-gate acked += chunklen; 2384*0Sstevel@tonic-gate sctp->sctp_unacked -= chunklen - sizeof (*sdc); 2385*0Sstevel@tonic-gate ASSERT(sctp->sctp_unacked >= 0); 2386*0Sstevel@tonic-gate } 2387*0Sstevel@tonic-gate mp = mp->b_next; 2388*0Sstevel@tonic-gate if (mp == NULL) { 2389*0Sstevel@tonic-gate ump = ump->b_next; 2390*0Sstevel@tonic-gate if (ump == NULL) { 2391*0Sstevel@tonic-gate goto ret; 2392*0Sstevel@tonic-gate } 2393*0Sstevel@tonic-gate mp = ump->b_cont; 2394*0Sstevel@tonic-gate } 2395*0Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp)) { 2396*0Sstevel@tonic-gate goto ret; 2397*0Sstevel@tonic-gate } 2398*0Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 2399*0Sstevel@tonic-gate xtsn = ntohl(sdc->sdh_tsn); 2400*0Sstevel@tonic-gate } 2401*0Sstevel@tonic-gate ssf++; 2402*0Sstevel@tonic-gate } 2403*0Sstevel@tonic-gate if (sctp->sctp_prsctp_aware) 2404*0Sstevel@tonic-gate sctp_check_abandoned_data(sctp, sctp->sctp_current); 2405*0Sstevel@tonic-gate if (sctp->sctp_chk_fast_rexmit) 2406*0Sstevel@tonic-gate sctp_fast_rexmit(sctp); 2407*0Sstevel@tonic-gate ret: 2408*0Sstevel@tonic-gate trysend += sctp_set_frwnd(sctp, ntohl(sc->ssc_a_rwnd)); 2409*0Sstevel@tonic-gate 2410*0Sstevel@tonic-gate /* 2411*0Sstevel@tonic-gate * If receive window is closed while there is unsent data, 2412*0Sstevel@tonic-gate * set a timer for doing zero window probes. 2413*0Sstevel@tonic-gate */ 2414*0Sstevel@tonic-gate if (sctp->sctp_frwnd == 0 && sctp->sctp_unacked == 0 && 2415*0Sstevel@tonic-gate sctp->sctp_unsent != 0) { 2416*0Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, sctp->sctp_current, 2417*0Sstevel@tonic-gate sctp->sctp_current->rto); 2418*0Sstevel@tonic-gate } 2419*0Sstevel@tonic-gate 2420*0Sstevel@tonic-gate /* 2421*0Sstevel@tonic-gate * Set cwnd for all destinations. 2422*0Sstevel@tonic-gate * Congestion window gets increased only when cumulative 2423*0Sstevel@tonic-gate * TSN moves forward, we're not in fast recovery, and 2424*0Sstevel@tonic-gate * cwnd has been fully utilized (almost fully, need to allow 2425*0Sstevel@tonic-gate * some leeway due to non-MSS sized messages). 2426*0Sstevel@tonic-gate */ 2427*0Sstevel@tonic-gate if (sctp->sctp_current->acked == acked) { 2428*0Sstevel@tonic-gate /* 2429*0Sstevel@tonic-gate * Fast-path, only data sent to sctp_current got acked. 2430*0Sstevel@tonic-gate */ 2431*0Sstevel@tonic-gate fp = sctp->sctp_current; 2432*0Sstevel@tonic-gate if (cumack_forward && !fast_recovery && 2433*0Sstevel@tonic-gate (fp->acked + fp->suna > fp->cwnd - fp->sfa_pmss)) { 2434*0Sstevel@tonic-gate if (fp->cwnd < fp->ssthresh) { 2435*0Sstevel@tonic-gate /* 2436*0Sstevel@tonic-gate * Slow start 2437*0Sstevel@tonic-gate */ 2438*0Sstevel@tonic-gate if (fp->acked > fp->sfa_pmss) { 2439*0Sstevel@tonic-gate fp->cwnd += fp->sfa_pmss; 2440*0Sstevel@tonic-gate } else { 2441*0Sstevel@tonic-gate fp->cwnd += fp->acked; 2442*0Sstevel@tonic-gate } 2443*0Sstevel@tonic-gate fp->cwnd = MIN(fp->cwnd, sctp->sctp_cwnd_max); 2444*0Sstevel@tonic-gate } else { 2445*0Sstevel@tonic-gate /* 2446*0Sstevel@tonic-gate * Congestion avoidance 2447*0Sstevel@tonic-gate */ 2448*0Sstevel@tonic-gate fp->pba += fp->acked; 2449*0Sstevel@tonic-gate if (fp->pba >= fp->cwnd) { 2450*0Sstevel@tonic-gate fp->pba -= fp->cwnd; 2451*0Sstevel@tonic-gate fp->cwnd += fp->sfa_pmss; 2452*0Sstevel@tonic-gate fp->cwnd = MIN(fp->cwnd, 2453*0Sstevel@tonic-gate sctp->sctp_cwnd_max); 2454*0Sstevel@tonic-gate } 2455*0Sstevel@tonic-gate } 2456*0Sstevel@tonic-gate } 2457*0Sstevel@tonic-gate /* 2458*0Sstevel@tonic-gate * Limit the burst of transmitted data segments. 2459*0Sstevel@tonic-gate */ 2460*0Sstevel@tonic-gate if (fp->suna + sctp_maxburst * fp->sfa_pmss < fp->cwnd) { 2461*0Sstevel@tonic-gate fp->cwnd = fp->suna + sctp_maxburst * fp->sfa_pmss; 2462*0Sstevel@tonic-gate } 2463*0Sstevel@tonic-gate fp->acked = 0; 2464*0Sstevel@tonic-gate return (trysend); 2465*0Sstevel@tonic-gate } 2466*0Sstevel@tonic-gate for (fp = sctp->sctp_faddrs; fp; fp = fp->next) { 2467*0Sstevel@tonic-gate if (cumack_forward && fp->acked && !fast_recovery && 2468*0Sstevel@tonic-gate (fp->acked + fp->suna > fp->cwnd - fp->sfa_pmss)) { 2469*0Sstevel@tonic-gate if (fp->cwnd < fp->ssthresh) { 2470*0Sstevel@tonic-gate if (fp->acked > fp->sfa_pmss) { 2471*0Sstevel@tonic-gate fp->cwnd += fp->sfa_pmss; 2472*0Sstevel@tonic-gate } else { 2473*0Sstevel@tonic-gate fp->cwnd += fp->acked; 2474*0Sstevel@tonic-gate } 2475*0Sstevel@tonic-gate fp->cwnd = MIN(fp->cwnd, sctp->sctp_cwnd_max); 2476*0Sstevel@tonic-gate } else { 2477*0Sstevel@tonic-gate fp->pba += fp->acked; 2478*0Sstevel@tonic-gate if (fp->pba >= fp->cwnd) { 2479*0Sstevel@tonic-gate fp->pba -= fp->cwnd; 2480*0Sstevel@tonic-gate fp->cwnd += fp->sfa_pmss; 2481*0Sstevel@tonic-gate fp->cwnd = MIN(fp->cwnd, 2482*0Sstevel@tonic-gate sctp->sctp_cwnd_max); 2483*0Sstevel@tonic-gate } 2484*0Sstevel@tonic-gate } 2485*0Sstevel@tonic-gate } 2486*0Sstevel@tonic-gate if (fp->suna + sctp_maxburst * fp->sfa_pmss < fp->cwnd) { 2487*0Sstevel@tonic-gate fp->cwnd = fp->suna + sctp_maxburst * fp->sfa_pmss; 2488*0Sstevel@tonic-gate } 2489*0Sstevel@tonic-gate fp->acked = 0; 2490*0Sstevel@tonic-gate } 2491*0Sstevel@tonic-gate return (trysend); 2492*0Sstevel@tonic-gate } 2493*0Sstevel@tonic-gate 2494*0Sstevel@tonic-gate /* 2495*0Sstevel@tonic-gate * Returns 0 if the caller should stop processing any more chunks, 2496*0Sstevel@tonic-gate * 1 if the caller should skip this chunk and continue processing. 2497*0Sstevel@tonic-gate */ 2498*0Sstevel@tonic-gate static int 2499*0Sstevel@tonic-gate sctp_strange_chunk(sctp_t *sctp, sctp_chunk_hdr_t *ch, sctp_faddr_t *fp) 2500*0Sstevel@tonic-gate { 2501*0Sstevel@tonic-gate mblk_t *errmp; 2502*0Sstevel@tonic-gate size_t len; 2503*0Sstevel@tonic-gate 2504*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 2505*0Sstevel@tonic-gate /* check top two bits for action required */ 2506*0Sstevel@tonic-gate if (ch->sch_id & 0x40) { /* also matches 0xc0 */ 2507*0Sstevel@tonic-gate len = ntohs(ch->sch_len); 2508*0Sstevel@tonic-gate errmp = sctp_make_err(sctp, SCTP_ERR_UNREC_CHUNK, ch, len); 2509*0Sstevel@tonic-gate if (errmp != NULL) 2510*0Sstevel@tonic-gate sctp_send_err(sctp, errmp, fp); 2511*0Sstevel@tonic-gate if ((ch->sch_id & 0xc0) == 0xc0) { 2512*0Sstevel@tonic-gate /* skip and continue */ 2513*0Sstevel@tonic-gate return (1); 2514*0Sstevel@tonic-gate } else { 2515*0Sstevel@tonic-gate /* stop processing */ 2516*0Sstevel@tonic-gate return (0); 2517*0Sstevel@tonic-gate } 2518*0Sstevel@tonic-gate } 2519*0Sstevel@tonic-gate if (ch->sch_id & 0x80) { 2520*0Sstevel@tonic-gate /* skip and continue, no error */ 2521*0Sstevel@tonic-gate return (1); 2522*0Sstevel@tonic-gate } 2523*0Sstevel@tonic-gate /* top two bits are clear; stop processing and no error */ 2524*0Sstevel@tonic-gate return (0); 2525*0Sstevel@tonic-gate } 2526*0Sstevel@tonic-gate 2527*0Sstevel@tonic-gate /* 2528*0Sstevel@tonic-gate * Basic sanity checks on all input chunks and parameters: they must 2529*0Sstevel@tonic-gate * be of legitimate size for their purported type, and must follow 2530*0Sstevel@tonic-gate * ordering conventions as defined in rfc2960. 2531*0Sstevel@tonic-gate * 2532*0Sstevel@tonic-gate * Returns 1 if the chunk and all encloded params are legitimate, 2533*0Sstevel@tonic-gate * 0 otherwise. 2534*0Sstevel@tonic-gate */ 2535*0Sstevel@tonic-gate /*ARGSUSED*/ 2536*0Sstevel@tonic-gate static int 2537*0Sstevel@tonic-gate sctp_check_input(sctp_t *sctp, sctp_chunk_hdr_t *ch, ssize_t len, int first) 2538*0Sstevel@tonic-gate { 2539*0Sstevel@tonic-gate sctp_parm_hdr_t *ph; 2540*0Sstevel@tonic-gate void *p = NULL; 2541*0Sstevel@tonic-gate ssize_t clen; 2542*0Sstevel@tonic-gate uint16_t ch_len; 2543*0Sstevel@tonic-gate 2544*0Sstevel@tonic-gate ch_len = ntohs(ch->sch_len); 2545*0Sstevel@tonic-gate if (ch_len > len) { 2546*0Sstevel@tonic-gate return (0); 2547*0Sstevel@tonic-gate } 2548*0Sstevel@tonic-gate 2549*0Sstevel@tonic-gate switch (ch->sch_id) { 2550*0Sstevel@tonic-gate case CHUNK_DATA: 2551*0Sstevel@tonic-gate if (ch_len < sizeof (sctp_data_hdr_t)) { 2552*0Sstevel@tonic-gate return (0); 2553*0Sstevel@tonic-gate } 2554*0Sstevel@tonic-gate return (1); 2555*0Sstevel@tonic-gate case CHUNK_INIT: 2556*0Sstevel@tonic-gate case CHUNK_INIT_ACK: 2557*0Sstevel@tonic-gate { 2558*0Sstevel@tonic-gate ssize_t remlen = len; 2559*0Sstevel@tonic-gate 2560*0Sstevel@tonic-gate /* 2561*0Sstevel@tonic-gate * INIT and INIT-ACK chunks must not be bundled with 2562*0Sstevel@tonic-gate * any other. 2563*0Sstevel@tonic-gate */ 2564*0Sstevel@tonic-gate if (!first || sctp_next_chunk(ch, &remlen) != NULL || 2565*0Sstevel@tonic-gate (ch_len < (sizeof (*ch) + 2566*0Sstevel@tonic-gate sizeof (sctp_init_chunk_t)))) { 2567*0Sstevel@tonic-gate return (0); 2568*0Sstevel@tonic-gate } 2569*0Sstevel@tonic-gate /* may have params that need checking */ 2570*0Sstevel@tonic-gate p = (char *)(ch + 1) + sizeof (sctp_init_chunk_t); 2571*0Sstevel@tonic-gate clen = ch_len - (sizeof (*ch) + 2572*0Sstevel@tonic-gate sizeof (sctp_init_chunk_t)); 2573*0Sstevel@tonic-gate } 2574*0Sstevel@tonic-gate break; 2575*0Sstevel@tonic-gate case CHUNK_SACK: 2576*0Sstevel@tonic-gate if (ch_len < (sizeof (*ch) + sizeof (sctp_sack_chunk_t))) { 2577*0Sstevel@tonic-gate return (0); 2578*0Sstevel@tonic-gate } 2579*0Sstevel@tonic-gate /* dup and gap reports checked by got_sack() */ 2580*0Sstevel@tonic-gate return (1); 2581*0Sstevel@tonic-gate case CHUNK_SHUTDOWN: 2582*0Sstevel@tonic-gate if (ch_len < (sizeof (*ch) + sizeof (uint32_t))) { 2583*0Sstevel@tonic-gate return (0); 2584*0Sstevel@tonic-gate } 2585*0Sstevel@tonic-gate return (1); 2586*0Sstevel@tonic-gate case CHUNK_ABORT: 2587*0Sstevel@tonic-gate case CHUNK_ERROR: 2588*0Sstevel@tonic-gate if (ch_len < sizeof (*ch)) { 2589*0Sstevel@tonic-gate return (0); 2590*0Sstevel@tonic-gate } 2591*0Sstevel@tonic-gate /* may have params that need checking */ 2592*0Sstevel@tonic-gate p = ch + 1; 2593*0Sstevel@tonic-gate clen = ch_len - sizeof (*ch); 2594*0Sstevel@tonic-gate break; 2595*0Sstevel@tonic-gate case CHUNK_ECNE: 2596*0Sstevel@tonic-gate case CHUNK_CWR: 2597*0Sstevel@tonic-gate case CHUNK_HEARTBEAT: 2598*0Sstevel@tonic-gate case CHUNK_HEARTBEAT_ACK: 2599*0Sstevel@tonic-gate /* Full ASCONF chunk and parameter checks are in asconf.c */ 2600*0Sstevel@tonic-gate case CHUNK_ASCONF: 2601*0Sstevel@tonic-gate case CHUNK_ASCONF_ACK: 2602*0Sstevel@tonic-gate if (ch_len < sizeof (*ch)) { 2603*0Sstevel@tonic-gate return (0); 2604*0Sstevel@tonic-gate } 2605*0Sstevel@tonic-gate /* heartbeat data checked by process_heartbeat() */ 2606*0Sstevel@tonic-gate return (1); 2607*0Sstevel@tonic-gate case CHUNK_SHUTDOWN_COMPLETE: 2608*0Sstevel@tonic-gate { 2609*0Sstevel@tonic-gate ssize_t remlen = len; 2610*0Sstevel@tonic-gate 2611*0Sstevel@tonic-gate /* 2612*0Sstevel@tonic-gate * SHUTDOWN-COMPLETE chunk must not be bundled with any 2613*0Sstevel@tonic-gate * other 2614*0Sstevel@tonic-gate */ 2615*0Sstevel@tonic-gate if (!first || sctp_next_chunk(ch, &remlen) != NULL || 2616*0Sstevel@tonic-gate ch_len < sizeof (*ch)) { 2617*0Sstevel@tonic-gate return (0); 2618*0Sstevel@tonic-gate } 2619*0Sstevel@tonic-gate } 2620*0Sstevel@tonic-gate return (1); 2621*0Sstevel@tonic-gate case CHUNK_COOKIE: 2622*0Sstevel@tonic-gate case CHUNK_COOKIE_ACK: 2623*0Sstevel@tonic-gate case CHUNK_SHUTDOWN_ACK: 2624*0Sstevel@tonic-gate if (ch_len < sizeof (*ch) || !first) { 2625*0Sstevel@tonic-gate return (0); 2626*0Sstevel@tonic-gate } 2627*0Sstevel@tonic-gate return (1); 2628*0Sstevel@tonic-gate case CHUNK_FORWARD_TSN: 2629*0Sstevel@tonic-gate if (ch_len < (sizeof (*ch) + sizeof (uint32_t))) 2630*0Sstevel@tonic-gate return (0); 2631*0Sstevel@tonic-gate return (1); 2632*0Sstevel@tonic-gate default: 2633*0Sstevel@tonic-gate return (1); /* handled by strange_chunk() */ 2634*0Sstevel@tonic-gate } 2635*0Sstevel@tonic-gate 2636*0Sstevel@tonic-gate /* check and byteorder parameters */ 2637*0Sstevel@tonic-gate if (clen <= 0) { 2638*0Sstevel@tonic-gate return (1); 2639*0Sstevel@tonic-gate } 2640*0Sstevel@tonic-gate ASSERT(p != NULL); 2641*0Sstevel@tonic-gate 2642*0Sstevel@tonic-gate ph = p; 2643*0Sstevel@tonic-gate while (ph != NULL && clen > 0) { 2644*0Sstevel@tonic-gate ch_len = ntohs(ph->sph_len); 2645*0Sstevel@tonic-gate if (ch_len > len || ch_len < sizeof (*ph)) { 2646*0Sstevel@tonic-gate return (0); 2647*0Sstevel@tonic-gate } 2648*0Sstevel@tonic-gate ph = sctp_next_parm(ph, &clen); 2649*0Sstevel@tonic-gate } 2650*0Sstevel@tonic-gate 2651*0Sstevel@tonic-gate /* All OK */ 2652*0Sstevel@tonic-gate return (1); 2653*0Sstevel@tonic-gate } 2654*0Sstevel@tonic-gate 2655*0Sstevel@tonic-gate /* ARGSUSED */ 2656*0Sstevel@tonic-gate static sctp_hdr_t * 2657*0Sstevel@tonic-gate find_sctp_hdrs(mblk_t *mp, in6_addr_t *src, in6_addr_t *dst, 2658*0Sstevel@tonic-gate uint_t *ifindex, uint_t *ip_hdr_len, ip6_pkt_t *ipp, in_pktinfo_t *pinfo) 2659*0Sstevel@tonic-gate { 2660*0Sstevel@tonic-gate uchar_t *rptr; 2661*0Sstevel@tonic-gate ipha_t *ip4h; 2662*0Sstevel@tonic-gate ip6_t *ip6h; 2663*0Sstevel@tonic-gate mblk_t *mp1; 2664*0Sstevel@tonic-gate 2665*0Sstevel@tonic-gate rptr = mp->b_rptr; 2666*0Sstevel@tonic-gate if (IPH_HDR_VERSION(rptr) == IPV4_VERSION) { 2667*0Sstevel@tonic-gate *ip_hdr_len = IPH_HDR_LENGTH(rptr); 2668*0Sstevel@tonic-gate ip4h = (ipha_t *)rptr; 2669*0Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(ip4h->ipha_src, src); 2670*0Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(ip4h->ipha_dst, dst); 2671*0Sstevel@tonic-gate 2672*0Sstevel@tonic-gate ipp->ipp_fields |= IPPF_HOPLIMIT; 2673*0Sstevel@tonic-gate ipp->ipp_hoplimit = ((ipha_t *)rptr)->ipha_ttl; 2674*0Sstevel@tonic-gate if (pinfo != NULL && (pinfo->in_pkt_flags & IPF_RECVIF)) { 2675*0Sstevel@tonic-gate ipp->ipp_fields |= IPPF_IFINDEX; 2676*0Sstevel@tonic-gate ipp->ipp_ifindex = pinfo->in_pkt_ifindex; 2677*0Sstevel@tonic-gate } 2678*0Sstevel@tonic-gate } else { 2679*0Sstevel@tonic-gate ASSERT(IPH_HDR_VERSION(rptr) == IPV6_VERSION); 2680*0Sstevel@tonic-gate ip6h = (ip6_t *)rptr; 2681*0Sstevel@tonic-gate ipp->ipp_fields = IPPF_HOPLIMIT; 2682*0Sstevel@tonic-gate ipp->ipp_hoplimit = ip6h->ip6_hops; 2683*0Sstevel@tonic-gate 2684*0Sstevel@tonic-gate if (ip6h->ip6_nxt != IPPROTO_SCTP) { 2685*0Sstevel@tonic-gate /* Look for ifindex information */ 2686*0Sstevel@tonic-gate if (ip6h->ip6_nxt == IPPROTO_RAW) { 2687*0Sstevel@tonic-gate ip6i_t *ip6i = (ip6i_t *)ip6h; 2688*0Sstevel@tonic-gate 2689*0Sstevel@tonic-gate if (ip6i->ip6i_flags & IP6I_IFINDEX) { 2690*0Sstevel@tonic-gate ASSERT(ip6i->ip6i_ifindex != 0); 2691*0Sstevel@tonic-gate ipp->ipp_fields |= IPPF_IFINDEX; 2692*0Sstevel@tonic-gate ipp->ipp_ifindex = ip6i->ip6i_ifindex; 2693*0Sstevel@tonic-gate } 2694*0Sstevel@tonic-gate rptr = (uchar_t *)&ip6i[1]; 2695*0Sstevel@tonic-gate mp->b_rptr = rptr; 2696*0Sstevel@tonic-gate if (rptr == mp->b_wptr) { 2697*0Sstevel@tonic-gate mp1 = mp->b_cont; 2698*0Sstevel@tonic-gate freeb(mp); 2699*0Sstevel@tonic-gate mp = mp1; 2700*0Sstevel@tonic-gate rptr = mp->b_rptr; 2701*0Sstevel@tonic-gate } 2702*0Sstevel@tonic-gate ASSERT(mp->b_wptr - rptr >= 2703*0Sstevel@tonic-gate IPV6_HDR_LEN + sizeof (sctp_hdr_t)); 2704*0Sstevel@tonic-gate ip6h = (ip6_t *)rptr; 2705*0Sstevel@tonic-gate } 2706*0Sstevel@tonic-gate /* 2707*0Sstevel@tonic-gate * Find any potentially interesting extension headers 2708*0Sstevel@tonic-gate * as well as the length of the IPv6 + extension 2709*0Sstevel@tonic-gate * headers. 2710*0Sstevel@tonic-gate */ 2711*0Sstevel@tonic-gate *ip_hdr_len = ip_find_hdr_v6(mp, ip6h, ipp, NULL); 2712*0Sstevel@tonic-gate } else { 2713*0Sstevel@tonic-gate *ip_hdr_len = IPV6_HDR_LEN; 2714*0Sstevel@tonic-gate } 2715*0Sstevel@tonic-gate *src = ip6h->ip6_src; 2716*0Sstevel@tonic-gate *dst = ip6h->ip6_dst; 2717*0Sstevel@tonic-gate } 2718*0Sstevel@tonic-gate ASSERT((uintptr_t)(mp->b_wptr - rptr) <= (uintptr_t)INT_MAX); 2719*0Sstevel@tonic-gate return ((sctp_hdr_t *)&rptr[*ip_hdr_len]); 2720*0Sstevel@tonic-gate #undef IPVER 2721*0Sstevel@tonic-gate } 2722*0Sstevel@tonic-gate 2723*0Sstevel@tonic-gate static mblk_t * 2724*0Sstevel@tonic-gate sctp_check_in_policy(mblk_t *mp, mblk_t *ipsec_mp) 2725*0Sstevel@tonic-gate { 2726*0Sstevel@tonic-gate ipsec_in_t *ii; 2727*0Sstevel@tonic-gate boolean_t check = B_TRUE; 2728*0Sstevel@tonic-gate boolean_t policy_present; 2729*0Sstevel@tonic-gate ipha_t *ipha; 2730*0Sstevel@tonic-gate ip6_t *ip6h; 2731*0Sstevel@tonic-gate 2732*0Sstevel@tonic-gate ii = (ipsec_in_t *)ipsec_mp->b_rptr; 2733*0Sstevel@tonic-gate ASSERT(ii->ipsec_in_type == IPSEC_IN); 2734*0Sstevel@tonic-gate if (ii->ipsec_in_dont_check) { 2735*0Sstevel@tonic-gate check = B_FALSE; 2736*0Sstevel@tonic-gate if (!ii->ipsec_in_secure) { 2737*0Sstevel@tonic-gate freeb(ipsec_mp); 2738*0Sstevel@tonic-gate ipsec_mp = NULL; 2739*0Sstevel@tonic-gate } 2740*0Sstevel@tonic-gate } 2741*0Sstevel@tonic-gate if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) { 2742*0Sstevel@tonic-gate policy_present = ipsec_inbound_v4_policy_present; 2743*0Sstevel@tonic-gate ipha = (ipha_t *)mp->b_rptr; 2744*0Sstevel@tonic-gate ip6h = NULL; 2745*0Sstevel@tonic-gate } else { 2746*0Sstevel@tonic-gate policy_present = ipsec_inbound_v6_policy_present; 2747*0Sstevel@tonic-gate ipha = NULL; 2748*0Sstevel@tonic-gate ip6h = (ip6_t *)mp->b_rptr; 2749*0Sstevel@tonic-gate } 2750*0Sstevel@tonic-gate 2751*0Sstevel@tonic-gate if (check && policy_present) { 2752*0Sstevel@tonic-gate /* 2753*0Sstevel@tonic-gate * The conn_t parameter is NULL because we already know 2754*0Sstevel@tonic-gate * nobody's home. 2755*0Sstevel@tonic-gate */ 2756*0Sstevel@tonic-gate ipsec_mp = ipsec_check_global_policy(ipsec_mp, (conn_t *)NULL, 2757*0Sstevel@tonic-gate ipha, ip6h, B_TRUE); 2758*0Sstevel@tonic-gate if (ipsec_mp == NULL) 2759*0Sstevel@tonic-gate return (NULL); 2760*0Sstevel@tonic-gate } 2761*0Sstevel@tonic-gate if (ipsec_mp != NULL) 2762*0Sstevel@tonic-gate freeb(ipsec_mp); 2763*0Sstevel@tonic-gate return (mp); 2764*0Sstevel@tonic-gate } 2765*0Sstevel@tonic-gate 2766*0Sstevel@tonic-gate /* Handle out-of-the-blue packets */ 2767*0Sstevel@tonic-gate void 2768*0Sstevel@tonic-gate sctp_ootb_input(mblk_t *mp, ill_t *recv_ill, uint_t ipif_seqid, 2769*0Sstevel@tonic-gate zoneid_t zoneid, boolean_t mctl_present) 2770*0Sstevel@tonic-gate { 2771*0Sstevel@tonic-gate sctp_t *sctp; 2772*0Sstevel@tonic-gate sctp_chunk_hdr_t *ch; 2773*0Sstevel@tonic-gate sctp_hdr_t *sctph; 2774*0Sstevel@tonic-gate in6_addr_t src, dst; 2775*0Sstevel@tonic-gate uint_t ip_hdr_len; 2776*0Sstevel@tonic-gate uint_t ifindex; 2777*0Sstevel@tonic-gate ip6_pkt_t ipp; 2778*0Sstevel@tonic-gate ssize_t mlen; 2779*0Sstevel@tonic-gate in_pktinfo_t *pinfo = NULL; 2780*0Sstevel@tonic-gate mblk_t *first_mp; 2781*0Sstevel@tonic-gate 2782*0Sstevel@tonic-gate BUMP_MIB(&sctp_mib, sctpOutOfBlue); 2783*0Sstevel@tonic-gate BUMP_MIB(&sctp_mib, sctpInSCTPPkts); 2784*0Sstevel@tonic-gate 2785*0Sstevel@tonic-gate first_mp = mp; 2786*0Sstevel@tonic-gate if (mctl_present) 2787*0Sstevel@tonic-gate mp = mp->b_cont; 2788*0Sstevel@tonic-gate 2789*0Sstevel@tonic-gate /* Initiate IPPf processing, if needed. */ 2790*0Sstevel@tonic-gate if (IPP_ENABLED(IPP_LOCAL_IN)) { 2791*0Sstevel@tonic-gate ip_process(IPP_LOCAL_IN, &mp, 2792*0Sstevel@tonic-gate recv_ill->ill_phyint->phyint_ifindex); 2793*0Sstevel@tonic-gate if (mp == NULL) { 2794*0Sstevel@tonic-gate if (mctl_present) 2795*0Sstevel@tonic-gate freeb(first_mp); 2796*0Sstevel@tonic-gate return; 2797*0Sstevel@tonic-gate } 2798*0Sstevel@tonic-gate } 2799*0Sstevel@tonic-gate 2800*0Sstevel@tonic-gate if (mp->b_cont != NULL) { 2801*0Sstevel@tonic-gate /* 2802*0Sstevel@tonic-gate * All subsequent code is vastly simplified if it can 2803*0Sstevel@tonic-gate * assume a single contiguous chunk of data. 2804*0Sstevel@tonic-gate */ 2805*0Sstevel@tonic-gate if (pullupmsg(mp, -1) == 0) { 2806*0Sstevel@tonic-gate BUMP_MIB(&ip_mib, ipInDiscards); 2807*0Sstevel@tonic-gate freemsg(first_mp); 2808*0Sstevel@tonic-gate return; 2809*0Sstevel@tonic-gate } 2810*0Sstevel@tonic-gate } 2811*0Sstevel@tonic-gate 2812*0Sstevel@tonic-gate /* 2813*0Sstevel@tonic-gate * We don't really need to call this function... Need to 2814*0Sstevel@tonic-gate * optimize later. 2815*0Sstevel@tonic-gate */ 2816*0Sstevel@tonic-gate sctph = find_sctp_hdrs(mp, &src, &dst, &ifindex, &ip_hdr_len, 2817*0Sstevel@tonic-gate &ipp, pinfo); 2818*0Sstevel@tonic-gate mlen = mp->b_wptr - (uchar_t *)(sctph + 1); 2819*0Sstevel@tonic-gate if ((ch = sctp_first_chunk((uchar_t *)(sctph + 1), mlen)) == NULL) { 2820*0Sstevel@tonic-gate dprint(3, ("sctp_ootb_input: invalid packet\n")); 2821*0Sstevel@tonic-gate BUMP_MIB(&ip_mib, ipInDiscards); 2822*0Sstevel@tonic-gate freemsg(first_mp); 2823*0Sstevel@tonic-gate return; 2824*0Sstevel@tonic-gate } 2825*0Sstevel@tonic-gate 2826*0Sstevel@tonic-gate switch (ch->sch_id) { 2827*0Sstevel@tonic-gate case CHUNK_INIT: 2828*0Sstevel@tonic-gate /* no listener; send abort */ 2829*0Sstevel@tonic-gate if (mctl_present && sctp_check_in_policy(mp, first_mp) == NULL) 2830*0Sstevel@tonic-gate return; 2831*0Sstevel@tonic-gate sctp_send_abort(gsctp, sctp_init2vtag(ch), 0, 2832*0Sstevel@tonic-gate NULL, 0, mp, 0, B_TRUE); 2833*0Sstevel@tonic-gate break; 2834*0Sstevel@tonic-gate case CHUNK_INIT_ACK: 2835*0Sstevel@tonic-gate /* check for changed src addr */ 2836*0Sstevel@tonic-gate sctp = sctp_addrlist2sctp(mp, sctph, ch, ipif_seqid, zoneid); 2837*0Sstevel@tonic-gate if (sctp != NULL) { 2838*0Sstevel@tonic-gate /* success; proceed to normal path */ 2839*0Sstevel@tonic-gate mutex_enter(&sctp->sctp_lock); 2840*0Sstevel@tonic-gate if (sctp->sctp_running) { 2841*0Sstevel@tonic-gate if (!sctp_add_recvq(sctp, mp, B_FALSE)) { 2842*0Sstevel@tonic-gate BUMP_MIB(&ip_mib, ipInDiscards); 2843*0Sstevel@tonic-gate freemsg(mp); 2844*0Sstevel@tonic-gate } 2845*0Sstevel@tonic-gate mutex_exit(&sctp->sctp_lock); 2846*0Sstevel@tonic-gate } else { 2847*0Sstevel@tonic-gate /* 2848*0Sstevel@tonic-gate * If the source address is changed, we 2849*0Sstevel@tonic-gate * don't need to worry too much about 2850*0Sstevel@tonic-gate * out of order processing. So we don't 2851*0Sstevel@tonic-gate * check if the recvq is empty or not here. 2852*0Sstevel@tonic-gate */ 2853*0Sstevel@tonic-gate sctp->sctp_running = B_TRUE; 2854*0Sstevel@tonic-gate mutex_exit(&sctp->sctp_lock); 2855*0Sstevel@tonic-gate sctp_input_data(sctp, mp, NULL); 2856*0Sstevel@tonic-gate WAKE_SCTP(sctp); 2857*0Sstevel@tonic-gate sctp_process_sendq(sctp); 2858*0Sstevel@tonic-gate } 2859*0Sstevel@tonic-gate SCTP_REFRELE(sctp); 2860*0Sstevel@tonic-gate return; 2861*0Sstevel@tonic-gate } 2862*0Sstevel@tonic-gate if (mctl_present) 2863*0Sstevel@tonic-gate freeb(first_mp); 2864*0Sstevel@tonic-gate /* else bogus init ack; drop it */ 2865*0Sstevel@tonic-gate break; 2866*0Sstevel@tonic-gate case CHUNK_SHUTDOWN_ACK: 2867*0Sstevel@tonic-gate if (mctl_present && sctp_check_in_policy(mp, first_mp) == NULL) 2868*0Sstevel@tonic-gate return; 2869*0Sstevel@tonic-gate sctp_ootb_shutdown_ack(gsctp, mp, ip_hdr_len); 2870*0Sstevel@tonic-gate sctp_process_sendq(gsctp); 2871*0Sstevel@tonic-gate return; 2872*0Sstevel@tonic-gate case CHUNK_ERROR: 2873*0Sstevel@tonic-gate case CHUNK_ABORT: 2874*0Sstevel@tonic-gate case CHUNK_COOKIE_ACK: 2875*0Sstevel@tonic-gate case CHUNK_SHUTDOWN_COMPLETE: 2876*0Sstevel@tonic-gate if (mctl_present) 2877*0Sstevel@tonic-gate freeb(first_mp); 2878*0Sstevel@tonic-gate break; 2879*0Sstevel@tonic-gate default: 2880*0Sstevel@tonic-gate if (mctl_present && sctp_check_in_policy(mp, first_mp) == NULL) 2881*0Sstevel@tonic-gate return; 2882*0Sstevel@tonic-gate sctp_send_abort(gsctp, sctph->sh_verf, 0, NULL, 0, mp, 0, 2883*0Sstevel@tonic-gate B_TRUE); 2884*0Sstevel@tonic-gate break; 2885*0Sstevel@tonic-gate } 2886*0Sstevel@tonic-gate sctp_process_sendq(gsctp); 2887*0Sstevel@tonic-gate freemsg(mp); 2888*0Sstevel@tonic-gate } 2889*0Sstevel@tonic-gate 2890*0Sstevel@tonic-gate void 2891*0Sstevel@tonic-gate sctp_input(conn_t *connp, ipha_t *ipha, mblk_t *mp, mblk_t *first_mp, 2892*0Sstevel@tonic-gate ill_t *recv_ill, boolean_t isv4, boolean_t mctl_present) 2893*0Sstevel@tonic-gate { 2894*0Sstevel@tonic-gate sctp_t *sctp = CONN2SCTP(connp); 2895*0Sstevel@tonic-gate 2896*0Sstevel@tonic-gate /* 2897*0Sstevel@tonic-gate * We check some fields in conn_t without holding a lock. 2898*0Sstevel@tonic-gate * This should be fine. 2899*0Sstevel@tonic-gate */ 2900*0Sstevel@tonic-gate if (CONN_INBOUND_POLICY_PRESENT(connp) || mctl_present) { 2901*0Sstevel@tonic-gate first_mp = ipsec_check_inbound_policy(first_mp, connp, 2902*0Sstevel@tonic-gate ipha, NULL, mctl_present); 2903*0Sstevel@tonic-gate if (first_mp == NULL) { 2904*0Sstevel@tonic-gate SCTP_REFRELE(sctp); 2905*0Sstevel@tonic-gate return; 2906*0Sstevel@tonic-gate } 2907*0Sstevel@tonic-gate } 2908*0Sstevel@tonic-gate 2909*0Sstevel@tonic-gate /* Initiate IPPF processing for fastpath */ 2910*0Sstevel@tonic-gate if (IPP_ENABLED(IPP_LOCAL_IN)) { 2911*0Sstevel@tonic-gate ip_process(IPP_LOCAL_IN, &mp, 2912*0Sstevel@tonic-gate recv_ill->ill_phyint->phyint_ifindex); 2913*0Sstevel@tonic-gate if (mp == NULL) { 2914*0Sstevel@tonic-gate SCTP_REFRELE(sctp); 2915*0Sstevel@tonic-gate if (mctl_present) 2916*0Sstevel@tonic-gate freeb(first_mp); 2917*0Sstevel@tonic-gate return; 2918*0Sstevel@tonic-gate } else if (mctl_present) { 2919*0Sstevel@tonic-gate /* 2920*0Sstevel@tonic-gate * ip_process might return a new mp. 2921*0Sstevel@tonic-gate */ 2922*0Sstevel@tonic-gate ASSERT(first_mp != mp); 2923*0Sstevel@tonic-gate first_mp->b_cont = mp; 2924*0Sstevel@tonic-gate } else { 2925*0Sstevel@tonic-gate first_mp = mp; 2926*0Sstevel@tonic-gate } 2927*0Sstevel@tonic-gate } 2928*0Sstevel@tonic-gate 2929*0Sstevel@tonic-gate if (connp->conn_recvif || connp->conn_recvslla || 2930*0Sstevel@tonic-gate connp->conn_ipv6_recvpktinfo) { 2931*0Sstevel@tonic-gate int in_flags = 0; 2932*0Sstevel@tonic-gate 2933*0Sstevel@tonic-gate if (connp->conn_recvif || connp->conn_ipv6_recvpktinfo) { 2934*0Sstevel@tonic-gate in_flags = IPF_RECVIF; 2935*0Sstevel@tonic-gate } 2936*0Sstevel@tonic-gate if (connp->conn_recvslla) { 2937*0Sstevel@tonic-gate in_flags |= IPF_RECVSLLA; 2938*0Sstevel@tonic-gate } 2939*0Sstevel@tonic-gate if (isv4) { 2940*0Sstevel@tonic-gate mp = ip_add_info(mp, recv_ill, in_flags); 2941*0Sstevel@tonic-gate } else { 2942*0Sstevel@tonic-gate mp = ip_add_info_v6(mp, recv_ill, 2943*0Sstevel@tonic-gate &(((ip6_t *)ipha)->ip6_dst)); 2944*0Sstevel@tonic-gate } 2945*0Sstevel@tonic-gate if (mp == NULL) { 2946*0Sstevel@tonic-gate SCTP_REFRELE(sctp); 2947*0Sstevel@tonic-gate if (mctl_present) 2948*0Sstevel@tonic-gate freeb(first_mp); 2949*0Sstevel@tonic-gate return; 2950*0Sstevel@tonic-gate } else if (mctl_present) { 2951*0Sstevel@tonic-gate /* 2952*0Sstevel@tonic-gate * ip_add_info might return a new mp. 2953*0Sstevel@tonic-gate */ 2954*0Sstevel@tonic-gate ASSERT(first_mp != mp); 2955*0Sstevel@tonic-gate first_mp->b_cont = mp; 2956*0Sstevel@tonic-gate } else { 2957*0Sstevel@tonic-gate first_mp = mp; 2958*0Sstevel@tonic-gate } 2959*0Sstevel@tonic-gate } 2960*0Sstevel@tonic-gate 2961*0Sstevel@tonic-gate mutex_enter(&sctp->sctp_lock); 2962*0Sstevel@tonic-gate if (sctp->sctp_running) { 2963*0Sstevel@tonic-gate if (mctl_present) 2964*0Sstevel@tonic-gate mp->b_prev = first_mp; 2965*0Sstevel@tonic-gate if (!sctp_add_recvq(sctp, mp, B_FALSE)) { 2966*0Sstevel@tonic-gate BUMP_MIB(&ip_mib, ipInDiscards); 2967*0Sstevel@tonic-gate freemsg(first_mp); 2968*0Sstevel@tonic-gate } 2969*0Sstevel@tonic-gate mutex_exit(&sctp->sctp_lock); 2970*0Sstevel@tonic-gate SCTP_REFRELE(sctp); 2971*0Sstevel@tonic-gate return; 2972*0Sstevel@tonic-gate } else { 2973*0Sstevel@tonic-gate sctp->sctp_running = B_TRUE; 2974*0Sstevel@tonic-gate mutex_exit(&sctp->sctp_lock); 2975*0Sstevel@tonic-gate 2976*0Sstevel@tonic-gate mutex_enter(&sctp->sctp_recvq_lock); 2977*0Sstevel@tonic-gate if (sctp->sctp_recvq != NULL) { 2978*0Sstevel@tonic-gate if (mctl_present) 2979*0Sstevel@tonic-gate mp->b_prev = first_mp; 2980*0Sstevel@tonic-gate if (!sctp_add_recvq(sctp, mp, B_TRUE)) { 2981*0Sstevel@tonic-gate BUMP_MIB(&ip_mib, ipInDiscards); 2982*0Sstevel@tonic-gate freemsg(first_mp); 2983*0Sstevel@tonic-gate } 2984*0Sstevel@tonic-gate mutex_exit(&sctp->sctp_recvq_lock); 2985*0Sstevel@tonic-gate WAKE_SCTP(sctp); 2986*0Sstevel@tonic-gate SCTP_REFRELE(sctp); 2987*0Sstevel@tonic-gate return; 2988*0Sstevel@tonic-gate } 2989*0Sstevel@tonic-gate } 2990*0Sstevel@tonic-gate mutex_exit(&sctp->sctp_recvq_lock); 2991*0Sstevel@tonic-gate sctp_input_data(sctp, mp, (mctl_present ? first_mp : NULL)); 2992*0Sstevel@tonic-gate WAKE_SCTP(sctp); 2993*0Sstevel@tonic-gate sctp_process_sendq(sctp); 2994*0Sstevel@tonic-gate SCTP_REFRELE(sctp); 2995*0Sstevel@tonic-gate } 2996*0Sstevel@tonic-gate 2997*0Sstevel@tonic-gate static void 2998*0Sstevel@tonic-gate sctp_process_abort(sctp_t *sctp, sctp_chunk_hdr_t *ch, int err) 2999*0Sstevel@tonic-gate { 3000*0Sstevel@tonic-gate BUMP_MIB(&sctp_mib, sctpAborted); 3001*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 3002*0Sstevel@tonic-gate 3003*0Sstevel@tonic-gate sctp_assoc_event(sctp, SCTP_COMM_LOST, 3004*0Sstevel@tonic-gate ntohs(((sctp_parm_hdr_t *)(ch + 1))->sph_type), ch); 3005*0Sstevel@tonic-gate sctp_clean_death(sctp, err); 3006*0Sstevel@tonic-gate } 3007*0Sstevel@tonic-gate 3008*0Sstevel@tonic-gate void 3009*0Sstevel@tonic-gate sctp_input_data(sctp_t *sctp, mblk_t *mp, mblk_t *ipsec_mp) 3010*0Sstevel@tonic-gate { 3011*0Sstevel@tonic-gate sctp_chunk_hdr_t *ch; 3012*0Sstevel@tonic-gate ssize_t mlen; 3013*0Sstevel@tonic-gate int gotdata; 3014*0Sstevel@tonic-gate int trysend; 3015*0Sstevel@tonic-gate sctp_faddr_t *fp; 3016*0Sstevel@tonic-gate sctp_init_chunk_t *iack; 3017*0Sstevel@tonic-gate uint32_t tsn; 3018*0Sstevel@tonic-gate sctp_data_hdr_t *sdc; 3019*0Sstevel@tonic-gate ip6_pkt_t ipp; 3020*0Sstevel@tonic-gate in6_addr_t src; 3021*0Sstevel@tonic-gate in6_addr_t dst; 3022*0Sstevel@tonic-gate uint_t ifindex; 3023*0Sstevel@tonic-gate sctp_hdr_t *sctph; 3024*0Sstevel@tonic-gate uint_t ip_hdr_len; 3025*0Sstevel@tonic-gate mblk_t *dups = NULL; 3026*0Sstevel@tonic-gate int recv_adaption; 3027*0Sstevel@tonic-gate boolean_t wake_eager = B_FALSE; 3028*0Sstevel@tonic-gate mblk_t *pinfo_mp; 3029*0Sstevel@tonic-gate in_pktinfo_t *pinfo = NULL; 3030*0Sstevel@tonic-gate in6_addr_t peer_src; 3031*0Sstevel@tonic-gate int64_t now; 3032*0Sstevel@tonic-gate 3033*0Sstevel@tonic-gate if (DB_TYPE(mp) != M_DATA) { 3034*0Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_CTL); 3035*0Sstevel@tonic-gate if (MBLKL(mp) == sizeof (in_pktinfo_t) && 3036*0Sstevel@tonic-gate ((in_pktinfo_t *)mp->b_rptr)->in_pkt_ulp_type == 3037*0Sstevel@tonic-gate IN_PKTINFO) { 3038*0Sstevel@tonic-gate pinfo = (in_pktinfo_t *)mp->b_rptr; 3039*0Sstevel@tonic-gate pinfo_mp = mp; 3040*0Sstevel@tonic-gate mp = mp->b_cont; 3041*0Sstevel@tonic-gate } else { 3042*0Sstevel@tonic-gate if (ipsec_mp != NULL) 3043*0Sstevel@tonic-gate freeb(ipsec_mp); 3044*0Sstevel@tonic-gate sctp_icmp_error(sctp, mp); 3045*0Sstevel@tonic-gate return; 3046*0Sstevel@tonic-gate } 3047*0Sstevel@tonic-gate } 3048*0Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_DATA); 3049*0Sstevel@tonic-gate 3050*0Sstevel@tonic-gate if (mp->b_cont != NULL) { 3051*0Sstevel@tonic-gate /* 3052*0Sstevel@tonic-gate * All subsequent code is vastly simplified if it can 3053*0Sstevel@tonic-gate * assume a single contiguous chunk of data. 3054*0Sstevel@tonic-gate */ 3055*0Sstevel@tonic-gate if (pullupmsg(mp, -1) == 0) { 3056*0Sstevel@tonic-gate BUMP_MIB(&ip_mib, ipInDiscards); 3057*0Sstevel@tonic-gate if (ipsec_mp != NULL) 3058*0Sstevel@tonic-gate freeb(ipsec_mp); 3059*0Sstevel@tonic-gate if (pinfo != NULL) 3060*0Sstevel@tonic-gate freeb(pinfo_mp); 3061*0Sstevel@tonic-gate freemsg(mp); 3062*0Sstevel@tonic-gate return; 3063*0Sstevel@tonic-gate } 3064*0Sstevel@tonic-gate } 3065*0Sstevel@tonic-gate 3066*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ipkts); 3067*0Sstevel@tonic-gate sctph = find_sctp_hdrs(mp, &src, &dst, &ifindex, &ip_hdr_len, 3068*0Sstevel@tonic-gate &ipp, pinfo); 3069*0Sstevel@tonic-gate if (pinfo != NULL) 3070*0Sstevel@tonic-gate freeb(pinfo_mp); 3071*0Sstevel@tonic-gate mlen = mp->b_wptr - (uchar_t *)(sctph + 1); 3072*0Sstevel@tonic-gate ch = sctp_first_chunk((uchar_t *)(sctph + 1), mlen); 3073*0Sstevel@tonic-gate if (ch == NULL) { 3074*0Sstevel@tonic-gate BUMP_MIB(&ip_mib, ipInDiscards); 3075*0Sstevel@tonic-gate if (ipsec_mp != NULL) 3076*0Sstevel@tonic-gate freeb(ipsec_mp); 3077*0Sstevel@tonic-gate freemsg(mp); 3078*0Sstevel@tonic-gate return; 3079*0Sstevel@tonic-gate } 3080*0Sstevel@tonic-gate 3081*0Sstevel@tonic-gate if (!sctp_check_input(sctp, ch, mlen, 1)) { 3082*0Sstevel@tonic-gate BUMP_MIB(&ip_mib, ipInDiscards); 3083*0Sstevel@tonic-gate goto done; 3084*0Sstevel@tonic-gate } 3085*0Sstevel@tonic-gate /* 3086*0Sstevel@tonic-gate * Check verfication tag (special handling for INIT, 3087*0Sstevel@tonic-gate * COOKIE, SHUTDOWN_COMPLETE and SHUTDOWN_ACK chunks). 3088*0Sstevel@tonic-gate * ABORTs are handled in the chunk processing loop, since 3089*0Sstevel@tonic-gate * may not appear first. All other checked chunks must 3090*0Sstevel@tonic-gate * appear first, or will have been dropped by check_input(). 3091*0Sstevel@tonic-gate */ 3092*0Sstevel@tonic-gate switch (ch->sch_id) { 3093*0Sstevel@tonic-gate case CHUNK_INIT: 3094*0Sstevel@tonic-gate if (sctph->sh_verf != 0) { 3095*0Sstevel@tonic-gate /* drop it */ 3096*0Sstevel@tonic-gate goto done; 3097*0Sstevel@tonic-gate } 3098*0Sstevel@tonic-gate break; 3099*0Sstevel@tonic-gate case CHUNK_SHUTDOWN_COMPLETE: 3100*0Sstevel@tonic-gate if (sctph->sh_verf == sctp->sctp_lvtag) 3101*0Sstevel@tonic-gate break; 3102*0Sstevel@tonic-gate if (sctph->sh_verf == sctp->sctp_fvtag && 3103*0Sstevel@tonic-gate SCTP_GET_TBIT(ch)) { 3104*0Sstevel@tonic-gate break; 3105*0Sstevel@tonic-gate } 3106*0Sstevel@tonic-gate /* else drop it */ 3107*0Sstevel@tonic-gate goto done; 3108*0Sstevel@tonic-gate case CHUNK_ABORT: 3109*0Sstevel@tonic-gate case CHUNK_COOKIE: 3110*0Sstevel@tonic-gate /* handled below */ 3111*0Sstevel@tonic-gate break; 3112*0Sstevel@tonic-gate case CHUNK_SHUTDOWN_ACK: 3113*0Sstevel@tonic-gate if (sctp->sctp_state > SCTPS_BOUND && 3114*0Sstevel@tonic-gate sctp->sctp_state < SCTPS_ESTABLISHED) { 3115*0Sstevel@tonic-gate /* treat as OOTB */ 3116*0Sstevel@tonic-gate sctp_ootb_shutdown_ack(sctp, mp, ip_hdr_len); 3117*0Sstevel@tonic-gate if (ipsec_mp != NULL) 3118*0Sstevel@tonic-gate freeb(ipsec_mp); 3119*0Sstevel@tonic-gate return; 3120*0Sstevel@tonic-gate } 3121*0Sstevel@tonic-gate /* else fallthru */ 3122*0Sstevel@tonic-gate default: 3123*0Sstevel@tonic-gate /* 3124*0Sstevel@tonic-gate * All other packets must have a valid 3125*0Sstevel@tonic-gate * verification tag, however if this is a 3126*0Sstevel@tonic-gate * listener, we use a refined version of 3127*0Sstevel@tonic-gate * out-of-the-blue logic. 3128*0Sstevel@tonic-gate */ 3129*0Sstevel@tonic-gate if (sctph->sh_verf != sctp->sctp_lvtag && 3130*0Sstevel@tonic-gate sctp->sctp_state != SCTPS_LISTEN) { 3131*0Sstevel@tonic-gate /* drop it */ 3132*0Sstevel@tonic-gate goto done; 3133*0Sstevel@tonic-gate } 3134*0Sstevel@tonic-gate break; 3135*0Sstevel@tonic-gate } 3136*0Sstevel@tonic-gate 3137*0Sstevel@tonic-gate /* Have a valid sctp for this packet */ 3138*0Sstevel@tonic-gate fp = sctp_lookup_faddr(sctp, &src); 3139*0Sstevel@tonic-gate dprint(2, ("sctp_dispatch_rput: mp=%p fp=%p sctp=%p\n", mp, fp, sctp)); 3140*0Sstevel@tonic-gate 3141*0Sstevel@tonic-gate gotdata = 0; 3142*0Sstevel@tonic-gate trysend = 0; 3143*0Sstevel@tonic-gate 3144*0Sstevel@tonic-gate now = lbolt64; 3145*0Sstevel@tonic-gate /* Process the chunks */ 3146*0Sstevel@tonic-gate do { 3147*0Sstevel@tonic-gate dprint(3, ("sctp_dispatch_rput: state=%d, chunk id=%d\n", 3148*0Sstevel@tonic-gate sctp->sctp_state, (int)(ch->sch_id))); 3149*0Sstevel@tonic-gate 3150*0Sstevel@tonic-gate if (ch->sch_id == CHUNK_ABORT) { 3151*0Sstevel@tonic-gate if (sctph->sh_verf != sctp->sctp_lvtag && 3152*0Sstevel@tonic-gate sctph->sh_verf != sctp->sctp_fvtag) { 3153*0Sstevel@tonic-gate /* drop it */ 3154*0Sstevel@tonic-gate goto done; 3155*0Sstevel@tonic-gate } 3156*0Sstevel@tonic-gate } 3157*0Sstevel@tonic-gate 3158*0Sstevel@tonic-gate switch (sctp->sctp_state) { 3159*0Sstevel@tonic-gate 3160*0Sstevel@tonic-gate case SCTPS_ESTABLISHED: 3161*0Sstevel@tonic-gate case SCTPS_SHUTDOWN_PENDING: 3162*0Sstevel@tonic-gate case SCTPS_SHUTDOWN_SENT: 3163*0Sstevel@tonic-gate switch (ch->sch_id) { 3164*0Sstevel@tonic-gate case CHUNK_DATA: 3165*0Sstevel@tonic-gate /* 0-length data chunks are not allowed */ 3166*0Sstevel@tonic-gate if (ntohs(ch->sch_len) == sizeof (*sdc)) { 3167*0Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)ch; 3168*0Sstevel@tonic-gate tsn = sdc->sdh_tsn; 3169*0Sstevel@tonic-gate sctp_send_abort(sctp, sctp->sctp_fvtag, 3170*0Sstevel@tonic-gate SCTP_ERR_NO_USR_DATA, (char *)&tsn, 3171*0Sstevel@tonic-gate sizeof (tsn), mp, 0, B_FALSE); 3172*0Sstevel@tonic-gate sctp_assoc_event(sctp, SCTP_COMM_LOST, 3173*0Sstevel@tonic-gate 0, NULL); 3174*0Sstevel@tonic-gate sctp_clean_death(sctp, ECONNABORTED); 3175*0Sstevel@tonic-gate goto done; 3176*0Sstevel@tonic-gate } 3177*0Sstevel@tonic-gate 3178*0Sstevel@tonic-gate ASSERT(fp != NULL); 3179*0Sstevel@tonic-gate sctp->sctp_lastdata = fp; 3180*0Sstevel@tonic-gate sctp_data_chunk(sctp, ch, mp, &dups, fp, &ipp); 3181*0Sstevel@tonic-gate gotdata = 1; 3182*0Sstevel@tonic-gate /* Restart shutdown timer if shutting down */ 3183*0Sstevel@tonic-gate if (sctp->sctp_state == SCTPS_SHUTDOWN_SENT) { 3184*0Sstevel@tonic-gate /* 3185*0Sstevel@tonic-gate * If we have exceeded our max 3186*0Sstevel@tonic-gate * wait bound for waiting for a 3187*0Sstevel@tonic-gate * shutdown ack from the peer, 3188*0Sstevel@tonic-gate * abort the association. 3189*0Sstevel@tonic-gate */ 3190*0Sstevel@tonic-gate if (sctp_shutack_wait_bound != 0 && 3191*0Sstevel@tonic-gate TICK_TO_MSEC(now - 3192*0Sstevel@tonic-gate sctp->sctp_out_time) > 3193*0Sstevel@tonic-gate sctp_shutack_wait_bound) { 3194*0Sstevel@tonic-gate sctp_send_abort(sctp, 3195*0Sstevel@tonic-gate sctp->sctp_fvtag, 0, NULL, 3196*0Sstevel@tonic-gate 0, mp, 0, B_FALSE); 3197*0Sstevel@tonic-gate sctp_assoc_event(sctp, 3198*0Sstevel@tonic-gate SCTP_COMM_LOST, 0, NULL); 3199*0Sstevel@tonic-gate sctp_clean_death(sctp, 3200*0Sstevel@tonic-gate ECONNABORTED); 3201*0Sstevel@tonic-gate goto done; 3202*0Sstevel@tonic-gate } 3203*0Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, fp, 3204*0Sstevel@tonic-gate fp->rto); 3205*0Sstevel@tonic-gate } 3206*0Sstevel@tonic-gate break; 3207*0Sstevel@tonic-gate case CHUNK_SACK: 3208*0Sstevel@tonic-gate ASSERT(fp != NULL); 3209*0Sstevel@tonic-gate /* 3210*0Sstevel@tonic-gate * Peer is real and alive if it can ack our 3211*0Sstevel@tonic-gate * data. 3212*0Sstevel@tonic-gate */ 3213*0Sstevel@tonic-gate sctp_faddr_alive(sctp, fp); 3214*0Sstevel@tonic-gate trysend = sctp_got_sack(sctp, ch); 3215*0Sstevel@tonic-gate break; 3216*0Sstevel@tonic-gate case CHUNK_HEARTBEAT: 3217*0Sstevel@tonic-gate sctp_return_heartbeat(sctp, ch, mp); 3218*0Sstevel@tonic-gate break; 3219*0Sstevel@tonic-gate case CHUNK_HEARTBEAT_ACK: 3220*0Sstevel@tonic-gate sctp_process_heartbeat(sctp, ch); 3221*0Sstevel@tonic-gate break; 3222*0Sstevel@tonic-gate case CHUNK_SHUTDOWN: 3223*0Sstevel@tonic-gate sctp_shutdown_event(sctp); 3224*0Sstevel@tonic-gate trysend = sctp_shutdown_received(sctp, ch, 3225*0Sstevel@tonic-gate 0, 0); 3226*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 3227*0Sstevel@tonic-gate break; 3228*0Sstevel@tonic-gate case CHUNK_SHUTDOWN_ACK: 3229*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 3230*0Sstevel@tonic-gate if (sctp->sctp_state == SCTPS_SHUTDOWN_SENT) { 3231*0Sstevel@tonic-gate sctp_shutdown_complete(sctp); 3232*0Sstevel@tonic-gate BUMP_MIB(&sctp_mib, sctpShutdowns); 3233*0Sstevel@tonic-gate sctp_assoc_event(sctp, 3234*0Sstevel@tonic-gate SCTP_SHUTDOWN_COMP, 0, NULL); 3235*0Sstevel@tonic-gate sctp_clean_death(sctp, 0); 3236*0Sstevel@tonic-gate goto done; 3237*0Sstevel@tonic-gate } 3238*0Sstevel@tonic-gate break; 3239*0Sstevel@tonic-gate case CHUNK_ABORT: { 3240*0Sstevel@tonic-gate sctp_saddr_ipif_t *sp; 3241*0Sstevel@tonic-gate 3242*0Sstevel@tonic-gate /* Ignore if delete pending */ 3243*0Sstevel@tonic-gate sp = sctp_saddr_lookup(sctp, &dst); 3244*0Sstevel@tonic-gate ASSERT(sp != NULL); 3245*0Sstevel@tonic-gate if (sp->saddr_ipif_delete_pending) { 3246*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 3247*0Sstevel@tonic-gate break; 3248*0Sstevel@tonic-gate } 3249*0Sstevel@tonic-gate 3250*0Sstevel@tonic-gate sctp_process_abort(sctp, ch, ECONNRESET); 3251*0Sstevel@tonic-gate goto done; 3252*0Sstevel@tonic-gate } 3253*0Sstevel@tonic-gate case CHUNK_INIT: 3254*0Sstevel@tonic-gate sctp_send_initack(sctp, ch, mp); 3255*0Sstevel@tonic-gate break; 3256*0Sstevel@tonic-gate case CHUNK_COOKIE: 3257*0Sstevel@tonic-gate if (sctp_process_cookie(sctp, ch, mp, &iack, 3258*0Sstevel@tonic-gate sctph, &recv_adaption, NULL) != -1) { 3259*0Sstevel@tonic-gate sctp_send_cookie_ack(sctp); 3260*0Sstevel@tonic-gate sctp_assoc_event(sctp, SCTP_RESTART, 3261*0Sstevel@tonic-gate 0, NULL); 3262*0Sstevel@tonic-gate if (recv_adaption) { 3263*0Sstevel@tonic-gate sctp->sctp_recv_adaption = 1; 3264*0Sstevel@tonic-gate sctp_adaption_event(sctp); 3265*0Sstevel@tonic-gate } 3266*0Sstevel@tonic-gate } else { 3267*0Sstevel@tonic-gate BUMP_MIB(&sctp_mib, 3268*0Sstevel@tonic-gate sctpInInvalidCookie); 3269*0Sstevel@tonic-gate } 3270*0Sstevel@tonic-gate break; 3271*0Sstevel@tonic-gate case CHUNK_ERROR: { 3272*0Sstevel@tonic-gate int error; 3273*0Sstevel@tonic-gate 3274*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 3275*0Sstevel@tonic-gate error = sctp_handle_error(sctp, sctph, ch, mp); 3276*0Sstevel@tonic-gate if (error != 0) { 3277*0Sstevel@tonic-gate sctp_clean_death(sctp, error); 3278*0Sstevel@tonic-gate goto done; 3279*0Sstevel@tonic-gate } 3280*0Sstevel@tonic-gate break; 3281*0Sstevel@tonic-gate } 3282*0Sstevel@tonic-gate case CHUNK_ASCONF: 3283*0Sstevel@tonic-gate ASSERT(fp != NULL); 3284*0Sstevel@tonic-gate sctp_input_asconf(sctp, ch, fp); 3285*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 3286*0Sstevel@tonic-gate break; 3287*0Sstevel@tonic-gate case CHUNK_ASCONF_ACK: 3288*0Sstevel@tonic-gate ASSERT(fp != NULL); 3289*0Sstevel@tonic-gate sctp_faddr_alive(sctp, fp); 3290*0Sstevel@tonic-gate sctp_input_asconf_ack(sctp, ch, fp); 3291*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 3292*0Sstevel@tonic-gate break; 3293*0Sstevel@tonic-gate case CHUNK_FORWARD_TSN: 3294*0Sstevel@tonic-gate ASSERT(fp != NULL); 3295*0Sstevel@tonic-gate sctp->sctp_lastdata = fp; 3296*0Sstevel@tonic-gate sctp_process_forward_tsn(sctp, ch, fp, &ipp); 3297*0Sstevel@tonic-gate gotdata = 1; 3298*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 3299*0Sstevel@tonic-gate break; 3300*0Sstevel@tonic-gate default: 3301*0Sstevel@tonic-gate if (sctp_strange_chunk(sctp, ch, fp) == 0) { 3302*0Sstevel@tonic-gate goto nomorechunks; 3303*0Sstevel@tonic-gate } /* else skip and continue processing */ 3304*0Sstevel@tonic-gate break; 3305*0Sstevel@tonic-gate } 3306*0Sstevel@tonic-gate break; 3307*0Sstevel@tonic-gate 3308*0Sstevel@tonic-gate case SCTPS_LISTEN: 3309*0Sstevel@tonic-gate switch (ch->sch_id) { 3310*0Sstevel@tonic-gate case CHUNK_INIT: 3311*0Sstevel@tonic-gate sctp_send_initack(sctp, ch, mp); 3312*0Sstevel@tonic-gate break; 3313*0Sstevel@tonic-gate case CHUNK_COOKIE: { 3314*0Sstevel@tonic-gate sctp_t *eager; 3315*0Sstevel@tonic-gate 3316*0Sstevel@tonic-gate if (sctp_process_cookie(sctp, ch, mp, &iack, 3317*0Sstevel@tonic-gate sctph, &recv_adaption, &peer_src) == -1) { 3318*0Sstevel@tonic-gate BUMP_MIB(&sctp_mib, 3319*0Sstevel@tonic-gate sctpInInvalidCookie); 3320*0Sstevel@tonic-gate goto done; 3321*0Sstevel@tonic-gate } 3322*0Sstevel@tonic-gate 3323*0Sstevel@tonic-gate /* 3324*0Sstevel@tonic-gate * The cookie is good; ensure that 3325*0Sstevel@tonic-gate * the peer used the verification 3326*0Sstevel@tonic-gate * tag from the init ack in the header. 3327*0Sstevel@tonic-gate */ 3328*0Sstevel@tonic-gate if (iack->sic_inittag != sctph->sh_verf) 3329*0Sstevel@tonic-gate goto done; 3330*0Sstevel@tonic-gate 3331*0Sstevel@tonic-gate eager = sctp_conn_request(sctp, mp, ifindex, 3332*0Sstevel@tonic-gate ip_hdr_len, iack, ipsec_mp); 3333*0Sstevel@tonic-gate if (eager == NULL) { 3334*0Sstevel@tonic-gate sctp_send_abort(sctp, sctph->sh_verf, 3335*0Sstevel@tonic-gate SCTP_ERR_NO_RESOURCES, NULL, 0, mp, 3336*0Sstevel@tonic-gate 0, B_FALSE); 3337*0Sstevel@tonic-gate goto done; 3338*0Sstevel@tonic-gate } 3339*0Sstevel@tonic-gate 3340*0Sstevel@tonic-gate /* 3341*0Sstevel@tonic-gate * If there were extra chunks 3342*0Sstevel@tonic-gate * bundled with the cookie, 3343*0Sstevel@tonic-gate * they must be processed 3344*0Sstevel@tonic-gate * on the eager's queue. We 3345*0Sstevel@tonic-gate * accomplish this by refeeding 3346*0Sstevel@tonic-gate * the whole packet into the 3347*0Sstevel@tonic-gate * state machine on the right 3348*0Sstevel@tonic-gate * q. The packet (mp) gets 3349*0Sstevel@tonic-gate * there via the eager's 3350*0Sstevel@tonic-gate * cookie_mp field (overloaded 3351*0Sstevel@tonic-gate * with the active open role). 3352*0Sstevel@tonic-gate * This is picked up when 3353*0Sstevel@tonic-gate * processing the null bind 3354*0Sstevel@tonic-gate * request put on the eager's 3355*0Sstevel@tonic-gate * q by sctp_accept(). We must 3356*0Sstevel@tonic-gate * first revert the cookie 3357*0Sstevel@tonic-gate * chunk's length field to network 3358*0Sstevel@tonic-gate * byteorder so it can be 3359*0Sstevel@tonic-gate * properly reprocessed on the 3360*0Sstevel@tonic-gate * eager's queue. 3361*0Sstevel@tonic-gate */ 3362*0Sstevel@tonic-gate BUMP_MIB(&sctp_mib, sctpPassiveEstab); 3363*0Sstevel@tonic-gate if (mlen > ntohs(ch->sch_len)) { 3364*0Sstevel@tonic-gate eager->sctp_cookie_mp = dupb(mp); 3365*0Sstevel@tonic-gate /* 3366*0Sstevel@tonic-gate * If no mem, just let 3367*0Sstevel@tonic-gate * the peer retransmit. 3368*0Sstevel@tonic-gate */ 3369*0Sstevel@tonic-gate } 3370*0Sstevel@tonic-gate sctp_assoc_event(eager, SCTP_COMM_UP, 0, NULL); 3371*0Sstevel@tonic-gate if (recv_adaption) { 3372*0Sstevel@tonic-gate eager->sctp_recv_adaption = 1; 3373*0Sstevel@tonic-gate eager->sctp_rx_adaption_code = 3374*0Sstevel@tonic-gate sctp->sctp_rx_adaption_code; 3375*0Sstevel@tonic-gate sctp_adaption_event(eager); 3376*0Sstevel@tonic-gate } 3377*0Sstevel@tonic-gate 3378*0Sstevel@tonic-gate eager->sctp_active = now; 3379*0Sstevel@tonic-gate sctp_send_cookie_ack(eager); 3380*0Sstevel@tonic-gate 3381*0Sstevel@tonic-gate wake_eager = B_TRUE; 3382*0Sstevel@tonic-gate 3383*0Sstevel@tonic-gate /* 3384*0Sstevel@tonic-gate * Process rest of the chunks with eager. 3385*0Sstevel@tonic-gate */ 3386*0Sstevel@tonic-gate sctp = eager; 3387*0Sstevel@tonic-gate fp = sctp_lookup_faddr(sctp, &peer_src); 3388*0Sstevel@tonic-gate /* 3389*0Sstevel@tonic-gate * Confirm peer's original source. fp can 3390*0Sstevel@tonic-gate * only be NULL if peer does not use the 3391*0Sstevel@tonic-gate * original source as one of its addresses... 3392*0Sstevel@tonic-gate */ 3393*0Sstevel@tonic-gate if (fp == NULL) 3394*0Sstevel@tonic-gate fp = sctp_lookup_faddr(sctp, &src); 3395*0Sstevel@tonic-gate else 3396*0Sstevel@tonic-gate sctp_faddr_alive(sctp, fp); 3397*0Sstevel@tonic-gate 3398*0Sstevel@tonic-gate /* 3399*0Sstevel@tonic-gate * Validate the peer addresses. It also starts 3400*0Sstevel@tonic-gate * the heartbeat timer. 3401*0Sstevel@tonic-gate */ 3402*0Sstevel@tonic-gate sctp_validate_peer(sctp); 3403*0Sstevel@tonic-gate break; 3404*0Sstevel@tonic-gate } 3405*0Sstevel@tonic-gate /* Anything else is considered out-of-the-blue */ 3406*0Sstevel@tonic-gate case CHUNK_ERROR: 3407*0Sstevel@tonic-gate case CHUNK_ABORT: 3408*0Sstevel@tonic-gate case CHUNK_COOKIE_ACK: 3409*0Sstevel@tonic-gate case CHUNK_SHUTDOWN_COMPLETE: 3410*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 3411*0Sstevel@tonic-gate goto done; 3412*0Sstevel@tonic-gate default: 3413*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 3414*0Sstevel@tonic-gate sctp_send_abort(sctp, sctph->sh_verf, 0, NULL, 3415*0Sstevel@tonic-gate 0, mp, 0, B_TRUE); 3416*0Sstevel@tonic-gate goto done; 3417*0Sstevel@tonic-gate } 3418*0Sstevel@tonic-gate break; 3419*0Sstevel@tonic-gate 3420*0Sstevel@tonic-gate case SCTPS_COOKIE_WAIT: 3421*0Sstevel@tonic-gate switch (ch->sch_id) { 3422*0Sstevel@tonic-gate case CHUNK_INIT_ACK: 3423*0Sstevel@tonic-gate sctp_stop_faddr_timers(sctp); 3424*0Sstevel@tonic-gate sctp_faddr_alive(sctp, sctp->sctp_current); 3425*0Sstevel@tonic-gate sctp_send_cookie_echo(sctp, ch, mp); 3426*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 3427*0Sstevel@tonic-gate break; 3428*0Sstevel@tonic-gate case CHUNK_ABORT: 3429*0Sstevel@tonic-gate sctp_process_abort(sctp, ch, ECONNREFUSED); 3430*0Sstevel@tonic-gate goto done; 3431*0Sstevel@tonic-gate case CHUNK_INIT: 3432*0Sstevel@tonic-gate sctp_send_initack(sctp, ch, mp); 3433*0Sstevel@tonic-gate break; 3434*0Sstevel@tonic-gate case CHUNK_COOKIE: 3435*0Sstevel@tonic-gate if (sctp_process_cookie(sctp, ch, mp, &iack, 3436*0Sstevel@tonic-gate sctph, &recv_adaption, NULL) == -1) { 3437*0Sstevel@tonic-gate BUMP_MIB(&sctp_mib, 3438*0Sstevel@tonic-gate sctpInInvalidCookie); 3439*0Sstevel@tonic-gate break; 3440*0Sstevel@tonic-gate } 3441*0Sstevel@tonic-gate sctp_send_cookie_ack(sctp); 3442*0Sstevel@tonic-gate sctp_stop_faddr_timers(sctp); 3443*0Sstevel@tonic-gate if (!SCTP_IS_DETACHED(sctp)) { 3444*0Sstevel@tonic-gate sctp->sctp_ulp_connected(sctp->sctp_ulpd); 3445*0Sstevel@tonic-gate sctp_set_ulp_prop(sctp); 3446*0Sstevel@tonic-gate } 3447*0Sstevel@tonic-gate sctp->sctp_state = SCTPS_ESTABLISHED; 3448*0Sstevel@tonic-gate sctp->sctp_assoc_start_time = (uint32_t)lbolt; 3449*0Sstevel@tonic-gate BUMP_MIB(&sctp_mib, sctpActiveEstab); 3450*0Sstevel@tonic-gate if (sctp->sctp_cookie_mp) { 3451*0Sstevel@tonic-gate freemsg(sctp->sctp_cookie_mp); 3452*0Sstevel@tonic-gate sctp->sctp_cookie_mp = NULL; 3453*0Sstevel@tonic-gate } 3454*0Sstevel@tonic-gate 3455*0Sstevel@tonic-gate /* Validate the peer addresses. */ 3456*0Sstevel@tonic-gate sctp->sctp_active = now; 3457*0Sstevel@tonic-gate sctp_validate_peer(sctp); 3458*0Sstevel@tonic-gate 3459*0Sstevel@tonic-gate sctp_assoc_event(sctp, SCTP_COMM_UP, 0, NULL); 3460*0Sstevel@tonic-gate if (recv_adaption) { 3461*0Sstevel@tonic-gate sctp->sctp_recv_adaption = 1; 3462*0Sstevel@tonic-gate sctp_adaption_event(sctp); 3463*0Sstevel@tonic-gate } 3464*0Sstevel@tonic-gate /* Try sending queued data, or ASCONFs */ 3465*0Sstevel@tonic-gate trysend = 1; 3466*0Sstevel@tonic-gate break; 3467*0Sstevel@tonic-gate default: 3468*0Sstevel@tonic-gate if (sctp_strange_chunk(sctp, ch, fp) == 0) { 3469*0Sstevel@tonic-gate goto nomorechunks; 3470*0Sstevel@tonic-gate } /* else skip and continue processing */ 3471*0Sstevel@tonic-gate break; 3472*0Sstevel@tonic-gate } 3473*0Sstevel@tonic-gate break; 3474*0Sstevel@tonic-gate 3475*0Sstevel@tonic-gate case SCTPS_COOKIE_ECHOED: 3476*0Sstevel@tonic-gate switch (ch->sch_id) { 3477*0Sstevel@tonic-gate case CHUNK_COOKIE_ACK: 3478*0Sstevel@tonic-gate if (!SCTP_IS_DETACHED(sctp)) { 3479*0Sstevel@tonic-gate sctp->sctp_ulp_connected(sctp->sctp_ulpd); 3480*0Sstevel@tonic-gate sctp_set_ulp_prop(sctp); 3481*0Sstevel@tonic-gate } 3482*0Sstevel@tonic-gate if (sctp->sctp_unacked == 0) 3483*0Sstevel@tonic-gate sctp_stop_faddr_timers(sctp); 3484*0Sstevel@tonic-gate sctp->sctp_state = SCTPS_ESTABLISHED; 3485*0Sstevel@tonic-gate sctp->sctp_assoc_start_time = (uint32_t)lbolt; 3486*0Sstevel@tonic-gate BUMP_MIB(&sctp_mib, sctpActiveEstab); 3487*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 3488*0Sstevel@tonic-gate if (sctp->sctp_cookie_mp) { 3489*0Sstevel@tonic-gate freemsg(sctp->sctp_cookie_mp); 3490*0Sstevel@tonic-gate sctp->sctp_cookie_mp = NULL; 3491*0Sstevel@tonic-gate } 3492*0Sstevel@tonic-gate sctp_faddr_alive(sctp, fp); 3493*0Sstevel@tonic-gate /* Validate the peer addresses. */ 3494*0Sstevel@tonic-gate sctp->sctp_active = now; 3495*0Sstevel@tonic-gate sctp_validate_peer(sctp); 3496*0Sstevel@tonic-gate 3497*0Sstevel@tonic-gate /* Try sending queued data, or ASCONFs */ 3498*0Sstevel@tonic-gate trysend = 1; 3499*0Sstevel@tonic-gate sctp_assoc_event(sctp, SCTP_COMM_UP, 0, NULL); 3500*0Sstevel@tonic-gate sctp_adaption_event(sctp); 3501*0Sstevel@tonic-gate break; 3502*0Sstevel@tonic-gate case CHUNK_ABORT: 3503*0Sstevel@tonic-gate sctp_process_abort(sctp, ch, ECONNREFUSED); 3504*0Sstevel@tonic-gate goto done; 3505*0Sstevel@tonic-gate case CHUNK_COOKIE: 3506*0Sstevel@tonic-gate if (sctp_process_cookie(sctp, ch, mp, &iack, 3507*0Sstevel@tonic-gate sctph, &recv_adaption, NULL) == -1) { 3508*0Sstevel@tonic-gate BUMP_MIB(&sctp_mib, 3509*0Sstevel@tonic-gate sctpInInvalidCookie); 3510*0Sstevel@tonic-gate break; 3511*0Sstevel@tonic-gate } 3512*0Sstevel@tonic-gate sctp_send_cookie_ack(sctp); 3513*0Sstevel@tonic-gate 3514*0Sstevel@tonic-gate if (!SCTP_IS_DETACHED(sctp)) { 3515*0Sstevel@tonic-gate sctp->sctp_ulp_connected(sctp->sctp_ulpd); 3516*0Sstevel@tonic-gate sctp_set_ulp_prop(sctp); 3517*0Sstevel@tonic-gate } 3518*0Sstevel@tonic-gate if (sctp->sctp_unacked == 0) 3519*0Sstevel@tonic-gate sctp_stop_faddr_timers(sctp); 3520*0Sstevel@tonic-gate sctp->sctp_state = SCTPS_ESTABLISHED; 3521*0Sstevel@tonic-gate sctp->sctp_assoc_start_time = (uint32_t)lbolt; 3522*0Sstevel@tonic-gate BUMP_MIB(&sctp_mib, sctpActiveEstab); 3523*0Sstevel@tonic-gate if (sctp->sctp_cookie_mp) { 3524*0Sstevel@tonic-gate freemsg(sctp->sctp_cookie_mp); 3525*0Sstevel@tonic-gate sctp->sctp_cookie_mp = NULL; 3526*0Sstevel@tonic-gate } 3527*0Sstevel@tonic-gate /* Validate the peer addresses. */ 3528*0Sstevel@tonic-gate sctp->sctp_active = now; 3529*0Sstevel@tonic-gate sctp_validate_peer(sctp); 3530*0Sstevel@tonic-gate 3531*0Sstevel@tonic-gate sctp_assoc_event(sctp, SCTP_COMM_UP, 0, NULL); 3532*0Sstevel@tonic-gate if (recv_adaption) { 3533*0Sstevel@tonic-gate sctp->sctp_recv_adaption = 1; 3534*0Sstevel@tonic-gate sctp_adaption_event(sctp); 3535*0Sstevel@tonic-gate } 3536*0Sstevel@tonic-gate /* Try sending queued data, or ASCONFs */ 3537*0Sstevel@tonic-gate trysend = 1; 3538*0Sstevel@tonic-gate break; 3539*0Sstevel@tonic-gate case CHUNK_INIT: 3540*0Sstevel@tonic-gate sctp_send_initack(sctp, ch, mp); 3541*0Sstevel@tonic-gate break; 3542*0Sstevel@tonic-gate case CHUNK_ERROR: { 3543*0Sstevel@tonic-gate sctp_parm_hdr_t *p; 3544*0Sstevel@tonic-gate 3545*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 3546*0Sstevel@tonic-gate /* check for a stale cookie */ 3547*0Sstevel@tonic-gate if (ntohs(ch->sch_len) >= 3548*0Sstevel@tonic-gate (sizeof (*p) + sizeof (*ch)) + 3549*0Sstevel@tonic-gate sizeof (uint32_t)) { 3550*0Sstevel@tonic-gate 3551*0Sstevel@tonic-gate p = (sctp_parm_hdr_t *)(ch + 1); 3552*0Sstevel@tonic-gate if (p->sph_type == 3553*0Sstevel@tonic-gate htons(SCTP_ERR_STALE_COOKIE)) { 3554*0Sstevel@tonic-gate BUMP_MIB(&sctp_mib, 3555*0Sstevel@tonic-gate sctpAborted); 3556*0Sstevel@tonic-gate sctp_error_event(sctp, ch); 3557*0Sstevel@tonic-gate sctp_clean_death(sctp, 3558*0Sstevel@tonic-gate ECONNREFUSED); 3559*0Sstevel@tonic-gate goto done; 3560*0Sstevel@tonic-gate } 3561*0Sstevel@tonic-gate } 3562*0Sstevel@tonic-gate break; 3563*0Sstevel@tonic-gate } 3564*0Sstevel@tonic-gate case CHUNK_HEARTBEAT: 3565*0Sstevel@tonic-gate sctp_return_heartbeat(sctp, ch, mp); 3566*0Sstevel@tonic-gate break; 3567*0Sstevel@tonic-gate default: 3568*0Sstevel@tonic-gate if (sctp_strange_chunk(sctp, ch, fp) == 0) { 3569*0Sstevel@tonic-gate goto nomorechunks; 3570*0Sstevel@tonic-gate } /* else skip and continue processing */ 3571*0Sstevel@tonic-gate } /* switch (ch->sch_id) */ 3572*0Sstevel@tonic-gate break; 3573*0Sstevel@tonic-gate 3574*0Sstevel@tonic-gate case SCTPS_SHUTDOWN_ACK_SENT: 3575*0Sstevel@tonic-gate switch (ch->sch_id) { 3576*0Sstevel@tonic-gate case CHUNK_ABORT: 3577*0Sstevel@tonic-gate /* Pass gathered wisdom to IP for keeping */ 3578*0Sstevel@tonic-gate for (fp = sctp->sctp_faddrs; fp != NULL; 3579*0Sstevel@tonic-gate fp = fp->next) { 3580*0Sstevel@tonic-gate sctp_faddr2ire(sctp, fp); 3581*0Sstevel@tonic-gate } 3582*0Sstevel@tonic-gate sctp_process_abort(sctp, ch, 0); 3583*0Sstevel@tonic-gate goto done; 3584*0Sstevel@tonic-gate case CHUNK_SHUTDOWN_COMPLETE: 3585*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 3586*0Sstevel@tonic-gate BUMP_MIB(&sctp_mib, sctpShutdowns); 3587*0Sstevel@tonic-gate sctp_assoc_event(sctp, SCTP_SHUTDOWN_COMP, 0, 3588*0Sstevel@tonic-gate NULL); 3589*0Sstevel@tonic-gate 3590*0Sstevel@tonic-gate /* Pass gathered wisdom to IP for keeping */ 3591*0Sstevel@tonic-gate for (fp = sctp->sctp_faddrs; fp != NULL; 3592*0Sstevel@tonic-gate fp = fp->next) { 3593*0Sstevel@tonic-gate sctp_faddr2ire(sctp, fp); 3594*0Sstevel@tonic-gate } 3595*0Sstevel@tonic-gate sctp_clean_death(sctp, 0); 3596*0Sstevel@tonic-gate goto done; 3597*0Sstevel@tonic-gate case CHUNK_SHUTDOWN_ACK: 3598*0Sstevel@tonic-gate sctp_shutdown_complete(sctp); 3599*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 3600*0Sstevel@tonic-gate BUMP_MIB(&sctp_mib, sctpShutdowns); 3601*0Sstevel@tonic-gate sctp_assoc_event(sctp, SCTP_SHUTDOWN_COMP, 0, 3602*0Sstevel@tonic-gate NULL); 3603*0Sstevel@tonic-gate sctp_clean_death(sctp, 0); 3604*0Sstevel@tonic-gate goto done; 3605*0Sstevel@tonic-gate case CHUNK_COOKIE: 3606*0Sstevel@tonic-gate (void) sctp_shutdown_received(sctp, NULL, 3607*0Sstevel@tonic-gate 1, 0); 3608*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 3609*0Sstevel@tonic-gate break; 3610*0Sstevel@tonic-gate case CHUNK_HEARTBEAT: 3611*0Sstevel@tonic-gate sctp_return_heartbeat(sctp, ch, mp); 3612*0Sstevel@tonic-gate break; 3613*0Sstevel@tonic-gate default: 3614*0Sstevel@tonic-gate if (sctp_strange_chunk(sctp, ch, fp) == 0) { 3615*0Sstevel@tonic-gate goto nomorechunks; 3616*0Sstevel@tonic-gate } /* else skip and continue processing */ 3617*0Sstevel@tonic-gate break; 3618*0Sstevel@tonic-gate } 3619*0Sstevel@tonic-gate break; 3620*0Sstevel@tonic-gate 3621*0Sstevel@tonic-gate case SCTPS_SHUTDOWN_RECEIVED: 3622*0Sstevel@tonic-gate switch (ch->sch_id) { 3623*0Sstevel@tonic-gate case CHUNK_SHUTDOWN: 3624*0Sstevel@tonic-gate trysend = sctp_shutdown_received(sctp, ch, 3625*0Sstevel@tonic-gate 0, 0); 3626*0Sstevel@tonic-gate break; 3627*0Sstevel@tonic-gate case CHUNK_SACK: 3628*0Sstevel@tonic-gate trysend = sctp_got_sack(sctp, ch); 3629*0Sstevel@tonic-gate break; 3630*0Sstevel@tonic-gate case CHUNK_ABORT: 3631*0Sstevel@tonic-gate sctp_process_abort(sctp, ch, ECONNRESET); 3632*0Sstevel@tonic-gate goto done; 3633*0Sstevel@tonic-gate case CHUNK_HEARTBEAT: 3634*0Sstevel@tonic-gate sctp_return_heartbeat(sctp, ch, mp); 3635*0Sstevel@tonic-gate break; 3636*0Sstevel@tonic-gate default: 3637*0Sstevel@tonic-gate if (sctp_strange_chunk(sctp, ch, fp) == 0) { 3638*0Sstevel@tonic-gate goto nomorechunks; 3639*0Sstevel@tonic-gate } /* else skip and continue processing */ 3640*0Sstevel@tonic-gate break; 3641*0Sstevel@tonic-gate } 3642*0Sstevel@tonic-gate break; 3643*0Sstevel@tonic-gate 3644*0Sstevel@tonic-gate default: 3645*0Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 3646*0Sstevel@tonic-gate cmn_err(CE_WARN, "XXXdefault in dispatch state %d", 3647*0Sstevel@tonic-gate sctp->sctp_state); 3648*0Sstevel@tonic-gate break; 3649*0Sstevel@tonic-gate } /* switch (sctp->sctp_state) */ 3650*0Sstevel@tonic-gate 3651*0Sstevel@tonic-gate ch = sctp_next_chunk(ch, &mlen); 3652*0Sstevel@tonic-gate if (ch != NULL && !sctp_check_input(sctp, ch, mlen, 0)) 3653*0Sstevel@tonic-gate goto done; 3654*0Sstevel@tonic-gate } while (ch != NULL); 3655*0Sstevel@tonic-gate 3656*0Sstevel@tonic-gate /* Finished processing all chunks in packet */ 3657*0Sstevel@tonic-gate 3658*0Sstevel@tonic-gate nomorechunks: 3659*0Sstevel@tonic-gate /* SACK if necessary */ 3660*0Sstevel@tonic-gate if (gotdata) { 3661*0Sstevel@tonic-gate (sctp->sctp_sack_toggle)++; 3662*0Sstevel@tonic-gate sctp_sack(sctp, dups); 3663*0Sstevel@tonic-gate dups = NULL; 3664*0Sstevel@tonic-gate 3665*0Sstevel@tonic-gate if (!sctp->sctp_ack_timer_running) { 3666*0Sstevel@tonic-gate sctp->sctp_ack_timer_running = B_TRUE; 3667*0Sstevel@tonic-gate sctp_timer(sctp, sctp->sctp_ack_mp, 3668*0Sstevel@tonic-gate MSEC_TO_TICK(sctp_deferred_ack_interval)); 3669*0Sstevel@tonic-gate } 3670*0Sstevel@tonic-gate } 3671*0Sstevel@tonic-gate 3672*0Sstevel@tonic-gate if (trysend) { 3673*0Sstevel@tonic-gate sctp_output(sctp); 3674*0Sstevel@tonic-gate if (sctp->sctp_cxmit_list != NULL) 3675*0Sstevel@tonic-gate sctp_wput_asconf(sctp, NULL); 3676*0Sstevel@tonic-gate } 3677*0Sstevel@tonic-gate /* If there is unsent data, make sure a timer is running */ 3678*0Sstevel@tonic-gate if (sctp->sctp_unsent > 0 && !sctp->sctp_current->timer_running) { 3679*0Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, sctp->sctp_current, 3680*0Sstevel@tonic-gate sctp->sctp_current->rto); 3681*0Sstevel@tonic-gate } 3682*0Sstevel@tonic-gate 3683*0Sstevel@tonic-gate done: 3684*0Sstevel@tonic-gate if (dups != NULL) 3685*0Sstevel@tonic-gate freeb(dups); 3686*0Sstevel@tonic-gate if (ipsec_mp != NULL) 3687*0Sstevel@tonic-gate freeb(ipsec_mp); 3688*0Sstevel@tonic-gate freemsg(mp); 3689*0Sstevel@tonic-gate 3690*0Sstevel@tonic-gate if (wake_eager) { 3691*0Sstevel@tonic-gate /* 3692*0Sstevel@tonic-gate * sctp points to newly created control block, need to 3693*0Sstevel@tonic-gate * release it before exiting. Before releasing it and 3694*0Sstevel@tonic-gate * processing the sendq, need to grab a hold on it. 3695*0Sstevel@tonic-gate * Otherwise, another thread can close it while processing 3696*0Sstevel@tonic-gate * the sendq. 3697*0Sstevel@tonic-gate */ 3698*0Sstevel@tonic-gate SCTP_REFHOLD(sctp); 3699*0Sstevel@tonic-gate WAKE_SCTP(sctp); 3700*0Sstevel@tonic-gate sctp_process_sendq(sctp); 3701*0Sstevel@tonic-gate SCTP_REFRELE(sctp); 3702*0Sstevel@tonic-gate } 3703*0Sstevel@tonic-gate } 3704*0Sstevel@tonic-gate 3705*0Sstevel@tonic-gate /* 3706*0Sstevel@tonic-gate * Some amount of data got removed from rx q. 3707*0Sstevel@tonic-gate * Check if we should send a window update. 3708*0Sstevel@tonic-gate * 3709*0Sstevel@tonic-gate * Due to way sctp_rwnd updates are made, ULP can give reports out-of-order. 3710*0Sstevel@tonic-gate * To keep from dropping incoming data due to this, we only update 3711*0Sstevel@tonic-gate * sctp_rwnd when if it's larger than what we've reported to peer earlier. 3712*0Sstevel@tonic-gate */ 3713*0Sstevel@tonic-gate void 3714*0Sstevel@tonic-gate sctp_recvd(sctp_t *sctp, int len) 3715*0Sstevel@tonic-gate { 3716*0Sstevel@tonic-gate int32_t old, new; 3717*0Sstevel@tonic-gate 3718*0Sstevel@tonic-gate ASSERT(sctp != NULL); 3719*0Sstevel@tonic-gate RUN_SCTP(sctp); 3720*0Sstevel@tonic-gate 3721*0Sstevel@tonic-gate if (len < sctp->sctp_rwnd) { 3722*0Sstevel@tonic-gate WAKE_SCTP(sctp); 3723*0Sstevel@tonic-gate return; 3724*0Sstevel@tonic-gate } 3725*0Sstevel@tonic-gate ASSERT(sctp->sctp_rwnd >= sctp->sctp_rxqueued); 3726*0Sstevel@tonic-gate old = sctp->sctp_rwnd - sctp->sctp_rxqueued; 3727*0Sstevel@tonic-gate new = len - sctp->sctp_rxqueued; 3728*0Sstevel@tonic-gate sctp->sctp_rwnd = len; 3729*0Sstevel@tonic-gate 3730*0Sstevel@tonic-gate if (sctp->sctp_state >= SCTPS_ESTABLISHED && 3731*0Sstevel@tonic-gate ((old <= new >> 1) || (old < sctp->sctp_mss))) { 3732*0Sstevel@tonic-gate sctp->sctp_force_sack = 1; 3733*0Sstevel@tonic-gate BUMP_MIB(&sctp_mib, sctpOutWinUpdate); 3734*0Sstevel@tonic-gate sctp_sack(sctp, NULL); 3735*0Sstevel@tonic-gate old = 1; 3736*0Sstevel@tonic-gate } else { 3737*0Sstevel@tonic-gate old = 0; 3738*0Sstevel@tonic-gate } 3739*0Sstevel@tonic-gate WAKE_SCTP(sctp); 3740*0Sstevel@tonic-gate if (old > 0) { 3741*0Sstevel@tonic-gate sctp_process_sendq(sctp); 3742*0Sstevel@tonic-gate } 3743*0Sstevel@tonic-gate } 3744