17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 545916cd2Sjpk * Common Development and Distribution License (the "License"). 645916cd2Sjpk * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 2177c67f2fSkcpoon 227c478bd9Sstevel@tonic-gate /* 23c3c17166SGeorge Shepherd * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <sys/types.h> 277c478bd9Sstevel@tonic-gate #include <sys/systm.h> 287c478bd9Sstevel@tonic-gate #include <sys/stream.h> 297c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 307c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 317c478bd9Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 327c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 337c478bd9Sstevel@tonic-gate #include <sys/socket.h> 347c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 357c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate #include <netinet/in.h> 387c478bd9Sstevel@tonic-gate #include <netinet/ip6.h> 397c478bd9Sstevel@tonic-gate #include <netinet/tcp_seq.h> 407c478bd9Sstevel@tonic-gate #include <netinet/sctp.h> 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #include <inet/common.h> 437c478bd9Sstevel@tonic-gate #include <inet/ip.h> 44bd670b35SErik Nordmark #include <inet/ip_if.h> 457c478bd9Sstevel@tonic-gate #include <inet/ip6.h> 467c478bd9Sstevel@tonic-gate #include <inet/mib2.h> 477c478bd9Sstevel@tonic-gate #include <inet/ipclassifier.h> 487c478bd9Sstevel@tonic-gate #include <inet/ipp_common.h> 497c478bd9Sstevel@tonic-gate #include <inet/ipsec_impl.h> 507c478bd9Sstevel@tonic-gate #include <inet/sctp_ip.h> 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate #include "sctp_impl.h" 537c478bd9Sstevel@tonic-gate #include "sctp_asconf.h" 547c478bd9Sstevel@tonic-gate #include "sctp_addr.h" 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate static struct kmem_cache *sctp_kmem_set_cache; 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate /* 597c478bd9Sstevel@tonic-gate * PR-SCTP comments. 607c478bd9Sstevel@tonic-gate * 617c478bd9Sstevel@tonic-gate * When we get a valid Forward TSN chunk, we check the fragment list for this 627c478bd9Sstevel@tonic-gate * SSN and preceeding SSNs free all them. Further, if this Forward TSN causes 637c478bd9Sstevel@tonic-gate * the next expected SSN to be present in the stream queue, we deliver any 647c478bd9Sstevel@tonic-gate * such stranded messages upstream. We also update the SACK info. appropriately. 657c478bd9Sstevel@tonic-gate * When checking for advancing the cumulative ack (in sctp_cumack()) we must 667c478bd9Sstevel@tonic-gate * check for abandoned chunks and messages. While traversing the tramsmit 677c478bd9Sstevel@tonic-gate * list if we come across an abandoned chunk, we can skip the message (i.e. 687c478bd9Sstevel@tonic-gate * take it out of the (re)transmit list) since this message, and hence this 697c478bd9Sstevel@tonic-gate * chunk, has been marked abandoned by sctp_rexmit(). If we come across an 707c478bd9Sstevel@tonic-gate * unsent chunk for a message this now abandoned we need to check if a 717c478bd9Sstevel@tonic-gate * Forward TSN needs to be sent, this could be a case where we deferred sending 727c478bd9Sstevel@tonic-gate * a Forward TSN in sctp_get_msg_to_send(). Further, after processing a 737c478bd9Sstevel@tonic-gate * SACK we check if the Advanced peer ack point can be moved ahead, i.e. 747c478bd9Sstevel@tonic-gate * if we can send a Forward TSN via sctp_check_abandoned_data(). 757c478bd9Sstevel@tonic-gate */ 767c478bd9Sstevel@tonic-gate void 777c478bd9Sstevel@tonic-gate sctp_free_set(sctp_set_t *s) 787c478bd9Sstevel@tonic-gate { 797c478bd9Sstevel@tonic-gate sctp_set_t *p; 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate while (s) { 827c478bd9Sstevel@tonic-gate p = s->next; 837c478bd9Sstevel@tonic-gate kmem_cache_free(sctp_kmem_set_cache, s); 847c478bd9Sstevel@tonic-gate s = p; 857c478bd9Sstevel@tonic-gate } 867c478bd9Sstevel@tonic-gate } 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate static void 897c478bd9Sstevel@tonic-gate sctp_ack_add(sctp_set_t **head, uint32_t tsn, int *num) 907c478bd9Sstevel@tonic-gate { 917c478bd9Sstevel@tonic-gate sctp_set_t *p, *t; 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate if (head == NULL || num == NULL) 947c478bd9Sstevel@tonic-gate return; 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate ASSERT(*num >= 0); 977c478bd9Sstevel@tonic-gate ASSERT((*num == 0 && *head == NULL) || (*num > 0 && *head != NULL)); 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate if (*head == NULL) { 1007c478bd9Sstevel@tonic-gate *head = kmem_cache_alloc(sctp_kmem_set_cache, KM_NOSLEEP); 1017c478bd9Sstevel@tonic-gate if (*head == NULL) 1027c478bd9Sstevel@tonic-gate return; 1037c478bd9Sstevel@tonic-gate (*head)->prev = (*head)->next = NULL; 1047c478bd9Sstevel@tonic-gate (*head)->begin = tsn; 1057c478bd9Sstevel@tonic-gate (*head)->end = tsn; 1067c478bd9Sstevel@tonic-gate *num = 1; 1077c478bd9Sstevel@tonic-gate return; 1087c478bd9Sstevel@tonic-gate } 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate ASSERT((*head)->prev == NULL); 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate /* 1137c478bd9Sstevel@tonic-gate * Handle this special case here so we don't have to check 1147c478bd9Sstevel@tonic-gate * for it each time in the loop. 1157c478bd9Sstevel@tonic-gate */ 1167c478bd9Sstevel@tonic-gate if (SEQ_LT(tsn + 1, (*head)->begin)) { 1177c478bd9Sstevel@tonic-gate /* add a new set, and move the head pointer */ 1187c478bd9Sstevel@tonic-gate t = kmem_cache_alloc(sctp_kmem_set_cache, KM_NOSLEEP); 1197c478bd9Sstevel@tonic-gate if (t == NULL) 1207c478bd9Sstevel@tonic-gate return; 1217c478bd9Sstevel@tonic-gate t->next = *head; 1227c478bd9Sstevel@tonic-gate t->prev = NULL; 1237c478bd9Sstevel@tonic-gate (*head)->prev = t; 1247c478bd9Sstevel@tonic-gate t->begin = tsn; 1257c478bd9Sstevel@tonic-gate t->end = tsn; 1267c478bd9Sstevel@tonic-gate (*num)++; 1277c478bd9Sstevel@tonic-gate *head = t; 1287c478bd9Sstevel@tonic-gate return; 1297c478bd9Sstevel@tonic-gate } 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate /* 1327c478bd9Sstevel@tonic-gate * We need to handle the following cases, where p points to 1337c478bd9Sstevel@tonic-gate * the current set (as we walk through the loop): 1347c478bd9Sstevel@tonic-gate * 1357c478bd9Sstevel@tonic-gate * 1. tsn is entirely less than p; create a new set before p. 1367c478bd9Sstevel@tonic-gate * 2. tsn borders p from less; coalesce p with tsn. 1377c478bd9Sstevel@tonic-gate * 3. tsn is withing p; do nothing. 1387c478bd9Sstevel@tonic-gate * 4. tsn borders p from greater; coalesce p with tsn. 1397c478bd9Sstevel@tonic-gate * 4a. p may now border p->next from less; if so, coalesce those 1407c478bd9Sstevel@tonic-gate * two sets. 1417c478bd9Sstevel@tonic-gate * 5. tsn is entirely greater then all sets; add a new set at 1427c478bd9Sstevel@tonic-gate * the end. 1437c478bd9Sstevel@tonic-gate */ 1447c478bd9Sstevel@tonic-gate for (p = *head; ; p = p->next) { 1457c478bd9Sstevel@tonic-gate if (SEQ_LT(tsn + 1, p->begin)) { 1467c478bd9Sstevel@tonic-gate /* 1: add a new set before p. */ 1477c478bd9Sstevel@tonic-gate t = kmem_cache_alloc(sctp_kmem_set_cache, KM_NOSLEEP); 1487c478bd9Sstevel@tonic-gate if (t == NULL) 1497c478bd9Sstevel@tonic-gate return; 1507c478bd9Sstevel@tonic-gate t->next = p; 1517c478bd9Sstevel@tonic-gate t->prev = NULL; 1527c478bd9Sstevel@tonic-gate t->begin = tsn; 1537c478bd9Sstevel@tonic-gate t->end = tsn; 1547c478bd9Sstevel@tonic-gate if (p->prev) { 1557c478bd9Sstevel@tonic-gate t->prev = p->prev; 1567c478bd9Sstevel@tonic-gate p->prev->next = t; 1577c478bd9Sstevel@tonic-gate } 1587c478bd9Sstevel@tonic-gate p->prev = t; 1597c478bd9Sstevel@tonic-gate (*num)++; 1607c478bd9Sstevel@tonic-gate return; 1617c478bd9Sstevel@tonic-gate } 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate if ((tsn + 1) == p->begin) { 1647c478bd9Sstevel@tonic-gate /* 2: adjust p->begin */ 1657c478bd9Sstevel@tonic-gate p->begin = tsn; 1667c478bd9Sstevel@tonic-gate return; 1677c478bd9Sstevel@tonic-gate } 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate if (SEQ_GEQ(tsn, p->begin) && SEQ_LEQ(tsn, p->end)) { 1707c478bd9Sstevel@tonic-gate /* 3; do nothing */ 1717c478bd9Sstevel@tonic-gate return; 1727c478bd9Sstevel@tonic-gate } 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate if ((p->end + 1) == tsn) { 1757c478bd9Sstevel@tonic-gate /* 4; adjust p->end */ 1767c478bd9Sstevel@tonic-gate p->end = tsn; 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate if (p->next != NULL && (tsn + 1) == p->next->begin) { 1797c478bd9Sstevel@tonic-gate /* 4a: coalesce p and p->next */ 1807c478bd9Sstevel@tonic-gate t = p->next; 1817c478bd9Sstevel@tonic-gate p->end = t->end; 1827c478bd9Sstevel@tonic-gate p->next = t->next; 1837c478bd9Sstevel@tonic-gate if (t->next != NULL) 1847c478bd9Sstevel@tonic-gate t->next->prev = p; 1857c478bd9Sstevel@tonic-gate kmem_cache_free(sctp_kmem_set_cache, t); 1867c478bd9Sstevel@tonic-gate (*num)--; 1877c478bd9Sstevel@tonic-gate } 1887c478bd9Sstevel@tonic-gate return; 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate if (p->next == NULL) { 1927c478bd9Sstevel@tonic-gate /* 5: add new set at the end */ 1937c478bd9Sstevel@tonic-gate t = kmem_cache_alloc(sctp_kmem_set_cache, KM_NOSLEEP); 1947c478bd9Sstevel@tonic-gate if (t == NULL) 1957c478bd9Sstevel@tonic-gate return; 1967c478bd9Sstevel@tonic-gate t->next = NULL; 1977c478bd9Sstevel@tonic-gate t->prev = p; 1987c478bd9Sstevel@tonic-gate t->begin = tsn; 1997c478bd9Sstevel@tonic-gate t->end = tsn; 2007c478bd9Sstevel@tonic-gate p->next = t; 2017c478bd9Sstevel@tonic-gate (*num)++; 2027c478bd9Sstevel@tonic-gate return; 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate if (SEQ_GT(tsn, p->end + 1)) 2067c478bd9Sstevel@tonic-gate continue; 2077c478bd9Sstevel@tonic-gate } 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate static void 2117c478bd9Sstevel@tonic-gate sctp_ack_rem(sctp_set_t **head, uint32_t end, int *num) 2127c478bd9Sstevel@tonic-gate { 2137c478bd9Sstevel@tonic-gate sctp_set_t *p, *t; 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate if (head == NULL || *head == NULL || num == NULL) 2167c478bd9Sstevel@tonic-gate return; 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate /* Nothing to remove */ 2197c478bd9Sstevel@tonic-gate if (SEQ_LT(end, (*head)->begin)) 2207c478bd9Sstevel@tonic-gate return; 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate /* Find out where to start removing sets */ 2237c478bd9Sstevel@tonic-gate for (p = *head; p->next; p = p->next) { 2247c478bd9Sstevel@tonic-gate if (SEQ_LEQ(end, p->end)) 2257c478bd9Sstevel@tonic-gate break; 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate if (SEQ_LT(end, p->end) && SEQ_GEQ(end, p->begin)) { 2297c478bd9Sstevel@tonic-gate /* adjust p */ 2307c478bd9Sstevel@tonic-gate p->begin = end + 1; 2317c478bd9Sstevel@tonic-gate /* all done */ 2327c478bd9Sstevel@tonic-gate if (p == *head) 2337c478bd9Sstevel@tonic-gate return; 2347c478bd9Sstevel@tonic-gate } else if (SEQ_GEQ(end, p->end)) { 2357c478bd9Sstevel@tonic-gate /* remove this set too */ 2367c478bd9Sstevel@tonic-gate p = p->next; 2377c478bd9Sstevel@tonic-gate } 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate /* unlink everything before this set */ 2407c478bd9Sstevel@tonic-gate t = *head; 2417c478bd9Sstevel@tonic-gate *head = p; 2427c478bd9Sstevel@tonic-gate if (p != NULL && p->prev != NULL) { 2437c478bd9Sstevel@tonic-gate p->prev->next = NULL; 2447c478bd9Sstevel@tonic-gate p->prev = NULL; 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate sctp_free_set(t); 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate /* recount the number of sets */ 2507c478bd9Sstevel@tonic-gate *num = 0; 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate for (p = *head; p != NULL; p = p->next) 2537c478bd9Sstevel@tonic-gate (*num)++; 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate void 2577c478bd9Sstevel@tonic-gate sctp_sets_init() 2587c478bd9Sstevel@tonic-gate { 2597c478bd9Sstevel@tonic-gate sctp_kmem_set_cache = kmem_cache_create("sctp_set_cache", 2607c478bd9Sstevel@tonic-gate sizeof (sctp_set_t), 0, NULL, NULL, NULL, NULL, 2617c478bd9Sstevel@tonic-gate NULL, 0); 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate void 2657c478bd9Sstevel@tonic-gate sctp_sets_fini() 2667c478bd9Sstevel@tonic-gate { 2677c478bd9Sstevel@tonic-gate kmem_cache_destroy(sctp_kmem_set_cache); 2687c478bd9Sstevel@tonic-gate } 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate sctp_chunk_hdr_t * 2717c478bd9Sstevel@tonic-gate sctp_first_chunk(uchar_t *rptr, ssize_t remaining) 2727c478bd9Sstevel@tonic-gate { 2737c478bd9Sstevel@tonic-gate sctp_chunk_hdr_t *ch; 2747c478bd9Sstevel@tonic-gate uint16_t ch_len; 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate if (remaining < sizeof (*ch)) { 2777c478bd9Sstevel@tonic-gate return (NULL); 2787c478bd9Sstevel@tonic-gate } 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate ch = (sctp_chunk_hdr_t *)rptr; 2817c478bd9Sstevel@tonic-gate ch_len = ntohs(ch->sch_len); 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate if (ch_len < sizeof (*ch) || remaining < ch_len) { 2847c478bd9Sstevel@tonic-gate return (NULL); 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate return (ch); 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate sctp_chunk_hdr_t * 2917c478bd9Sstevel@tonic-gate sctp_next_chunk(sctp_chunk_hdr_t *ch, ssize_t *remaining) 2927c478bd9Sstevel@tonic-gate { 2937c478bd9Sstevel@tonic-gate int pad; 2947c478bd9Sstevel@tonic-gate uint16_t ch_len; 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate if (!ch) { 2977c478bd9Sstevel@tonic-gate return (NULL); 2987c478bd9Sstevel@tonic-gate } 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate ch_len = ntohs(ch->sch_len); 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate if ((pad = ch_len & (SCTP_ALIGN - 1)) != 0) { 3037c478bd9Sstevel@tonic-gate pad = SCTP_ALIGN - pad; 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate *remaining -= (ch_len + pad); 3077c478bd9Sstevel@tonic-gate ch = (sctp_chunk_hdr_t *)((char *)ch + ch_len + pad); 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate return (sctp_first_chunk((uchar_t *)ch, *remaining)); 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate /* 3137c478bd9Sstevel@tonic-gate * Attach ancillary data to a received SCTP segments. 3147c478bd9Sstevel@tonic-gate * If the source address (fp) is not the primary, send up a 3157c478bd9Sstevel@tonic-gate * unitdata_ind so recvfrom() can populate the msg_name field. 3167c478bd9Sstevel@tonic-gate * If ancillary data is also requested, we append it to the 3177c478bd9Sstevel@tonic-gate * unitdata_req. Otherwise, we just send up an optdata_ind. 3187c478bd9Sstevel@tonic-gate */ 3197c478bd9Sstevel@tonic-gate static int 3207c478bd9Sstevel@tonic-gate sctp_input_add_ancillary(sctp_t *sctp, mblk_t **mp, sctp_data_hdr_t *dcp, 321bd670b35SErik Nordmark sctp_faddr_t *fp, ip_pkt_t *ipp, ip_recv_attr_t *ira) 3227c478bd9Sstevel@tonic-gate { 3237c478bd9Sstevel@tonic-gate struct T_unitdata_ind *tudi; 3247c478bd9Sstevel@tonic-gate int optlen; 3257c478bd9Sstevel@tonic-gate int hdrlen; 3267c478bd9Sstevel@tonic-gate uchar_t *optptr; 3277c478bd9Sstevel@tonic-gate struct cmsghdr *cmsg; 3287c478bd9Sstevel@tonic-gate mblk_t *mp1; 3297c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin_buf[1]; 3307c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6; 3317c478bd9Sstevel@tonic-gate struct sockaddr_in *sin4; 332bd670b35SErik Nordmark crb_t addflag; /* Which pieces to add */ 333bd670b35SErik Nordmark conn_t *connp = sctp->sctp_connp; 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate sin4 = NULL; 3367c478bd9Sstevel@tonic-gate sin6 = NULL; 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate optlen = hdrlen = 0; 339bd670b35SErik Nordmark addflag.crb_all = 0; 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate /* Figure out address size */ 342bd670b35SErik Nordmark if (connp->conn_family == AF_INET) { 3437c478bd9Sstevel@tonic-gate sin4 = (struct sockaddr_in *)sin_buf; 3447c478bd9Sstevel@tonic-gate sin4->sin_family = AF_INET; 345bd670b35SErik Nordmark sin4->sin_port = connp->conn_fport; 3466be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India IN6_V4MAPPED_TO_IPADDR(&fp->sf_faddr, sin4->sin_addr.s_addr); 3477c478bd9Sstevel@tonic-gate hdrlen = sizeof (*tudi) + sizeof (*sin4); 3487c478bd9Sstevel@tonic-gate } else { 3497c478bd9Sstevel@tonic-gate sin6 = sin_buf; 3507c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 351bd670b35SErik Nordmark sin6->sin6_port = connp->conn_fport; 3526be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sin6->sin6_addr = fp->sf_faddr; 3537c478bd9Sstevel@tonic-gate hdrlen = sizeof (*tudi) + sizeof (*sin6); 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate /* If app asked to receive send / recv info */ 356bd670b35SErik Nordmark if (sctp->sctp_recvsndrcvinfo) 3577c478bd9Sstevel@tonic-gate optlen += sizeof (*cmsg) + sizeof (struct sctp_sndrcvinfo); 3587c478bd9Sstevel@tonic-gate 359bd670b35SErik Nordmark if (connp->conn_recv_ancillary.crb_all == 0) 3607c478bd9Sstevel@tonic-gate goto noancillary; 3617c478bd9Sstevel@tonic-gate 362bd670b35SErik Nordmark if (connp->conn_recv_ancillary.crb_ip_recvpktinfo && 363bd670b35SErik Nordmark ira->ira_ruifindex != sctp->sctp_recvifindex) { 3647c478bd9Sstevel@tonic-gate optlen += sizeof (*cmsg) + sizeof (struct in6_pktinfo); 3657c478bd9Sstevel@tonic-gate if (hdrlen == 0) 3667c478bd9Sstevel@tonic-gate hdrlen = sizeof (struct T_unitdata_ind); 367bd670b35SErik Nordmark addflag.crb_ip_recvpktinfo = 1; 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate /* If app asked for hoplimit and it has changed ... */ 370bd670b35SErik Nordmark if (connp->conn_recv_ancillary.crb_ipv6_recvhoplimit && 371bd670b35SErik Nordmark ipp->ipp_hoplimit != sctp->sctp_recvhops) { 3727c478bd9Sstevel@tonic-gate optlen += sizeof (*cmsg) + sizeof (uint_t); 3737c478bd9Sstevel@tonic-gate if (hdrlen == 0) 3747c478bd9Sstevel@tonic-gate hdrlen = sizeof (struct T_unitdata_ind); 375bd670b35SErik Nordmark addflag.crb_ipv6_recvhoplimit = 1; 376bd670b35SErik Nordmark } 377bd670b35SErik Nordmark /* If app asked for tclass and it has changed ... */ 378bd670b35SErik Nordmark if (connp->conn_recv_ancillary.crb_ipv6_recvtclass && 379bd670b35SErik Nordmark ipp->ipp_tclass != sctp->sctp_recvtclass) { 380bd670b35SErik Nordmark optlen += sizeof (struct T_opthdr) + sizeof (uint_t); 381bd670b35SErik Nordmark if (hdrlen == 0) 382bd670b35SErik Nordmark hdrlen = sizeof (struct T_unitdata_ind); 383bd670b35SErik Nordmark addflag.crb_ipv6_recvtclass = 1; 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate /* If app asked for hopbyhop headers and it has changed ... */ 386bd670b35SErik Nordmark if (connp->conn_recv_ancillary.crb_ipv6_recvhopopts && 38745916cd2Sjpk ip_cmpbuf(sctp->sctp_hopopts, sctp->sctp_hopoptslen, 3887c478bd9Sstevel@tonic-gate (ipp->ipp_fields & IPPF_HOPOPTS), 3897c478bd9Sstevel@tonic-gate ipp->ipp_hopopts, ipp->ipp_hopoptslen)) { 39045916cd2Sjpk optlen += sizeof (*cmsg) + ipp->ipp_hopoptslen - 39145916cd2Sjpk sctp->sctp_v6label_len; 3927c478bd9Sstevel@tonic-gate if (hdrlen == 0) 3937c478bd9Sstevel@tonic-gate hdrlen = sizeof (struct T_unitdata_ind); 394bd670b35SErik Nordmark addflag.crb_ipv6_recvhopopts = 1; 39545916cd2Sjpk if (!ip_allocbuf((void **)&sctp->sctp_hopopts, 3967c478bd9Sstevel@tonic-gate &sctp->sctp_hopoptslen, 3977c478bd9Sstevel@tonic-gate (ipp->ipp_fields & IPPF_HOPOPTS), 3987c478bd9Sstevel@tonic-gate ipp->ipp_hopopts, ipp->ipp_hopoptslen)) 3997c478bd9Sstevel@tonic-gate return (-1); 4007c478bd9Sstevel@tonic-gate } 4017c478bd9Sstevel@tonic-gate /* If app asked for dst headers before routing headers ... */ 402bd670b35SErik Nordmark if (connp->conn_recv_ancillary.crb_ipv6_recvrthdrdstopts && 403bd670b35SErik Nordmark ip_cmpbuf(sctp->sctp_rthdrdstopts, sctp->sctp_rthdrdstoptslen, 404bd670b35SErik Nordmark (ipp->ipp_fields & IPPF_RTHDRDSTOPTS), 405bd670b35SErik Nordmark ipp->ipp_rthdrdstopts, ipp->ipp_rthdrdstoptslen)) { 406bd670b35SErik Nordmark optlen += sizeof (*cmsg) + ipp->ipp_rthdrdstoptslen; 4077c478bd9Sstevel@tonic-gate if (hdrlen == 0) 4087c478bd9Sstevel@tonic-gate hdrlen = sizeof (struct T_unitdata_ind); 409bd670b35SErik Nordmark addflag.crb_ipv6_recvrthdrdstopts = 1; 410bd670b35SErik Nordmark if (!ip_allocbuf((void **)&sctp->sctp_rthdrdstopts, 411bd670b35SErik Nordmark &sctp->sctp_rthdrdstoptslen, 412bd670b35SErik Nordmark (ipp->ipp_fields & IPPF_RTHDRDSTOPTS), 413bd670b35SErik Nordmark ipp->ipp_rthdrdstopts, ipp->ipp_rthdrdstoptslen)) 4147c478bd9Sstevel@tonic-gate return (-1); 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate /* If app asked for routing headers and it has changed ... */ 417bd670b35SErik Nordmark if (connp->conn_recv_ancillary.crb_ipv6_recvrthdr && 418bd670b35SErik Nordmark ip_cmpbuf(sctp->sctp_rthdr, sctp->sctp_rthdrlen, 4197c478bd9Sstevel@tonic-gate (ipp->ipp_fields & IPPF_RTHDR), 4207c478bd9Sstevel@tonic-gate ipp->ipp_rthdr, ipp->ipp_rthdrlen)) { 4217c478bd9Sstevel@tonic-gate optlen += sizeof (*cmsg) + ipp->ipp_rthdrlen; 4227c478bd9Sstevel@tonic-gate if (hdrlen == 0) 4237c478bd9Sstevel@tonic-gate hdrlen = sizeof (struct T_unitdata_ind); 424bd670b35SErik Nordmark addflag.crb_ipv6_recvrthdr = 1; 42545916cd2Sjpk if (!ip_allocbuf((void **)&sctp->sctp_rthdr, 4267c478bd9Sstevel@tonic-gate &sctp->sctp_rthdrlen, 4277c478bd9Sstevel@tonic-gate (ipp->ipp_fields & IPPF_RTHDR), 4287c478bd9Sstevel@tonic-gate ipp->ipp_rthdr, ipp->ipp_rthdrlen)) 4297c478bd9Sstevel@tonic-gate return (-1); 4307c478bd9Sstevel@tonic-gate } 4317c478bd9Sstevel@tonic-gate /* If app asked for dest headers and it has changed ... */ 432bd670b35SErik Nordmark if (connp->conn_recv_ancillary.crb_ipv6_recvdstopts && 43345916cd2Sjpk ip_cmpbuf(sctp->sctp_dstopts, sctp->sctp_dstoptslen, 4347c478bd9Sstevel@tonic-gate (ipp->ipp_fields & IPPF_DSTOPTS), 4357c478bd9Sstevel@tonic-gate ipp->ipp_dstopts, ipp->ipp_dstoptslen)) { 4367c478bd9Sstevel@tonic-gate optlen += sizeof (*cmsg) + ipp->ipp_dstoptslen; 4377c478bd9Sstevel@tonic-gate if (hdrlen == 0) 4387c478bd9Sstevel@tonic-gate hdrlen = sizeof (struct T_unitdata_ind); 439bd670b35SErik Nordmark addflag.crb_ipv6_recvdstopts = 1; 44045916cd2Sjpk if (!ip_allocbuf((void **)&sctp->sctp_dstopts, 4417c478bd9Sstevel@tonic-gate &sctp->sctp_dstoptslen, 4427c478bd9Sstevel@tonic-gate (ipp->ipp_fields & IPPF_DSTOPTS), 4437c478bd9Sstevel@tonic-gate ipp->ipp_dstopts, ipp->ipp_dstoptslen)) 4447c478bd9Sstevel@tonic-gate return (-1); 4457c478bd9Sstevel@tonic-gate } 4467c478bd9Sstevel@tonic-gate noancillary: 4477c478bd9Sstevel@tonic-gate /* Nothing to add */ 4487c478bd9Sstevel@tonic-gate if (hdrlen == 0) 4497c478bd9Sstevel@tonic-gate return (-1); 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate mp1 = allocb(hdrlen + optlen + sizeof (void *), BPRI_MED); 4527c478bd9Sstevel@tonic-gate if (mp1 == NULL) 4537c478bd9Sstevel@tonic-gate return (-1); 4547c478bd9Sstevel@tonic-gate mp1->b_cont = *mp; 4557c478bd9Sstevel@tonic-gate *mp = mp1; 4567c478bd9Sstevel@tonic-gate mp1->b_rptr += sizeof (void *); /* pointer worth of padding */ 4577c478bd9Sstevel@tonic-gate mp1->b_wptr = mp1->b_rptr + hdrlen + optlen; 4587c478bd9Sstevel@tonic-gate DB_TYPE(mp1) = M_PROTO; 4597c478bd9Sstevel@tonic-gate tudi = (struct T_unitdata_ind *)mp1->b_rptr; 4607c478bd9Sstevel@tonic-gate tudi->PRIM_type = T_UNITDATA_IND; 4617c478bd9Sstevel@tonic-gate tudi->SRC_length = sin4 ? sizeof (*sin4) : sizeof (*sin6); 4627c478bd9Sstevel@tonic-gate tudi->SRC_offset = sizeof (*tudi); 4637c478bd9Sstevel@tonic-gate tudi->OPT_offset = sizeof (*tudi) + tudi->SRC_length; 4647c478bd9Sstevel@tonic-gate tudi->OPT_length = optlen; 4657c478bd9Sstevel@tonic-gate if (sin4) { 4667c478bd9Sstevel@tonic-gate bcopy(sin4, tudi + 1, sizeof (*sin4)); 4677c478bd9Sstevel@tonic-gate } else { 4687c478bd9Sstevel@tonic-gate bcopy(sin6, tudi + 1, sizeof (*sin6)); 4697c478bd9Sstevel@tonic-gate } 4707c478bd9Sstevel@tonic-gate optptr = (uchar_t *)tudi + tudi->OPT_offset; 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate if (sctp->sctp_recvsndrcvinfo) { 4737c478bd9Sstevel@tonic-gate /* XXX need backout method if memory allocation fails. */ 4747c478bd9Sstevel@tonic-gate struct sctp_sndrcvinfo *sri; 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate cmsg = (struct cmsghdr *)optptr; 4777c478bd9Sstevel@tonic-gate cmsg->cmsg_level = IPPROTO_SCTP; 4787c478bd9Sstevel@tonic-gate cmsg->cmsg_type = SCTP_SNDRCV; 4797c478bd9Sstevel@tonic-gate cmsg->cmsg_len = sizeof (*cmsg) + sizeof (*sri); 4807c478bd9Sstevel@tonic-gate optptr += sizeof (*cmsg); 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate sri = (struct sctp_sndrcvinfo *)(cmsg + 1); 4837c478bd9Sstevel@tonic-gate ASSERT(OK_32PTR(sri)); 4847c478bd9Sstevel@tonic-gate sri->sinfo_stream = ntohs(dcp->sdh_sid); 4857c478bd9Sstevel@tonic-gate sri->sinfo_ssn = ntohs(dcp->sdh_ssn); 4867c478bd9Sstevel@tonic-gate if (SCTP_DATA_GET_UBIT(dcp)) { 4877c478bd9Sstevel@tonic-gate sri->sinfo_flags = MSG_UNORDERED; 4887c478bd9Sstevel@tonic-gate } else { 4897c478bd9Sstevel@tonic-gate sri->sinfo_flags = 0; 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate sri->sinfo_ppid = dcp->sdh_payload_id; 4927c478bd9Sstevel@tonic-gate sri->sinfo_context = 0; 4937c478bd9Sstevel@tonic-gate sri->sinfo_timetolive = 0; 4947c478bd9Sstevel@tonic-gate sri->sinfo_tsn = ntohl(dcp->sdh_tsn); 4957c478bd9Sstevel@tonic-gate sri->sinfo_cumtsn = sctp->sctp_ftsn; 4967c478bd9Sstevel@tonic-gate sri->sinfo_assoc_id = 0; 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate optptr += sizeof (*sri); 4997c478bd9Sstevel@tonic-gate } 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate /* 5027c478bd9Sstevel@tonic-gate * If app asked for pktinfo and the index has changed ... 5037c478bd9Sstevel@tonic-gate * Note that the local address never changes for the connection. 5047c478bd9Sstevel@tonic-gate */ 505bd670b35SErik Nordmark if (addflag.crb_ip_recvpktinfo) { 5067c478bd9Sstevel@tonic-gate struct in6_pktinfo *pkti; 507bd670b35SErik Nordmark uint_t ifindex; 5087c478bd9Sstevel@tonic-gate 509bd670b35SErik Nordmark ifindex = ira->ira_ruifindex; 5107c478bd9Sstevel@tonic-gate cmsg = (struct cmsghdr *)optptr; 5117c478bd9Sstevel@tonic-gate cmsg->cmsg_level = IPPROTO_IPV6; 5127c478bd9Sstevel@tonic-gate cmsg->cmsg_type = IPV6_PKTINFO; 5137c478bd9Sstevel@tonic-gate cmsg->cmsg_len = sizeof (*cmsg) + sizeof (*pkti); 5147c478bd9Sstevel@tonic-gate optptr += sizeof (*cmsg); 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate pkti = (struct in6_pktinfo *)optptr; 517bd670b35SErik Nordmark if (connp->conn_family == AF_INET6) 5187c478bd9Sstevel@tonic-gate pkti->ipi6_addr = sctp->sctp_ip6h->ip6_src; 5197c478bd9Sstevel@tonic-gate else 5207c478bd9Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(sctp->sctp_ipha->ipha_src, 5217c478bd9Sstevel@tonic-gate &pkti->ipi6_addr); 522bd670b35SErik Nordmark 523bd670b35SErik Nordmark pkti->ipi6_ifindex = ifindex; 5247c478bd9Sstevel@tonic-gate optptr += sizeof (*pkti); 5257c478bd9Sstevel@tonic-gate ASSERT(OK_32PTR(optptr)); 5267c478bd9Sstevel@tonic-gate /* Save as "last" value */ 527bd670b35SErik Nordmark sctp->sctp_recvifindex = ifindex; 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate /* If app asked for hoplimit and it has changed ... */ 530bd670b35SErik Nordmark if (addflag.crb_ipv6_recvhoplimit) { 5317c478bd9Sstevel@tonic-gate cmsg = (struct cmsghdr *)optptr; 5327c478bd9Sstevel@tonic-gate cmsg->cmsg_level = IPPROTO_IPV6; 5337c478bd9Sstevel@tonic-gate cmsg->cmsg_type = IPV6_HOPLIMIT; 5347c478bd9Sstevel@tonic-gate cmsg->cmsg_len = sizeof (*cmsg) + sizeof (uint_t); 5357c478bd9Sstevel@tonic-gate optptr += sizeof (*cmsg); 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate *(uint_t *)optptr = ipp->ipp_hoplimit; 5387c478bd9Sstevel@tonic-gate optptr += sizeof (uint_t); 5397c478bd9Sstevel@tonic-gate ASSERT(OK_32PTR(optptr)); 5407c478bd9Sstevel@tonic-gate /* Save as "last" value */ 5417c478bd9Sstevel@tonic-gate sctp->sctp_recvhops = ipp->ipp_hoplimit; 5427c478bd9Sstevel@tonic-gate } 543bd670b35SErik Nordmark /* If app asked for tclass and it has changed ... */ 544bd670b35SErik Nordmark if (addflag.crb_ipv6_recvtclass) { 545bd670b35SErik Nordmark cmsg = (struct cmsghdr *)optptr; 546bd670b35SErik Nordmark cmsg->cmsg_level = IPPROTO_IPV6; 547bd670b35SErik Nordmark cmsg->cmsg_type = IPV6_TCLASS; 548bd670b35SErik Nordmark cmsg->cmsg_len = sizeof (*cmsg) + sizeof (uint_t); 549bd670b35SErik Nordmark optptr += sizeof (*cmsg); 550bd670b35SErik Nordmark 551bd670b35SErik Nordmark *(uint_t *)optptr = ipp->ipp_tclass; 552bd670b35SErik Nordmark optptr += sizeof (uint_t); 553bd670b35SErik Nordmark ASSERT(OK_32PTR(optptr)); 554bd670b35SErik Nordmark /* Save as "last" value */ 555bd670b35SErik Nordmark sctp->sctp_recvtclass = ipp->ipp_tclass; 556bd670b35SErik Nordmark } 557bd670b35SErik Nordmark if (addflag.crb_ipv6_recvhopopts) { 5587c478bd9Sstevel@tonic-gate cmsg = (struct cmsghdr *)optptr; 5597c478bd9Sstevel@tonic-gate cmsg->cmsg_level = IPPROTO_IPV6; 5607c478bd9Sstevel@tonic-gate cmsg->cmsg_type = IPV6_HOPOPTS; 5617c478bd9Sstevel@tonic-gate cmsg->cmsg_len = sizeof (*cmsg) + ipp->ipp_hopoptslen; 5627c478bd9Sstevel@tonic-gate optptr += sizeof (*cmsg); 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate bcopy(ipp->ipp_hopopts, optptr, ipp->ipp_hopoptslen); 5657c478bd9Sstevel@tonic-gate optptr += ipp->ipp_hopoptslen; 5667c478bd9Sstevel@tonic-gate ASSERT(OK_32PTR(optptr)); 5677c478bd9Sstevel@tonic-gate /* Save as last value */ 56845916cd2Sjpk ip_savebuf((void **)&sctp->sctp_hopopts, 5697c478bd9Sstevel@tonic-gate &sctp->sctp_hopoptslen, 5707c478bd9Sstevel@tonic-gate (ipp->ipp_fields & IPPF_HOPOPTS), 5717c478bd9Sstevel@tonic-gate ipp->ipp_hopopts, ipp->ipp_hopoptslen); 5727c478bd9Sstevel@tonic-gate } 573bd670b35SErik Nordmark if (addflag.crb_ipv6_recvrthdrdstopts) { 5747c478bd9Sstevel@tonic-gate cmsg = (struct cmsghdr *)optptr; 5757c478bd9Sstevel@tonic-gate cmsg->cmsg_level = IPPROTO_IPV6; 5767c478bd9Sstevel@tonic-gate cmsg->cmsg_type = IPV6_RTHDRDSTOPTS; 577bd670b35SErik Nordmark cmsg->cmsg_len = sizeof (*cmsg) + ipp->ipp_rthdrdstoptslen; 5787c478bd9Sstevel@tonic-gate optptr += sizeof (*cmsg); 5797c478bd9Sstevel@tonic-gate 580bd670b35SErik Nordmark bcopy(ipp->ipp_rthdrdstopts, optptr, ipp->ipp_rthdrdstoptslen); 581bd670b35SErik Nordmark optptr += ipp->ipp_rthdrdstoptslen; 5827c478bd9Sstevel@tonic-gate ASSERT(OK_32PTR(optptr)); 5837c478bd9Sstevel@tonic-gate /* Save as last value */ 584bd670b35SErik Nordmark ip_savebuf((void **)&sctp->sctp_rthdrdstopts, 585bd670b35SErik Nordmark &sctp->sctp_rthdrdstoptslen, 586bd670b35SErik Nordmark (ipp->ipp_fields & IPPF_RTHDRDSTOPTS), 587bd670b35SErik Nordmark ipp->ipp_rthdrdstopts, ipp->ipp_rthdrdstoptslen); 5887c478bd9Sstevel@tonic-gate } 589bd670b35SErik Nordmark if (addflag.crb_ipv6_recvrthdr) { 5907c478bd9Sstevel@tonic-gate cmsg = (struct cmsghdr *)optptr; 5917c478bd9Sstevel@tonic-gate cmsg->cmsg_level = IPPROTO_IPV6; 5927c478bd9Sstevel@tonic-gate cmsg->cmsg_type = IPV6_RTHDR; 5937c478bd9Sstevel@tonic-gate cmsg->cmsg_len = sizeof (*cmsg) + ipp->ipp_rthdrlen; 5947c478bd9Sstevel@tonic-gate optptr += sizeof (*cmsg); 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate bcopy(ipp->ipp_rthdr, optptr, ipp->ipp_rthdrlen); 5977c478bd9Sstevel@tonic-gate optptr += ipp->ipp_rthdrlen; 5987c478bd9Sstevel@tonic-gate ASSERT(OK_32PTR(optptr)); 5997c478bd9Sstevel@tonic-gate /* Save as last value */ 60045916cd2Sjpk ip_savebuf((void **)&sctp->sctp_rthdr, 6017c478bd9Sstevel@tonic-gate &sctp->sctp_rthdrlen, 6027c478bd9Sstevel@tonic-gate (ipp->ipp_fields & IPPF_RTHDR), 6037c478bd9Sstevel@tonic-gate ipp->ipp_rthdr, ipp->ipp_rthdrlen); 6047c478bd9Sstevel@tonic-gate } 605bd670b35SErik Nordmark if (addflag.crb_ipv6_recvdstopts) { 6067c478bd9Sstevel@tonic-gate cmsg = (struct cmsghdr *)optptr; 6077c478bd9Sstevel@tonic-gate cmsg->cmsg_level = IPPROTO_IPV6; 6087c478bd9Sstevel@tonic-gate cmsg->cmsg_type = IPV6_DSTOPTS; 6097c478bd9Sstevel@tonic-gate cmsg->cmsg_len = sizeof (*cmsg) + ipp->ipp_dstoptslen; 6107c478bd9Sstevel@tonic-gate optptr += sizeof (*cmsg); 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate bcopy(ipp->ipp_dstopts, optptr, ipp->ipp_dstoptslen); 6137c478bd9Sstevel@tonic-gate optptr += ipp->ipp_dstoptslen; 6147c478bd9Sstevel@tonic-gate ASSERT(OK_32PTR(optptr)); 6157c478bd9Sstevel@tonic-gate /* Save as last value */ 61645916cd2Sjpk ip_savebuf((void **)&sctp->sctp_dstopts, 6177c478bd9Sstevel@tonic-gate &sctp->sctp_dstoptslen, 6187c478bd9Sstevel@tonic-gate (ipp->ipp_fields & IPPF_DSTOPTS), 6197c478bd9Sstevel@tonic-gate ipp->ipp_dstopts, ipp->ipp_dstoptslen); 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate ASSERT(optptr == mp1->b_wptr); 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate return (0); 6257c478bd9Sstevel@tonic-gate } 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate void 6287c478bd9Sstevel@tonic-gate sctp_free_reass(sctp_instr_t *sip) 6297c478bd9Sstevel@tonic-gate { 6307c478bd9Sstevel@tonic-gate mblk_t *mp, *mpnext, *mctl; 631c3c17166SGeorge Shepherd #ifdef DEBUG 632c3c17166SGeorge Shepherd sctp_reass_t *srp; 633c3c17166SGeorge Shepherd #endif 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate for (mp = sip->istr_reass; mp != NULL; mp = mpnext) { 6367c478bd9Sstevel@tonic-gate mpnext = mp->b_next; 6377c478bd9Sstevel@tonic-gate mp->b_next = NULL; 6387c478bd9Sstevel@tonic-gate mp->b_prev = NULL; 6397c478bd9Sstevel@tonic-gate if (DB_TYPE(mp) == M_CTL) { 6407c478bd9Sstevel@tonic-gate mctl = mp; 641c3c17166SGeorge Shepherd #ifdef DEBUG 642c3c17166SGeorge Shepherd srp = (sctp_reass_t *)DB_BASE(mctl); 643c3c17166SGeorge Shepherd /* Partial delivery can leave empty srp */ 6446be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India ASSERT(mp->b_cont != NULL || srp->sr_got == 0); 645c3c17166SGeorge Shepherd #endif 6467c478bd9Sstevel@tonic-gate mp = mp->b_cont; 6477c478bd9Sstevel@tonic-gate mctl->b_cont = NULL; 6487c478bd9Sstevel@tonic-gate freeb(mctl); 6497c478bd9Sstevel@tonic-gate } 6507c478bd9Sstevel@tonic-gate freemsg(mp); 6517c478bd9Sstevel@tonic-gate } 65292baa190SGeorge Shepherd sip->istr_reass = NULL; 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate /* 6567c478bd9Sstevel@tonic-gate * If the series of data fragments of which dmp is a part is successfully 6577c478bd9Sstevel@tonic-gate * reassembled, the first mblk in the series is returned. dc is adjusted 6587c478bd9Sstevel@tonic-gate * to point at the data chunk in the lead mblk, and b_rptr also points to 6597c478bd9Sstevel@tonic-gate * the data chunk; the following mblk's b_rptr's point at the actual payload. 6607c478bd9Sstevel@tonic-gate * 6617c478bd9Sstevel@tonic-gate * If the series is not yet reassembled, NULL is returned. dc is not changed. 6627c478bd9Sstevel@tonic-gate * XXX should probably move this up into the state machine. 6637c478bd9Sstevel@tonic-gate */ 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate /* Fragment list for un-ordered messages. Partial delivery is not supported */ 6667c478bd9Sstevel@tonic-gate static mblk_t * 6677c478bd9Sstevel@tonic-gate sctp_uodata_frag(sctp_t *sctp, mblk_t *dmp, sctp_data_hdr_t **dc) 6687c478bd9Sstevel@tonic-gate { 6697c478bd9Sstevel@tonic-gate mblk_t *hmp; 6707c478bd9Sstevel@tonic-gate mblk_t *begin = NULL; 6717c478bd9Sstevel@tonic-gate mblk_t *end = NULL; 6727c478bd9Sstevel@tonic-gate sctp_data_hdr_t *qdc; 6737c478bd9Sstevel@tonic-gate uint32_t ntsn; 6747c478bd9Sstevel@tonic-gate uint32_t tsn = ntohl((*dc)->sdh_tsn); 6757c478bd9Sstevel@tonic-gate #ifdef DEBUG 6767c478bd9Sstevel@tonic-gate mblk_t *mp1; 6777c478bd9Sstevel@tonic-gate #endif 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate /* First frag. */ 6807c478bd9Sstevel@tonic-gate if (sctp->sctp_uo_frags == NULL) { 6817c478bd9Sstevel@tonic-gate sctp->sctp_uo_frags = dmp; 6827c478bd9Sstevel@tonic-gate return (NULL); 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate hmp = sctp->sctp_uo_frags; 6857c478bd9Sstevel@tonic-gate /* 6867c478bd9Sstevel@tonic-gate * Insert the segment according to the TSN, fragmented unordered 6877c478bd9Sstevel@tonic-gate * chunks are sequenced by TSN. 6887c478bd9Sstevel@tonic-gate */ 6897c478bd9Sstevel@tonic-gate while (hmp != NULL) { 6907c478bd9Sstevel@tonic-gate qdc = (sctp_data_hdr_t *)hmp->b_rptr; 6917c478bd9Sstevel@tonic-gate ntsn = ntohl(qdc->sdh_tsn); 6927c478bd9Sstevel@tonic-gate if (SEQ_GT(ntsn, tsn)) { 6937c478bd9Sstevel@tonic-gate if (hmp->b_prev == NULL) { 6947c478bd9Sstevel@tonic-gate dmp->b_next = hmp; 6957c478bd9Sstevel@tonic-gate hmp->b_prev = dmp; 6967c478bd9Sstevel@tonic-gate sctp->sctp_uo_frags = dmp; 6977c478bd9Sstevel@tonic-gate } else { 6987c478bd9Sstevel@tonic-gate dmp->b_next = hmp; 6997c478bd9Sstevel@tonic-gate dmp->b_prev = hmp->b_prev; 7007c478bd9Sstevel@tonic-gate hmp->b_prev->b_next = dmp; 7017c478bd9Sstevel@tonic-gate hmp->b_prev = dmp; 7027c478bd9Sstevel@tonic-gate } 7037c478bd9Sstevel@tonic-gate break; 7047c478bd9Sstevel@tonic-gate } 7057c478bd9Sstevel@tonic-gate if (hmp->b_next == NULL) { 7067c478bd9Sstevel@tonic-gate hmp->b_next = dmp; 7077c478bd9Sstevel@tonic-gate dmp->b_prev = hmp; 7087c478bd9Sstevel@tonic-gate break; 7097c478bd9Sstevel@tonic-gate } 7107c478bd9Sstevel@tonic-gate hmp = hmp->b_next; 7117c478bd9Sstevel@tonic-gate } 7127c478bd9Sstevel@tonic-gate /* check if we completed a msg */ 7137c478bd9Sstevel@tonic-gate if (SCTP_DATA_GET_BBIT(*dc)) { 7147c478bd9Sstevel@tonic-gate begin = dmp; 7157c478bd9Sstevel@tonic-gate } else if (SCTP_DATA_GET_EBIT(*dc)) { 7167c478bd9Sstevel@tonic-gate end = dmp; 7177c478bd9Sstevel@tonic-gate } 7187c478bd9Sstevel@tonic-gate /* 7197c478bd9Sstevel@tonic-gate * We walk consecutive TSNs backwards till we get a seg. with 7207c478bd9Sstevel@tonic-gate * the B bit 7217c478bd9Sstevel@tonic-gate */ 7227c478bd9Sstevel@tonic-gate if (begin == NULL) { 7237c478bd9Sstevel@tonic-gate for (hmp = dmp->b_prev; hmp != NULL; hmp = hmp->b_prev) { 7247c478bd9Sstevel@tonic-gate qdc = (sctp_data_hdr_t *)hmp->b_rptr; 7257c478bd9Sstevel@tonic-gate ntsn = ntohl(qdc->sdh_tsn); 7267c478bd9Sstevel@tonic-gate if ((int32_t)(tsn - ntsn) > 1) { 7277c478bd9Sstevel@tonic-gate return (NULL); 7287c478bd9Sstevel@tonic-gate } 7297c478bd9Sstevel@tonic-gate if (SCTP_DATA_GET_BBIT(qdc)) { 7307c478bd9Sstevel@tonic-gate begin = hmp; 7317c478bd9Sstevel@tonic-gate break; 7327c478bd9Sstevel@tonic-gate } 7337c478bd9Sstevel@tonic-gate tsn = ntsn; 7347c478bd9Sstevel@tonic-gate } 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate tsn = ntohl((*dc)->sdh_tsn); 7377c478bd9Sstevel@tonic-gate /* 7387c478bd9Sstevel@tonic-gate * We walk consecutive TSNs till we get a seg. with the E bit 7397c478bd9Sstevel@tonic-gate */ 7407c478bd9Sstevel@tonic-gate if (end == NULL) { 7417c478bd9Sstevel@tonic-gate for (hmp = dmp->b_next; hmp != NULL; hmp = hmp->b_next) { 7427c478bd9Sstevel@tonic-gate qdc = (sctp_data_hdr_t *)hmp->b_rptr; 7437c478bd9Sstevel@tonic-gate ntsn = ntohl(qdc->sdh_tsn); 7447c478bd9Sstevel@tonic-gate if ((int32_t)(ntsn - tsn) > 1) { 7457c478bd9Sstevel@tonic-gate return (NULL); 7467c478bd9Sstevel@tonic-gate } 7477c478bd9Sstevel@tonic-gate if (SCTP_DATA_GET_EBIT(qdc)) { 7487c478bd9Sstevel@tonic-gate end = hmp; 7497c478bd9Sstevel@tonic-gate break; 7507c478bd9Sstevel@tonic-gate } 7517c478bd9Sstevel@tonic-gate tsn = ntsn; 7527c478bd9Sstevel@tonic-gate } 7537c478bd9Sstevel@tonic-gate } 7547c478bd9Sstevel@tonic-gate if (begin == NULL || end == NULL) { 7557c478bd9Sstevel@tonic-gate return (NULL); 7567c478bd9Sstevel@tonic-gate } 7577c478bd9Sstevel@tonic-gate /* Got one!, Remove the msg from the list */ 7587c478bd9Sstevel@tonic-gate if (sctp->sctp_uo_frags == begin) { 7597c478bd9Sstevel@tonic-gate ASSERT(begin->b_prev == NULL); 7607c478bd9Sstevel@tonic-gate sctp->sctp_uo_frags = end->b_next; 7617c478bd9Sstevel@tonic-gate if (end->b_next != NULL) 7627c478bd9Sstevel@tonic-gate end->b_next->b_prev = NULL; 7637c478bd9Sstevel@tonic-gate } else { 7647c478bd9Sstevel@tonic-gate begin->b_prev->b_next = end->b_next; 7657c478bd9Sstevel@tonic-gate if (end->b_next != NULL) 7667c478bd9Sstevel@tonic-gate end->b_next->b_prev = begin->b_prev; 7677c478bd9Sstevel@tonic-gate } 7687c478bd9Sstevel@tonic-gate begin->b_prev = NULL; 7697c478bd9Sstevel@tonic-gate end->b_next = NULL; 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate /* 7727c478bd9Sstevel@tonic-gate * Null out b_next and b_prev and chain using b_cont. 7737c478bd9Sstevel@tonic-gate */ 7747c478bd9Sstevel@tonic-gate dmp = end = begin; 7757c478bd9Sstevel@tonic-gate hmp = begin->b_next; 7767c478bd9Sstevel@tonic-gate *dc = (sctp_data_hdr_t *)begin->b_rptr; 7777c478bd9Sstevel@tonic-gate begin->b_next = NULL; 7787c478bd9Sstevel@tonic-gate while (hmp != NULL) { 7797c478bd9Sstevel@tonic-gate qdc = (sctp_data_hdr_t *)hmp->b_rptr; 7807c478bd9Sstevel@tonic-gate hmp->b_rptr = (uchar_t *)(qdc + 1); 7817c478bd9Sstevel@tonic-gate end = hmp->b_next; 7827c478bd9Sstevel@tonic-gate dmp->b_cont = hmp; 7837c478bd9Sstevel@tonic-gate dmp = hmp; 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate if (end != NULL) 7867c478bd9Sstevel@tonic-gate hmp->b_next = NULL; 7877c478bd9Sstevel@tonic-gate hmp->b_prev = NULL; 7887c478bd9Sstevel@tonic-gate hmp = end; 7897c478bd9Sstevel@tonic-gate } 7907c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_reassmsgs); 7917c478bd9Sstevel@tonic-gate #ifdef DEBUG 7927c478bd9Sstevel@tonic-gate mp1 = begin; 7937c478bd9Sstevel@tonic-gate while (mp1 != NULL) { 7947c478bd9Sstevel@tonic-gate ASSERT(mp1->b_next == NULL); 7957c478bd9Sstevel@tonic-gate ASSERT(mp1->b_prev == NULL); 7967c478bd9Sstevel@tonic-gate mp1 = mp1->b_cont; 7977c478bd9Sstevel@tonic-gate } 7987c478bd9Sstevel@tonic-gate #endif 7997c478bd9Sstevel@tonic-gate return (begin); 8007c478bd9Sstevel@tonic-gate } 8017d546a59Svi117747 8027d546a59Svi117747 /* 8037d546a59Svi117747 * Try partial delivery. 8047d546a59Svi117747 */ 8057d546a59Svi117747 static mblk_t * 8067d546a59Svi117747 sctp_try_partial_delivery(sctp_t *sctp, mblk_t *hmp, sctp_reass_t *srp, 8077d546a59Svi117747 sctp_data_hdr_t **dc) 8087d546a59Svi117747 { 8097d546a59Svi117747 mblk_t *mp; 8107d546a59Svi117747 mblk_t *dmp; 8117d546a59Svi117747 mblk_t *qmp; 8127d546a59Svi117747 mblk_t *prev; 8137d546a59Svi117747 sctp_data_hdr_t *qdc; 8147d546a59Svi117747 uint32_t tsn; 8157d546a59Svi117747 8167d546a59Svi117747 ASSERT(DB_TYPE(hmp) == M_CTL); 8177d546a59Svi117747 8187d546a59Svi117747 dprint(4, ("trypartial: got=%d, needed=%d\n", 8196be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India (int)(srp->sr_got), (int)(srp->sr_needed))); 8207d546a59Svi117747 821bd670b35SErik Nordmark mp = hmp->b_cont; 8227d546a59Svi117747 qdc = (sctp_data_hdr_t *)mp->b_rptr; 8237d546a59Svi117747 8246be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India ASSERT(SCTP_DATA_GET_BBIT(qdc) && srp->sr_hasBchunk); 8257d546a59Svi117747 8267d546a59Svi117747 tsn = ntohl(qdc->sdh_tsn) + 1; 8277d546a59Svi117747 8287d546a59Svi117747 /* 8297d546a59Svi117747 * This loop has two exit conditions: the 8307d546a59Svi117747 * end of received chunks has been reached, or 8317d546a59Svi117747 * there is a break in the sequence. We want 8327d546a59Svi117747 * to chop the reassembly list as follows (the 8337d546a59Svi117747 * numbers are TSNs): 8347d546a59Svi117747 * 10 -> 11 -> (end of chunks) 8357d546a59Svi117747 * 10 -> 11 -> | 13 (break in sequence) 8367d546a59Svi117747 */ 8377d546a59Svi117747 prev = mp; 8387d546a59Svi117747 mp = mp->b_cont; 8397d546a59Svi117747 while (mp != NULL) { 8407d546a59Svi117747 qdc = (sctp_data_hdr_t *)mp->b_rptr; 8417d546a59Svi117747 if (ntohl(qdc->sdh_tsn) != tsn) 8427d546a59Svi117747 break; 8437d546a59Svi117747 prev = mp; 8447d546a59Svi117747 mp = mp->b_cont; 8457d546a59Svi117747 tsn++; 8467d546a59Svi117747 } 8477d546a59Svi117747 /* 8487d546a59Svi117747 * We are sending all the fragments upstream, we have to retain 8497d546a59Svi117747 * the srp info for further fragments. 8507d546a59Svi117747 */ 8517d546a59Svi117747 if (mp == NULL) { 8527d546a59Svi117747 dmp = hmp->b_cont; 8537d546a59Svi117747 hmp->b_cont = NULL; 8546be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_nexttsn = tsn; 8556be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_msglen = 0; 8566be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_needed = 0; 8576be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_got = 0; 8586be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_tail = NULL; 8597d546a59Svi117747 } else { 860c3c17166SGeorge Shepherd /* 861c3c17166SGeorge Shepherd * There is a gap then some ordered frags which are not 862c3c17166SGeorge Shepherd * the next deliverable tsn. When the next deliverable 863c3c17166SGeorge Shepherd * frag arrives it will be set as the new list head in 864c3c17166SGeorge Shepherd * sctp_data_frag() by setting the B bit. 865c3c17166SGeorge Shepherd */ 8667d546a59Svi117747 dmp = hmp->b_cont; 8677d546a59Svi117747 hmp->b_cont = mp; 8687d546a59Svi117747 } 8696be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_hasBchunk = B_FALSE; 8707d546a59Svi117747 /* 8717d546a59Svi117747 * mp now points at the last chunk in the sequence, 8727d546a59Svi117747 * and prev points to mp's previous in the list. 873c3c17166SGeorge Shepherd * We chop the list at prev. Subsequent fragment 874c3c17166SGeorge Shepherd * deliveries will follow the normal reassembly 875c3c17166SGeorge Shepherd * path unless they too exceed the sctp_pd_point. 8767d546a59Svi117747 */ 8777d546a59Svi117747 prev->b_cont = NULL; 8786be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_partial_delivered = B_TRUE; 8797d546a59Svi117747 8807d546a59Svi117747 dprint(4, ("trypartial: got some, got=%d, needed=%d\n", 8816be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India (int)(srp->sr_got), (int)(srp->sr_needed))); 8827d546a59Svi117747 8837d546a59Svi117747 /* 8847d546a59Svi117747 * Adjust all mblk's except the lead so their rptr's point to the 8857d546a59Svi117747 * payload. sctp_data_chunk() will need to process the lead's 8867d546a59Svi117747 * data chunk section, so leave it's rptr pointing at the data chunk. 8877d546a59Svi117747 */ 8887d546a59Svi117747 *dc = (sctp_data_hdr_t *)dmp->b_rptr; 8896be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (srp->sr_tail != NULL) { 8906be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_got--; 8916be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India ASSERT(srp->sr_got != 0); 8926be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (srp->sr_needed != 0) { 8936be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_needed--; 8946be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India ASSERT(srp->sr_needed != 0); 8957d546a59Svi117747 } 8966be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_msglen -= ntohs((*dc)->sdh_len); 8977d546a59Svi117747 } 8987d546a59Svi117747 for (qmp = dmp->b_cont; qmp != NULL; qmp = qmp->b_cont) { 8997d546a59Svi117747 qdc = (sctp_data_hdr_t *)qmp->b_rptr; 9007d546a59Svi117747 qmp->b_rptr = (uchar_t *)(qdc + 1); 9017d546a59Svi117747 9027d546a59Svi117747 /* 9037d546a59Svi117747 * Deduct the balance from got and needed here, now that 9047d546a59Svi117747 * we know we are actually delivering these data. 9057d546a59Svi117747 */ 9066be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (srp->sr_tail != NULL) { 9076be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_got--; 9086be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India ASSERT(srp->sr_got != 0); 9096be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (srp->sr_needed != 0) { 9106be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_needed--; 9116be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India ASSERT(srp->sr_needed != 0); 9127d546a59Svi117747 } 9136be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_msglen -= ntohs(qdc->sdh_len); 9147d546a59Svi117747 } 9157d546a59Svi117747 } 9166be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India ASSERT(srp->sr_msglen == 0); 9177d546a59Svi117747 BUMP_LOCAL(sctp->sctp_reassmsgs); 9187d546a59Svi117747 9197d546a59Svi117747 return (dmp); 9207d546a59Svi117747 } 9217d546a59Svi117747 9227c478bd9Sstevel@tonic-gate /* 923c3c17166SGeorge Shepherd * Handle received fragments for ordered delivery to upper layer protocol. 924c3c17166SGeorge Shepherd * Manage the per message reassembly queue and if this fragment completes 925c3c17166SGeorge Shepherd * reassembly of the message, or qualifies the already reassembled data 926c3c17166SGeorge Shepherd * for partial delivery, prepare the message for delivery upstream. 927c3c17166SGeorge Shepherd * 928c3c17166SGeorge Shepherd * tpfinished in the caller remains set only when the incoming fragment 929c3c17166SGeorge Shepherd * has completed the reassembly of the message associated with its ssn. 9307c478bd9Sstevel@tonic-gate */ 9317c478bd9Sstevel@tonic-gate static mblk_t * 9327c478bd9Sstevel@tonic-gate sctp_data_frag(sctp_t *sctp, mblk_t *dmp, sctp_data_hdr_t **dc, int *error, 9337d546a59Svi117747 sctp_instr_t *sip, boolean_t *tpfinished) 9347c478bd9Sstevel@tonic-gate { 935c3c17166SGeorge Shepherd mblk_t *reassq_curr, *reassq_next, *reassq_prev; 936c3c17166SGeorge Shepherd mblk_t *new_reassq; 9377c478bd9Sstevel@tonic-gate mblk_t *qmp; 9387c478bd9Sstevel@tonic-gate mblk_t *first_mp; 9397c478bd9Sstevel@tonic-gate sctp_reass_t *srp; 9407c478bd9Sstevel@tonic-gate sctp_data_hdr_t *qdc; 9417c478bd9Sstevel@tonic-gate sctp_data_hdr_t *bdc; 9427c478bd9Sstevel@tonic-gate sctp_data_hdr_t *edc; 9437c478bd9Sstevel@tonic-gate uint32_t tsn; 9447d546a59Svi117747 uint16_t fraglen = 0; 9457c478bd9Sstevel@tonic-gate 9467c478bd9Sstevel@tonic-gate *error = 0; 9477c478bd9Sstevel@tonic-gate 948c3c17166SGeorge Shepherd /* 949c3c17166SGeorge Shepherd * Find the reassembly queue for this data chunk, if none 950c3c17166SGeorge Shepherd * yet exists, a new per message queue will be created and 951c3c17166SGeorge Shepherd * appended to the end of the list of per message queues. 952c3c17166SGeorge Shepherd * 953c3c17166SGeorge Shepherd * sip points on sctp_instr_t representing instream messages 954c3c17166SGeorge Shepherd * as yet undelivered for this stream (sid) of the association. 955c3c17166SGeorge Shepherd */ 956c3c17166SGeorge Shepherd reassq_next = reassq_prev = sip->istr_reass; 957c3c17166SGeorge Shepherd for (; reassq_next != NULL; reassq_next = reassq_next->b_next) { 958c3c17166SGeorge Shepherd srp = (sctp_reass_t *)DB_BASE(reassq_next); 9596be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (ntohs((*dc)->sdh_ssn) == srp->sr_ssn) { 960c3c17166SGeorge Shepherd reassq_curr = reassq_next; 9617c478bd9Sstevel@tonic-gate goto foundit; 9626be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India } else if (SSN_GT(srp->sr_ssn, ntohs((*dc)->sdh_ssn))) 9637c478bd9Sstevel@tonic-gate break; 964c3c17166SGeorge Shepherd reassq_prev = reassq_next; 9657c478bd9Sstevel@tonic-gate } 9667c478bd9Sstevel@tonic-gate 9677d546a59Svi117747 /* 968c3c17166SGeorge Shepherd * First fragment of this message received, allocate a M_CTL that 969c3c17166SGeorge Shepherd * will head the reassembly queue for this message. The message 970c3c17166SGeorge Shepherd * and all its fragments are identified by having the same ssn. 971c3c17166SGeorge Shepherd * 972c3c17166SGeorge Shepherd * Arriving fragments will be inserted in tsn order on the 973c3c17166SGeorge Shepherd * reassembly queue for this message (ssn), linked by b_cont. 9747d546a59Svi117747 */ 975c3c17166SGeorge Shepherd if ((new_reassq = allocb(sizeof (*srp), BPRI_MED)) == NULL) { 976c3c17166SGeorge Shepherd *error = ENOMEM; 9777d546a59Svi117747 return (NULL); 9787d546a59Svi117747 } 979c3c17166SGeorge Shepherd DB_TYPE(new_reassq) = M_CTL; 980c3c17166SGeorge Shepherd srp = (sctp_reass_t *)DB_BASE(new_reassq); 981c3c17166SGeorge Shepherd new_reassq->b_cont = dmp; 9827c478bd9Sstevel@tonic-gate 983c3c17166SGeorge Shepherd /* 984c3c17166SGeorge Shepherd * All per ssn reassembly queues, (one for each message) on 985c3c17166SGeorge Shepherd * this stream are doubly linked by b_next/b_prev back to the 986c3c17166SGeorge Shepherd * instr_reass of the instream structure associated with this 987c3c17166SGeorge Shepherd * stream id, (sip is initialized as sctp->sctp_instr[sid]). 988c3c17166SGeorge Shepherd * Insert the new reassembly queue in the correct (ssn) order. 989c3c17166SGeorge Shepherd */ 990c3c17166SGeorge Shepherd if (reassq_next != NULL) { 991c3c17166SGeorge Shepherd if (sip->istr_reass == reassq_next) { 992c3c17166SGeorge Shepherd /* head insertion */ 993c3c17166SGeorge Shepherd sip->istr_reass = new_reassq; 994c3c17166SGeorge Shepherd new_reassq->b_next = reassq_next; 995c3c17166SGeorge Shepherd new_reassq->b_prev = NULL; 996c3c17166SGeorge Shepherd reassq_next->b_prev = new_reassq; 9977c478bd9Sstevel@tonic-gate } else { 998c3c17166SGeorge Shepherd /* mid queue insertion */ 999c3c17166SGeorge Shepherd reassq_prev->b_next = new_reassq; 1000c3c17166SGeorge Shepherd new_reassq->b_prev = reassq_prev; 1001c3c17166SGeorge Shepherd new_reassq->b_next = reassq_next; 1002c3c17166SGeorge Shepherd reassq_next->b_prev = new_reassq; 10037c478bd9Sstevel@tonic-gate } 10047c478bd9Sstevel@tonic-gate } else { 1005c3c17166SGeorge Shepherd /* place new reassembly queue at the end */ 10067c478bd9Sstevel@tonic-gate if (sip->istr_reass == NULL) { 1007c3c17166SGeorge Shepherd sip->istr_reass = new_reassq; 1008c3c17166SGeorge Shepherd new_reassq->b_prev = NULL; 10097c478bd9Sstevel@tonic-gate } else { 1010c3c17166SGeorge Shepherd reassq_prev->b_next = new_reassq; 1011c3c17166SGeorge Shepherd new_reassq->b_prev = reassq_prev; 10127c478bd9Sstevel@tonic-gate } 1013c3c17166SGeorge Shepherd new_reassq->b_next = NULL; 10147c478bd9Sstevel@tonic-gate } 10156be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_partial_delivered = B_FALSE; 10166be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_ssn = ntohs((*dc)->sdh_ssn); 10176be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_hasBchunk = B_FALSE; 10187d546a59Svi117747 empty_srp: 10196be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_needed = 0; 10206be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_got = 1; 1021c3c17166SGeorge Shepherd /* tail always the highest tsn on the reassembly queue for this ssn */ 10226be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_tail = dmp; 10237d546a59Svi117747 if (SCTP_DATA_GET_BBIT(*dc)) { 1024c3c17166SGeorge Shepherd /* Incoming frag is flagged as the beginning of message */ 10256be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_msglen = ntohs((*dc)->sdh_len); 10266be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_nexttsn = ntohl((*dc)->sdh_tsn) + 1; 10276be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_hasBchunk = B_TRUE; 10286be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India } else if (srp->sr_partial_delivered && 10296be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_nexttsn == ntohl((*dc)->sdh_tsn)) { 1030c3c17166SGeorge Shepherd /* 1031c3c17166SGeorge Shepherd * The real beginning fragment of the message was already 1032c3c17166SGeorge Shepherd * delivered upward, so this is the earliest frag expected. 1033c3c17166SGeorge Shepherd * Fake the B-bit then see if this frag also completes the 1034c3c17166SGeorge Shepherd * message. 1035c3c17166SGeorge Shepherd */ 10367d546a59Svi117747 SCTP_DATA_SET_BBIT(*dc); 10376be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_hasBchunk = B_TRUE; 10386be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_msglen = ntohs((*dc)->sdh_len); 1039c3c17166SGeorge Shepherd if (SCTP_DATA_GET_EBIT(*dc)) { 1040c3c17166SGeorge Shepherd /* This frag is marked as the end of message */ 10416be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_needed = 1; 1042c3c17166SGeorge Shepherd /* Got all fragments of this message now */ 1043c3c17166SGeorge Shepherd goto frag_done; 1044c3c17166SGeorge Shepherd } 10456be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_nexttsn++; 10467d546a59Svi117747 } 1047c3c17166SGeorge Shepherd 1048c3c17166SGeorge Shepherd /* The only fragment of this message currently queued */ 1049c3c17166SGeorge Shepherd *tpfinished = B_FALSE; 10507c478bd9Sstevel@tonic-gate return (NULL); 10517c478bd9Sstevel@tonic-gate foundit: 10527c478bd9Sstevel@tonic-gate /* 1053c3c17166SGeorge Shepherd * This message already has a reassembly queue. Insert the new frag 1054c3c17166SGeorge Shepherd * in the reassembly queue. Try the tail first, on the assumption 1055c3c17166SGeorge Shepherd * that the fragments are arriving in order. 10567c478bd9Sstevel@tonic-gate */ 10576be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India qmp = srp->sr_tail; 10587d546a59Svi117747 10597d546a59Svi117747 /* 1060c3c17166SGeorge Shepherd * A NULL tail means all existing fragments of the message have 1061c3c17166SGeorge Shepherd * been entirely consumed during a partially delivery. 10627d546a59Svi117747 */ 10637d546a59Svi117747 if (qmp == NULL) { 10646be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India ASSERT(srp->sr_got == 0 && srp->sr_needed == 0 && 10656be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_partial_delivered); 1066c3c17166SGeorge Shepherd ASSERT(reassq_curr->b_cont == NULL); 1067c3c17166SGeorge Shepherd reassq_curr->b_cont = dmp; 10687d546a59Svi117747 goto empty_srp; 1069c3c17166SGeorge Shepherd } else { 1070c3c17166SGeorge Shepherd /* 1071c3c17166SGeorge Shepherd * If partial delivery did take place but the next arriving 1072c3c17166SGeorge Shepherd * fragment was not the next to be delivered, or partial 1073c3c17166SGeorge Shepherd * delivery broke off due to a gap, fragments remain on the 1074c3c17166SGeorge Shepherd * tail. The next fragment due to be delivered still has to 1075c3c17166SGeorge Shepherd * be set as the new head of list upon arrival. Fake B-bit 1076c3c17166SGeorge Shepherd * on that frag then see if it also completes the message. 1077c3c17166SGeorge Shepherd */ 10786be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (srp->sr_partial_delivered && 10796be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_nexttsn == ntohl((*dc)->sdh_tsn)) { 1080c3c17166SGeorge Shepherd SCTP_DATA_SET_BBIT(*dc); 10816be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_hasBchunk = B_TRUE; 1082c3c17166SGeorge Shepherd if (SCTP_DATA_GET_EBIT(*dc)) { 1083c3c17166SGeorge Shepherd /* Got all fragments of this message now */ 1084c3c17166SGeorge Shepherd goto frag_done; 10857d546a59Svi117747 } 1086c3c17166SGeorge Shepherd } 1087c3c17166SGeorge Shepherd } 1088c3c17166SGeorge Shepherd 1089c3c17166SGeorge Shepherd /* grab the frag header of already queued tail frag for comparison */ 10907c478bd9Sstevel@tonic-gate qdc = (sctp_data_hdr_t *)qmp->b_rptr; 10917c478bd9Sstevel@tonic-gate ASSERT(qmp->b_cont == NULL); 10927c478bd9Sstevel@tonic-gate 1093c3c17166SGeorge Shepherd /* check if the frag goes on the tail in order */ 10947c478bd9Sstevel@tonic-gate if (SEQ_GT(ntohl((*dc)->sdh_tsn), ntohl(qdc->sdh_tsn))) { 10957c478bd9Sstevel@tonic-gate qmp->b_cont = dmp; 10966be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_tail = dmp; 10977c478bd9Sstevel@tonic-gate dmp->b_cont = NULL; 10986be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (srp->sr_hasBchunk && srp->sr_nexttsn == 10996be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India ntohl((*dc)->sdh_tsn)) { 11006be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_msglen += ntohs((*dc)->sdh_len); 11016be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_nexttsn++; 11027d546a59Svi117747 } 11037c478bd9Sstevel@tonic-gate goto inserted; 11047c478bd9Sstevel@tonic-gate } 11057c478bd9Sstevel@tonic-gate 1106c3c17166SGeorge Shepherd /* Next check if we should insert this frag at the beginning */ 1107c3c17166SGeorge Shepherd qmp = reassq_curr->b_cont; 11087c478bd9Sstevel@tonic-gate qdc = (sctp_data_hdr_t *)qmp->b_rptr; 11097c478bd9Sstevel@tonic-gate if (SEQ_LT(ntohl((*dc)->sdh_tsn), ntohl(qdc->sdh_tsn))) { 11107c478bd9Sstevel@tonic-gate dmp->b_cont = qmp; 1111c3c17166SGeorge Shepherd reassq_curr->b_cont = dmp; 11127d546a59Svi117747 if (SCTP_DATA_GET_BBIT(*dc)) { 11136be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_hasBchunk = B_TRUE; 11146be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_nexttsn = ntohl((*dc)->sdh_tsn); 11157c478bd9Sstevel@tonic-gate } 11167d546a59Svi117747 goto preinserted; 11177c478bd9Sstevel@tonic-gate } 11187c478bd9Sstevel@tonic-gate 1119c3c17166SGeorge Shepherd /* Insert this frag in it's correct order in the middle */ 11207c478bd9Sstevel@tonic-gate for (;;) { 11217c478bd9Sstevel@tonic-gate /* Tail check above should have caught this */ 11227c478bd9Sstevel@tonic-gate ASSERT(qmp->b_cont != NULL); 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate qdc = (sctp_data_hdr_t *)qmp->b_cont->b_rptr; 11257c478bd9Sstevel@tonic-gate if (SEQ_LT(ntohl((*dc)->sdh_tsn), ntohl(qdc->sdh_tsn))) { 11267c478bd9Sstevel@tonic-gate /* insert here */ 11277c478bd9Sstevel@tonic-gate dmp->b_cont = qmp->b_cont; 11287c478bd9Sstevel@tonic-gate qmp->b_cont = dmp; 11297c478bd9Sstevel@tonic-gate break; 11307c478bd9Sstevel@tonic-gate } 11317c478bd9Sstevel@tonic-gate qmp = qmp->b_cont; 11327c478bd9Sstevel@tonic-gate } 11337d546a59Svi117747 preinserted: 1134c3c17166SGeorge Shepherd /* 1135c3c17166SGeorge Shepherd * Need head of message and to be due to deliver, otherwise skip 1136c3c17166SGeorge Shepherd * the recalculation of the message length below. 1137c3c17166SGeorge Shepherd */ 11386be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (!srp->sr_hasBchunk || ntohl((*dc)->sdh_tsn) != srp->sr_nexttsn) 11397d546a59Svi117747 goto inserted; 11407d546a59Svi117747 /* 11417d546a59Svi117747 * fraglen contains the length of consecutive chunks of fragments. 1142c3c17166SGeorge Shepherd * starting from the chunk we just inserted. 11437d546a59Svi117747 */ 11446be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India tsn = srp->sr_nexttsn; 11457d546a59Svi117747 for (qmp = dmp; qmp != NULL; qmp = qmp->b_cont) { 11467d546a59Svi117747 qdc = (sctp_data_hdr_t *)qmp->b_rptr; 11477d546a59Svi117747 if (tsn != ntohl(qdc->sdh_tsn)) 11487d546a59Svi117747 break; 11497d546a59Svi117747 fraglen += ntohs(qdc->sdh_len); 11507d546a59Svi117747 tsn++; 11517d546a59Svi117747 } 11526be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_nexttsn = tsn; 11536be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_msglen += fraglen; 11547c478bd9Sstevel@tonic-gate inserted: 11556be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_got++; 1156c3c17166SGeorge Shepherd first_mp = reassq_curr->b_cont; 1157c3c17166SGeorge Shepherd /* Prior to this frag either the beginning or end frag was missing */ 11586be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (srp->sr_needed == 0) { 1159c3c17166SGeorge Shepherd /* used to check if we have the first and last fragments */ 11607c478bd9Sstevel@tonic-gate bdc = (sctp_data_hdr_t *)first_mp->b_rptr; 11616be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India edc = (sctp_data_hdr_t *)srp->sr_tail->b_rptr; 11627c478bd9Sstevel@tonic-gate 1163c3c17166SGeorge Shepherd /* 1164c3c17166SGeorge Shepherd * If we now have both the beginning and the end of the message, 1165c3c17166SGeorge Shepherd * calculate how many fragments in the complete message. 1166c3c17166SGeorge Shepherd */ 11677d546a59Svi117747 if (SCTP_DATA_GET_BBIT(bdc) && SCTP_DATA_GET_EBIT(edc)) { 11686be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_needed = ntohl(edc->sdh_tsn) - 11697c478bd9Sstevel@tonic-gate ntohl(bdc->sdh_tsn) + 1; 11707c478bd9Sstevel@tonic-gate } 11717d546a59Svi117747 } 11727c478bd9Sstevel@tonic-gate 11737d546a59Svi117747 /* 11747d546a59Svi117747 * Try partial delivery if the message length has exceeded the 11757d546a59Svi117747 * partial delivery point. Only do this if we can immediately 11767d546a59Svi117747 * deliver the partially assembled message, and only partially 11777d546a59Svi117747 * deliver one message at a time (i.e. messages cannot be 1178c3c17166SGeorge Shepherd * intermixed arriving at the upper layer). 1179c3c17166SGeorge Shepherd * sctp_try_partial_delivery() will return a message consisting 1180c3c17166SGeorge Shepherd * of only consecutive fragments. 11817d546a59Svi117747 */ 11826be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (srp->sr_needed != srp->sr_got) { 1183c3c17166SGeorge Shepherd /* we don't have the full message yet */ 11847d546a59Svi117747 dmp = NULL; 1185c3c17166SGeorge Shepherd if (ntohl((*dc)->sdh_tsn) <= sctp->sctp_ftsn && 11866be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_msglen >= sctp->sctp_pd_point && 11876be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_ssn == sip->nextseq) { 1188c3c17166SGeorge Shepherd dmp = sctp_try_partial_delivery(sctp, reassq_curr, 1189c3c17166SGeorge Shepherd srp, dc); 11907c478bd9Sstevel@tonic-gate } 1191c3c17166SGeorge Shepherd *tpfinished = B_FALSE; 1192c3c17166SGeorge Shepherd /* 1193c3c17166SGeorge Shepherd * NULL unless a segment of the message now qualified for 1194c3c17166SGeorge Shepherd * partial_delivery and has been prepared for delivery by 1195c3c17166SGeorge Shepherd * sctp_try_partial_delivery(). 1196c3c17166SGeorge Shepherd */ 11977d546a59Svi117747 return (dmp); 11987c478bd9Sstevel@tonic-gate } 11997d546a59Svi117747 frag_done: 12007c478bd9Sstevel@tonic-gate /* 1201c3c17166SGeorge Shepherd * Reassembly complete for this message, prepare the data for delivery. 1202c3c17166SGeorge Shepherd * First unlink the reassembly queue for this ssn from the list of 1203c3c17166SGeorge Shepherd * messages in reassembly. 12047c478bd9Sstevel@tonic-gate */ 1205c3c17166SGeorge Shepherd if (sip->istr_reass == reassq_curr) { 1206c3c17166SGeorge Shepherd sip->istr_reass = reassq_curr->b_next; 1207c3c17166SGeorge Shepherd if (reassq_curr->b_next) 1208c3c17166SGeorge Shepherd reassq_curr->b_next->b_prev = NULL; 12097c478bd9Sstevel@tonic-gate } else { 1210c3c17166SGeorge Shepherd ASSERT(reassq_curr->b_prev != NULL); 1211c3c17166SGeorge Shepherd reassq_curr->b_prev->b_next = reassq_curr->b_next; 1212c3c17166SGeorge Shepherd if (reassq_curr->b_next) 1213c3c17166SGeorge Shepherd reassq_curr->b_next->b_prev = reassq_curr->b_prev; 12147c478bd9Sstevel@tonic-gate } 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate /* 1217c3c17166SGeorge Shepherd * Need to clean up b_prev and b_next as freeb() will 1218c3c17166SGeorge Shepherd * ASSERT that they are unused. 12197c478bd9Sstevel@tonic-gate */ 1220c3c17166SGeorge Shepherd reassq_curr->b_next = NULL; 1221c3c17166SGeorge Shepherd reassq_curr->b_prev = NULL; 1222c3c17166SGeorge Shepherd 1223c3c17166SGeorge Shepherd dmp = reassq_curr; 1224c3c17166SGeorge Shepherd /* point to the head of the reassembled data message */ 12257c478bd9Sstevel@tonic-gate dmp = dmp->b_cont; 1226c3c17166SGeorge Shepherd reassq_curr->b_cont = NULL; 1227c3c17166SGeorge Shepherd freeb(reassq_curr); 1228c3c17166SGeorge Shepherd /* Tell our caller that we are returning a complete message. */ 12297d546a59Svi117747 *tpfinished = B_TRUE; 12307c478bd9Sstevel@tonic-gate 12317c478bd9Sstevel@tonic-gate /* 12327c478bd9Sstevel@tonic-gate * Adjust all mblk's except the lead so their rptr's point to the 1233c3c17166SGeorge Shepherd * payload. sctp_data_chunk() will need to process the lead's data 1234c3c17166SGeorge Shepherd * data chunk section, so leave its rptr pointing at the data chunk 1235c3c17166SGeorge Shepherd * header. 12367c478bd9Sstevel@tonic-gate */ 12377c478bd9Sstevel@tonic-gate *dc = (sctp_data_hdr_t *)dmp->b_rptr; 12387d546a59Svi117747 for (qmp = dmp->b_cont; qmp != NULL; qmp = qmp->b_cont) { 12397c478bd9Sstevel@tonic-gate qdc = (sctp_data_hdr_t *)qmp->b_rptr; 12407c478bd9Sstevel@tonic-gate qmp->b_rptr = (uchar_t *)(qdc + 1); 12417c478bd9Sstevel@tonic-gate } 12427c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_reassmsgs); 12437c478bd9Sstevel@tonic-gate 12447c478bd9Sstevel@tonic-gate return (dmp); 12457c478bd9Sstevel@tonic-gate } 1246c3c17166SGeorge Shepherd 12477c478bd9Sstevel@tonic-gate static void 12487c478bd9Sstevel@tonic-gate sctp_add_dup(uint32_t tsn, mblk_t **dups) 12497c478bd9Sstevel@tonic-gate { 12507c478bd9Sstevel@tonic-gate mblk_t *mp; 12517c478bd9Sstevel@tonic-gate size_t bsize = SCTP_DUP_MBLK_SZ * sizeof (tsn); 12527c478bd9Sstevel@tonic-gate 12537c478bd9Sstevel@tonic-gate if (dups == NULL) { 12547c478bd9Sstevel@tonic-gate return; 12557c478bd9Sstevel@tonic-gate } 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate /* first time? */ 12587c478bd9Sstevel@tonic-gate if (*dups == NULL) { 12597c478bd9Sstevel@tonic-gate *dups = allocb(bsize, BPRI_MED); 12607c478bd9Sstevel@tonic-gate if (*dups == NULL) { 12617c478bd9Sstevel@tonic-gate return; 12627c478bd9Sstevel@tonic-gate } 12637c478bd9Sstevel@tonic-gate } 12647c478bd9Sstevel@tonic-gate 12657c478bd9Sstevel@tonic-gate mp = *dups; 12667c478bd9Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) >= bsize) { 12677c478bd9Sstevel@tonic-gate /* maximum reached */ 12687c478bd9Sstevel@tonic-gate return; 12697c478bd9Sstevel@tonic-gate } 12707c478bd9Sstevel@tonic-gate 12717c478bd9Sstevel@tonic-gate /* add the duplicate tsn */ 12727c478bd9Sstevel@tonic-gate bcopy(&tsn, mp->b_wptr, sizeof (tsn)); 12737c478bd9Sstevel@tonic-gate mp->b_wptr += sizeof (tsn); 12747c478bd9Sstevel@tonic-gate ASSERT((mp->b_wptr - mp->b_rptr) <= bsize); 12757c478bd9Sstevel@tonic-gate } 12767c478bd9Sstevel@tonic-gate 1277c3c17166SGeorge Shepherd /* 1278c3c17166SGeorge Shepherd * All incoming sctp data, complete messages and fragments are handled by 1279c3c17166SGeorge Shepherd * this function. Unless the U-bit is set in the data chunk it will be 1280c3c17166SGeorge Shepherd * delivered in order or queued until an in-order delivery can be made. 1281c3c17166SGeorge Shepherd */ 12827c478bd9Sstevel@tonic-gate static void 12837c478bd9Sstevel@tonic-gate sctp_data_chunk(sctp_t *sctp, sctp_chunk_hdr_t *ch, mblk_t *mp, mblk_t **dups, 1284bd670b35SErik Nordmark sctp_faddr_t *fp, ip_pkt_t *ipp, ip_recv_attr_t *ira) 12857c478bd9Sstevel@tonic-gate { 12867c478bd9Sstevel@tonic-gate sctp_data_hdr_t *dc; 12877c478bd9Sstevel@tonic-gate mblk_t *dmp, *pmp; 12887c478bd9Sstevel@tonic-gate sctp_instr_t *instr; 12897c478bd9Sstevel@tonic-gate int ubit; 1290c3c17166SGeorge Shepherd int sid; 12917c478bd9Sstevel@tonic-gate int isfrag; 12927c478bd9Sstevel@tonic-gate uint16_t ssn; 12937c478bd9Sstevel@tonic-gate uint32_t oftsn; 12947c478bd9Sstevel@tonic-gate boolean_t can_deliver = B_TRUE; 12957c478bd9Sstevel@tonic-gate uint32_t tsn; 12967c478bd9Sstevel@tonic-gate int dlen; 12977d546a59Svi117747 boolean_t tpfinished = B_TRUE; 1298f4b3ec61Sdh155122 sctp_stack_t *sctps = sctp->sctp_sctps; 12990f1702c5SYu Xiangning int error; 13007c478bd9Sstevel@tonic-gate 13017c478bd9Sstevel@tonic-gate /* The following are used multiple times, so we inline them */ 13027c478bd9Sstevel@tonic-gate #define SCTP_ACK_IT(sctp, tsn) \ 13037c478bd9Sstevel@tonic-gate if (tsn == sctp->sctp_ftsn) { \ 13047c478bd9Sstevel@tonic-gate dprint(2, ("data_chunk: acking next %x\n", tsn)); \ 1305769b977dSvi117747 (sctp)->sctp_ftsn++; \ 1306769b977dSvi117747 if ((sctp)->sctp_sack_gaps > 0) \ 1307769b977dSvi117747 (sctp)->sctp_force_sack = 1; \ 13087c478bd9Sstevel@tonic-gate } else if (SEQ_GT(tsn, sctp->sctp_ftsn)) { \ 13097c478bd9Sstevel@tonic-gate /* Got a gap; record it */ \ 13109f13099eSGeorge Shepherd BUMP_LOCAL(sctp->sctp_outseqtsns); \ 13117c478bd9Sstevel@tonic-gate dprint(2, ("data_chunk: acking gap %x\n", tsn)); \ 1312769b977dSvi117747 sctp_ack_add(&sctp->sctp_sack_info, tsn, \ 13137c478bd9Sstevel@tonic-gate &sctp->sctp_sack_gaps); \ 13147c478bd9Sstevel@tonic-gate sctp->sctp_force_sack = 1; \ 13157c478bd9Sstevel@tonic-gate } 13167c478bd9Sstevel@tonic-gate 13177c478bd9Sstevel@tonic-gate dmp = NULL; 13187c478bd9Sstevel@tonic-gate 13197c478bd9Sstevel@tonic-gate dc = (sctp_data_hdr_t *)ch; 13207c478bd9Sstevel@tonic-gate tsn = ntohl(dc->sdh_tsn); 13217c478bd9Sstevel@tonic-gate 132245916cd2Sjpk dprint(3, ("sctp_data_chunk: mp=%p tsn=%x\n", (void *)mp, tsn)); 13237c478bd9Sstevel@tonic-gate 13247c478bd9Sstevel@tonic-gate /* Check for duplicates */ 13257c478bd9Sstevel@tonic-gate if (SEQ_LT(tsn, sctp->sctp_ftsn)) { 13267c478bd9Sstevel@tonic-gate dprint(4, ("sctp_data_chunk: dropping duplicate\n")); 13279f13099eSGeorge Shepherd BUMP_LOCAL(sctp->sctp_idupchunks); 13287c478bd9Sstevel@tonic-gate sctp->sctp_force_sack = 1; 13297c478bd9Sstevel@tonic-gate sctp_add_dup(dc->sdh_tsn, dups); 13307c478bd9Sstevel@tonic-gate return; 13317c478bd9Sstevel@tonic-gate } 13327c478bd9Sstevel@tonic-gate 1333c3c17166SGeorge Shepherd /* Check for dups of sack'ed data */ 13347c478bd9Sstevel@tonic-gate if (sctp->sctp_sack_info != NULL) { 13357c478bd9Sstevel@tonic-gate sctp_set_t *sp; 13367c478bd9Sstevel@tonic-gate 13377c478bd9Sstevel@tonic-gate for (sp = sctp->sctp_sack_info; sp; sp = sp->next) { 13387c478bd9Sstevel@tonic-gate if (SEQ_GEQ(tsn, sp->begin) && SEQ_LEQ(tsn, sp->end)) { 13397c478bd9Sstevel@tonic-gate dprint(4, 13407f093707Skcpoon ("sctp_data_chunk: dropping dup > " 13417f093707Skcpoon "cumtsn\n")); 13429f13099eSGeorge Shepherd BUMP_LOCAL(sctp->sctp_idupchunks); 13437c478bd9Sstevel@tonic-gate sctp->sctp_force_sack = 1; 13447c478bd9Sstevel@tonic-gate sctp_add_dup(dc->sdh_tsn, dups); 13457c478bd9Sstevel@tonic-gate return; 13467c478bd9Sstevel@tonic-gate } 13477c478bd9Sstevel@tonic-gate } 13487c478bd9Sstevel@tonic-gate } 13497c478bd9Sstevel@tonic-gate 1350c3c17166SGeorge Shepherd /* We can no longer deliver anything up, but still need to handle it. */ 13517c478bd9Sstevel@tonic-gate if (SCTP_IS_DETACHED(sctp)) { 13525dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpInClosed); 13537c478bd9Sstevel@tonic-gate can_deliver = B_FALSE; 13547c478bd9Sstevel@tonic-gate } 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate dlen = ntohs(dc->sdh_len) - sizeof (*dc); 13577c478bd9Sstevel@tonic-gate 1358f0c3911fSGeorge Shepherd /* 1359f0c3911fSGeorge Shepherd * Check for buffer space. Note if this is the next expected TSN 1360f0c3911fSGeorge Shepherd * we have to take it to avoid deadlock because we cannot deliver 1361f0c3911fSGeorge Shepherd * later queued TSNs and thus clear buffer space without it. 1362f0c3911fSGeorge Shepherd * We drop anything that is purely zero window probe data here. 1363f0c3911fSGeorge Shepherd */ 1364f0c3911fSGeorge Shepherd if ((sctp->sctp_rwnd - sctp->sctp_rxqueued < dlen) && 1365f0c3911fSGeorge Shepherd (tsn != sctp->sctp_ftsn || sctp->sctp_rwnd == 0)) { 13667c478bd9Sstevel@tonic-gate /* Drop and SACK, but don't advance the cumulative TSN. */ 13677c478bd9Sstevel@tonic-gate sctp->sctp_force_sack = 1; 13687c478bd9Sstevel@tonic-gate dprint(0, ("sctp_data_chunk: exceed rwnd %d rxqueued %d " 136912f47623Skcpoon "dlen %d ssn %d tsn %x\n", sctp->sctp_rwnd, 137012f47623Skcpoon sctp->sctp_rxqueued, dlen, ntohs(dc->sdh_ssn), 137112f47623Skcpoon ntohl(dc->sdh_tsn))); 13727c478bd9Sstevel@tonic-gate return; 13737c478bd9Sstevel@tonic-gate } 13747c478bd9Sstevel@tonic-gate 1375c3c17166SGeorge Shepherd sid = ntohs(dc->sdh_sid); 1376c3c17166SGeorge Shepherd 1377c3c17166SGeorge Shepherd /* Data received for a stream not negotiated for this association */ 1378c3c17166SGeorge Shepherd if (sid >= sctp->sctp_num_istr) { 137947b33325SGeorge Shepherd sctp_bsc_t inval_parm; 13807c478bd9Sstevel@tonic-gate 138147b33325SGeorge Shepherd /* Will populate the CAUSE block in the ERROR chunk. */ 138247b33325SGeorge Shepherd inval_parm.bsc_sid = dc->sdh_sid; 138347b33325SGeorge Shepherd /* RESERVED, ignored at the receiving end */ 138447b33325SGeorge Shepherd inval_parm.bsc_pad = 0; 138547b33325SGeorge Shepherd 13867c478bd9Sstevel@tonic-gate /* ack and drop it */ 138747b33325SGeorge Shepherd sctp_add_err(sctp, SCTP_ERR_BAD_SID, (void *)&inval_parm, 138847b33325SGeorge Shepherd sizeof (sctp_bsc_t), fp); 13897c478bd9Sstevel@tonic-gate SCTP_ACK_IT(sctp, tsn); 13907c478bd9Sstevel@tonic-gate return; 13917c478bd9Sstevel@tonic-gate } 13927c478bd9Sstevel@tonic-gate 1393c3c17166SGeorge Shepherd /* unordered delivery OK for this data if ubit set */ 13947c478bd9Sstevel@tonic-gate ubit = SCTP_DATA_GET_UBIT(dc); 13957c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_instr != NULL); 1396c3c17166SGeorge Shepherd 1397c3c17166SGeorge Shepherd /* select per stream structure for this stream from the array */ 1398c3c17166SGeorge Shepherd instr = &sctp->sctp_instr[sid]; 13997c478bd9Sstevel@tonic-gate /* Initialize the stream, if not yet used */ 14007c478bd9Sstevel@tonic-gate if (instr->sctp == NULL) 14017c478bd9Sstevel@tonic-gate instr->sctp = sctp; 14027d546a59Svi117747 1403c3c17166SGeorge Shepherd /* Begin and End bit set would mean a complete message */ 14047c478bd9Sstevel@tonic-gate isfrag = !(SCTP_DATA_GET_BBIT(dc) && SCTP_DATA_GET_EBIT(dc)); 1405c3c17166SGeorge Shepherd 1406c3c17166SGeorge Shepherd /* The ssn of this sctp message and of any fragments in it */ 14077c478bd9Sstevel@tonic-gate ssn = ntohs(dc->sdh_ssn); 14087c478bd9Sstevel@tonic-gate 14097c478bd9Sstevel@tonic-gate dmp = dupb(mp); 14107c478bd9Sstevel@tonic-gate if (dmp == NULL) { 1411c3c17166SGeorge Shepherd /* drop it and don't ack, let the peer retransmit */ 14127c478bd9Sstevel@tonic-gate return; 14137c478bd9Sstevel@tonic-gate } 1414c3c17166SGeorge Shepherd /* 1415c3c17166SGeorge Shepherd * Past header and payload, note: the underlying buffer may 1416c3c17166SGeorge Shepherd * contain further chunks from the same incoming IP packet, 1417c3c17166SGeorge Shepherd * if so db_ref will be greater than one. 1418c3c17166SGeorge Shepherd */ 14197c478bd9Sstevel@tonic-gate dmp->b_wptr = (uchar_t *)ch + ntohs(ch->sch_len); 14207c478bd9Sstevel@tonic-gate 14217c478bd9Sstevel@tonic-gate sctp->sctp_rxqueued += dlen; 14227c478bd9Sstevel@tonic-gate 14237c478bd9Sstevel@tonic-gate oftsn = sctp->sctp_ftsn; 14247c478bd9Sstevel@tonic-gate 14257c478bd9Sstevel@tonic-gate if (isfrag) { 14267c478bd9Sstevel@tonic-gate 14270f1702c5SYu Xiangning error = 0; 14287c478bd9Sstevel@tonic-gate /* fragmented data chunk */ 14297c478bd9Sstevel@tonic-gate dmp->b_rptr = (uchar_t *)dc; 14307c478bd9Sstevel@tonic-gate if (ubit) { 1431c3c17166SGeorge Shepherd /* prepare data for unordered delivery */ 14327c478bd9Sstevel@tonic-gate dmp = sctp_uodata_frag(sctp, dmp, &dc); 14337c478bd9Sstevel@tonic-gate #if DEBUG 14347c478bd9Sstevel@tonic-gate if (dmp != NULL) { 14357c478bd9Sstevel@tonic-gate ASSERT(instr == 1436c3c17166SGeorge Shepherd &sctp->sctp_instr[sid]); 14377c478bd9Sstevel@tonic-gate } 14387c478bd9Sstevel@tonic-gate #endif 14397c478bd9Sstevel@tonic-gate } else { 1440c3c17166SGeorge Shepherd /* 1441c3c17166SGeorge Shepherd * Assemble fragments and queue for ordered delivery, 1442c3c17166SGeorge Shepherd * dmp returned is NULL or the head of a complete or 1443c3c17166SGeorge Shepherd * "partial delivery" message. Any returned message 1444c3c17166SGeorge Shepherd * and all its fragments will have the same ssn as the 1445c3c17166SGeorge Shepherd * input fragment currently being handled. 1446c3c17166SGeorge Shepherd */ 14477c478bd9Sstevel@tonic-gate dmp = sctp_data_frag(sctp, dmp, &dc, &error, instr, 14487d546a59Svi117747 &tpfinished); 14497c478bd9Sstevel@tonic-gate } 1450c3c17166SGeorge Shepherd if (error == ENOMEM) { 1451c3c17166SGeorge Shepherd /* back out the adjustment made earlier */ 14527c478bd9Sstevel@tonic-gate sctp->sctp_rxqueued -= dlen; 14537c478bd9Sstevel@tonic-gate /* 1454c3c17166SGeorge Shepherd * Don't ack the segment, 1455c3c17166SGeorge Shepherd * the peer will retransmit. 14567c478bd9Sstevel@tonic-gate */ 14577c478bd9Sstevel@tonic-gate return; 14587c478bd9Sstevel@tonic-gate } 14597c478bd9Sstevel@tonic-gate 14607c478bd9Sstevel@tonic-gate if (dmp == NULL) { 14617c478bd9Sstevel@tonic-gate /* 1462c3c17166SGeorge Shepherd * The frag has been queued for later in-order delivery, 1463c3c17166SGeorge Shepherd * but the cumulative TSN may need to advance, so also 1464c3c17166SGeorge Shepherd * need to perform the gap ack checks at the done label. 14657c478bd9Sstevel@tonic-gate */ 14667c478bd9Sstevel@tonic-gate SCTP_ACK_IT(sctp, tsn); 1467c3c17166SGeorge Shepherd DTRACE_PROBE4(sctp_data_frag_queued, sctp_t *, sctp, 1468c3c17166SGeorge Shepherd int, sid, int, tsn, uint16_t, ssn); 14697c478bd9Sstevel@tonic-gate goto done; 14707c478bd9Sstevel@tonic-gate } 14717c478bd9Sstevel@tonic-gate } 14727c478bd9Sstevel@tonic-gate 14738042ac43Sgeorges /* 1474c3c17166SGeorge Shepherd * Unless message is the next for delivery to the ulp, queue complete 1475c3c17166SGeorge Shepherd * message in the correct order for ordered delivery. 1476c3c17166SGeorge Shepherd * Note: tpfinished is true when the incoming chunk contains a complete 14778042ac43Sgeorges * message or is the final missing fragment which completed a message. 14788042ac43Sgeorges */ 14798042ac43Sgeorges if (!ubit && tpfinished && ssn != instr->nextseq) { 14807c478bd9Sstevel@tonic-gate /* Adjust rptr to point at the data chunk for compares */ 14817c478bd9Sstevel@tonic-gate dmp->b_rptr = (uchar_t *)dc; 14827c478bd9Sstevel@tonic-gate 14837c478bd9Sstevel@tonic-gate dprint(2, 14847c478bd9Sstevel@tonic-gate ("data_chunk: inserted %x in pq (ssn %d expected %d)\n", 14857c478bd9Sstevel@tonic-gate ntohl(dc->sdh_tsn), (int)(ssn), (int)(instr->nextseq))); 14867c478bd9Sstevel@tonic-gate 14877c478bd9Sstevel@tonic-gate if (instr->istr_msgs == NULL) { 14887c478bd9Sstevel@tonic-gate instr->istr_msgs = dmp; 14897c478bd9Sstevel@tonic-gate ASSERT(dmp->b_prev == NULL && dmp->b_next == NULL); 14907c478bd9Sstevel@tonic-gate } else { 14917c478bd9Sstevel@tonic-gate mblk_t *imblk = instr->istr_msgs; 14927c478bd9Sstevel@tonic-gate sctp_data_hdr_t *idc; 14937c478bd9Sstevel@tonic-gate 14947c478bd9Sstevel@tonic-gate /* 14957c478bd9Sstevel@tonic-gate * XXXNeed to take sequence wraps into account, 14967c478bd9Sstevel@tonic-gate * ... and a more efficient insertion algo. 14977c478bd9Sstevel@tonic-gate */ 14987c478bd9Sstevel@tonic-gate for (;;) { 14997c478bd9Sstevel@tonic-gate idc = (sctp_data_hdr_t *)imblk->b_rptr; 15007c478bd9Sstevel@tonic-gate if (SSN_GT(ntohs(idc->sdh_ssn), 15017c478bd9Sstevel@tonic-gate ntohs(dc->sdh_ssn))) { 15027c478bd9Sstevel@tonic-gate if (instr->istr_msgs == imblk) { 15037c478bd9Sstevel@tonic-gate instr->istr_msgs = dmp; 15047c478bd9Sstevel@tonic-gate dmp->b_next = imblk; 15057c478bd9Sstevel@tonic-gate imblk->b_prev = dmp; 15067c478bd9Sstevel@tonic-gate } else { 15077c478bd9Sstevel@tonic-gate ASSERT(imblk->b_prev != NULL); 15087c478bd9Sstevel@tonic-gate imblk->b_prev->b_next = dmp; 15097c478bd9Sstevel@tonic-gate dmp->b_prev = imblk->b_prev; 15107c478bd9Sstevel@tonic-gate imblk->b_prev = dmp; 15117c478bd9Sstevel@tonic-gate dmp->b_next = imblk; 15127c478bd9Sstevel@tonic-gate } 15137c478bd9Sstevel@tonic-gate break; 15147c478bd9Sstevel@tonic-gate } 15157c478bd9Sstevel@tonic-gate if (imblk->b_next == NULL) { 15167c478bd9Sstevel@tonic-gate imblk->b_next = dmp; 15177c478bd9Sstevel@tonic-gate dmp->b_prev = imblk; 15187c478bd9Sstevel@tonic-gate break; 15197c478bd9Sstevel@tonic-gate } 15207c478bd9Sstevel@tonic-gate imblk = imblk->b_next; 15217c478bd9Sstevel@tonic-gate } 15227c478bd9Sstevel@tonic-gate } 15237c478bd9Sstevel@tonic-gate (instr->istr_nmsgs)++; 15247c478bd9Sstevel@tonic-gate (sctp->sctp_istr_nmsgs)++; 15257c478bd9Sstevel@tonic-gate SCTP_ACK_IT(sctp, tsn); 1526c3c17166SGeorge Shepherd DTRACE_PROBE4(sctp_pqueue_completemsg, sctp_t *, sctp, 1527c3c17166SGeorge Shepherd int, sid, int, tsn, uint16_t, ssn); 15287c478bd9Sstevel@tonic-gate return; 15297c478bd9Sstevel@tonic-gate } 15307c478bd9Sstevel@tonic-gate 15317c478bd9Sstevel@tonic-gate /* 1532c3c17166SGeorge Shepherd * Deliver the data directly. Recalculate dlen now since 1533c3c17166SGeorge Shepherd * we may have just reassembled this data. 15347c478bd9Sstevel@tonic-gate */ 15357c478bd9Sstevel@tonic-gate dlen = dmp->b_wptr - (uchar_t *)dc - sizeof (*dc); 15367c478bd9Sstevel@tonic-gate for (pmp = dmp->b_cont; pmp != NULL; pmp = pmp->b_cont) 1537f0c3911fSGeorge Shepherd dlen += MBLKL(pmp); 15387c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_rxqueued >= dlen); 15397c478bd9Sstevel@tonic-gate 15407c478bd9Sstevel@tonic-gate /* Deliver the message. */ 15417c478bd9Sstevel@tonic-gate sctp->sctp_rxqueued -= dlen; 15427c478bd9Sstevel@tonic-gate 15437c478bd9Sstevel@tonic-gate if (can_deliver) { 1544c3c17166SGeorge Shepherd /* step past header to the payload */ 15457c478bd9Sstevel@tonic-gate dmp->b_rptr = (uchar_t *)(dc + 1); 1546bd670b35SErik Nordmark if (sctp_input_add_ancillary(sctp, &dmp, dc, fp, 1547bd670b35SErik Nordmark ipp, ira) == 0) { 15487c478bd9Sstevel@tonic-gate dprint(1, ("sctp_data_chunk: delivering %lu bytes\n", 15497c478bd9Sstevel@tonic-gate msgdsize(dmp))); 15500f1702c5SYu Xiangning /* 1551c3c17166SGeorge Shepherd * We overload the meaning of b_flag for SCTP sockfs 1552c3c17166SGeorge Shepherd * internal use, to advise sockfs of partial delivery 1553c3c17166SGeorge Shepherd * semantics. 15540f1702c5SYu Xiangning */ 15550f1702c5SYu Xiangning dmp->b_flag = tpfinished ? 0 : SCTP_PARTIAL_DATA; 1556*a215d4ebSKacheong Poon if (sctp->sctp_flowctrld) { 1557*a215d4ebSKacheong Poon sctp->sctp_rwnd -= dlen; 1558*a215d4ebSKacheong Poon if (sctp->sctp_rwnd < 0) 1559f0c3911fSGeorge Shepherd sctp->sctp_rwnd = 0; 1560*a215d4ebSKacheong Poon } 1561*a215d4ebSKacheong Poon if (sctp->sctp_ulp_recv(sctp->sctp_ulpd, dmp, 1562*a215d4ebSKacheong Poon msgdsize(dmp), 0, &error, NULL) <= 0) { 1563*a215d4ebSKacheong Poon sctp->sctp_flowctrld = B_TRUE; 1564*a215d4ebSKacheong Poon } 15657c478bd9Sstevel@tonic-gate SCTP_ACK_IT(sctp, tsn); 15667c478bd9Sstevel@tonic-gate } else { 1567c3c17166SGeorge Shepherd /* No memory don't ack, the peer will retransmit. */ 15687c478bd9Sstevel@tonic-gate freemsg(dmp); 15697c478bd9Sstevel@tonic-gate return; 15707c478bd9Sstevel@tonic-gate } 15717c478bd9Sstevel@tonic-gate } else { 1572c3c17166SGeorge Shepherd /* Closed above, ack to peer and free the data */ 15737c478bd9Sstevel@tonic-gate freemsg(dmp); 15747c478bd9Sstevel@tonic-gate SCTP_ACK_IT(sctp, tsn); 15757c478bd9Sstevel@tonic-gate } 15767c478bd9Sstevel@tonic-gate 15777c478bd9Sstevel@tonic-gate /* 1578c3c17166SGeorge Shepherd * Data now enqueued, may already have been processed and free'd 15797c478bd9Sstevel@tonic-gate * by the ULP (or we may have just freed it above, if we could not 1580c3c17166SGeorge Shepherd * deliver), so we must not reference it (this is why we saved the 1581c3c17166SGeorge Shepherd * ssn and ubit earlier). 15827c478bd9Sstevel@tonic-gate */ 15837c478bd9Sstevel@tonic-gate if (ubit != 0) { 15847c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_iudchunks); 15857c478bd9Sstevel@tonic-gate goto done; 15867c478bd9Sstevel@tonic-gate } 15877c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_idchunks); 15887c478bd9Sstevel@tonic-gate 15897c478bd9Sstevel@tonic-gate /* 1590c3c17166SGeorge Shepherd * There was a partial delivery and it has not finished, 1591c3c17166SGeorge Shepherd * don't pull anything from the pqueues or increment the 1592c3c17166SGeorge Shepherd * nextseq. This msg must complete before starting on 1593c3c17166SGeorge Shepherd * the next ssn and the partial message must have the 1594c3c17166SGeorge Shepherd * same ssn as the next expected message.. 15957c478bd9Sstevel@tonic-gate */ 15967c478bd9Sstevel@tonic-gate if (!tpfinished) { 1597c3c17166SGeorge Shepherd DTRACE_PROBE4(sctp_partial_delivery, sctp_t *, sctp, 1598c3c17166SGeorge Shepherd int, sid, int, tsn, uint16_t, ssn); 1599c3c17166SGeorge Shepherd /* 1600c3c17166SGeorge Shepherd * Verify the partial delivery is part of the 1601c3c17166SGeorge Shepherd * message expected for ordered delivery. 1602c3c17166SGeorge Shepherd */ 1603c3c17166SGeorge Shepherd if (ssn != instr->nextseq) { 1604c3c17166SGeorge Shepherd DTRACE_PROBE4(sctp_partial_delivery_error, 1605c3c17166SGeorge Shepherd sctp_t *, sctp, int, sid, int, tsn, 1606c3c17166SGeorge Shepherd uint16_t, ssn); 1607c3c17166SGeorge Shepherd cmn_err(CE_WARN, "sctp partial" 1608c3c17166SGeorge Shepherd " delivery error, sctp 0x%p" 1609c3c17166SGeorge Shepherd " sid = 0x%x ssn != nextseq" 1610c3c17166SGeorge Shepherd " tsn 0x%x ftsn 0x%x" 1611c3c17166SGeorge Shepherd " ssn 0x%x nextseq 0x%x", 1612c3c17166SGeorge Shepherd (void *)sctp, sid, 1613c3c17166SGeorge Shepherd tsn, sctp->sctp_ftsn, ssn, 1614c3c17166SGeorge Shepherd instr->nextseq); 1615c3c17166SGeorge Shepherd } 1616c3c17166SGeorge Shepherd 1617c3c17166SGeorge Shepherd ASSERT(ssn == instr->nextseq); 16187c478bd9Sstevel@tonic-gate goto done; 16197c478bd9Sstevel@tonic-gate } 16207c478bd9Sstevel@tonic-gate 1621c3c17166SGeorge Shepherd if (ssn != instr->nextseq) { 1622c3c17166SGeorge Shepherd DTRACE_PROBE4(sctp_inorder_delivery_error, 1623c3c17166SGeorge Shepherd sctp_t *, sctp, int, sid, int, tsn, 1624c3c17166SGeorge Shepherd uint16_t, ssn); 1625c3c17166SGeorge Shepherd cmn_err(CE_WARN, "sctp in-order delivery error, sctp 0x%p " 1626c3c17166SGeorge Shepherd "sid = 0x%x ssn != nextseq ssn 0x%x nextseq 0x%x", 1627c3c17166SGeorge Shepherd (void *)sctp, sid, ssn, instr->nextseq); 1628c3c17166SGeorge Shepherd } 1629c3c17166SGeorge Shepherd 1630c3c17166SGeorge Shepherd ASSERT(ssn == instr->nextseq); 1631c3c17166SGeorge Shepherd 1632c3c17166SGeorge Shepherd DTRACE_PROBE4(sctp_deliver_completemsg, sctp_t *, sctp, int, sid, 1633c3c17166SGeorge Shepherd int, tsn, uint16_t, ssn); 1634c3c17166SGeorge Shepherd 16357c478bd9Sstevel@tonic-gate instr->nextseq = ssn + 1; 1636c3c17166SGeorge Shepherd 1637c3c17166SGeorge Shepherd /* 1638c3c17166SGeorge Shepherd * Deliver any successive data chunks waiting in the instr pqueue 1639c3c17166SGeorge Shepherd * for the data just sent up. 1640c3c17166SGeorge Shepherd */ 16417c478bd9Sstevel@tonic-gate while (instr->istr_nmsgs > 0) { 16427c478bd9Sstevel@tonic-gate dmp = (mblk_t *)instr->istr_msgs; 16437c478bd9Sstevel@tonic-gate dc = (sctp_data_hdr_t *)dmp->b_rptr; 16447c478bd9Sstevel@tonic-gate ssn = ntohs(dc->sdh_ssn); 1645c3c17166SGeorge Shepherd tsn = ntohl(dc->sdh_tsn); 1646c3c17166SGeorge Shepherd /* Stop at the first gap in the sequence */ 16477c478bd9Sstevel@tonic-gate if (ssn != instr->nextseq) 16487c478bd9Sstevel@tonic-gate break; 16497c478bd9Sstevel@tonic-gate 1650c3c17166SGeorge Shepherd DTRACE_PROBE4(sctp_deliver_pqueuedmsg, sctp_t *, sctp, 1651c3c17166SGeorge Shepherd int, sid, int, tsn, uint16_t, ssn); 1652c3c17166SGeorge Shepherd /* 1653c3c17166SGeorge Shepherd * Ready to deliver all data before the gap 1654c3c17166SGeorge Shepherd * to the upper layer. 1655c3c17166SGeorge Shepherd */ 16567c478bd9Sstevel@tonic-gate (instr->istr_nmsgs)--; 16577c478bd9Sstevel@tonic-gate (instr->nextseq)++; 16587c478bd9Sstevel@tonic-gate (sctp->sctp_istr_nmsgs)--; 16597c478bd9Sstevel@tonic-gate 16607c478bd9Sstevel@tonic-gate instr->istr_msgs = instr->istr_msgs->b_next; 16617c478bd9Sstevel@tonic-gate if (instr->istr_msgs != NULL) 16627c478bd9Sstevel@tonic-gate instr->istr_msgs->b_prev = NULL; 16637c478bd9Sstevel@tonic-gate dmp->b_next = dmp->b_prev = NULL; 16647c478bd9Sstevel@tonic-gate 16657c478bd9Sstevel@tonic-gate dprint(2, ("data_chunk: pulling %x from pq (ssn %d)\n", 16667c478bd9Sstevel@tonic-gate ntohl(dc->sdh_tsn), (int)ssn)); 16677c478bd9Sstevel@tonic-gate 16687c478bd9Sstevel@tonic-gate /* 1669c3c17166SGeorge Shepherd * Composite messages indicate this chunk was reassembled, 1670c3c17166SGeorge Shepherd * each b_cont represents another TSN; Follow the chain to 1671c3c17166SGeorge Shepherd * reach the frag with the last tsn in order to advance ftsn 1672c3c17166SGeorge Shepherd * shortly by calling SCTP_ACK_IT(). 16737c478bd9Sstevel@tonic-gate */ 16747c478bd9Sstevel@tonic-gate dlen = dmp->b_wptr - dmp->b_rptr - sizeof (*dc); 16757c478bd9Sstevel@tonic-gate for (pmp = dmp->b_cont; pmp; pmp = pmp->b_cont) 1676f0c3911fSGeorge Shepherd dlen += MBLKL(pmp); 16777c478bd9Sstevel@tonic-gate 16787c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_rxqueued >= dlen); 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate sctp->sctp_rxqueued -= dlen; 16817c478bd9Sstevel@tonic-gate if (can_deliver) { 16827c478bd9Sstevel@tonic-gate dmp->b_rptr = (uchar_t *)(dc + 1); 16837c478bd9Sstevel@tonic-gate if (sctp_input_add_ancillary(sctp, &dmp, dc, fp, 1684bd670b35SErik Nordmark ipp, ira) == 0) { 16857c478bd9Sstevel@tonic-gate dprint(1, ("sctp_data_chunk: delivering %lu " 16867c478bd9Sstevel@tonic-gate "bytes\n", msgdsize(dmp))); 16870f1702c5SYu Xiangning /* 1688c3c17166SGeorge Shepherd * Meaning of b_flag overloaded for SCTP sockfs 1689c3c17166SGeorge Shepherd * internal use, advise sockfs of partial 1690c3c17166SGeorge Shepherd * delivery semantics. 16910f1702c5SYu Xiangning */ 16920f1702c5SYu Xiangning dmp->b_flag = tpfinished ? 16930f1702c5SYu Xiangning 0 : SCTP_PARTIAL_DATA; 1694*a215d4ebSKacheong Poon if (sctp->sctp_flowctrld) { 1695*a215d4ebSKacheong Poon sctp->sctp_rwnd -= dlen; 1696*a215d4ebSKacheong Poon if (sctp->sctp_rwnd < 0) 1697f0c3911fSGeorge Shepherd sctp->sctp_rwnd = 0; 1698*a215d4ebSKacheong Poon } 1699*a215d4ebSKacheong Poon if (sctp->sctp_ulp_recv(sctp->sctp_ulpd, dmp, 1700*a215d4ebSKacheong Poon msgdsize(dmp), 0, &error, NULL) <= 0) { 1701*a215d4ebSKacheong Poon sctp->sctp_flowctrld = B_TRUE; 1702*a215d4ebSKacheong Poon } 17037c478bd9Sstevel@tonic-gate SCTP_ACK_IT(sctp, tsn); 17047c478bd9Sstevel@tonic-gate } else { 1705c3c17166SGeorge Shepherd /* don't ack, the peer will retransmit */ 17067c478bd9Sstevel@tonic-gate freemsg(dmp); 17077c478bd9Sstevel@tonic-gate return; 17087c478bd9Sstevel@tonic-gate } 17097c478bd9Sstevel@tonic-gate } else { 1710c3c17166SGeorge Shepherd /* Closed above, ack and free the data */ 17117c478bd9Sstevel@tonic-gate freemsg(dmp); 17127c478bd9Sstevel@tonic-gate SCTP_ACK_IT(sctp, tsn); 17137c478bd9Sstevel@tonic-gate } 17147c478bd9Sstevel@tonic-gate } 17157c478bd9Sstevel@tonic-gate 17167c478bd9Sstevel@tonic-gate done: 17177c478bd9Sstevel@tonic-gate 17187c478bd9Sstevel@tonic-gate /* 17197c478bd9Sstevel@tonic-gate * If there are gap reports pending, check if advancing 17207c478bd9Sstevel@tonic-gate * the ftsn here closes a gap. If so, we can advance 17217c478bd9Sstevel@tonic-gate * ftsn to the end of the set. 17227c478bd9Sstevel@tonic-gate */ 17237c478bd9Sstevel@tonic-gate if (sctp->sctp_sack_info != NULL && 17247c478bd9Sstevel@tonic-gate sctp->sctp_ftsn == sctp->sctp_sack_info->begin) { 17257c478bd9Sstevel@tonic-gate sctp->sctp_ftsn = sctp->sctp_sack_info->end + 1; 17267c478bd9Sstevel@tonic-gate } 17277c478bd9Sstevel@tonic-gate /* 17287c478bd9Sstevel@tonic-gate * If ftsn has moved forward, maybe we can remove gap reports. 17297c478bd9Sstevel@tonic-gate * NB: dmp may now be NULL, so don't dereference it here. 17307c478bd9Sstevel@tonic-gate */ 17317c478bd9Sstevel@tonic-gate if (oftsn != sctp->sctp_ftsn && sctp->sctp_sack_info != NULL) { 17327c478bd9Sstevel@tonic-gate sctp_ack_rem(&sctp->sctp_sack_info, sctp->sctp_ftsn - 1, 17337c478bd9Sstevel@tonic-gate &sctp->sctp_sack_gaps); 17347c478bd9Sstevel@tonic-gate dprint(2, ("data_chunk: removed acks before %x (num=%d)\n", 17357c478bd9Sstevel@tonic-gate sctp->sctp_ftsn - 1, sctp->sctp_sack_gaps)); 17367c478bd9Sstevel@tonic-gate } 17377c478bd9Sstevel@tonic-gate 17387c478bd9Sstevel@tonic-gate #ifdef DEBUG 17397c478bd9Sstevel@tonic-gate if (sctp->sctp_sack_info != NULL) { 17407c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_ftsn != sctp->sctp_sack_info->begin); 17417c478bd9Sstevel@tonic-gate } 17427c478bd9Sstevel@tonic-gate #endif 17437c478bd9Sstevel@tonic-gate 17447c478bd9Sstevel@tonic-gate #undef SCTP_ACK_IT 17457c478bd9Sstevel@tonic-gate } 17467c478bd9Sstevel@tonic-gate 17477c478bd9Sstevel@tonic-gate void 17487c478bd9Sstevel@tonic-gate sctp_fill_sack(sctp_t *sctp, unsigned char *dst, int sacklen) 17497c478bd9Sstevel@tonic-gate { 17507c478bd9Sstevel@tonic-gate sctp_chunk_hdr_t *sch; 17517c478bd9Sstevel@tonic-gate sctp_sack_chunk_t *sc; 17527c478bd9Sstevel@tonic-gate sctp_sack_frag_t *sf; 17537c478bd9Sstevel@tonic-gate uint16_t num_gaps = sctp->sctp_sack_gaps; 17547c478bd9Sstevel@tonic-gate sctp_set_t *sp; 17557c478bd9Sstevel@tonic-gate 17567c478bd9Sstevel@tonic-gate /* Chunk hdr */ 17577c478bd9Sstevel@tonic-gate sch = (sctp_chunk_hdr_t *)dst; 17587c478bd9Sstevel@tonic-gate sch->sch_id = CHUNK_SACK; 17597c478bd9Sstevel@tonic-gate sch->sch_flags = 0; 17607c478bd9Sstevel@tonic-gate sch->sch_len = htons(sacklen); 17617c478bd9Sstevel@tonic-gate 17627c478bd9Sstevel@tonic-gate /* SACK chunk */ 17637c478bd9Sstevel@tonic-gate sctp->sctp_lastacked = sctp->sctp_ftsn - 1; 17647c478bd9Sstevel@tonic-gate 17657c478bd9Sstevel@tonic-gate sc = (sctp_sack_chunk_t *)(sch + 1); 17667c478bd9Sstevel@tonic-gate sc->ssc_cumtsn = htonl(sctp->sctp_lastacked); 17677c478bd9Sstevel@tonic-gate if (sctp->sctp_rxqueued < sctp->sctp_rwnd) { 17687c478bd9Sstevel@tonic-gate sc->ssc_a_rwnd = htonl(sctp->sctp_rwnd - sctp->sctp_rxqueued); 17697c478bd9Sstevel@tonic-gate } else { 17707c478bd9Sstevel@tonic-gate sc->ssc_a_rwnd = 0; 17717c478bd9Sstevel@tonic-gate } 1772*a215d4ebSKacheong Poon /* Remember the last window sent to peer. */ 1773*a215d4ebSKacheong Poon sctp->sctp_arwnd = sc->ssc_a_rwnd; 17747c478bd9Sstevel@tonic-gate sc->ssc_numfrags = htons(num_gaps); 17757c478bd9Sstevel@tonic-gate sc->ssc_numdups = 0; 17767c478bd9Sstevel@tonic-gate 17777c478bd9Sstevel@tonic-gate /* lay in gap reports */ 17787c478bd9Sstevel@tonic-gate sf = (sctp_sack_frag_t *)(sc + 1); 17797c478bd9Sstevel@tonic-gate for (sp = sctp->sctp_sack_info; sp; sp = sp->next) { 17807c478bd9Sstevel@tonic-gate uint16_t offset; 17817c478bd9Sstevel@tonic-gate 17827c478bd9Sstevel@tonic-gate /* start */ 17837c478bd9Sstevel@tonic-gate if (sp->begin > sctp->sctp_lastacked) { 17847c478bd9Sstevel@tonic-gate offset = (uint16_t)(sp->begin - sctp->sctp_lastacked); 17857c478bd9Sstevel@tonic-gate } else { 17867c478bd9Sstevel@tonic-gate /* sequence number wrap */ 17877c478bd9Sstevel@tonic-gate offset = (uint16_t)(UINT32_MAX - sctp->sctp_lastacked + 17887c478bd9Sstevel@tonic-gate sp->begin); 17897c478bd9Sstevel@tonic-gate } 17907c478bd9Sstevel@tonic-gate sf->ssf_start = htons(offset); 17917c478bd9Sstevel@tonic-gate 17927c478bd9Sstevel@tonic-gate /* end */ 17937c478bd9Sstevel@tonic-gate if (sp->end >= sp->begin) { 17947c478bd9Sstevel@tonic-gate offset += (uint16_t)(sp->end - sp->begin); 17957c478bd9Sstevel@tonic-gate } else { 17967c478bd9Sstevel@tonic-gate /* sequence number wrap */ 17977c478bd9Sstevel@tonic-gate offset += (uint16_t)(UINT32_MAX - sp->begin + sp->end); 17987c478bd9Sstevel@tonic-gate } 17997c478bd9Sstevel@tonic-gate sf->ssf_end = htons(offset); 18007c478bd9Sstevel@tonic-gate 18017c478bd9Sstevel@tonic-gate sf++; 18027c478bd9Sstevel@tonic-gate /* This is just for debugging (a la the following assertion) */ 18037c478bd9Sstevel@tonic-gate num_gaps--; 18047c478bd9Sstevel@tonic-gate } 18057c478bd9Sstevel@tonic-gate 18067c478bd9Sstevel@tonic-gate ASSERT(num_gaps == 0); 18077c478bd9Sstevel@tonic-gate 18087c478bd9Sstevel@tonic-gate /* If the SACK timer is running, stop it */ 18097c478bd9Sstevel@tonic-gate if (sctp->sctp_ack_timer_running) { 18107c478bd9Sstevel@tonic-gate sctp_timer_stop(sctp->sctp_ack_mp); 18117c478bd9Sstevel@tonic-gate sctp->sctp_ack_timer_running = B_FALSE; 18127c478bd9Sstevel@tonic-gate } 18137c478bd9Sstevel@tonic-gate 18147c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_obchunks); 18159f13099eSGeorge Shepherd BUMP_LOCAL(sctp->sctp_osacks); 18167c478bd9Sstevel@tonic-gate } 18177c478bd9Sstevel@tonic-gate 18187c478bd9Sstevel@tonic-gate mblk_t * 18197c478bd9Sstevel@tonic-gate sctp_make_sack(sctp_t *sctp, sctp_faddr_t *sendto, mblk_t *dups) 18207c478bd9Sstevel@tonic-gate { 18217c478bd9Sstevel@tonic-gate mblk_t *smp; 18227c478bd9Sstevel@tonic-gate size_t slen; 18237c478bd9Sstevel@tonic-gate sctp_chunk_hdr_t *sch; 18247c478bd9Sstevel@tonic-gate sctp_sack_chunk_t *sc; 18251c25cdbdSkcpoon int32_t acks_max; 1826f4b3ec61Sdh155122 sctp_stack_t *sctps = sctp->sctp_sctps; 18277f093707Skcpoon uint32_t dups_len; 18287f093707Skcpoon sctp_faddr_t *fp; 18297c478bd9Sstevel@tonic-gate 1830bd670b35SErik Nordmark ASSERT(sendto != NULL); 1831bd670b35SErik Nordmark 18327c478bd9Sstevel@tonic-gate if (sctp->sctp_force_sack) { 18337c478bd9Sstevel@tonic-gate sctp->sctp_force_sack = 0; 18347c478bd9Sstevel@tonic-gate goto checks_done; 18357c478bd9Sstevel@tonic-gate } 18367c478bd9Sstevel@tonic-gate 1837f4b3ec61Sdh155122 acks_max = sctps->sctps_deferred_acks_max; 18387c478bd9Sstevel@tonic-gate if (sctp->sctp_state == SCTPS_ESTABLISHED) { 18391c25cdbdSkcpoon if (sctp->sctp_sack_toggle < acks_max) { 18407c478bd9Sstevel@tonic-gate /* no need to SACK right now */ 18417c478bd9Sstevel@tonic-gate dprint(2, ("sctp_make_sack: %p no sack (toggle)\n", 184245916cd2Sjpk (void *)sctp)); 18437c478bd9Sstevel@tonic-gate return (NULL); 18441c25cdbdSkcpoon } else if (sctp->sctp_sack_toggle >= acks_max) { 18457c478bd9Sstevel@tonic-gate sctp->sctp_sack_toggle = 0; 18467c478bd9Sstevel@tonic-gate } 18477c478bd9Sstevel@tonic-gate } 18487c478bd9Sstevel@tonic-gate 18497c478bd9Sstevel@tonic-gate if (sctp->sctp_ftsn == sctp->sctp_lastacked + 1) { 185045916cd2Sjpk dprint(2, ("sctp_make_sack: %p no sack (already)\n", 185145916cd2Sjpk (void *)sctp)); 18527c478bd9Sstevel@tonic-gate return (NULL); 18537c478bd9Sstevel@tonic-gate } 18547c478bd9Sstevel@tonic-gate 18557c478bd9Sstevel@tonic-gate checks_done: 18567c478bd9Sstevel@tonic-gate dprint(2, ("sctp_make_sack: acking %x\n", sctp->sctp_ftsn - 1)); 18577c478bd9Sstevel@tonic-gate 18587f093707Skcpoon if (dups != NULL) 18597f093707Skcpoon dups_len = MBLKL(dups); 18607f093707Skcpoon else 18617f093707Skcpoon dups_len = 0; 18627c478bd9Sstevel@tonic-gate slen = sizeof (*sch) + sizeof (*sc) + 18637c478bd9Sstevel@tonic-gate (sizeof (sctp_sack_frag_t) * sctp->sctp_sack_gaps); 18647f093707Skcpoon 18657f093707Skcpoon /* 18667f093707Skcpoon * If there are error chunks, check and see if we can send the 18677f093707Skcpoon * SACK chunk and error chunks together in one packet. If not, 18687f093707Skcpoon * send the error chunks out now. 18697f093707Skcpoon */ 18707f093707Skcpoon if (sctp->sctp_err_chunks != NULL) { 18717f093707Skcpoon fp = SCTP_CHUNK_DEST(sctp->sctp_err_chunks); 18726be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (sctp->sctp_err_len + slen + dups_len > fp->sf_pmss) { 18737f093707Skcpoon if ((smp = sctp_make_mp(sctp, fp, 0)) == NULL) { 18747f093707Skcpoon SCTP_KSTAT(sctps, sctp_send_err_failed); 18757f093707Skcpoon SCTP_KSTAT(sctps, sctp_send_sack_failed); 18767f093707Skcpoon freemsg(sctp->sctp_err_chunks); 18777f093707Skcpoon sctp->sctp_err_chunks = NULL; 18787f093707Skcpoon sctp->sctp_err_len = 0; 18797f093707Skcpoon return (NULL); 18807f093707Skcpoon } 18817f093707Skcpoon smp->b_cont = sctp->sctp_err_chunks; 18826be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp_set_iplen(sctp, smp, fp->sf_ixa); 18836be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India (void) conn_ip_output(smp, fp->sf_ixa); 1884bd670b35SErik Nordmark BUMP_LOCAL(sctp->sctp_opkts); 18857f093707Skcpoon sctp->sctp_err_chunks = NULL; 18867f093707Skcpoon sctp->sctp_err_len = 0; 18877f093707Skcpoon } 18887f093707Skcpoon } 18897c478bd9Sstevel@tonic-gate smp = sctp_make_mp(sctp, sendto, slen); 18907c478bd9Sstevel@tonic-gate if (smp == NULL) { 1891f4b3ec61Sdh155122 SCTP_KSTAT(sctps, sctp_send_sack_failed); 18927c478bd9Sstevel@tonic-gate return (NULL); 18937c478bd9Sstevel@tonic-gate } 18947c478bd9Sstevel@tonic-gate sch = (sctp_chunk_hdr_t *)smp->b_wptr; 18957c478bd9Sstevel@tonic-gate 18967c478bd9Sstevel@tonic-gate sctp_fill_sack(sctp, smp->b_wptr, slen); 18977c478bd9Sstevel@tonic-gate smp->b_wptr += slen; 18987f093707Skcpoon if (dups != NULL) { 18997c478bd9Sstevel@tonic-gate sc = (sctp_sack_chunk_t *)(sch + 1); 19007f093707Skcpoon sc->ssc_numdups = htons(MBLKL(dups) / sizeof (uint32_t)); 19017f093707Skcpoon sch->sch_len = htons(slen + dups_len); 19027c478bd9Sstevel@tonic-gate smp->b_cont = dups; 19037c478bd9Sstevel@tonic-gate } 19047c478bd9Sstevel@tonic-gate 19057f093707Skcpoon if (sctp->sctp_err_chunks != NULL) { 19067f093707Skcpoon linkb(smp, sctp->sctp_err_chunks); 19077f093707Skcpoon sctp->sctp_err_chunks = NULL; 19087f093707Skcpoon sctp->sctp_err_len = 0; 19097f093707Skcpoon } 19107c478bd9Sstevel@tonic-gate return (smp); 19117c478bd9Sstevel@tonic-gate } 19127c478bd9Sstevel@tonic-gate 19137f093707Skcpoon /* 19147f093707Skcpoon * Check and see if we need to send a SACK chunk. If it is needed, 19157f093707Skcpoon * send it out. Return true if a SACK chunk is sent, false otherwise. 19167f093707Skcpoon */ 19177f093707Skcpoon boolean_t 19187c478bd9Sstevel@tonic-gate sctp_sack(sctp_t *sctp, mblk_t *dups) 19197c478bd9Sstevel@tonic-gate { 19207c478bd9Sstevel@tonic-gate mblk_t *smp; 1921f4b3ec61Sdh155122 sctp_stack_t *sctps = sctp->sctp_sctps; 19227c478bd9Sstevel@tonic-gate 19237c478bd9Sstevel@tonic-gate /* If we are shutting down, let send_shutdown() bundle the SACK */ 19247c478bd9Sstevel@tonic-gate if (sctp->sctp_state == SCTPS_SHUTDOWN_SENT) { 19257c478bd9Sstevel@tonic-gate sctp_send_shutdown(sctp, 0); 19267c478bd9Sstevel@tonic-gate } 19277c478bd9Sstevel@tonic-gate 19287c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_lastdata != NULL); 19297c478bd9Sstevel@tonic-gate 19307c478bd9Sstevel@tonic-gate if ((smp = sctp_make_sack(sctp, sctp->sctp_lastdata, dups)) == NULL) { 19317c478bd9Sstevel@tonic-gate /* The caller of sctp_sack() will not free the dups mblk. */ 19327c478bd9Sstevel@tonic-gate if (dups != NULL) 19337c478bd9Sstevel@tonic-gate freeb(dups); 19347f093707Skcpoon return (B_FALSE); 19357c478bd9Sstevel@tonic-gate } 19367c478bd9Sstevel@tonic-gate dprint(2, ("sctp_sack: sending to %p %x:%x:%x:%x\n", 193745916cd2Sjpk (void *)sctp->sctp_lastdata, 19386be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India SCTP_PRINTADDR(sctp->sctp_lastdata->sf_faddr))); 19397c478bd9Sstevel@tonic-gate 19405dd46ab5SKacheong Poon sctp->sctp_active = LBOLT_FASTPATH64; 19417c478bd9Sstevel@tonic-gate 19425dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpOutAck); 1943bd670b35SErik Nordmark 19446be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp_set_iplen(sctp, smp, sctp->sctp_lastdata->sf_ixa); 19456be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India (void) conn_ip_output(smp, sctp->sctp_lastdata->sf_ixa); 1946bd670b35SErik Nordmark BUMP_LOCAL(sctp->sctp_opkts); 19477f093707Skcpoon return (B_TRUE); 19487c478bd9Sstevel@tonic-gate } 19497c478bd9Sstevel@tonic-gate 19507c478bd9Sstevel@tonic-gate /* 19517c478bd9Sstevel@tonic-gate * This is called if we have a message that was partially sent and is 19527c478bd9Sstevel@tonic-gate * abandoned. The cum TSN will be the last chunk sent for this message, 19537c478bd9Sstevel@tonic-gate * subsequent chunks will be marked ABANDONED. We send a Forward TSN 19547c478bd9Sstevel@tonic-gate * chunk in this case with the TSN of the last sent chunk so that the 19557c478bd9Sstevel@tonic-gate * peer can clean up its fragment list for this message. This message 19567c478bd9Sstevel@tonic-gate * will be removed from the transmit list when the peer sends a SACK 19577c478bd9Sstevel@tonic-gate * back. 19587c478bd9Sstevel@tonic-gate */ 19597c478bd9Sstevel@tonic-gate int 19607c478bd9Sstevel@tonic-gate sctp_check_abandoned_msg(sctp_t *sctp, mblk_t *meta) 19617c478bd9Sstevel@tonic-gate { 19627c478bd9Sstevel@tonic-gate sctp_data_hdr_t *dh; 19637c478bd9Sstevel@tonic-gate mblk_t *nmp; 19647c478bd9Sstevel@tonic-gate mblk_t *head; 19657c478bd9Sstevel@tonic-gate int32_t unsent = 0; 19667c478bd9Sstevel@tonic-gate mblk_t *mp1 = meta->b_cont; 19677c478bd9Sstevel@tonic-gate uint32_t adv_pap = sctp->sctp_adv_pap; 19687c478bd9Sstevel@tonic-gate sctp_faddr_t *fp = sctp->sctp_current; 1969f4b3ec61Sdh155122 sctp_stack_t *sctps = sctp->sctp_sctps; 19707c478bd9Sstevel@tonic-gate 19717c478bd9Sstevel@tonic-gate dh = (sctp_data_hdr_t *)mp1->b_rptr; 19727c478bd9Sstevel@tonic-gate if (SEQ_GEQ(sctp->sctp_lastack_rxd, ntohl(dh->sdh_tsn))) { 19737c478bd9Sstevel@tonic-gate sctp_ftsn_set_t *sets = NULL; 19747c478bd9Sstevel@tonic-gate uint_t nsets = 0; 19757c478bd9Sstevel@tonic-gate uint32_t seglen = sizeof (uint32_t); 19767c478bd9Sstevel@tonic-gate boolean_t ubit = SCTP_DATA_GET_UBIT(dh); 19777c478bd9Sstevel@tonic-gate 19787c478bd9Sstevel@tonic-gate while (mp1->b_next != NULL && SCTP_CHUNK_ISSENT(mp1->b_next)) 19797c478bd9Sstevel@tonic-gate mp1 = mp1->b_next; 19807c478bd9Sstevel@tonic-gate dh = (sctp_data_hdr_t *)mp1->b_rptr; 19817c478bd9Sstevel@tonic-gate sctp->sctp_adv_pap = ntohl(dh->sdh_tsn); 19827c478bd9Sstevel@tonic-gate if (!ubit && 19837c478bd9Sstevel@tonic-gate !sctp_add_ftsn_set(&sets, fp, meta, &nsets, &seglen)) { 19847c478bd9Sstevel@tonic-gate sctp->sctp_adv_pap = adv_pap; 19857c478bd9Sstevel@tonic-gate return (ENOMEM); 19867c478bd9Sstevel@tonic-gate } 19877c478bd9Sstevel@tonic-gate nmp = sctp_make_ftsn_chunk(sctp, fp, sets, nsets, seglen); 19887c478bd9Sstevel@tonic-gate sctp_free_ftsn_set(sets); 19897c478bd9Sstevel@tonic-gate if (nmp == NULL) { 19907c478bd9Sstevel@tonic-gate sctp->sctp_adv_pap = adv_pap; 19917c478bd9Sstevel@tonic-gate return (ENOMEM); 19927c478bd9Sstevel@tonic-gate } 1993df19b344Svi117747 head = sctp_add_proto_hdr(sctp, fp, nmp, 0, NULL); 19947c478bd9Sstevel@tonic-gate if (head == NULL) { 19957c478bd9Sstevel@tonic-gate sctp->sctp_adv_pap = adv_pap; 19967c478bd9Sstevel@tonic-gate freemsg(nmp); 1997f4b3ec61Sdh155122 SCTP_KSTAT(sctps, sctp_send_ftsn_failed); 19987c478bd9Sstevel@tonic-gate return (ENOMEM); 19997c478bd9Sstevel@tonic-gate } 20007c478bd9Sstevel@tonic-gate SCTP_MSG_SET_ABANDONED(meta); 20016be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp_set_iplen(sctp, head, fp->sf_ixa); 20026be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India (void) conn_ip_output(head, fp->sf_ixa); 2003bd670b35SErik Nordmark BUMP_LOCAL(sctp->sctp_opkts); 20046be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (!fp->sf_timer_running) 20056be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->sf_rto); 20067c478bd9Sstevel@tonic-gate mp1 = mp1->b_next; 20077c478bd9Sstevel@tonic-gate while (mp1 != NULL) { 20087c478bd9Sstevel@tonic-gate ASSERT(!SCTP_CHUNK_ISSENT(mp1)); 20097c478bd9Sstevel@tonic-gate ASSERT(!SCTP_CHUNK_ABANDONED(mp1)); 20107c478bd9Sstevel@tonic-gate SCTP_ABANDON_CHUNK(mp1); 20117c478bd9Sstevel@tonic-gate dh = (sctp_data_hdr_t *)mp1->b_rptr; 20127c478bd9Sstevel@tonic-gate unsent += ntohs(dh->sdh_len) - sizeof (*dh); 20137c478bd9Sstevel@tonic-gate mp1 = mp1->b_next; 20147c478bd9Sstevel@tonic-gate } 20157c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_unsent >= unsent); 20167c478bd9Sstevel@tonic-gate sctp->sctp_unsent -= unsent; 20177c478bd9Sstevel@tonic-gate /* 20187c478bd9Sstevel@tonic-gate * Update ULP the amount of queued data, which is 20197c478bd9Sstevel@tonic-gate * sent-unack'ed + unsent. 20207c478bd9Sstevel@tonic-gate */ 20210f1702c5SYu Xiangning if (!SCTP_IS_DETACHED(sctp)) 20220f1702c5SYu Xiangning SCTP_TXQ_UPDATE(sctp); 20237c478bd9Sstevel@tonic-gate return (0); 20247c478bd9Sstevel@tonic-gate } 20257c478bd9Sstevel@tonic-gate return (-1); 20267c478bd9Sstevel@tonic-gate } 20277c478bd9Sstevel@tonic-gate 20287c478bd9Sstevel@tonic-gate uint32_t 20297c478bd9Sstevel@tonic-gate sctp_cumack(sctp_t *sctp, uint32_t tsn, mblk_t **first_unacked) 20307c478bd9Sstevel@tonic-gate { 20317c478bd9Sstevel@tonic-gate mblk_t *ump, *nump, *mp = NULL; 20327c478bd9Sstevel@tonic-gate uint16_t chunklen; 20337c478bd9Sstevel@tonic-gate uint32_t xtsn; 20347c478bd9Sstevel@tonic-gate sctp_faddr_t *fp; 20357c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 20367c478bd9Sstevel@tonic-gate uint32_t cumack_forward = 0; 20377c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *mhdr; 2038f4b3ec61Sdh155122 sctp_stack_t *sctps = sctp->sctp_sctps; 20397c478bd9Sstevel@tonic-gate 20407c478bd9Sstevel@tonic-gate ump = sctp->sctp_xmit_head; 20417c478bd9Sstevel@tonic-gate 20427c478bd9Sstevel@tonic-gate /* 20437c478bd9Sstevel@tonic-gate * Free messages only when they're completely acked. 20447c478bd9Sstevel@tonic-gate */ 20457c478bd9Sstevel@tonic-gate while (ump != NULL) { 20467c478bd9Sstevel@tonic-gate mhdr = (sctp_msg_hdr_t *)ump->b_rptr; 20477c478bd9Sstevel@tonic-gate for (mp = ump->b_cont; mp != NULL; mp = mp->b_next) { 20487c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_ABANDONED(mp)) { 20497c478bd9Sstevel@tonic-gate ASSERT(SCTP_IS_MSG_ABANDONED(ump)); 20507c478bd9Sstevel@tonic-gate mp = NULL; 20517c478bd9Sstevel@tonic-gate break; 20527c478bd9Sstevel@tonic-gate } 20537c478bd9Sstevel@tonic-gate /* 20547c478bd9Sstevel@tonic-gate * We check for abandoned message if we are PR-SCTP 20557c478bd9Sstevel@tonic-gate * aware, if this is not the first chunk in the 20567c478bd9Sstevel@tonic-gate * message (b_cont) and if the message is marked 20577c478bd9Sstevel@tonic-gate * abandoned. 20587c478bd9Sstevel@tonic-gate */ 20597c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp)) { 20607c478bd9Sstevel@tonic-gate if (sctp->sctp_prsctp_aware && 20617c478bd9Sstevel@tonic-gate mp != ump->b_cont && 20627c478bd9Sstevel@tonic-gate (SCTP_IS_MSG_ABANDONED(ump) || 20637c478bd9Sstevel@tonic-gate SCTP_MSG_TO_BE_ABANDONED(ump, mhdr, 20647c478bd9Sstevel@tonic-gate sctp))) { 20657c478bd9Sstevel@tonic-gate (void) sctp_check_abandoned_msg(sctp, 20667c478bd9Sstevel@tonic-gate ump); 20677c478bd9Sstevel@tonic-gate } 20687c478bd9Sstevel@tonic-gate goto cum_ack_done; 20697c478bd9Sstevel@tonic-gate } 20707c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 20717c478bd9Sstevel@tonic-gate xtsn = ntohl(sdc->sdh_tsn); 20727c478bd9Sstevel@tonic-gate if (SEQ_GEQ(sctp->sctp_lastack_rxd, xtsn)) 20737c478bd9Sstevel@tonic-gate continue; 20747c478bd9Sstevel@tonic-gate if (SEQ_GEQ(tsn, xtsn)) { 20757c478bd9Sstevel@tonic-gate fp = SCTP_CHUNK_DEST(mp); 20767c478bd9Sstevel@tonic-gate chunklen = ntohs(sdc->sdh_len); 20777c478bd9Sstevel@tonic-gate 20787c478bd9Sstevel@tonic-gate if (sctp->sctp_out_time != 0 && 20797c478bd9Sstevel@tonic-gate xtsn == sctp->sctp_rtt_tsn) { 20807c478bd9Sstevel@tonic-gate /* Got a new RTT measurement */ 20817c478bd9Sstevel@tonic-gate sctp_update_rtt(sctp, fp, 2082d3d50737SRafael Vanoni ddi_get_lbolt64() - 2083d3d50737SRafael Vanoni sctp->sctp_out_time); 20847c478bd9Sstevel@tonic-gate sctp->sctp_out_time = 0; 20857c478bd9Sstevel@tonic-gate } 20867c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_ISACKED(mp)) 20877c478bd9Sstevel@tonic-gate continue; 208877c67f2fSkcpoon SCTP_CHUNK_SET_SACKCNT(mp, 0); 20897c478bd9Sstevel@tonic-gate SCTP_CHUNK_ACKED(mp); 20906be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India ASSERT(fp->sf_suna >= chunklen); 20916be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_suna -= chunklen; 20926be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_acked += chunklen; 20937c478bd9Sstevel@tonic-gate cumack_forward += chunklen; 20947c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_unacked >= 20957c478bd9Sstevel@tonic-gate (chunklen - sizeof (*sdc))); 20967c478bd9Sstevel@tonic-gate sctp->sctp_unacked -= 20977c478bd9Sstevel@tonic-gate (chunklen - sizeof (*sdc)); 20986be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp->sf_suna == 0) { 20997c478bd9Sstevel@tonic-gate /* all outstanding data acked */ 21006be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_pba = 0; 21017c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_STOP(fp); 21027c478bd9Sstevel@tonic-gate } else { 21037c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, fp, 21046be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_rto); 21057c478bd9Sstevel@tonic-gate } 21067c478bd9Sstevel@tonic-gate } else { 21077c478bd9Sstevel@tonic-gate goto cum_ack_done; 21087c478bd9Sstevel@tonic-gate } 21097c478bd9Sstevel@tonic-gate } 21107c478bd9Sstevel@tonic-gate nump = ump->b_next; 21117c478bd9Sstevel@tonic-gate if (nump != NULL) 21127c478bd9Sstevel@tonic-gate nump->b_prev = NULL; 21137c478bd9Sstevel@tonic-gate if (ump == sctp->sctp_xmit_tail) 21147c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail = nump; 21157c478bd9Sstevel@tonic-gate if (SCTP_IS_MSG_ABANDONED(ump)) { 21167c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_prsctpdrop); 21177c478bd9Sstevel@tonic-gate ump->b_next = NULL; 21187c478bd9Sstevel@tonic-gate sctp_sendfail_event(sctp, ump, 0, B_TRUE); 21197c478bd9Sstevel@tonic-gate } else { 21207c478bd9Sstevel@tonic-gate sctp_free_msg(ump); 21217c478bd9Sstevel@tonic-gate } 21227c478bd9Sstevel@tonic-gate sctp->sctp_xmit_head = ump = nump; 21237c478bd9Sstevel@tonic-gate } 21247c478bd9Sstevel@tonic-gate cum_ack_done: 21257c478bd9Sstevel@tonic-gate *first_unacked = mp; 21267c478bd9Sstevel@tonic-gate if (cumack_forward > 0) { 21275dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpInAck); 21287c478bd9Sstevel@tonic-gate if (SEQ_GT(sctp->sctp_lastack_rxd, sctp->sctp_recovery_tsn)) { 21297c478bd9Sstevel@tonic-gate sctp->sctp_recovery_tsn = sctp->sctp_lastack_rxd; 21307c478bd9Sstevel@tonic-gate } 21317c478bd9Sstevel@tonic-gate 21327c478bd9Sstevel@tonic-gate /* 21337c478bd9Sstevel@tonic-gate * Update ULP the amount of queued data, which is 21347c478bd9Sstevel@tonic-gate * sent-unack'ed + unsent. 21357c478bd9Sstevel@tonic-gate */ 21360f1702c5SYu Xiangning if (!SCTP_IS_DETACHED(sctp)) 21370f1702c5SYu Xiangning SCTP_TXQ_UPDATE(sctp); 21387c478bd9Sstevel@tonic-gate 21397c478bd9Sstevel@tonic-gate /* Time to send a shutdown? */ 21407c478bd9Sstevel@tonic-gate if (sctp->sctp_state == SCTPS_SHUTDOWN_PENDING) { 21417c478bd9Sstevel@tonic-gate sctp_send_shutdown(sctp, 0); 21427c478bd9Sstevel@tonic-gate } 21437c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unacked = mp; 21447c478bd9Sstevel@tonic-gate } else { 21457c478bd9Sstevel@tonic-gate /* dup ack */ 21465dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpInDupAck); 21477c478bd9Sstevel@tonic-gate } 21487c478bd9Sstevel@tonic-gate sctp->sctp_lastack_rxd = tsn; 21497c478bd9Sstevel@tonic-gate if (SEQ_LT(sctp->sctp_adv_pap, sctp->sctp_lastack_rxd)) 21507c478bd9Sstevel@tonic-gate sctp->sctp_adv_pap = sctp->sctp_lastack_rxd; 21517c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_xmit_head || sctp->sctp_unacked == 0); 21527c478bd9Sstevel@tonic-gate 21537c478bd9Sstevel@tonic-gate return (cumack_forward); 21547c478bd9Sstevel@tonic-gate } 21557c478bd9Sstevel@tonic-gate 21567c478bd9Sstevel@tonic-gate static int 21577c478bd9Sstevel@tonic-gate sctp_set_frwnd(sctp_t *sctp, uint32_t frwnd) 21587c478bd9Sstevel@tonic-gate { 21597c478bd9Sstevel@tonic-gate uint32_t orwnd; 21607c478bd9Sstevel@tonic-gate 21617c478bd9Sstevel@tonic-gate if (sctp->sctp_unacked > frwnd) { 21627c478bd9Sstevel@tonic-gate sctp->sctp_frwnd = 0; 21637c478bd9Sstevel@tonic-gate return (0); 21647c478bd9Sstevel@tonic-gate } 21657c478bd9Sstevel@tonic-gate orwnd = sctp->sctp_frwnd; 21667c478bd9Sstevel@tonic-gate sctp->sctp_frwnd = frwnd - sctp->sctp_unacked; 21677c478bd9Sstevel@tonic-gate if (orwnd < sctp->sctp_frwnd) { 21687c478bd9Sstevel@tonic-gate return (1); 21697c478bd9Sstevel@tonic-gate } else { 21707c478bd9Sstevel@tonic-gate return (0); 21717c478bd9Sstevel@tonic-gate } 21727c478bd9Sstevel@tonic-gate } 21737c478bd9Sstevel@tonic-gate 21747c478bd9Sstevel@tonic-gate /* 21757c478bd9Sstevel@tonic-gate * For un-ordered messages. 21767c478bd9Sstevel@tonic-gate * Walk the sctp->sctp_uo_frag list and remove any fragments with TSN 21777c478bd9Sstevel@tonic-gate * less than/equal to ftsn. Fragments for un-ordered messages are 21787c478bd9Sstevel@tonic-gate * strictly in sequence (w.r.t TSN). 21797c478bd9Sstevel@tonic-gate */ 21807c478bd9Sstevel@tonic-gate static int 21817c478bd9Sstevel@tonic-gate sctp_ftsn_check_uo_frag(sctp_t *sctp, uint32_t ftsn) 21827c478bd9Sstevel@tonic-gate { 21837c478bd9Sstevel@tonic-gate mblk_t *hmp; 21847c478bd9Sstevel@tonic-gate mblk_t *hmp_next; 21857c478bd9Sstevel@tonic-gate sctp_data_hdr_t *dc; 21867c478bd9Sstevel@tonic-gate int dlen = 0; 21877c478bd9Sstevel@tonic-gate 21887c478bd9Sstevel@tonic-gate hmp = sctp->sctp_uo_frags; 21897c478bd9Sstevel@tonic-gate while (hmp != NULL) { 21907c478bd9Sstevel@tonic-gate hmp_next = hmp->b_next; 21917c478bd9Sstevel@tonic-gate dc = (sctp_data_hdr_t *)hmp->b_rptr; 21927c478bd9Sstevel@tonic-gate if (SEQ_GT(ntohl(dc->sdh_tsn), ftsn)) 21937c478bd9Sstevel@tonic-gate return (dlen); 21947c478bd9Sstevel@tonic-gate sctp->sctp_uo_frags = hmp_next; 21957c478bd9Sstevel@tonic-gate if (hmp_next != NULL) 21967c478bd9Sstevel@tonic-gate hmp_next->b_prev = NULL; 21977c478bd9Sstevel@tonic-gate hmp->b_next = NULL; 21987c478bd9Sstevel@tonic-gate dlen += ntohs(dc->sdh_len) - sizeof (*dc); 21997c478bd9Sstevel@tonic-gate freeb(hmp); 22007c478bd9Sstevel@tonic-gate hmp = hmp_next; 22017c478bd9Sstevel@tonic-gate } 22027c478bd9Sstevel@tonic-gate return (dlen); 22037c478bd9Sstevel@tonic-gate } 22047c478bd9Sstevel@tonic-gate 22057c478bd9Sstevel@tonic-gate /* 22067c478bd9Sstevel@tonic-gate * For ordered messages. 22077c478bd9Sstevel@tonic-gate * Check for existing fragments for an sid-ssn pair reported as abandoned, 22087c478bd9Sstevel@tonic-gate * hence will not receive, in the Forward TSN. If there are fragments, then 22097c478bd9Sstevel@tonic-gate * we just nuke them. If and when Partial Delivery API is supported, we 22107c478bd9Sstevel@tonic-gate * would need to send a notification to the upper layer about this. 22117c478bd9Sstevel@tonic-gate */ 22127c478bd9Sstevel@tonic-gate static int 22137c478bd9Sstevel@tonic-gate sctp_ftsn_check_frag(sctp_t *sctp, uint16_t ssn, sctp_instr_t *sip) 22147c478bd9Sstevel@tonic-gate { 22157c478bd9Sstevel@tonic-gate sctp_reass_t *srp; 22167c478bd9Sstevel@tonic-gate mblk_t *hmp; 22177c478bd9Sstevel@tonic-gate mblk_t *dmp; 22187c478bd9Sstevel@tonic-gate mblk_t *hmp_next; 22197c478bd9Sstevel@tonic-gate sctp_data_hdr_t *dc; 22207c478bd9Sstevel@tonic-gate int dlen = 0; 22217c478bd9Sstevel@tonic-gate 22227c478bd9Sstevel@tonic-gate hmp = sip->istr_reass; 22237c478bd9Sstevel@tonic-gate while (hmp != NULL) { 22247c478bd9Sstevel@tonic-gate hmp_next = hmp->b_next; 22257c478bd9Sstevel@tonic-gate srp = (sctp_reass_t *)DB_BASE(hmp); 22266be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (SSN_GT(srp->sr_ssn, ssn)) 22277c478bd9Sstevel@tonic-gate return (dlen); 22287c478bd9Sstevel@tonic-gate /* 22297c478bd9Sstevel@tonic-gate * If we had sent part of this message up, send a partial 22307c478bd9Sstevel@tonic-gate * delivery event. Since this is ordered delivery, we should 22317c478bd9Sstevel@tonic-gate * have sent partial message only for the next in sequence, 22327c478bd9Sstevel@tonic-gate * hence the ASSERT. See comments in sctp_data_chunk() for 22337c478bd9Sstevel@tonic-gate * trypartial. 22347c478bd9Sstevel@tonic-gate */ 22356be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (srp->sr_partial_delivered) { 22366be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (srp->sr_ssn != sip->nextseq) 2237c3c17166SGeorge Shepherd cmn_err(CE_WARN, "sctp partial" 2238c3c17166SGeorge Shepherd " delivery notify, sctp 0x%p" 2239c3c17166SGeorge Shepherd " sip = 0x%p ssn != nextseq" 2240c3c17166SGeorge Shepherd " ssn 0x%x nextseq 0x%x", 2241c3c17166SGeorge Shepherd (void *)sctp, (void *)sip, 22426be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India srp->sr_ssn, sip->nextseq); 22436be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India ASSERT(sip->nextseq == srp->sr_ssn); 22447c478bd9Sstevel@tonic-gate sctp_partial_delivery_event(sctp); 22457c478bd9Sstevel@tonic-gate } 22467c478bd9Sstevel@tonic-gate /* Take it out of the reass queue */ 22477c478bd9Sstevel@tonic-gate sip->istr_reass = hmp_next; 22487c478bd9Sstevel@tonic-gate if (hmp_next != NULL) 22497c478bd9Sstevel@tonic-gate hmp_next->b_prev = NULL; 22507c478bd9Sstevel@tonic-gate hmp->b_next = NULL; 22517c478bd9Sstevel@tonic-gate ASSERT(hmp->b_prev == NULL); 22527c478bd9Sstevel@tonic-gate dmp = hmp; 22537d546a59Svi117747 ASSERT(DB_TYPE(hmp) == M_CTL); 22547c478bd9Sstevel@tonic-gate dmp = hmp->b_cont; 22557c478bd9Sstevel@tonic-gate hmp->b_cont = NULL; 22567c478bd9Sstevel@tonic-gate freeb(hmp); 22577c478bd9Sstevel@tonic-gate hmp = dmp; 22587c478bd9Sstevel@tonic-gate while (dmp != NULL) { 22597c478bd9Sstevel@tonic-gate dc = (sctp_data_hdr_t *)dmp->b_rptr; 22607c478bd9Sstevel@tonic-gate dlen += ntohs(dc->sdh_len) - sizeof (*dc); 22617c478bd9Sstevel@tonic-gate dmp = dmp->b_cont; 22627c478bd9Sstevel@tonic-gate } 22637c478bd9Sstevel@tonic-gate freemsg(hmp); 22647c478bd9Sstevel@tonic-gate hmp = hmp_next; 22657c478bd9Sstevel@tonic-gate } 22667c478bd9Sstevel@tonic-gate return (dlen); 22677c478bd9Sstevel@tonic-gate } 22687c478bd9Sstevel@tonic-gate 22697c478bd9Sstevel@tonic-gate /* 22707c478bd9Sstevel@tonic-gate * Update sctp_ftsn to the cumulative TSN from the Forward TSN chunk. Remove 22717c478bd9Sstevel@tonic-gate * any SACK gaps less than the newly updated sctp_ftsn. Walk through the 22727c478bd9Sstevel@tonic-gate * sid-ssn pair in the Forward TSN and for each, clean the fragment list 22737c478bd9Sstevel@tonic-gate * for this pair, if needed, and check if we can deliver subsequent 22747c478bd9Sstevel@tonic-gate * messages, if any, from the instream queue (that were waiting for this 22757c478bd9Sstevel@tonic-gate * sid-ssn message to show up). Once we are done try to update the SACK 22767c478bd9Sstevel@tonic-gate * info. We could get a duplicate Forward TSN, in which case just send 2277bd670b35SErik Nordmark * a SACK. If any of the sid values in the Forward TSN is invalid, 22787c478bd9Sstevel@tonic-gate * send back an "Invalid Stream Identifier" error and continue processing 22797c478bd9Sstevel@tonic-gate * the rest. 22807c478bd9Sstevel@tonic-gate */ 22817c478bd9Sstevel@tonic-gate static void 22827c478bd9Sstevel@tonic-gate sctp_process_forward_tsn(sctp_t *sctp, sctp_chunk_hdr_t *ch, sctp_faddr_t *fp, 2283bd670b35SErik Nordmark ip_pkt_t *ipp, ip_recv_attr_t *ira) 22847c478bd9Sstevel@tonic-gate { 22857c478bd9Sstevel@tonic-gate uint32_t *ftsn = (uint32_t *)(ch + 1); 22867c478bd9Sstevel@tonic-gate ftsn_entry_t *ftsn_entry; 22877c478bd9Sstevel@tonic-gate sctp_instr_t *instr; 22887c478bd9Sstevel@tonic-gate boolean_t can_deliver = B_TRUE; 22897c478bd9Sstevel@tonic-gate size_t dlen; 22907c478bd9Sstevel@tonic-gate int flen; 22917c478bd9Sstevel@tonic-gate mblk_t *dmp; 22927c478bd9Sstevel@tonic-gate mblk_t *pmp; 22937c478bd9Sstevel@tonic-gate sctp_data_hdr_t *dc; 22947c478bd9Sstevel@tonic-gate ssize_t remaining; 2295f4b3ec61Sdh155122 sctp_stack_t *sctps = sctp->sctp_sctps; 22967c478bd9Sstevel@tonic-gate 22977c478bd9Sstevel@tonic-gate *ftsn = ntohl(*ftsn); 22987c478bd9Sstevel@tonic-gate remaining = ntohs(ch->sch_len) - sizeof (*ch) - sizeof (*ftsn); 22997c478bd9Sstevel@tonic-gate 23007c478bd9Sstevel@tonic-gate if (SCTP_IS_DETACHED(sctp)) { 23015dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpInClosed); 23027c478bd9Sstevel@tonic-gate can_deliver = B_FALSE; 23037c478bd9Sstevel@tonic-gate } 23047c478bd9Sstevel@tonic-gate /* 23057c478bd9Sstevel@tonic-gate * un-ordered messages don't have SID-SSN pair entries, we check 23067c478bd9Sstevel@tonic-gate * for any fragments (for un-ordered message) to be discarded using 23077c478bd9Sstevel@tonic-gate * the cumulative FTSN. 23087c478bd9Sstevel@tonic-gate */ 23097c478bd9Sstevel@tonic-gate flen = sctp_ftsn_check_uo_frag(sctp, *ftsn); 23107c478bd9Sstevel@tonic-gate if (flen > 0) { 23117c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_rxqueued >= flen); 23127c478bd9Sstevel@tonic-gate sctp->sctp_rxqueued -= flen; 23137c478bd9Sstevel@tonic-gate } 23147c478bd9Sstevel@tonic-gate ftsn_entry = (ftsn_entry_t *)(ftsn + 1); 23157c478bd9Sstevel@tonic-gate while (remaining >= sizeof (*ftsn_entry)) { 23167c478bd9Sstevel@tonic-gate ftsn_entry->ftsn_sid = ntohs(ftsn_entry->ftsn_sid); 23177c478bd9Sstevel@tonic-gate ftsn_entry->ftsn_ssn = ntohs(ftsn_entry->ftsn_ssn); 23187c478bd9Sstevel@tonic-gate if (ftsn_entry->ftsn_sid >= sctp->sctp_num_istr) { 231947b33325SGeorge Shepherd sctp_bsc_t inval_parm; 23207c478bd9Sstevel@tonic-gate 232147b33325SGeorge Shepherd /* Will populate the CAUSE block in the ERROR chunk. */ 232247b33325SGeorge Shepherd inval_parm.bsc_sid = htons(ftsn_entry->ftsn_sid); 232347b33325SGeorge Shepherd /* RESERVED, ignored at the receiving end */ 232447b33325SGeorge Shepherd inval_parm.bsc_pad = 0; 232547b33325SGeorge Shepherd 232647b33325SGeorge Shepherd sctp_add_err(sctp, SCTP_ERR_BAD_SID, 232747b33325SGeorge Shepherd (void *)&inval_parm, sizeof (sctp_bsc_t), fp); 23287c478bd9Sstevel@tonic-gate ftsn_entry++; 23297c478bd9Sstevel@tonic-gate remaining -= sizeof (*ftsn_entry); 23307c478bd9Sstevel@tonic-gate continue; 23317c478bd9Sstevel@tonic-gate } 23327c478bd9Sstevel@tonic-gate instr = &sctp->sctp_instr[ftsn_entry->ftsn_sid]; 23337c478bd9Sstevel@tonic-gate flen = sctp_ftsn_check_frag(sctp, ftsn_entry->ftsn_ssn, instr); 23347c478bd9Sstevel@tonic-gate /* Indicates frags were nuked, update rxqueued */ 23357c478bd9Sstevel@tonic-gate if (flen > 0) { 23367c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_rxqueued >= flen); 23377c478bd9Sstevel@tonic-gate sctp->sctp_rxqueued -= flen; 23387c478bd9Sstevel@tonic-gate } 23397c478bd9Sstevel@tonic-gate /* 23407c478bd9Sstevel@tonic-gate * It is possible to receive an FTSN chunk with SSN smaller 23417c478bd9Sstevel@tonic-gate * than then nextseq if this chunk is a retransmission because 23427c478bd9Sstevel@tonic-gate * of incomplete processing when it was first processed. 23437c478bd9Sstevel@tonic-gate */ 23447c478bd9Sstevel@tonic-gate if (SSN_GE(ftsn_entry->ftsn_ssn, instr->nextseq)) 23457c478bd9Sstevel@tonic-gate instr->nextseq = ftsn_entry->ftsn_ssn + 1; 23467c478bd9Sstevel@tonic-gate while (instr->istr_nmsgs > 0) { 23477c478bd9Sstevel@tonic-gate mblk_t *next; 23487c478bd9Sstevel@tonic-gate 23497c478bd9Sstevel@tonic-gate dmp = (mblk_t *)instr->istr_msgs; 23507c478bd9Sstevel@tonic-gate dc = (sctp_data_hdr_t *)dmp->b_rptr; 23517c478bd9Sstevel@tonic-gate if (ntohs(dc->sdh_ssn) != instr->nextseq) 23527c478bd9Sstevel@tonic-gate break; 23537c478bd9Sstevel@tonic-gate 23547c478bd9Sstevel@tonic-gate next = dmp->b_next; 23557c478bd9Sstevel@tonic-gate dlen = dmp->b_wptr - dmp->b_rptr - sizeof (*dc); 23567c478bd9Sstevel@tonic-gate for (pmp = dmp->b_cont; pmp != NULL; 23577c478bd9Sstevel@tonic-gate pmp = pmp->b_cont) { 2358f0c3911fSGeorge Shepherd dlen += MBLKL(pmp); 23597c478bd9Sstevel@tonic-gate } 23607c478bd9Sstevel@tonic-gate if (can_deliver) { 23610f1702c5SYu Xiangning int error; 23627c478bd9Sstevel@tonic-gate 23637c478bd9Sstevel@tonic-gate dmp->b_rptr = (uchar_t *)(dc + 1); 23647c478bd9Sstevel@tonic-gate dmp->b_next = NULL; 23657c478bd9Sstevel@tonic-gate ASSERT(dmp->b_prev == NULL); 23667c478bd9Sstevel@tonic-gate if (sctp_input_add_ancillary(sctp, 2367bd670b35SErik Nordmark &dmp, dc, fp, ipp, ira) == 0) { 23687c478bd9Sstevel@tonic-gate sctp->sctp_rxqueued -= dlen; 23690f1702c5SYu Xiangning /* 23700f1702c5SYu Xiangning * Override b_flag for SCTP sockfs 23710f1702c5SYu Xiangning * internal use 23720f1702c5SYu Xiangning */ 23730f1702c5SYu Xiangning 23740f1702c5SYu Xiangning dmp->b_flag = 0; 2375*a215d4ebSKacheong Poon if (sctp->sctp_flowctrld) { 2376*a215d4ebSKacheong Poon sctp->sctp_rwnd -= dlen; 2377*a215d4ebSKacheong Poon if (sctp->sctp_rwnd < 0) 2378f0c3911fSGeorge Shepherd sctp->sctp_rwnd = 0; 2379*a215d4ebSKacheong Poon } 2380*a215d4ebSKacheong Poon if (sctp->sctp_ulp_recv( 2381*a215d4ebSKacheong Poon sctp->sctp_ulpd, dmp, msgdsize(dmp), 2382*a215d4ebSKacheong Poon 0, &error, NULL) <= 0) { 2383*a215d4ebSKacheong Poon sctp->sctp_flowctrld = B_TRUE; 2384*a215d4ebSKacheong Poon } 23857c478bd9Sstevel@tonic-gate } else { 23867c478bd9Sstevel@tonic-gate /* 23877c478bd9Sstevel@tonic-gate * We will resume processing when 23887c478bd9Sstevel@tonic-gate * the FTSN chunk is re-xmitted. 23897c478bd9Sstevel@tonic-gate */ 23907c478bd9Sstevel@tonic-gate dmp->b_rptr = (uchar_t *)dc; 23917c478bd9Sstevel@tonic-gate dmp->b_next = next; 23927c478bd9Sstevel@tonic-gate dprint(0, 23937c478bd9Sstevel@tonic-gate ("FTSN dequeuing %u failed\n", 23947c478bd9Sstevel@tonic-gate ntohs(dc->sdh_ssn))); 23957c478bd9Sstevel@tonic-gate return; 23967c478bd9Sstevel@tonic-gate } 23977c478bd9Sstevel@tonic-gate } else { 23987c478bd9Sstevel@tonic-gate sctp->sctp_rxqueued -= dlen; 23997c478bd9Sstevel@tonic-gate ASSERT(dmp->b_prev == NULL); 24007c478bd9Sstevel@tonic-gate dmp->b_next = NULL; 24017c478bd9Sstevel@tonic-gate freemsg(dmp); 24027c478bd9Sstevel@tonic-gate } 24037c478bd9Sstevel@tonic-gate instr->istr_nmsgs--; 24047c478bd9Sstevel@tonic-gate instr->nextseq++; 24057c478bd9Sstevel@tonic-gate sctp->sctp_istr_nmsgs--; 24067c478bd9Sstevel@tonic-gate if (next != NULL) 24077c478bd9Sstevel@tonic-gate next->b_prev = NULL; 24087c478bd9Sstevel@tonic-gate instr->istr_msgs = next; 24097c478bd9Sstevel@tonic-gate } 24107c478bd9Sstevel@tonic-gate ftsn_entry++; 24117c478bd9Sstevel@tonic-gate remaining -= sizeof (*ftsn_entry); 24127c478bd9Sstevel@tonic-gate } 24137c478bd9Sstevel@tonic-gate /* Duplicate FTSN */ 24147c478bd9Sstevel@tonic-gate if (*ftsn <= (sctp->sctp_ftsn - 1)) { 24157c478bd9Sstevel@tonic-gate sctp->sctp_force_sack = 1; 24167c478bd9Sstevel@tonic-gate return; 24177c478bd9Sstevel@tonic-gate } 24187c478bd9Sstevel@tonic-gate /* Advance cum TSN to that reported in the Forward TSN chunk */ 24197c478bd9Sstevel@tonic-gate sctp->sctp_ftsn = *ftsn + 1; 24207c478bd9Sstevel@tonic-gate 24217c478bd9Sstevel@tonic-gate /* Remove all the SACK gaps before the new cum TSN */ 24227c478bd9Sstevel@tonic-gate if (sctp->sctp_sack_info != NULL) { 24237c478bd9Sstevel@tonic-gate sctp_ack_rem(&sctp->sctp_sack_info, sctp->sctp_ftsn - 1, 24247c478bd9Sstevel@tonic-gate &sctp->sctp_sack_gaps); 24257c478bd9Sstevel@tonic-gate } 24267c478bd9Sstevel@tonic-gate /* 24277c478bd9Sstevel@tonic-gate * If there are gap reports pending, check if advancing 24287c478bd9Sstevel@tonic-gate * the ftsn here closes a gap. If so, we can advance 24297c478bd9Sstevel@tonic-gate * ftsn to the end of the set. 24307c478bd9Sstevel@tonic-gate * If ftsn has moved forward, maybe we can remove gap reports. 24317c478bd9Sstevel@tonic-gate */ 24327c478bd9Sstevel@tonic-gate if (sctp->sctp_sack_info != NULL && 24337c478bd9Sstevel@tonic-gate sctp->sctp_ftsn == sctp->sctp_sack_info->begin) { 24347c478bd9Sstevel@tonic-gate sctp->sctp_ftsn = sctp->sctp_sack_info->end + 1; 24357c478bd9Sstevel@tonic-gate sctp_ack_rem(&sctp->sctp_sack_info, sctp->sctp_ftsn - 1, 24367c478bd9Sstevel@tonic-gate &sctp->sctp_sack_gaps); 24377c478bd9Sstevel@tonic-gate } 24387c478bd9Sstevel@tonic-gate } 24397c478bd9Sstevel@tonic-gate 24407c478bd9Sstevel@tonic-gate /* 24417c478bd9Sstevel@tonic-gate * When we have processed a SACK we check to see if we can advance the 24427c478bd9Sstevel@tonic-gate * cumulative TSN if there are abandoned chunks immediately following 24437c478bd9Sstevel@tonic-gate * the updated cumulative TSN. If there are, we attempt to send a 24447c478bd9Sstevel@tonic-gate * Forward TSN chunk. 24457c478bd9Sstevel@tonic-gate */ 24467c478bd9Sstevel@tonic-gate static void 24477c478bd9Sstevel@tonic-gate sctp_check_abandoned_data(sctp_t *sctp, sctp_faddr_t *fp) 24487c478bd9Sstevel@tonic-gate { 24497c478bd9Sstevel@tonic-gate mblk_t *meta = sctp->sctp_xmit_head; 24507c478bd9Sstevel@tonic-gate mblk_t *mp; 24517c478bd9Sstevel@tonic-gate mblk_t *nmp; 24527c478bd9Sstevel@tonic-gate uint32_t seglen; 24537c478bd9Sstevel@tonic-gate uint32_t adv_pap = sctp->sctp_adv_pap; 24547c478bd9Sstevel@tonic-gate 24557c478bd9Sstevel@tonic-gate /* 24567c478bd9Sstevel@tonic-gate * We only check in the first meta since otherwise we can't 24577c478bd9Sstevel@tonic-gate * advance the cumulative ack point. We just look for chunks 24587c478bd9Sstevel@tonic-gate * marked for retransmission, else we might prematurely 24597c478bd9Sstevel@tonic-gate * send an FTSN for a sent, but unacked, chunk. 24607c478bd9Sstevel@tonic-gate */ 24617c478bd9Sstevel@tonic-gate for (mp = meta->b_cont; mp != NULL; mp = mp->b_next) { 24627c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp)) 24637c478bd9Sstevel@tonic-gate return; 24647c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_WANT_REXMIT(mp)) 24657c478bd9Sstevel@tonic-gate break; 24667c478bd9Sstevel@tonic-gate } 24677c478bd9Sstevel@tonic-gate if (mp == NULL) 24687c478bd9Sstevel@tonic-gate return; 24697c478bd9Sstevel@tonic-gate sctp_check_adv_ack_pt(sctp, meta, mp); 24707c478bd9Sstevel@tonic-gate if (SEQ_GT(sctp->sctp_adv_pap, adv_pap)) { 24717c478bd9Sstevel@tonic-gate sctp_make_ftsns(sctp, meta, mp, &nmp, fp, &seglen); 24727c478bd9Sstevel@tonic-gate if (nmp == NULL) { 24737c478bd9Sstevel@tonic-gate sctp->sctp_adv_pap = adv_pap; 24746be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (!fp->sf_timer_running) 24756be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->sf_rto); 24767c478bd9Sstevel@tonic-gate return; 24777c478bd9Sstevel@tonic-gate } 24786be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp_set_iplen(sctp, nmp, fp->sf_ixa); 24796be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India (void) conn_ip_output(nmp, fp->sf_ixa); 2480bd670b35SErik Nordmark BUMP_LOCAL(sctp->sctp_opkts); 24816be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (!fp->sf_timer_running) 24826be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->sf_rto); 24837c478bd9Sstevel@tonic-gate } 24847c478bd9Sstevel@tonic-gate } 24857c478bd9Sstevel@tonic-gate 24861d8c4025Svi117747 /* 24871d8c4025Svi117747 * The processing here follows the same logic in sctp_got_sack(), the reason 24881d8c4025Svi117747 * we do this separately is because, usually, gap blocks are ordered and 24891d8c4025Svi117747 * we can process it in sctp_got_sack(). However if they aren't we would 24901d8c4025Svi117747 * need to do some additional non-optimal stuff when we start processing the 24911d8c4025Svi117747 * unordered gaps. To that effect sctp_got_sack() does the processing in the 24921d8c4025Svi117747 * simple case and this does the same in the more involved case. 24931d8c4025Svi117747 */ 24941d8c4025Svi117747 static uint32_t 24951d8c4025Svi117747 sctp_process_uo_gaps(sctp_t *sctp, uint32_t ctsn, sctp_sack_frag_t *ssf, 24961d8c4025Svi117747 int num_gaps, mblk_t *umphead, mblk_t *mphead, int *trysend, 24971d8c4025Svi117747 boolean_t *fast_recovery, uint32_t fr_xtsn) 24981d8c4025Svi117747 { 24991d8c4025Svi117747 uint32_t xtsn; 25001d8c4025Svi117747 uint32_t gapstart = 0; 25011d8c4025Svi117747 uint32_t gapend = 0; 25021d8c4025Svi117747 int gapcnt; 25031d8c4025Svi117747 uint16_t chunklen; 25041d8c4025Svi117747 sctp_data_hdr_t *sdc; 25051d8c4025Svi117747 int gstart; 25061d8c4025Svi117747 mblk_t *ump = umphead; 25071d8c4025Svi117747 mblk_t *mp = mphead; 25081d8c4025Svi117747 sctp_faddr_t *fp; 25091d8c4025Svi117747 uint32_t acked = 0; 2510f4b3ec61Sdh155122 sctp_stack_t *sctps = sctp->sctp_sctps; 25111d8c4025Svi117747 25121d8c4025Svi117747 /* 25131d8c4025Svi117747 * gstart tracks the last (in the order of TSN) gapstart that 25141d8c4025Svi117747 * we process in this SACK gaps walk. 25151d8c4025Svi117747 */ 25161d8c4025Svi117747 gstart = ctsn; 25171d8c4025Svi117747 25181d8c4025Svi117747 sdc = (sctp_data_hdr_t *)mp->b_rptr; 25191d8c4025Svi117747 xtsn = ntohl(sdc->sdh_tsn); 25201d8c4025Svi117747 for (gapcnt = 0; gapcnt < num_gaps; gapcnt++, ssf++) { 25211d8c4025Svi117747 if (gapstart != 0) { 25221d8c4025Svi117747 /* 25231d8c4025Svi117747 * If we have reached the end of the transmit list or 25241d8c4025Svi117747 * hit an unsent chunk or encountered an unordered gap 25251d8c4025Svi117747 * block start from the ctsn again. 25261d8c4025Svi117747 */ 25271d8c4025Svi117747 if (ump == NULL || !SCTP_CHUNK_ISSENT(mp) || 25281d8c4025Svi117747 SEQ_LT(ctsn + ntohs(ssf->ssf_start), xtsn)) { 25291d8c4025Svi117747 ump = umphead; 25301d8c4025Svi117747 mp = mphead; 25311d8c4025Svi117747 sdc = (sctp_data_hdr_t *)mp->b_rptr; 25321d8c4025Svi117747 xtsn = ntohl(sdc->sdh_tsn); 25331d8c4025Svi117747 } 25341d8c4025Svi117747 } 25351d8c4025Svi117747 25361d8c4025Svi117747 gapstart = ctsn + ntohs(ssf->ssf_start); 25371d8c4025Svi117747 gapend = ctsn + ntohs(ssf->ssf_end); 25381d8c4025Svi117747 25392282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India /* 25402282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India * Sanity checks: 25412282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India * 25422282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India * 1. SACK for TSN we have not sent - ABORT 25432282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India * 2. Invalid or spurious gaps, ignore all gaps 25442282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India */ 25451d8c4025Svi117747 if (SEQ_GT(gapstart, sctp->sctp_ltsn - 1) || 25461d8c4025Svi117747 SEQ_GT(gapend, sctp->sctp_ltsn - 1)) { 25475dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpInAckUnsent); 25481d8c4025Svi117747 *trysend = -1; 25491d8c4025Svi117747 return (acked); 25502282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India } else if (SEQ_LT(gapend, gapstart) || 25512282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India SEQ_LEQ(gapstart, ctsn)) { 25521d8c4025Svi117747 break; 25531d8c4025Svi117747 } 25541d8c4025Svi117747 /* 25551d8c4025Svi117747 * The xtsn can be the TSN processed for the last gap 25561d8c4025Svi117747 * (gapend) or it could be the cumulative TSN. We continue 25571d8c4025Svi117747 * with the last xtsn as long as the gaps are ordered, when 25581d8c4025Svi117747 * we hit an unordered gap, we re-start from the cumulative 25591d8c4025Svi117747 * TSN. For the first gap it is always the cumulative TSN. 25601d8c4025Svi117747 */ 25611d8c4025Svi117747 while (xtsn != gapstart) { 25621d8c4025Svi117747 /* 25631d8c4025Svi117747 * We can't reliably check for reneged chunks 25641d8c4025Svi117747 * when walking the unordered list, so we don't. 25651d8c4025Svi117747 * In case the peer reneges then we will end up 25661d8c4025Svi117747 * sending the reneged chunk via timeout. 25671d8c4025Svi117747 */ 25681d8c4025Svi117747 mp = mp->b_next; 25691d8c4025Svi117747 if (mp == NULL) { 25701d8c4025Svi117747 ump = ump->b_next; 25711d8c4025Svi117747 /* 25721d8c4025Svi117747 * ump can't be NULL because of the sanity 25731d8c4025Svi117747 * check above. 25741d8c4025Svi117747 */ 25751d8c4025Svi117747 ASSERT(ump != NULL); 25761d8c4025Svi117747 mp = ump->b_cont; 25771d8c4025Svi117747 } 25781d8c4025Svi117747 /* 25791d8c4025Svi117747 * mp can't be unsent because of the sanity check 25801d8c4025Svi117747 * above. 25811d8c4025Svi117747 */ 25821d8c4025Svi117747 ASSERT(SCTP_CHUNK_ISSENT(mp)); 25831d8c4025Svi117747 sdc = (sctp_data_hdr_t *)mp->b_rptr; 25841d8c4025Svi117747 xtsn = ntohl(sdc->sdh_tsn); 25851d8c4025Svi117747 } 25861d8c4025Svi117747 /* 25871d8c4025Svi117747 * Now that we have found the chunk with TSN == 'gapstart', 25881d8c4025Svi117747 * let's walk till we hit the chunk with TSN == 'gapend'. 25891d8c4025Svi117747 * All intermediate chunks will be marked ACKED, if they 25901d8c4025Svi117747 * haven't already been. 25911d8c4025Svi117747 */ 25921d8c4025Svi117747 while (SEQ_LEQ(xtsn, gapend)) { 25931d8c4025Svi117747 /* 25941d8c4025Svi117747 * SACKed 25951d8c4025Svi117747 */ 25961d8c4025Svi117747 SCTP_CHUNK_SET_SACKCNT(mp, 0); 25971d8c4025Svi117747 if (!SCTP_CHUNK_ISACKED(mp)) { 25981d8c4025Svi117747 SCTP_CHUNK_ACKED(mp); 25991d8c4025Svi117747 26001d8c4025Svi117747 fp = SCTP_CHUNK_DEST(mp); 26011d8c4025Svi117747 chunklen = ntohs(sdc->sdh_len); 26026be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India ASSERT(fp->sf_suna >= chunklen); 26036be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_suna -= chunklen; 26046be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp->sf_suna == 0) { 26051d8c4025Svi117747 /* All outstanding data acked. */ 26066be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_pba = 0; 26071d8c4025Svi117747 SCTP_FADDR_TIMER_STOP(fp); 26081d8c4025Svi117747 } 26096be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_acked += chunklen; 26101d8c4025Svi117747 acked += chunklen; 26111d8c4025Svi117747 sctp->sctp_unacked -= chunklen - sizeof (*sdc); 26121d8c4025Svi117747 ASSERT(sctp->sctp_unacked >= 0); 26131d8c4025Svi117747 } 26141d8c4025Svi117747 /* 26151d8c4025Svi117747 * Move to the next message in the transmit list 26161d8c4025Svi117747 * if we are done with all the chunks from the current 26171d8c4025Svi117747 * message. Note, it is possible to hit the end of the 26181d8c4025Svi117747 * transmit list here, i.e. if we have already completed 26191d8c4025Svi117747 * processing the gap block. 26201d8c4025Svi117747 */ 26211d8c4025Svi117747 mp = mp->b_next; 26221d8c4025Svi117747 if (mp == NULL) { 26231d8c4025Svi117747 ump = ump->b_next; 26241d8c4025Svi117747 if (ump == NULL) { 26251d8c4025Svi117747 ASSERT(xtsn == gapend); 26261d8c4025Svi117747 break; 26271d8c4025Svi117747 } 26281d8c4025Svi117747 mp = ump->b_cont; 26291d8c4025Svi117747 } 26301d8c4025Svi117747 /* 26311d8c4025Svi117747 * Likewise, we can hit an unsent chunk once we have 26321d8c4025Svi117747 * completed processing the gap block. 26331d8c4025Svi117747 */ 26341d8c4025Svi117747 if (!SCTP_CHUNK_ISSENT(mp)) { 26351d8c4025Svi117747 ASSERT(xtsn == gapend); 26361d8c4025Svi117747 break; 26371d8c4025Svi117747 } 26381d8c4025Svi117747 sdc = (sctp_data_hdr_t *)mp->b_rptr; 26391d8c4025Svi117747 xtsn = ntohl(sdc->sdh_tsn); 26401d8c4025Svi117747 } 26411d8c4025Svi117747 /* 26421d8c4025Svi117747 * We keep track of the last gap we successfully processed 26431d8c4025Svi117747 * so that we can terminate the walk below for incrementing 26441d8c4025Svi117747 * the SACK count. 26451d8c4025Svi117747 */ 26461d8c4025Svi117747 if (SEQ_LT(gstart, gapstart)) 26471d8c4025Svi117747 gstart = gapstart; 26481d8c4025Svi117747 } 26491d8c4025Svi117747 /* 26501d8c4025Svi117747 * Check if have incremented the SACK count for all unacked TSNs in 26511d8c4025Svi117747 * sctp_got_sack(), if so we are done. 26521d8c4025Svi117747 */ 26531d8c4025Svi117747 if (SEQ_LEQ(gstart, fr_xtsn)) 26541d8c4025Svi117747 return (acked); 26551d8c4025Svi117747 26561d8c4025Svi117747 ump = umphead; 26571d8c4025Svi117747 mp = mphead; 26581d8c4025Svi117747 sdc = (sctp_data_hdr_t *)mp->b_rptr; 26591d8c4025Svi117747 xtsn = ntohl(sdc->sdh_tsn); 26601d8c4025Svi117747 while (SEQ_LT(xtsn, gstart)) { 26611d8c4025Svi117747 /* 26621d8c4025Svi117747 * We have incremented SACK count for TSNs less than fr_tsn 26631d8c4025Svi117747 * in sctp_got_sack(), so don't increment them again here. 26641d8c4025Svi117747 */ 26651d8c4025Svi117747 if (SEQ_GT(xtsn, fr_xtsn) && !SCTP_CHUNK_ISACKED(mp)) { 26661d8c4025Svi117747 SCTP_CHUNK_SET_SACKCNT(mp, SCTP_CHUNK_SACKCNT(mp) + 1); 2667f4b3ec61Sdh155122 if (SCTP_CHUNK_SACKCNT(mp) == 2668f4b3ec61Sdh155122 sctps->sctps_fast_rxt_thresh) { 2669c3c17166SGeorge Shepherd SCTP_CHUNK_REXMIT(sctp, mp); 26701d8c4025Svi117747 sctp->sctp_chk_fast_rexmit = B_TRUE; 26711d8c4025Svi117747 *trysend = 1; 26721d8c4025Svi117747 if (!*fast_recovery) { 26731d8c4025Svi117747 /* 26741d8c4025Svi117747 * Entering fast recovery. 26751d8c4025Svi117747 */ 26761d8c4025Svi117747 fp = SCTP_CHUNK_DEST(mp); 26776be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_ssthresh = fp->sf_cwnd / 2; 26786be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp->sf_ssthresh < 2 * fp->sf_pmss) { 26796be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_ssthresh = 26806be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 2 * fp->sf_pmss; 26811d8c4025Svi117747 } 26826be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_cwnd = fp->sf_ssthresh; 26836be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_pba = 0; 26841d8c4025Svi117747 sctp->sctp_recovery_tsn = 26851d8c4025Svi117747 sctp->sctp_ltsn - 1; 26861d8c4025Svi117747 *fast_recovery = B_TRUE; 26871d8c4025Svi117747 } 26881d8c4025Svi117747 } 26891d8c4025Svi117747 } 26901d8c4025Svi117747 mp = mp->b_next; 26911d8c4025Svi117747 if (mp == NULL) { 26921d8c4025Svi117747 ump = ump->b_next; 26931d8c4025Svi117747 /* We can't get to the end of the transmit list here */ 26941d8c4025Svi117747 ASSERT(ump != NULL); 26951d8c4025Svi117747 mp = ump->b_cont; 26961d8c4025Svi117747 } 26971d8c4025Svi117747 /* We can't hit an unsent chunk here */ 26981d8c4025Svi117747 ASSERT(SCTP_CHUNK_ISSENT(mp)); 26991d8c4025Svi117747 sdc = (sctp_data_hdr_t *)mp->b_rptr; 27001d8c4025Svi117747 xtsn = ntohl(sdc->sdh_tsn); 27011d8c4025Svi117747 } 27021d8c4025Svi117747 return (acked); 27031d8c4025Svi117747 } 27041d8c4025Svi117747 27057c478bd9Sstevel@tonic-gate static int 27067c478bd9Sstevel@tonic-gate sctp_got_sack(sctp_t *sctp, sctp_chunk_hdr_t *sch) 27077c478bd9Sstevel@tonic-gate { 27087c478bd9Sstevel@tonic-gate sctp_sack_chunk_t *sc; 27097c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 27107c478bd9Sstevel@tonic-gate sctp_sack_frag_t *ssf; 27117c478bd9Sstevel@tonic-gate mblk_t *ump; 27127c478bd9Sstevel@tonic-gate mblk_t *mp; 27131d8c4025Svi117747 mblk_t *mp1; 27141d8c4025Svi117747 uint32_t cumtsn; 27157c478bd9Sstevel@tonic-gate uint32_t xtsn; 27161d8c4025Svi117747 uint32_t gapstart = 0; 27171d8c4025Svi117747 uint32_t gapend = 0; 27187c478bd9Sstevel@tonic-gate uint32_t acked = 0; 27197c478bd9Sstevel@tonic-gate uint16_t chunklen; 27207c478bd9Sstevel@tonic-gate sctp_faddr_t *fp; 27217c478bd9Sstevel@tonic-gate int num_gaps; 27227c478bd9Sstevel@tonic-gate int trysend = 0; 27237c478bd9Sstevel@tonic-gate int i; 27247c478bd9Sstevel@tonic-gate boolean_t fast_recovery = B_FALSE; 27257c478bd9Sstevel@tonic-gate boolean_t cumack_forward = B_FALSE; 27267c478bd9Sstevel@tonic-gate boolean_t fwd_tsn = B_FALSE; 2727f4b3ec61Sdh155122 sctp_stack_t *sctps = sctp->sctp_sctps; 27287c478bd9Sstevel@tonic-gate 27297c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 27309f13099eSGeorge Shepherd BUMP_LOCAL(sctp->sctp_isacks); 27317c478bd9Sstevel@tonic-gate chunklen = ntohs(sch->sch_len); 27327c478bd9Sstevel@tonic-gate if (chunklen < (sizeof (*sch) + sizeof (*sc))) 27337c478bd9Sstevel@tonic-gate return (0); 27347c478bd9Sstevel@tonic-gate 27357c478bd9Sstevel@tonic-gate sc = (sctp_sack_chunk_t *)(sch + 1); 27361d8c4025Svi117747 cumtsn = ntohl(sc->ssc_cumtsn); 27377c478bd9Sstevel@tonic-gate 27381d8c4025Svi117747 dprint(2, ("got sack cumtsn %x -> %x\n", sctp->sctp_lastack_rxd, 27391d8c4025Svi117747 cumtsn)); 27407c478bd9Sstevel@tonic-gate 27417c478bd9Sstevel@tonic-gate /* out of order */ 27421d8c4025Svi117747 if (SEQ_LT(cumtsn, sctp->sctp_lastack_rxd)) 27437c478bd9Sstevel@tonic-gate return (0); 27447c478bd9Sstevel@tonic-gate 27451d8c4025Svi117747 if (SEQ_GT(cumtsn, sctp->sctp_ltsn - 1)) { 27465dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpInAckUnsent); 27471d8c4025Svi117747 /* Send an ABORT */ 27481d8c4025Svi117747 return (-1); 27497c478bd9Sstevel@tonic-gate } 27507c478bd9Sstevel@tonic-gate 27517c478bd9Sstevel@tonic-gate /* 27527c478bd9Sstevel@tonic-gate * Cwnd only done when not in fast recovery mode. 27537c478bd9Sstevel@tonic-gate */ 27547c478bd9Sstevel@tonic-gate if (SEQ_LT(sctp->sctp_lastack_rxd, sctp->sctp_recovery_tsn)) 27557c478bd9Sstevel@tonic-gate fast_recovery = B_TRUE; 27567c478bd9Sstevel@tonic-gate 27577c478bd9Sstevel@tonic-gate /* 27587c478bd9Sstevel@tonic-gate * .. and if the cum TSN is not moving ahead on account Forward TSN 27597c478bd9Sstevel@tonic-gate */ 27607c478bd9Sstevel@tonic-gate if (SEQ_LT(sctp->sctp_lastack_rxd, sctp->sctp_adv_pap)) 27617c478bd9Sstevel@tonic-gate fwd_tsn = B_TRUE; 27627c478bd9Sstevel@tonic-gate 27631d8c4025Svi117747 if (cumtsn == sctp->sctp_lastack_rxd && 27647c478bd9Sstevel@tonic-gate (sctp->sctp_xmit_unacked == NULL || 27657c478bd9Sstevel@tonic-gate !SCTP_CHUNK_ABANDONED(sctp->sctp_xmit_unacked))) { 27667c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_unacked != NULL) 27677c478bd9Sstevel@tonic-gate mp = sctp->sctp_xmit_unacked; 27687c478bd9Sstevel@tonic-gate else if (sctp->sctp_xmit_head != NULL) 27697c478bd9Sstevel@tonic-gate mp = sctp->sctp_xmit_head->b_cont; 27707c478bd9Sstevel@tonic-gate else 27717c478bd9Sstevel@tonic-gate mp = NULL; 27725dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpInDupAck); 2773769b977dSvi117747 /* 2774769b977dSvi117747 * If we were doing a zero win probe and the win 2775769b977dSvi117747 * has now opened to at least MSS, re-transmit the 2776769b977dSvi117747 * zero win probe via sctp_rexmit_packet(). 2777769b977dSvi117747 */ 2778769b977dSvi117747 if (mp != NULL && sctp->sctp_zero_win_probe && 27796be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India ntohl(sc->ssc_a_rwnd) >= sctp->sctp_current->sf_pmss) { 2780769b977dSvi117747 mblk_t *pkt; 2781769b977dSvi117747 uint_t pkt_len; 2782769b977dSvi117747 mblk_t *mp1 = mp; 2783769b977dSvi117747 mblk_t *meta = sctp->sctp_xmit_head; 2784769b977dSvi117747 2785769b977dSvi117747 /* 2786769b977dSvi117747 * Reset the RTO since we have been backing-off 2787769b977dSvi117747 * to send the ZWP. 2788769b977dSvi117747 */ 2789769b977dSvi117747 fp = sctp->sctp_current; 27906be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_rto = fp->sf_srtt + 4 * fp->sf_rttvar; 27919f13099eSGeorge Shepherd SCTP_MAX_RTO(sctp, fp); 2792769b977dSvi117747 /* Resend the ZWP */ 2793769b977dSvi117747 pkt = sctp_rexmit_packet(sctp, &meta, &mp1, fp, 2794769b977dSvi117747 &pkt_len); 2795769b977dSvi117747 if (pkt == NULL) { 2796f4b3ec61Sdh155122 SCTP_KSTAT(sctps, sctp_ss_rexmit_failed); 2797769b977dSvi117747 return (0); 2798769b977dSvi117747 } 27996be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India ASSERT(pkt_len <= fp->sf_pmss); 2800769b977dSvi117747 sctp->sctp_zero_win_probe = B_FALSE; 2801769b977dSvi117747 sctp->sctp_rxt_nxttsn = sctp->sctp_ltsn; 2802769b977dSvi117747 sctp->sctp_rxt_maxtsn = sctp->sctp_ltsn; 28036be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp_set_iplen(sctp, pkt, fp->sf_ixa); 28046be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India (void) conn_ip_output(pkt, fp->sf_ixa); 2805bd670b35SErik Nordmark BUMP_LOCAL(sctp->sctp_opkts); 2806769b977dSvi117747 } 28077c478bd9Sstevel@tonic-gate } else { 2808769b977dSvi117747 if (sctp->sctp_zero_win_probe) { 2809769b977dSvi117747 /* 2810769b977dSvi117747 * Reset the RTO since we have been backing-off 2811769b977dSvi117747 * to send the ZWP. 2812769b977dSvi117747 */ 2813769b977dSvi117747 fp = sctp->sctp_current; 28146be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_rto = fp->sf_srtt + 4 * fp->sf_rttvar; 28159f13099eSGeorge Shepherd SCTP_MAX_RTO(sctp, fp); 2816769b977dSvi117747 sctp->sctp_zero_win_probe = B_FALSE; 2817769b977dSvi117747 /* This is probably not required */ 2818769b977dSvi117747 if (!sctp->sctp_rexmitting) { 2819769b977dSvi117747 sctp->sctp_rxt_nxttsn = sctp->sctp_ltsn; 2820769b977dSvi117747 sctp->sctp_rxt_maxtsn = sctp->sctp_ltsn; 2821769b977dSvi117747 } 2822769b977dSvi117747 } 28231d8c4025Svi117747 acked = sctp_cumack(sctp, cumtsn, &mp); 28247c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unacked = mp; 28257c478bd9Sstevel@tonic-gate if (acked > 0) { 28267c478bd9Sstevel@tonic-gate trysend = 1; 28277c478bd9Sstevel@tonic-gate cumack_forward = B_TRUE; 28287c478bd9Sstevel@tonic-gate if (fwd_tsn && SEQ_GEQ(sctp->sctp_lastack_rxd, 28297c478bd9Sstevel@tonic-gate sctp->sctp_adv_pap)) { 28307c478bd9Sstevel@tonic-gate cumack_forward = B_FALSE; 28317c478bd9Sstevel@tonic-gate } 28327c478bd9Sstevel@tonic-gate } 28337c478bd9Sstevel@tonic-gate } 28347c478bd9Sstevel@tonic-gate num_gaps = ntohs(sc->ssc_numfrags); 28359f13099eSGeorge Shepherd UPDATE_LOCAL(sctp->sctp_gapcnt, num_gaps); 28367c478bd9Sstevel@tonic-gate if (num_gaps == 0 || mp == NULL || !SCTP_CHUNK_ISSENT(mp) || 28377c478bd9Sstevel@tonic-gate chunklen < (sizeof (*sch) + sizeof (*sc) + 28387c478bd9Sstevel@tonic-gate num_gaps * sizeof (*ssf))) { 28397c478bd9Sstevel@tonic-gate goto ret; 28407c478bd9Sstevel@tonic-gate } 28411d8c4025Svi117747 #ifdef DEBUG 28421d8c4025Svi117747 /* 28431d8c4025Svi117747 * Since we delete any message that has been acked completely, 28441d8c4025Svi117747 * the unacked chunk must belong to sctp_xmit_head (as 28451d8c4025Svi117747 * we don't have a back pointer from the mp to the meta data 28461d8c4025Svi117747 * we do this). 28471d8c4025Svi117747 */ 28481d8c4025Svi117747 { 28491d8c4025Svi117747 mblk_t *mp2 = sctp->sctp_xmit_head->b_cont; 28507c478bd9Sstevel@tonic-gate 28511d8c4025Svi117747 while (mp2 != NULL) { 28521d8c4025Svi117747 if (mp2 == mp) 28531d8c4025Svi117747 break; 28541d8c4025Svi117747 mp2 = mp2->b_next; 28551d8c4025Svi117747 } 28561d8c4025Svi117747 ASSERT(mp2 != NULL); 28571d8c4025Svi117747 } 28581d8c4025Svi117747 #endif 28597c478bd9Sstevel@tonic-gate ump = sctp->sctp_xmit_head; 28607c478bd9Sstevel@tonic-gate 28617c478bd9Sstevel@tonic-gate /* 28621d8c4025Svi117747 * Just remember where we started from, in case we need to call 28631d8c4025Svi117747 * sctp_process_uo_gaps() if the gap blocks are unordered. 28641d8c4025Svi117747 */ 28651d8c4025Svi117747 mp1 = mp; 28661d8c4025Svi117747 28671d8c4025Svi117747 sdc = (sctp_data_hdr_t *)mp->b_rptr; 28681d8c4025Svi117747 xtsn = ntohl(sdc->sdh_tsn); 28691d8c4025Svi117747 ASSERT(xtsn == cumtsn + 1); 28701d8c4025Svi117747 28711d8c4025Svi117747 /* 28727c478bd9Sstevel@tonic-gate * Go through SACK gaps. They are ordered based on start TSN. 28737c478bd9Sstevel@tonic-gate */ 28747c478bd9Sstevel@tonic-gate ssf = (sctp_sack_frag_t *)(sc + 1); 28751d8c4025Svi117747 for (i = 0; i < num_gaps; i++, ssf++) { 28761d8c4025Svi117747 if (gapstart != 0) { 28771d8c4025Svi117747 /* check for unordered gap */ 28781d8c4025Svi117747 if (SEQ_LEQ(cumtsn + ntohs(ssf->ssf_start), gapstart)) { 28791d8c4025Svi117747 acked += sctp_process_uo_gaps(sctp, 28801d8c4025Svi117747 cumtsn, ssf, num_gaps - i, 28811d8c4025Svi117747 sctp->sctp_xmit_head, mp1, 28821d8c4025Svi117747 &trysend, &fast_recovery, gapstart); 28831d8c4025Svi117747 if (trysend < 0) { 28845dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpInAckUnsent); 28851d8c4025Svi117747 return (-1); 28861d8c4025Svi117747 } 28871d8c4025Svi117747 break; 28881d8c4025Svi117747 } 28891d8c4025Svi117747 } 28901d8c4025Svi117747 gapstart = cumtsn + ntohs(ssf->ssf_start); 28911d8c4025Svi117747 gapend = cumtsn + ntohs(ssf->ssf_end); 28927c478bd9Sstevel@tonic-gate 28932282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India /* 28942282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India * Sanity checks: 28952282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India * 28962282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India * 1. SACK for TSN we have not sent - ABORT 28972282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India * 2. Invalid or spurious gaps, ignore all gaps 28982282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India */ 28991d8c4025Svi117747 if (SEQ_GT(gapstart, sctp->sctp_ltsn - 1) || 29001d8c4025Svi117747 SEQ_GT(gapend, sctp->sctp_ltsn - 1)) { 29015dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpInAckUnsent); 29021d8c4025Svi117747 return (-1); 29032282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India } else if (SEQ_LT(gapend, gapstart) || 29042282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India SEQ_LEQ(gapstart, cumtsn)) { 29051d8c4025Svi117747 break; 29061d8c4025Svi117747 } 29071d8c4025Svi117747 /* 29081d8c4025Svi117747 * Let's start at the current TSN (for the 1st gap we start 29091d8c4025Svi117747 * from the cumulative TSN, for subsequent ones we start from 29101d8c4025Svi117747 * where the previous gapend was found - second while loop 29111d8c4025Svi117747 * below) and walk the transmit list till we find the TSN 29121d8c4025Svi117747 * corresponding to gapstart. All the unacked chunks till we 29131d8c4025Svi117747 * get to the chunk with TSN == gapstart will have their 29141d8c4025Svi117747 * SACKCNT incremented by 1. Note since the gap blocks are 29151d8c4025Svi117747 * ordered, we won't be incrementing the SACKCNT for an 29161d8c4025Svi117747 * unacked chunk by more than one while processing the gap 29171d8c4025Svi117747 * blocks. If the SACKCNT for any unacked chunk exceeds 29181d8c4025Svi117747 * the fast retransmit threshold, we will fast retransmit 29191d8c4025Svi117747 * after processing all the gap blocks. 29201d8c4025Svi117747 */ 29212282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India ASSERT(SEQ_LEQ(xtsn, gapstart)); 29227c478bd9Sstevel@tonic-gate while (xtsn != gapstart) { 29237c478bd9Sstevel@tonic-gate SCTP_CHUNK_SET_SACKCNT(mp, SCTP_CHUNK_SACKCNT(mp) + 1); 2924f4b3ec61Sdh155122 if (SCTP_CHUNK_SACKCNT(mp) == 2925f4b3ec61Sdh155122 sctps->sctps_fast_rxt_thresh) { 2926c3c17166SGeorge Shepherd SCTP_CHUNK_REXMIT(sctp, mp); 29277c478bd9Sstevel@tonic-gate sctp->sctp_chk_fast_rexmit = B_TRUE; 29287c478bd9Sstevel@tonic-gate trysend = 1; 29297c478bd9Sstevel@tonic-gate if (!fast_recovery) { 29307c478bd9Sstevel@tonic-gate /* 29317c478bd9Sstevel@tonic-gate * Entering fast recovery. 29327c478bd9Sstevel@tonic-gate */ 29337c478bd9Sstevel@tonic-gate fp = SCTP_CHUNK_DEST(mp); 29346be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_ssthresh = fp->sf_cwnd / 2; 29356be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp->sf_ssthresh < 2 * fp->sf_pmss) { 29366be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_ssthresh = 29376be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 2 * fp->sf_pmss; 29387c478bd9Sstevel@tonic-gate } 29396be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_cwnd = fp->sf_ssthresh; 29406be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_pba = 0; 29417c478bd9Sstevel@tonic-gate sctp->sctp_recovery_tsn = 29427c478bd9Sstevel@tonic-gate sctp->sctp_ltsn - 1; 29437c478bd9Sstevel@tonic-gate fast_recovery = B_TRUE; 29447c478bd9Sstevel@tonic-gate } 29457c478bd9Sstevel@tonic-gate } 29467c478bd9Sstevel@tonic-gate 29477c478bd9Sstevel@tonic-gate /* 29487c478bd9Sstevel@tonic-gate * Peer may have reneged on this chunk, so un-sack 29497c478bd9Sstevel@tonic-gate * it now. If the peer did renege, we need to 29507c478bd9Sstevel@tonic-gate * readjust unacked. 29517c478bd9Sstevel@tonic-gate */ 29527c478bd9Sstevel@tonic-gate if (SCTP_CHUNK_ISACKED(mp)) { 29537c478bd9Sstevel@tonic-gate chunklen = ntohs(sdc->sdh_len); 29547c478bd9Sstevel@tonic-gate fp = SCTP_CHUNK_DEST(mp); 29556be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_suna += chunklen; 29567c478bd9Sstevel@tonic-gate sctp->sctp_unacked += chunklen - sizeof (*sdc); 2957c3c17166SGeorge Shepherd SCTP_CHUNK_CLEAR_ACKED(sctp, mp); 29586be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (!fp->sf_timer_running) { 29597c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, fp, 29606be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_rto); 29617c478bd9Sstevel@tonic-gate } 29627c478bd9Sstevel@tonic-gate } 29637c478bd9Sstevel@tonic-gate 29647c478bd9Sstevel@tonic-gate mp = mp->b_next; 29657c478bd9Sstevel@tonic-gate if (mp == NULL) { 29667c478bd9Sstevel@tonic-gate ump = ump->b_next; 29671d8c4025Svi117747 /* 29681d8c4025Svi117747 * ump can't be NULL given the sanity check 29692282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India * above. But if it is NULL, it means that 29702282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India * there is a data corruption. We'd better 29712282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India * panic. 29721d8c4025Svi117747 */ 29732282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (ump == NULL) { 29742282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India panic("Memory corruption detected: gap " 29752282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India "start TSN 0x%x missing from the " 29762282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India "xmit list: %p", gapstart, 29772282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India (void *)sctp); 29782282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India } 29797c478bd9Sstevel@tonic-gate mp = ump->b_cont; 29807c478bd9Sstevel@tonic-gate } 29811d8c4025Svi117747 /* 29821d8c4025Svi117747 * mp can't be unsent given the sanity check above. 29831d8c4025Svi117747 */ 29841d8c4025Svi117747 ASSERT(SCTP_CHUNK_ISSENT(mp)); 29857c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 29867c478bd9Sstevel@tonic-gate xtsn = ntohl(sdc->sdh_tsn); 29877c478bd9Sstevel@tonic-gate } 29881d8c4025Svi117747 /* 29891d8c4025Svi117747 * Now that we have found the chunk with TSN == 'gapstart', 29901d8c4025Svi117747 * let's walk till we hit the chunk with TSN == 'gapend'. 29911d8c4025Svi117747 * All intermediate chunks will be marked ACKED, if they 29921d8c4025Svi117747 * haven't already been. 29931d8c4025Svi117747 */ 29947c478bd9Sstevel@tonic-gate while (SEQ_LEQ(xtsn, gapend)) { 29957c478bd9Sstevel@tonic-gate /* 29967c478bd9Sstevel@tonic-gate * SACKed 29977c478bd9Sstevel@tonic-gate */ 29987c478bd9Sstevel@tonic-gate SCTP_CHUNK_SET_SACKCNT(mp, 0); 29997c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISACKED(mp)) { 30007c478bd9Sstevel@tonic-gate SCTP_CHUNK_ACKED(mp); 30017c478bd9Sstevel@tonic-gate 30027c478bd9Sstevel@tonic-gate fp = SCTP_CHUNK_DEST(mp); 30037c478bd9Sstevel@tonic-gate chunklen = ntohs(sdc->sdh_len); 30046be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India ASSERT(fp->sf_suna >= chunklen); 30056be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_suna -= chunklen; 30066be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp->sf_suna == 0) { 30077c478bd9Sstevel@tonic-gate /* All outstanding data acked. */ 30086be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_pba = 0; 30097c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_STOP(fp); 30107c478bd9Sstevel@tonic-gate } 30116be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_acked += chunklen; 30127c478bd9Sstevel@tonic-gate acked += chunklen; 30137c478bd9Sstevel@tonic-gate sctp->sctp_unacked -= chunklen - sizeof (*sdc); 30147c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_unacked >= 0); 30157c478bd9Sstevel@tonic-gate } 30161d8c4025Svi117747 /* Go to the next chunk of the current message */ 30177c478bd9Sstevel@tonic-gate mp = mp->b_next; 30181d8c4025Svi117747 /* 30191d8c4025Svi117747 * Move to the next message in the transmit list 30201d8c4025Svi117747 * if we are done with all the chunks from the current 30211d8c4025Svi117747 * message. Note, it is possible to hit the end of the 30221d8c4025Svi117747 * transmit list here, i.e. if we have already completed 30232282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India * processing the gap block. But the TSN must be equal 30242282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India * to the gapend because of the above sanity check. 30252282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India * If it is not equal, it means that some data is 30262282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India * missing. 30271d8c4025Svi117747 * Also, note that we break here, which means we 30281d8c4025Svi117747 * continue processing gap blocks, if any. In case of 30291d8c4025Svi117747 * ordered gap blocks there can't be any following 30301d8c4025Svi117747 * this (if there is it will fail the sanity check 30311d8c4025Svi117747 * above). In case of un-ordered gap blocks we will 30321d8c4025Svi117747 * switch to sctp_process_uo_gaps(). In either case 30331d8c4025Svi117747 * it should be fine to continue with NULL ump/mp, 30341d8c4025Svi117747 * but we just reset it to xmit_head. 30351d8c4025Svi117747 */ 30367c478bd9Sstevel@tonic-gate if (mp == NULL) { 30377c478bd9Sstevel@tonic-gate ump = ump->b_next; 30387c478bd9Sstevel@tonic-gate if (ump == NULL) { 30392282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (xtsn != gapend) { 30402282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India panic("Memory corruption " 30412282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India "detected: gap end TSN " 30422282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India "0x%x missing from the " 30432282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India "xmit list: %p", gapend, 30442282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India (void *)sctp); 30452282c4abSchandrasekar marimuthu - Sun Microsystems - Bangalore India } 30461d8c4025Svi117747 ump = sctp->sctp_xmit_head; 30471d8c4025Svi117747 mp = mp1; 30481d8c4025Svi117747 sdc = (sctp_data_hdr_t *)mp->b_rptr; 30491d8c4025Svi117747 xtsn = ntohl(sdc->sdh_tsn); 30501d8c4025Svi117747 break; 30517c478bd9Sstevel@tonic-gate } 30527c478bd9Sstevel@tonic-gate mp = ump->b_cont; 30537c478bd9Sstevel@tonic-gate } 30541d8c4025Svi117747 /* 30551d8c4025Svi117747 * Likewise, we could hit an unsent chunk once we have 30561d8c4025Svi117747 * completed processing the gap block. Again, it is 30571d8c4025Svi117747 * fine to continue processing gap blocks with mp 30581d8c4025Svi117747 * pointing to the unsent chunk, because if there 30591d8c4025Svi117747 * are more ordered gap blocks, they will fail the 30601d8c4025Svi117747 * sanity check, and if there are un-ordered gap blocks, 30611d8c4025Svi117747 * we will continue processing in sctp_process_uo_gaps() 30621d8c4025Svi117747 * We just reset the mp to the one we started with. 30631d8c4025Svi117747 */ 30647c478bd9Sstevel@tonic-gate if (!SCTP_CHUNK_ISSENT(mp)) { 30651d8c4025Svi117747 ASSERT(xtsn == gapend); 30661d8c4025Svi117747 ump = sctp->sctp_xmit_head; 30671d8c4025Svi117747 mp = mp1; 30681d8c4025Svi117747 sdc = (sctp_data_hdr_t *)mp->b_rptr; 30691d8c4025Svi117747 xtsn = ntohl(sdc->sdh_tsn); 30701d8c4025Svi117747 break; 30717c478bd9Sstevel@tonic-gate } 30727c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 30737c478bd9Sstevel@tonic-gate xtsn = ntohl(sdc->sdh_tsn); 30747c478bd9Sstevel@tonic-gate } 30757c478bd9Sstevel@tonic-gate } 30767c478bd9Sstevel@tonic-gate if (sctp->sctp_prsctp_aware) 30777c478bd9Sstevel@tonic-gate sctp_check_abandoned_data(sctp, sctp->sctp_current); 30787c478bd9Sstevel@tonic-gate if (sctp->sctp_chk_fast_rexmit) 30797c478bd9Sstevel@tonic-gate sctp_fast_rexmit(sctp); 30807c478bd9Sstevel@tonic-gate ret: 30817c478bd9Sstevel@tonic-gate trysend += sctp_set_frwnd(sctp, ntohl(sc->ssc_a_rwnd)); 30827c478bd9Sstevel@tonic-gate 30837c478bd9Sstevel@tonic-gate /* 30847c478bd9Sstevel@tonic-gate * If receive window is closed while there is unsent data, 30857c478bd9Sstevel@tonic-gate * set a timer for doing zero window probes. 30867c478bd9Sstevel@tonic-gate */ 30877c478bd9Sstevel@tonic-gate if (sctp->sctp_frwnd == 0 && sctp->sctp_unacked == 0 && 30887c478bd9Sstevel@tonic-gate sctp->sctp_unsent != 0) { 30897c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, sctp->sctp_current, 30906be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp->sctp_current->sf_rto); 30917c478bd9Sstevel@tonic-gate } 30927c478bd9Sstevel@tonic-gate 30937c478bd9Sstevel@tonic-gate /* 30947c478bd9Sstevel@tonic-gate * Set cwnd for all destinations. 30957c478bd9Sstevel@tonic-gate * Congestion window gets increased only when cumulative 30967c478bd9Sstevel@tonic-gate * TSN moves forward, we're not in fast recovery, and 30977c478bd9Sstevel@tonic-gate * cwnd has been fully utilized (almost fully, need to allow 30987c478bd9Sstevel@tonic-gate * some leeway due to non-MSS sized messages). 30997c478bd9Sstevel@tonic-gate */ 31006be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (sctp->sctp_current->sf_acked == acked) { 31017c478bd9Sstevel@tonic-gate /* 31027c478bd9Sstevel@tonic-gate * Fast-path, only data sent to sctp_current got acked. 31037c478bd9Sstevel@tonic-gate */ 31047c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 31057c478bd9Sstevel@tonic-gate if (cumack_forward && !fast_recovery && 31066be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India (fp->sf_acked + fp->sf_suna > fp->sf_cwnd - fp->sf_pmss)) { 31076be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp->sf_cwnd < fp->sf_ssthresh) { 31087c478bd9Sstevel@tonic-gate /* 31097c478bd9Sstevel@tonic-gate * Slow start 31107c478bd9Sstevel@tonic-gate */ 31116be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp->sf_acked > fp->sf_pmss) { 31126be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_cwnd += fp->sf_pmss; 31137c478bd9Sstevel@tonic-gate } else { 31146be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_cwnd += fp->sf_acked; 31157c478bd9Sstevel@tonic-gate } 31166be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_cwnd = MIN(fp->sf_cwnd, 31176be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp->sctp_cwnd_max); 31187c478bd9Sstevel@tonic-gate } else { 31197c478bd9Sstevel@tonic-gate /* 31207c478bd9Sstevel@tonic-gate * Congestion avoidance 31217c478bd9Sstevel@tonic-gate */ 31226be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_pba += fp->sf_acked; 31236be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp->sf_pba >= fp->sf_cwnd) { 31246be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_pba -= fp->sf_cwnd; 31256be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_cwnd += fp->sf_pmss; 31266be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_cwnd = MIN(fp->sf_cwnd, 31277c478bd9Sstevel@tonic-gate sctp->sctp_cwnd_max); 31287c478bd9Sstevel@tonic-gate } 31297c478bd9Sstevel@tonic-gate } 31307c478bd9Sstevel@tonic-gate } 31317c478bd9Sstevel@tonic-gate /* 31327c478bd9Sstevel@tonic-gate * Limit the burst of transmitted data segments. 31337c478bd9Sstevel@tonic-gate */ 31346be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp->sf_suna + sctps->sctps_maxburst * fp->sf_pmss < 31356be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_cwnd) { 31366be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_cwnd = fp->sf_suna + sctps->sctps_maxburst * 31376be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_pmss; 31387c478bd9Sstevel@tonic-gate } 31396be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_acked = 0; 314077c67f2fSkcpoon goto check_ss_rxmit; 31417c478bd9Sstevel@tonic-gate } 31426be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->sf_next) { 31436be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (cumack_forward && fp->sf_acked && !fast_recovery && 31446be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India (fp->sf_acked + fp->sf_suna > fp->sf_cwnd - fp->sf_pmss)) { 31456be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp->sf_cwnd < fp->sf_ssthresh) { 31466be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp->sf_acked > fp->sf_pmss) { 31476be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_cwnd += fp->sf_pmss; 31487c478bd9Sstevel@tonic-gate } else { 31496be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_cwnd += fp->sf_acked; 31507c478bd9Sstevel@tonic-gate } 31516be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_cwnd = MIN(fp->sf_cwnd, 31526be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp->sctp_cwnd_max); 31537c478bd9Sstevel@tonic-gate } else { 31546be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_pba += fp->sf_acked; 31556be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp->sf_pba >= fp->sf_cwnd) { 31566be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_pba -= fp->sf_cwnd; 31576be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_cwnd += fp->sf_pmss; 31586be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_cwnd = MIN(fp->sf_cwnd, 31597c478bd9Sstevel@tonic-gate sctp->sctp_cwnd_max); 31607c478bd9Sstevel@tonic-gate } 31617c478bd9Sstevel@tonic-gate } 31627c478bd9Sstevel@tonic-gate } 31636be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp->sf_suna + sctps->sctps_maxburst * fp->sf_pmss < 31646be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_cwnd) { 31656be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_cwnd = fp->sf_suna + sctps->sctps_maxburst * 31666be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_pmss; 31677c478bd9Sstevel@tonic-gate } 31686be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_acked = 0; 31697c478bd9Sstevel@tonic-gate } 31701d19ca10Svi117747 fp = sctp->sctp_current; 317177c67f2fSkcpoon check_ss_rxmit: 317277c67f2fSkcpoon /* 317377c67f2fSkcpoon * If this is a SACK following a timeout, check if there are 317477c67f2fSkcpoon * still unacked chunks (sent before the timeout) that we can 317577c67f2fSkcpoon * send. 317677c67f2fSkcpoon */ 317777c67f2fSkcpoon if (sctp->sctp_rexmitting) { 317877c67f2fSkcpoon if (SEQ_LT(sctp->sctp_lastack_rxd, sctp->sctp_rxt_maxtsn)) { 317977c67f2fSkcpoon /* 318077c67f2fSkcpoon * As we are in retransmission phase, we may get a 318177c67f2fSkcpoon * SACK which indicates some new chunks are received 318277c67f2fSkcpoon * but cum_tsn does not advance. During this 318377c67f2fSkcpoon * phase, the other side advances cum_tsn only because 318477c67f2fSkcpoon * it receives our retransmitted chunks. Only 318577c67f2fSkcpoon * this signals that some chunks are still 318677c67f2fSkcpoon * missing. 318777c67f2fSkcpoon */ 318812f47623Skcpoon if (cumack_forward) { 31896be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_rxt_unacked -= acked; 319077c67f2fSkcpoon sctp_ss_rexmit(sctp); 319112f47623Skcpoon } 319277c67f2fSkcpoon } else { 319377c67f2fSkcpoon sctp->sctp_rexmitting = B_FALSE; 319477c67f2fSkcpoon sctp->sctp_rxt_nxttsn = sctp->sctp_ltsn; 319577c67f2fSkcpoon sctp->sctp_rxt_maxtsn = sctp->sctp_ltsn; 31966be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_rxt_unacked = 0; 319777c67f2fSkcpoon } 319877c67f2fSkcpoon } 31997c478bd9Sstevel@tonic-gate return (trysend); 32007c478bd9Sstevel@tonic-gate } 32017c478bd9Sstevel@tonic-gate 32027c478bd9Sstevel@tonic-gate /* 32037c478bd9Sstevel@tonic-gate * Returns 0 if the caller should stop processing any more chunks, 32047c478bd9Sstevel@tonic-gate * 1 if the caller should skip this chunk and continue processing. 32057c478bd9Sstevel@tonic-gate */ 32067c478bd9Sstevel@tonic-gate static int 32077c478bd9Sstevel@tonic-gate sctp_strange_chunk(sctp_t *sctp, sctp_chunk_hdr_t *ch, sctp_faddr_t *fp) 32087c478bd9Sstevel@tonic-gate { 32097c478bd9Sstevel@tonic-gate size_t len; 32107c478bd9Sstevel@tonic-gate 32117c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 32127c478bd9Sstevel@tonic-gate /* check top two bits for action required */ 32137c478bd9Sstevel@tonic-gate if (ch->sch_id & 0x40) { /* also matches 0xc0 */ 32147c478bd9Sstevel@tonic-gate len = ntohs(ch->sch_len); 32157f093707Skcpoon sctp_add_err(sctp, SCTP_ERR_UNREC_CHUNK, ch, len, fp); 32167f093707Skcpoon 32177c478bd9Sstevel@tonic-gate if ((ch->sch_id & 0xc0) == 0xc0) { 32187c478bd9Sstevel@tonic-gate /* skip and continue */ 32197c478bd9Sstevel@tonic-gate return (1); 32207c478bd9Sstevel@tonic-gate } else { 32217c478bd9Sstevel@tonic-gate /* stop processing */ 32227c478bd9Sstevel@tonic-gate return (0); 32237c478bd9Sstevel@tonic-gate } 32247c478bd9Sstevel@tonic-gate } 32257c478bd9Sstevel@tonic-gate if (ch->sch_id & 0x80) { 32267c478bd9Sstevel@tonic-gate /* skip and continue, no error */ 32277c478bd9Sstevel@tonic-gate return (1); 32287c478bd9Sstevel@tonic-gate } 32297c478bd9Sstevel@tonic-gate /* top two bits are clear; stop processing and no error */ 32307c478bd9Sstevel@tonic-gate return (0); 32317c478bd9Sstevel@tonic-gate } 32327c478bd9Sstevel@tonic-gate 32337c478bd9Sstevel@tonic-gate /* 32347c478bd9Sstevel@tonic-gate * Basic sanity checks on all input chunks and parameters: they must 32357c478bd9Sstevel@tonic-gate * be of legitimate size for their purported type, and must follow 32367c478bd9Sstevel@tonic-gate * ordering conventions as defined in rfc2960. 32377c478bd9Sstevel@tonic-gate * 32387c478bd9Sstevel@tonic-gate * Returns 1 if the chunk and all encloded params are legitimate, 32397c478bd9Sstevel@tonic-gate * 0 otherwise. 32407c478bd9Sstevel@tonic-gate */ 32417c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 32427c478bd9Sstevel@tonic-gate static int 32437c478bd9Sstevel@tonic-gate sctp_check_input(sctp_t *sctp, sctp_chunk_hdr_t *ch, ssize_t len, int first) 32447c478bd9Sstevel@tonic-gate { 32457c478bd9Sstevel@tonic-gate sctp_parm_hdr_t *ph; 32467c478bd9Sstevel@tonic-gate void *p = NULL; 32477c478bd9Sstevel@tonic-gate ssize_t clen; 32487c478bd9Sstevel@tonic-gate uint16_t ch_len; 32497c478bd9Sstevel@tonic-gate 32507c478bd9Sstevel@tonic-gate ch_len = ntohs(ch->sch_len); 32517c478bd9Sstevel@tonic-gate if (ch_len > len) { 32527c478bd9Sstevel@tonic-gate return (0); 32537c478bd9Sstevel@tonic-gate } 32547c478bd9Sstevel@tonic-gate 32557c478bd9Sstevel@tonic-gate switch (ch->sch_id) { 32567c478bd9Sstevel@tonic-gate case CHUNK_DATA: 32577c478bd9Sstevel@tonic-gate if (ch_len < sizeof (sctp_data_hdr_t)) { 32587c478bd9Sstevel@tonic-gate return (0); 32597c478bd9Sstevel@tonic-gate } 32607c478bd9Sstevel@tonic-gate return (1); 32617c478bd9Sstevel@tonic-gate case CHUNK_INIT: 32627c478bd9Sstevel@tonic-gate case CHUNK_INIT_ACK: 32637c478bd9Sstevel@tonic-gate { 32647c478bd9Sstevel@tonic-gate ssize_t remlen = len; 32657c478bd9Sstevel@tonic-gate 32667c478bd9Sstevel@tonic-gate /* 32677c478bd9Sstevel@tonic-gate * INIT and INIT-ACK chunks must not be bundled with 32687c478bd9Sstevel@tonic-gate * any other. 32697c478bd9Sstevel@tonic-gate */ 32707c478bd9Sstevel@tonic-gate if (!first || sctp_next_chunk(ch, &remlen) != NULL || 32717c478bd9Sstevel@tonic-gate (ch_len < (sizeof (*ch) + 32727c478bd9Sstevel@tonic-gate sizeof (sctp_init_chunk_t)))) { 32737c478bd9Sstevel@tonic-gate return (0); 32747c478bd9Sstevel@tonic-gate } 32757c478bd9Sstevel@tonic-gate /* may have params that need checking */ 32767c478bd9Sstevel@tonic-gate p = (char *)(ch + 1) + sizeof (sctp_init_chunk_t); 32777c478bd9Sstevel@tonic-gate clen = ch_len - (sizeof (*ch) + 32787c478bd9Sstevel@tonic-gate sizeof (sctp_init_chunk_t)); 32797c478bd9Sstevel@tonic-gate } 32807c478bd9Sstevel@tonic-gate break; 32817c478bd9Sstevel@tonic-gate case CHUNK_SACK: 32827c478bd9Sstevel@tonic-gate if (ch_len < (sizeof (*ch) + sizeof (sctp_sack_chunk_t))) { 32837c478bd9Sstevel@tonic-gate return (0); 32847c478bd9Sstevel@tonic-gate } 32857c478bd9Sstevel@tonic-gate /* dup and gap reports checked by got_sack() */ 32867c478bd9Sstevel@tonic-gate return (1); 32877c478bd9Sstevel@tonic-gate case CHUNK_SHUTDOWN: 32887c478bd9Sstevel@tonic-gate if (ch_len < (sizeof (*ch) + sizeof (uint32_t))) { 32897c478bd9Sstevel@tonic-gate return (0); 32907c478bd9Sstevel@tonic-gate } 32917c478bd9Sstevel@tonic-gate return (1); 32927c478bd9Sstevel@tonic-gate case CHUNK_ABORT: 32937c478bd9Sstevel@tonic-gate case CHUNK_ERROR: 32947c478bd9Sstevel@tonic-gate if (ch_len < sizeof (*ch)) { 32957c478bd9Sstevel@tonic-gate return (0); 32967c478bd9Sstevel@tonic-gate } 32977c478bd9Sstevel@tonic-gate /* may have params that need checking */ 32987c478bd9Sstevel@tonic-gate p = ch + 1; 32997c478bd9Sstevel@tonic-gate clen = ch_len - sizeof (*ch); 33007c478bd9Sstevel@tonic-gate break; 33017c478bd9Sstevel@tonic-gate case CHUNK_ECNE: 33027c478bd9Sstevel@tonic-gate case CHUNK_CWR: 33037c478bd9Sstevel@tonic-gate case CHUNK_HEARTBEAT: 33047c478bd9Sstevel@tonic-gate case CHUNK_HEARTBEAT_ACK: 33057c478bd9Sstevel@tonic-gate /* Full ASCONF chunk and parameter checks are in asconf.c */ 33067c478bd9Sstevel@tonic-gate case CHUNK_ASCONF: 33077c478bd9Sstevel@tonic-gate case CHUNK_ASCONF_ACK: 33087c478bd9Sstevel@tonic-gate if (ch_len < sizeof (*ch)) { 33097c478bd9Sstevel@tonic-gate return (0); 33107c478bd9Sstevel@tonic-gate } 33117c478bd9Sstevel@tonic-gate /* heartbeat data checked by process_heartbeat() */ 33127c478bd9Sstevel@tonic-gate return (1); 33137c478bd9Sstevel@tonic-gate case CHUNK_SHUTDOWN_COMPLETE: 33147c478bd9Sstevel@tonic-gate { 33157c478bd9Sstevel@tonic-gate ssize_t remlen = len; 33167c478bd9Sstevel@tonic-gate 33177c478bd9Sstevel@tonic-gate /* 33187c478bd9Sstevel@tonic-gate * SHUTDOWN-COMPLETE chunk must not be bundled with any 33197c478bd9Sstevel@tonic-gate * other 33207c478bd9Sstevel@tonic-gate */ 33217c478bd9Sstevel@tonic-gate if (!first || sctp_next_chunk(ch, &remlen) != NULL || 33227c478bd9Sstevel@tonic-gate ch_len < sizeof (*ch)) { 33237c478bd9Sstevel@tonic-gate return (0); 33247c478bd9Sstevel@tonic-gate } 33257c478bd9Sstevel@tonic-gate } 33267c478bd9Sstevel@tonic-gate return (1); 33277c478bd9Sstevel@tonic-gate case CHUNK_COOKIE: 33287c478bd9Sstevel@tonic-gate case CHUNK_COOKIE_ACK: 33297c478bd9Sstevel@tonic-gate case CHUNK_SHUTDOWN_ACK: 33307c478bd9Sstevel@tonic-gate if (ch_len < sizeof (*ch) || !first) { 33317c478bd9Sstevel@tonic-gate return (0); 33327c478bd9Sstevel@tonic-gate } 33337c478bd9Sstevel@tonic-gate return (1); 33347c478bd9Sstevel@tonic-gate case CHUNK_FORWARD_TSN: 33357c478bd9Sstevel@tonic-gate if (ch_len < (sizeof (*ch) + sizeof (uint32_t))) 33367c478bd9Sstevel@tonic-gate return (0); 33377c478bd9Sstevel@tonic-gate return (1); 33387c478bd9Sstevel@tonic-gate default: 33397c478bd9Sstevel@tonic-gate return (1); /* handled by strange_chunk() */ 33407c478bd9Sstevel@tonic-gate } 33417c478bd9Sstevel@tonic-gate 33427c478bd9Sstevel@tonic-gate /* check and byteorder parameters */ 33437c478bd9Sstevel@tonic-gate if (clen <= 0) { 33447c478bd9Sstevel@tonic-gate return (1); 33457c478bd9Sstevel@tonic-gate } 33467c478bd9Sstevel@tonic-gate ASSERT(p != NULL); 33477c478bd9Sstevel@tonic-gate 33487c478bd9Sstevel@tonic-gate ph = p; 33497c478bd9Sstevel@tonic-gate while (ph != NULL && clen > 0) { 33507c478bd9Sstevel@tonic-gate ch_len = ntohs(ph->sph_len); 33517c478bd9Sstevel@tonic-gate if (ch_len > len || ch_len < sizeof (*ph)) { 33527c478bd9Sstevel@tonic-gate return (0); 33537c478bd9Sstevel@tonic-gate } 33547c478bd9Sstevel@tonic-gate ph = sctp_next_parm(ph, &clen); 33557c478bd9Sstevel@tonic-gate } 33567c478bd9Sstevel@tonic-gate 33577c478bd9Sstevel@tonic-gate /* All OK */ 33587c478bd9Sstevel@tonic-gate return (1); 33597c478bd9Sstevel@tonic-gate } 33607c478bd9Sstevel@tonic-gate 33617c478bd9Sstevel@tonic-gate static mblk_t * 3362bd670b35SErik Nordmark sctp_check_in_policy(mblk_t *mp, ip_recv_attr_t *ira, ip_stack_t *ipst) 33637c478bd9Sstevel@tonic-gate { 33647c478bd9Sstevel@tonic-gate boolean_t policy_present; 33657c478bd9Sstevel@tonic-gate ipha_t *ipha; 33667c478bd9Sstevel@tonic-gate ip6_t *ip6h; 3367bd670b35SErik Nordmark netstack_t *ns = ipst->ips_netstack; 3368bd670b35SErik Nordmark ipsec_stack_t *ipss = ns->netstack_ipsec; 33697c478bd9Sstevel@tonic-gate 33707c478bd9Sstevel@tonic-gate if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) { 3371f4b3ec61Sdh155122 policy_present = ipss->ipsec_inbound_v4_policy_present; 33727c478bd9Sstevel@tonic-gate ipha = (ipha_t *)mp->b_rptr; 33737c478bd9Sstevel@tonic-gate ip6h = NULL; 33747c478bd9Sstevel@tonic-gate } else { 3375f4b3ec61Sdh155122 policy_present = ipss->ipsec_inbound_v6_policy_present; 33767c478bd9Sstevel@tonic-gate ipha = NULL; 33777c478bd9Sstevel@tonic-gate ip6h = (ip6_t *)mp->b_rptr; 33787c478bd9Sstevel@tonic-gate } 33797c478bd9Sstevel@tonic-gate 3380bd670b35SErik Nordmark if (policy_present) { 33817c478bd9Sstevel@tonic-gate /* 33827c478bd9Sstevel@tonic-gate * The conn_t parameter is NULL because we already know 33837c478bd9Sstevel@tonic-gate * nobody's home. 33847c478bd9Sstevel@tonic-gate */ 3385bd670b35SErik Nordmark mp = ipsec_check_global_policy(mp, (conn_t *)NULL, 3386bd670b35SErik Nordmark ipha, ip6h, ira, ns); 3387bd670b35SErik Nordmark if (mp == NULL) 33887c478bd9Sstevel@tonic-gate return (NULL); 33897c478bd9Sstevel@tonic-gate } 33907c478bd9Sstevel@tonic-gate return (mp); 33917c478bd9Sstevel@tonic-gate } 33927c478bd9Sstevel@tonic-gate 33937c478bd9Sstevel@tonic-gate /* Handle out-of-the-blue packets */ 33947c478bd9Sstevel@tonic-gate void 3395bd670b35SErik Nordmark sctp_ootb_input(mblk_t *mp, ip_recv_attr_t *ira, ip_stack_t *ipst) 33967c478bd9Sstevel@tonic-gate { 33977c478bd9Sstevel@tonic-gate sctp_t *sctp; 33987c478bd9Sstevel@tonic-gate sctp_chunk_hdr_t *ch; 33997c478bd9Sstevel@tonic-gate sctp_hdr_t *sctph; 34007c478bd9Sstevel@tonic-gate in6_addr_t src, dst; 3401bd670b35SErik Nordmark uint_t ip_hdr_len = ira->ira_ip_hdr_length; 34027c478bd9Sstevel@tonic-gate ssize_t mlen; 3403f4b3ec61Sdh155122 sctp_stack_t *sctps; 3404bd670b35SErik Nordmark boolean_t secure; 3405bd670b35SErik Nordmark zoneid_t zoneid = ira->ira_zoneid; 3406bd670b35SErik Nordmark uchar_t *rptr; 34077c478bd9Sstevel@tonic-gate 3408bd670b35SErik Nordmark ASSERT(ira->ira_ill == NULL); 3409bd670b35SErik Nordmark 3410bd670b35SErik Nordmark secure = ira->ira_flags & IRAF_IPSEC_SECURE; 3411bd670b35SErik Nordmark 3412f4b3ec61Sdh155122 sctps = ipst->ips_netstack->netstack_sctp; 3413f4b3ec61Sdh155122 34145dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpOutOfBlue); 34155dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpInSCTPPkts); 3416f4b3ec61Sdh155122 34177c478bd9Sstevel@tonic-gate if (mp->b_cont != NULL) { 34187c478bd9Sstevel@tonic-gate /* 34197c478bd9Sstevel@tonic-gate * All subsequent code is vastly simplified if it can 34207c478bd9Sstevel@tonic-gate * assume a single contiguous chunk of data. 34217c478bd9Sstevel@tonic-gate */ 34227c478bd9Sstevel@tonic-gate if (pullupmsg(mp, -1) == 0) { 3423bd670b35SErik Nordmark BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsInDiscards); 3424bd670b35SErik Nordmark ip_drop_input("ipIfStatsInDiscards", mp, NULL); 3425bd670b35SErik Nordmark freemsg(mp); 34267c478bd9Sstevel@tonic-gate return; 34277c478bd9Sstevel@tonic-gate } 34287c478bd9Sstevel@tonic-gate } 34297c478bd9Sstevel@tonic-gate 3430bd670b35SErik Nordmark rptr = mp->b_rptr; 3431bd670b35SErik Nordmark sctph = ((sctp_hdr_t *)&rptr[ip_hdr_len]); 3432bd670b35SErik Nordmark if (ira->ira_flags & IRAF_IS_IPV4) { 3433bd670b35SErik Nordmark ipha_t *ipha; 3434bd670b35SErik Nordmark 3435bd670b35SErik Nordmark ipha = (ipha_t *)rptr; 3436bd670b35SErik Nordmark IN6_IPADDR_TO_V4MAPPED(ipha->ipha_src, &src); 3437bd670b35SErik Nordmark IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &dst); 3438bd670b35SErik Nordmark } else { 3439bd670b35SErik Nordmark ip6_t *ip6h; 3440bd670b35SErik Nordmark 3441bd670b35SErik Nordmark ip6h = (ip6_t *)rptr; 3442bd670b35SErik Nordmark src = ip6h->ip6_src; 3443bd670b35SErik Nordmark dst = ip6h->ip6_dst; 3444bd670b35SErik Nordmark } 3445bd670b35SErik Nordmark 34467c478bd9Sstevel@tonic-gate mlen = mp->b_wptr - (uchar_t *)(sctph + 1); 34477c478bd9Sstevel@tonic-gate if ((ch = sctp_first_chunk((uchar_t *)(sctph + 1), mlen)) == NULL) { 34487c478bd9Sstevel@tonic-gate dprint(3, ("sctp_ootb_input: invalid packet\n")); 3449bd670b35SErik Nordmark BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsInDiscards); 3450bd670b35SErik Nordmark ip_drop_input("ipIfStatsInDiscards", mp, NULL); 3451bd670b35SErik Nordmark freemsg(mp); 34527c478bd9Sstevel@tonic-gate return; 34537c478bd9Sstevel@tonic-gate } 34547c478bd9Sstevel@tonic-gate 34557c478bd9Sstevel@tonic-gate switch (ch->sch_id) { 34567c478bd9Sstevel@tonic-gate case CHUNK_INIT: 34577c478bd9Sstevel@tonic-gate /* no listener; send abort */ 3458bd670b35SErik Nordmark if (secure && sctp_check_in_policy(mp, ira, ipst) == NULL) 34597c478bd9Sstevel@tonic-gate return; 3460bd670b35SErik Nordmark sctp_ootb_send_abort(sctp_init2vtag(ch), 0, 3461bd670b35SErik Nordmark NULL, 0, mp, 0, B_TRUE, ira, ipst); 34627c478bd9Sstevel@tonic-gate break; 34637c478bd9Sstevel@tonic-gate case CHUNK_INIT_ACK: 34647c478bd9Sstevel@tonic-gate /* check for changed src addr */ 3465e35d2278Svi117747 sctp = sctp_addrlist2sctp(mp, sctph, ch, zoneid, sctps); 34667c478bd9Sstevel@tonic-gate if (sctp != NULL) { 34677c478bd9Sstevel@tonic-gate /* success; proceed to normal path */ 34687c478bd9Sstevel@tonic-gate mutex_enter(&sctp->sctp_lock); 34697c478bd9Sstevel@tonic-gate if (sctp->sctp_running) { 3470bd670b35SErik Nordmark sctp_add_recvq(sctp, mp, B_FALSE, ira); 34717c478bd9Sstevel@tonic-gate mutex_exit(&sctp->sctp_lock); 34727c478bd9Sstevel@tonic-gate } else { 34737c478bd9Sstevel@tonic-gate /* 34747c478bd9Sstevel@tonic-gate * If the source address is changed, we 34757c478bd9Sstevel@tonic-gate * don't need to worry too much about 34767c478bd9Sstevel@tonic-gate * out of order processing. So we don't 34777c478bd9Sstevel@tonic-gate * check if the recvq is empty or not here. 34787c478bd9Sstevel@tonic-gate */ 34797c478bd9Sstevel@tonic-gate sctp->sctp_running = B_TRUE; 34807c478bd9Sstevel@tonic-gate mutex_exit(&sctp->sctp_lock); 3481bd670b35SErik Nordmark sctp_input_data(sctp, mp, ira); 34827c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 34837c478bd9Sstevel@tonic-gate } 34847c478bd9Sstevel@tonic-gate SCTP_REFRELE(sctp); 34857c478bd9Sstevel@tonic-gate return; 34867c478bd9Sstevel@tonic-gate } 34877c478bd9Sstevel@tonic-gate /* else bogus init ack; drop it */ 34887c478bd9Sstevel@tonic-gate break; 34897c478bd9Sstevel@tonic-gate case CHUNK_SHUTDOWN_ACK: 3490bd670b35SErik Nordmark if (secure && sctp_check_in_policy(mp, ira, ipst) == NULL) 34917c478bd9Sstevel@tonic-gate return; 3492bd670b35SErik Nordmark sctp_ootb_shutdown_ack(mp, ip_hdr_len, ira, ipst); 34937c478bd9Sstevel@tonic-gate return; 34947c478bd9Sstevel@tonic-gate case CHUNK_ERROR: 34957c478bd9Sstevel@tonic-gate case CHUNK_ABORT: 34967c478bd9Sstevel@tonic-gate case CHUNK_COOKIE_ACK: 34977c478bd9Sstevel@tonic-gate case CHUNK_SHUTDOWN_COMPLETE: 34987c478bd9Sstevel@tonic-gate break; 34997c478bd9Sstevel@tonic-gate default: 3500bd670b35SErik Nordmark if (secure && sctp_check_in_policy(mp, ira, ipst) == NULL) 35017c478bd9Sstevel@tonic-gate return; 3502bd670b35SErik Nordmark sctp_ootb_send_abort(sctph->sh_verf, 0, 3503bd670b35SErik Nordmark NULL, 0, mp, 0, B_TRUE, ira, ipst); 35047c478bd9Sstevel@tonic-gate break; 35057c478bd9Sstevel@tonic-gate } 35067c478bd9Sstevel@tonic-gate freemsg(mp); 35077c478bd9Sstevel@tonic-gate } 35087c478bd9Sstevel@tonic-gate 3509bd670b35SErik Nordmark /* 3510bd670b35SErik Nordmark * Handle sctp packets. 3511bd670b35SErik Nordmark * Note that we rele the sctp_t (the caller got a reference on it). 3512bd670b35SErik Nordmark */ 35137c478bd9Sstevel@tonic-gate void 3514bd670b35SErik Nordmark sctp_input(conn_t *connp, ipha_t *ipha, ip6_t *ip6h, mblk_t *mp, 3515bd670b35SErik Nordmark ip_recv_attr_t *ira) 35167c478bd9Sstevel@tonic-gate { 35177c478bd9Sstevel@tonic-gate sctp_t *sctp = CONN2SCTP(connp); 3518bd670b35SErik Nordmark boolean_t secure; 3519bd670b35SErik Nordmark ill_t *ill = ira->ira_ill; 3520bd670b35SErik Nordmark ip_stack_t *ipst = ill->ill_ipst; 3521f4b3ec61Sdh155122 ipsec_stack_t *ipss = ipst->ips_netstack->netstack_ipsec; 3522bd670b35SErik Nordmark iaflags_t iraflags = ira->ira_flags; 3523bd670b35SErik Nordmark ill_t *rill = ira->ira_rill; 3524bd670b35SErik Nordmark 3525bd670b35SErik Nordmark secure = iraflags & IRAF_IPSEC_SECURE; 35267c478bd9Sstevel@tonic-gate 35277c478bd9Sstevel@tonic-gate /* 35287c478bd9Sstevel@tonic-gate * We check some fields in conn_t without holding a lock. 35297c478bd9Sstevel@tonic-gate * This should be fine. 35307c478bd9Sstevel@tonic-gate */ 3531bd670b35SErik Nordmark if (((iraflags & IRAF_IS_IPV4) ? 3532bd670b35SErik Nordmark CONN_INBOUND_POLICY_PRESENT(connp, ipss) : 3533bd670b35SErik Nordmark CONN_INBOUND_POLICY_PRESENT_V6(connp, ipss)) || 3534bd670b35SErik Nordmark secure) { 3535bd670b35SErik Nordmark mp = ipsec_check_inbound_policy(mp, connp, ipha, 3536bd670b35SErik Nordmark ip6h, ira); 35377c478bd9Sstevel@tonic-gate if (mp == NULL) { 3538bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 3539bd670b35SErik Nordmark /* Note that mp is NULL */ 3540bd670b35SErik Nordmark ip_drop_input("ipIfStatsInDiscards", mp, ill); 35417c478bd9Sstevel@tonic-gate SCTP_REFRELE(sctp); 35427c478bd9Sstevel@tonic-gate return; 35437c478bd9Sstevel@tonic-gate } 35447c478bd9Sstevel@tonic-gate } 35457c478bd9Sstevel@tonic-gate 3546bd670b35SErik Nordmark ira->ira_ill = ira->ira_rill = NULL; 35477c478bd9Sstevel@tonic-gate 35487c478bd9Sstevel@tonic-gate mutex_enter(&sctp->sctp_lock); 35497c478bd9Sstevel@tonic-gate if (sctp->sctp_running) { 3550bd670b35SErik Nordmark sctp_add_recvq(sctp, mp, B_FALSE, ira); 35517c478bd9Sstevel@tonic-gate mutex_exit(&sctp->sctp_lock); 3552bd670b35SErik Nordmark goto done; 35537c478bd9Sstevel@tonic-gate } else { 35547c478bd9Sstevel@tonic-gate sctp->sctp_running = B_TRUE; 35557c478bd9Sstevel@tonic-gate mutex_exit(&sctp->sctp_lock); 35567c478bd9Sstevel@tonic-gate 35577c478bd9Sstevel@tonic-gate mutex_enter(&sctp->sctp_recvq_lock); 35587c478bd9Sstevel@tonic-gate if (sctp->sctp_recvq != NULL) { 3559bd670b35SErik Nordmark sctp_add_recvq(sctp, mp, B_TRUE, ira); 35607c478bd9Sstevel@tonic-gate mutex_exit(&sctp->sctp_recvq_lock); 35617c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 3562bd670b35SErik Nordmark goto done; 35637c478bd9Sstevel@tonic-gate } 35647c478bd9Sstevel@tonic-gate } 35657c478bd9Sstevel@tonic-gate mutex_exit(&sctp->sctp_recvq_lock); 3566bd670b35SErik Nordmark if (ira->ira_flags & IRAF_ICMP_ERROR) 3567bd670b35SErik Nordmark sctp_icmp_error(sctp, mp); 3568bd670b35SErik Nordmark else 3569bd670b35SErik Nordmark sctp_input_data(sctp, mp, ira); 35707c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 3571bd670b35SErik Nordmark 3572bd670b35SErik Nordmark done: 35737c478bd9Sstevel@tonic-gate SCTP_REFRELE(sctp); 3574bd670b35SErik Nordmark ira->ira_ill = ill; 3575bd670b35SErik Nordmark ira->ira_rill = rill; 35767c478bd9Sstevel@tonic-gate } 35777c478bd9Sstevel@tonic-gate 35787c478bd9Sstevel@tonic-gate static void 35797c478bd9Sstevel@tonic-gate sctp_process_abort(sctp_t *sctp, sctp_chunk_hdr_t *ch, int err) 35807c478bd9Sstevel@tonic-gate { 3581f4b3ec61Sdh155122 sctp_stack_t *sctps = sctp->sctp_sctps; 3582f4b3ec61Sdh155122 35835dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpAborted); 35847c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 35857c478bd9Sstevel@tonic-gate 35866be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India /* 35876be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India * SCTP_COMM_LOST is only sent up if the association is 35886be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India * established (sctp_state >= SCTPS_ESTABLISHED). 35896be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India */ 35906be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (sctp->sctp_state >= SCTPS_ESTABLISHED) { 35917c478bd9Sstevel@tonic-gate sctp_assoc_event(sctp, SCTP_COMM_LOST, 35927c478bd9Sstevel@tonic-gate ntohs(((sctp_parm_hdr_t *)(ch + 1))->sph_type), ch); 35936be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India } 35946be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 35957c478bd9Sstevel@tonic-gate sctp_clean_death(sctp, err); 35967c478bd9Sstevel@tonic-gate } 35977c478bd9Sstevel@tonic-gate 35987c478bd9Sstevel@tonic-gate void 3599bd670b35SErik Nordmark sctp_input_data(sctp_t *sctp, mblk_t *mp, ip_recv_attr_t *ira) 36007c478bd9Sstevel@tonic-gate { 36017c478bd9Sstevel@tonic-gate sctp_chunk_hdr_t *ch; 36027c478bd9Sstevel@tonic-gate ssize_t mlen; 36037c478bd9Sstevel@tonic-gate int gotdata; 36047c478bd9Sstevel@tonic-gate int trysend; 36057c478bd9Sstevel@tonic-gate sctp_faddr_t *fp; 36067c478bd9Sstevel@tonic-gate sctp_init_chunk_t *iack; 36077c478bd9Sstevel@tonic-gate uint32_t tsn; 36087c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 3609bd670b35SErik Nordmark ip_pkt_t ipp; 36107c478bd9Sstevel@tonic-gate in6_addr_t src; 36117c478bd9Sstevel@tonic-gate in6_addr_t dst; 36127c478bd9Sstevel@tonic-gate uint_t ifindex; 36137c478bd9Sstevel@tonic-gate sctp_hdr_t *sctph; 3614bd670b35SErik Nordmark uint_t ip_hdr_len = ira->ira_ip_hdr_length; 36157c478bd9Sstevel@tonic-gate mblk_t *dups = NULL; 3616558fbd03Skcpoon int recv_adaptation; 36177c478bd9Sstevel@tonic-gate boolean_t wake_eager = B_FALSE; 36187c478bd9Sstevel@tonic-gate in6_addr_t peer_src; 36197c478bd9Sstevel@tonic-gate int64_t now; 3620f4b3ec61Sdh155122 sctp_stack_t *sctps = sctp->sctp_sctps; 3621f4b3ec61Sdh155122 ip_stack_t *ipst = sctps->sctps_netstack->netstack_ip; 36227f093707Skcpoon boolean_t hb_already = B_FALSE; 3623de8c4a14SErik Nordmark cred_t *cr; 3624de8c4a14SErik Nordmark pid_t cpid; 3625bd670b35SErik Nordmark uchar_t *rptr; 3626bd670b35SErik Nordmark conn_t *connp = sctp->sctp_connp; 36273e1dae9fSAnil udupa boolean_t shutdown_ack_needed = B_FALSE; 36287c478bd9Sstevel@tonic-gate 36297c478bd9Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_DATA); 3630bd670b35SErik Nordmark ASSERT(ira->ira_ill == NULL); 36317c478bd9Sstevel@tonic-gate 36327c478bd9Sstevel@tonic-gate if (mp->b_cont != NULL) { 36337c478bd9Sstevel@tonic-gate /* 36347c478bd9Sstevel@tonic-gate * All subsequent code is vastly simplified if it can 36357c478bd9Sstevel@tonic-gate * assume a single contiguous chunk of data. 36367c478bd9Sstevel@tonic-gate */ 36377c478bd9Sstevel@tonic-gate if (pullupmsg(mp, -1) == 0) { 3638f4b3ec61Sdh155122 BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsInDiscards); 3639bd670b35SErik Nordmark ip_drop_input("ipIfStatsInDiscards", mp, NULL); 36407c478bd9Sstevel@tonic-gate freemsg(mp); 36417c478bd9Sstevel@tonic-gate return; 36427c478bd9Sstevel@tonic-gate } 36437c478bd9Sstevel@tonic-gate } 36447c478bd9Sstevel@tonic-gate 36457c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ipkts); 3646bd670b35SErik Nordmark ifindex = ira->ira_ruifindex; 3647bd670b35SErik Nordmark 3648bd670b35SErik Nordmark rptr = mp->b_rptr; 3649bd670b35SErik Nordmark 3650bd670b35SErik Nordmark ipp.ipp_fields = 0; 3651bd670b35SErik Nordmark if (connp->conn_recv_ancillary.crb_all != 0) { 3652bd670b35SErik Nordmark /* 3653bd670b35SErik Nordmark * Record packet information in the ip_pkt_t 3654bd670b35SErik Nordmark */ 3655bd670b35SErik Nordmark if (ira->ira_flags & IRAF_IS_IPV4) { 3656bd670b35SErik Nordmark (void) ip_find_hdr_v4((ipha_t *)rptr, &ipp, 3657bd670b35SErik Nordmark B_FALSE); 3658bd670b35SErik Nordmark } else { 3659bd670b35SErik Nordmark uint8_t nexthdrp; 3660bd670b35SErik Nordmark 3661bd670b35SErik Nordmark /* 3662bd670b35SErik Nordmark * IPv6 packets can only be received by applications 3663bd670b35SErik Nordmark * that are prepared to receive IPv6 addresses. 3664bd670b35SErik Nordmark * The IP fanout must ensure this. 3665bd670b35SErik Nordmark */ 3666bd670b35SErik Nordmark ASSERT(connp->conn_family == AF_INET6); 3667bd670b35SErik Nordmark 3668bd670b35SErik Nordmark (void) ip_find_hdr_v6(mp, (ip6_t *)rptr, B_TRUE, &ipp, 3669bd670b35SErik Nordmark &nexthdrp); 3670bd670b35SErik Nordmark ASSERT(nexthdrp == IPPROTO_SCTP); 3671bd670b35SErik Nordmark 3672bd670b35SErik Nordmark /* Could have caused a pullup? */ 3673bd670b35SErik Nordmark rptr = mp->b_rptr; 3674bd670b35SErik Nordmark } 3675bd670b35SErik Nordmark } 3676bd670b35SErik Nordmark 3677bd670b35SErik Nordmark sctph = ((sctp_hdr_t *)&rptr[ip_hdr_len]); 3678bd670b35SErik Nordmark 3679bd670b35SErik Nordmark if (ira->ira_flags & IRAF_IS_IPV4) { 3680bd670b35SErik Nordmark ipha_t *ipha; 3681bd670b35SErik Nordmark 3682bd670b35SErik Nordmark ipha = (ipha_t *)rptr; 3683bd670b35SErik Nordmark IN6_IPADDR_TO_V4MAPPED(ipha->ipha_src, &src); 3684bd670b35SErik Nordmark IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &dst); 3685bd670b35SErik Nordmark } else { 3686bd670b35SErik Nordmark ip6_t *ip6h; 3687bd670b35SErik Nordmark 3688bd670b35SErik Nordmark ip6h = (ip6_t *)rptr; 3689bd670b35SErik Nordmark src = ip6h->ip6_src; 3690bd670b35SErik Nordmark dst = ip6h->ip6_dst; 3691bd670b35SErik Nordmark } 3692bd670b35SErik Nordmark 36937c478bd9Sstevel@tonic-gate mlen = mp->b_wptr - (uchar_t *)(sctph + 1); 36947c478bd9Sstevel@tonic-gate ch = sctp_first_chunk((uchar_t *)(sctph + 1), mlen); 36957c478bd9Sstevel@tonic-gate if (ch == NULL) { 3696f4b3ec61Sdh155122 BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsInDiscards); 3697bd670b35SErik Nordmark ip_drop_input("ipIfStatsInDiscards", mp, NULL); 36987c478bd9Sstevel@tonic-gate freemsg(mp); 36997c478bd9Sstevel@tonic-gate return; 37007c478bd9Sstevel@tonic-gate } 37017c478bd9Sstevel@tonic-gate 37027c478bd9Sstevel@tonic-gate if (!sctp_check_input(sctp, ch, mlen, 1)) { 3703f4b3ec61Sdh155122 BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsInDiscards); 3704bd670b35SErik Nordmark ip_drop_input("ipIfStatsInDiscards", mp, NULL); 37057c478bd9Sstevel@tonic-gate goto done; 37067c478bd9Sstevel@tonic-gate } 37077c478bd9Sstevel@tonic-gate /* 37087c478bd9Sstevel@tonic-gate * Check verfication tag (special handling for INIT, 37097c478bd9Sstevel@tonic-gate * COOKIE, SHUTDOWN_COMPLETE and SHUTDOWN_ACK chunks). 37107c478bd9Sstevel@tonic-gate * ABORTs are handled in the chunk processing loop, since 37117c478bd9Sstevel@tonic-gate * may not appear first. All other checked chunks must 37127c478bd9Sstevel@tonic-gate * appear first, or will have been dropped by check_input(). 37137c478bd9Sstevel@tonic-gate */ 37147c478bd9Sstevel@tonic-gate switch (ch->sch_id) { 37157c478bd9Sstevel@tonic-gate case CHUNK_INIT: 37167c478bd9Sstevel@tonic-gate if (sctph->sh_verf != 0) { 37177c478bd9Sstevel@tonic-gate /* drop it */ 37187c478bd9Sstevel@tonic-gate goto done; 37197c478bd9Sstevel@tonic-gate } 37207c478bd9Sstevel@tonic-gate break; 37217c478bd9Sstevel@tonic-gate case CHUNK_SHUTDOWN_COMPLETE: 37227c478bd9Sstevel@tonic-gate if (sctph->sh_verf == sctp->sctp_lvtag) 37237c478bd9Sstevel@tonic-gate break; 37247c478bd9Sstevel@tonic-gate if (sctph->sh_verf == sctp->sctp_fvtag && 37257c478bd9Sstevel@tonic-gate SCTP_GET_TBIT(ch)) { 37267c478bd9Sstevel@tonic-gate break; 37277c478bd9Sstevel@tonic-gate } 37287c478bd9Sstevel@tonic-gate /* else drop it */ 37297c478bd9Sstevel@tonic-gate goto done; 37307c478bd9Sstevel@tonic-gate case CHUNK_ABORT: 37317c478bd9Sstevel@tonic-gate case CHUNK_COOKIE: 37327c478bd9Sstevel@tonic-gate /* handled below */ 37337c478bd9Sstevel@tonic-gate break; 37347c478bd9Sstevel@tonic-gate case CHUNK_SHUTDOWN_ACK: 37357c478bd9Sstevel@tonic-gate if (sctp->sctp_state > SCTPS_BOUND && 37367c478bd9Sstevel@tonic-gate sctp->sctp_state < SCTPS_ESTABLISHED) { 37377c478bd9Sstevel@tonic-gate /* treat as OOTB */ 3738bd670b35SErik Nordmark sctp_ootb_shutdown_ack(mp, ip_hdr_len, ira, ipst); 37397c478bd9Sstevel@tonic-gate return; 37407c478bd9Sstevel@tonic-gate } 37417c478bd9Sstevel@tonic-gate /* else fallthru */ 37427c478bd9Sstevel@tonic-gate default: 37437c478bd9Sstevel@tonic-gate /* 37447c478bd9Sstevel@tonic-gate * All other packets must have a valid 37457c478bd9Sstevel@tonic-gate * verification tag, however if this is a 37467c478bd9Sstevel@tonic-gate * listener, we use a refined version of 37477c478bd9Sstevel@tonic-gate * out-of-the-blue logic. 37487c478bd9Sstevel@tonic-gate */ 37497c478bd9Sstevel@tonic-gate if (sctph->sh_verf != sctp->sctp_lvtag && 37507c478bd9Sstevel@tonic-gate sctp->sctp_state != SCTPS_LISTEN) { 37517c478bd9Sstevel@tonic-gate /* drop it */ 37527c478bd9Sstevel@tonic-gate goto done; 37537c478bd9Sstevel@tonic-gate } 37547c478bd9Sstevel@tonic-gate break; 37557c478bd9Sstevel@tonic-gate } 37567c478bd9Sstevel@tonic-gate 37577c478bd9Sstevel@tonic-gate /* Have a valid sctp for this packet */ 37587c478bd9Sstevel@tonic-gate fp = sctp_lookup_faddr(sctp, &src); 375945916cd2Sjpk dprint(2, ("sctp_dispatch_rput: mp=%p fp=%p sctp=%p\n", (void *)mp, 376045916cd2Sjpk (void *)fp, (void *)sctp)); 37617c478bd9Sstevel@tonic-gate 37627c478bd9Sstevel@tonic-gate gotdata = 0; 37637c478bd9Sstevel@tonic-gate trysend = 0; 37647c478bd9Sstevel@tonic-gate 37655dd46ab5SKacheong Poon now = LBOLT_FASTPATH64; 37667c478bd9Sstevel@tonic-gate /* Process the chunks */ 37677c478bd9Sstevel@tonic-gate do { 37687c478bd9Sstevel@tonic-gate dprint(3, ("sctp_dispatch_rput: state=%d, chunk id=%d\n", 37697c478bd9Sstevel@tonic-gate sctp->sctp_state, (int)(ch->sch_id))); 37707c478bd9Sstevel@tonic-gate 37717c478bd9Sstevel@tonic-gate if (ch->sch_id == CHUNK_ABORT) { 37727c478bd9Sstevel@tonic-gate if (sctph->sh_verf != sctp->sctp_lvtag && 37737c478bd9Sstevel@tonic-gate sctph->sh_verf != sctp->sctp_fvtag) { 37747c478bd9Sstevel@tonic-gate /* drop it */ 37757c478bd9Sstevel@tonic-gate goto done; 37767c478bd9Sstevel@tonic-gate } 37777c478bd9Sstevel@tonic-gate } 37787c478bd9Sstevel@tonic-gate 37797c478bd9Sstevel@tonic-gate switch (sctp->sctp_state) { 37807c478bd9Sstevel@tonic-gate 37817c478bd9Sstevel@tonic-gate case SCTPS_ESTABLISHED: 37827c478bd9Sstevel@tonic-gate case SCTPS_SHUTDOWN_PENDING: 37837c478bd9Sstevel@tonic-gate case SCTPS_SHUTDOWN_SENT: 37847c478bd9Sstevel@tonic-gate switch (ch->sch_id) { 37857c478bd9Sstevel@tonic-gate case CHUNK_DATA: 37867c478bd9Sstevel@tonic-gate /* 0-length data chunks are not allowed */ 37877c478bd9Sstevel@tonic-gate if (ntohs(ch->sch_len) == sizeof (*sdc)) { 37887c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)ch; 37897c478bd9Sstevel@tonic-gate tsn = sdc->sdh_tsn; 37907c478bd9Sstevel@tonic-gate sctp_send_abort(sctp, sctp->sctp_fvtag, 37917c478bd9Sstevel@tonic-gate SCTP_ERR_NO_USR_DATA, (char *)&tsn, 3792bd670b35SErik Nordmark sizeof (tsn), mp, 0, B_FALSE, ira); 37937c478bd9Sstevel@tonic-gate sctp_assoc_event(sctp, SCTP_COMM_LOST, 37947c478bd9Sstevel@tonic-gate 0, NULL); 37957c478bd9Sstevel@tonic-gate sctp_clean_death(sctp, ECONNABORTED); 37967c478bd9Sstevel@tonic-gate goto done; 37977c478bd9Sstevel@tonic-gate } 37987c478bd9Sstevel@tonic-gate 37997c478bd9Sstevel@tonic-gate ASSERT(fp != NULL); 38007c478bd9Sstevel@tonic-gate sctp->sctp_lastdata = fp; 3801bd670b35SErik Nordmark sctp_data_chunk(sctp, ch, mp, &dups, fp, 3802bd670b35SErik Nordmark &ipp, ira); 38037c478bd9Sstevel@tonic-gate gotdata = 1; 38047c478bd9Sstevel@tonic-gate /* Restart shutdown timer if shutting down */ 38057c478bd9Sstevel@tonic-gate if (sctp->sctp_state == SCTPS_SHUTDOWN_SENT) { 38067c478bd9Sstevel@tonic-gate /* 38077c478bd9Sstevel@tonic-gate * If we have exceeded our max 38087c478bd9Sstevel@tonic-gate * wait bound for waiting for a 38097c478bd9Sstevel@tonic-gate * shutdown ack from the peer, 38107c478bd9Sstevel@tonic-gate * abort the association. 38117c478bd9Sstevel@tonic-gate */ 3812f4b3ec61Sdh155122 if (sctps->sctps_shutack_wait_bound != 3813f4b3ec61Sdh155122 0 && 38147c478bd9Sstevel@tonic-gate TICK_TO_MSEC(now - 38157c478bd9Sstevel@tonic-gate sctp->sctp_out_time) > 3816f4b3ec61Sdh155122 sctps->sctps_shutack_wait_bound) { 38177c478bd9Sstevel@tonic-gate sctp_send_abort(sctp, 38187c478bd9Sstevel@tonic-gate sctp->sctp_fvtag, 0, NULL, 3819bd670b35SErik Nordmark 0, mp, 0, B_FALSE, ira); 38207c478bd9Sstevel@tonic-gate sctp_assoc_event(sctp, 38217c478bd9Sstevel@tonic-gate SCTP_COMM_LOST, 0, NULL); 38227c478bd9Sstevel@tonic-gate sctp_clean_death(sctp, 38237c478bd9Sstevel@tonic-gate ECONNABORTED); 38247c478bd9Sstevel@tonic-gate goto done; 38257c478bd9Sstevel@tonic-gate } 38267c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, fp, 38276be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India fp->sf_rto); 38287c478bd9Sstevel@tonic-gate } 38297c478bd9Sstevel@tonic-gate break; 38307c478bd9Sstevel@tonic-gate case CHUNK_SACK: 38317c478bd9Sstevel@tonic-gate ASSERT(fp != NULL); 38327c478bd9Sstevel@tonic-gate /* 38337c478bd9Sstevel@tonic-gate * Peer is real and alive if it can ack our 38347c478bd9Sstevel@tonic-gate * data. 38357c478bd9Sstevel@tonic-gate */ 38367c478bd9Sstevel@tonic-gate sctp_faddr_alive(sctp, fp); 38377c478bd9Sstevel@tonic-gate trysend = sctp_got_sack(sctp, ch); 38381d8c4025Svi117747 if (trysend < 0) { 38391d8c4025Svi117747 sctp_send_abort(sctp, sctph->sh_verf, 3840bd670b35SErik Nordmark 0, NULL, 0, mp, 0, B_FALSE, ira); 38411d8c4025Svi117747 sctp_assoc_event(sctp, 38421d8c4025Svi117747 SCTP_COMM_LOST, 0, NULL); 38431d8c4025Svi117747 sctp_clean_death(sctp, 38441d8c4025Svi117747 ECONNABORTED); 38451d8c4025Svi117747 goto done; 38461d8c4025Svi117747 } 38477c478bd9Sstevel@tonic-gate break; 38487c478bd9Sstevel@tonic-gate case CHUNK_HEARTBEAT: 38497f093707Skcpoon if (!hb_already) { 38507f093707Skcpoon /* 38517f093707Skcpoon * In any one packet, there should 38527f093707Skcpoon * only be one heartbeat chunk. So 38537f093707Skcpoon * we should not process more than 38547f093707Skcpoon * once. 38557f093707Skcpoon */ 38567c478bd9Sstevel@tonic-gate sctp_return_heartbeat(sctp, ch, mp); 38577f093707Skcpoon hb_already = B_TRUE; 38587f093707Skcpoon } 38597c478bd9Sstevel@tonic-gate break; 38607c478bd9Sstevel@tonic-gate case CHUNK_HEARTBEAT_ACK: 38617c478bd9Sstevel@tonic-gate sctp_process_heartbeat(sctp, ch); 38627c478bd9Sstevel@tonic-gate break; 38637c478bd9Sstevel@tonic-gate case CHUNK_SHUTDOWN: 38647c478bd9Sstevel@tonic-gate sctp_shutdown_event(sctp); 38657c478bd9Sstevel@tonic-gate trysend = sctp_shutdown_received(sctp, ch, 386677c67f2fSkcpoon B_FALSE, B_FALSE, fp); 38677c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 38687c478bd9Sstevel@tonic-gate break; 38697c478bd9Sstevel@tonic-gate case CHUNK_SHUTDOWN_ACK: 38707c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 38717c478bd9Sstevel@tonic-gate if (sctp->sctp_state == SCTPS_SHUTDOWN_SENT) { 38727c478bd9Sstevel@tonic-gate sctp_shutdown_complete(sctp); 38735dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpShutdowns); 38747c478bd9Sstevel@tonic-gate sctp_assoc_event(sctp, 38757c478bd9Sstevel@tonic-gate SCTP_SHUTDOWN_COMP, 0, NULL); 38767c478bd9Sstevel@tonic-gate sctp_clean_death(sctp, 0); 38777c478bd9Sstevel@tonic-gate goto done; 38787c478bd9Sstevel@tonic-gate } 38797c478bd9Sstevel@tonic-gate break; 38807c478bd9Sstevel@tonic-gate case CHUNK_ABORT: { 38817c478bd9Sstevel@tonic-gate sctp_saddr_ipif_t *sp; 38827c478bd9Sstevel@tonic-gate 38837c478bd9Sstevel@tonic-gate /* Ignore if delete pending */ 38841d8c4025Svi117747 sp = sctp_saddr_lookup(sctp, &dst, 0); 38857c478bd9Sstevel@tonic-gate ASSERT(sp != NULL); 38867c478bd9Sstevel@tonic-gate if (sp->saddr_ipif_delete_pending) { 38877c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 38887c478bd9Sstevel@tonic-gate break; 38897c478bd9Sstevel@tonic-gate } 38907c478bd9Sstevel@tonic-gate 38917c478bd9Sstevel@tonic-gate sctp_process_abort(sctp, ch, ECONNRESET); 38927c478bd9Sstevel@tonic-gate goto done; 38937c478bd9Sstevel@tonic-gate } 38947c478bd9Sstevel@tonic-gate case CHUNK_INIT: 3895bd670b35SErik Nordmark sctp_send_initack(sctp, sctph, ch, mp, ira); 38967c478bd9Sstevel@tonic-gate break; 38977c478bd9Sstevel@tonic-gate case CHUNK_COOKIE: 38987c478bd9Sstevel@tonic-gate if (sctp_process_cookie(sctp, ch, mp, &iack, 3899bd670b35SErik Nordmark sctph, &recv_adaptation, NULL, ira) != -1) { 39007c478bd9Sstevel@tonic-gate sctp_send_cookie_ack(sctp); 39017c478bd9Sstevel@tonic-gate sctp_assoc_event(sctp, SCTP_RESTART, 39027c478bd9Sstevel@tonic-gate 0, NULL); 3903558fbd03Skcpoon if (recv_adaptation) { 3904558fbd03Skcpoon sctp->sctp_recv_adaptation = 1; 3905558fbd03Skcpoon sctp_adaptation_event(sctp); 39067c478bd9Sstevel@tonic-gate } 39077c478bd9Sstevel@tonic-gate } else { 39085dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, 39097c478bd9Sstevel@tonic-gate sctpInInvalidCookie); 39107c478bd9Sstevel@tonic-gate } 39117c478bd9Sstevel@tonic-gate break; 39127c478bd9Sstevel@tonic-gate case CHUNK_ERROR: { 39137c478bd9Sstevel@tonic-gate int error; 39147c478bd9Sstevel@tonic-gate 39157c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 3916bd670b35SErik Nordmark error = sctp_handle_error(sctp, sctph, ch, mp, 3917bd670b35SErik Nordmark ira); 39187c478bd9Sstevel@tonic-gate if (error != 0) { 3919c9da23f8Skcpoon sctp_assoc_event(sctp, SCTP_COMM_LOST, 3920c9da23f8Skcpoon 0, NULL); 39217c478bd9Sstevel@tonic-gate sctp_clean_death(sctp, error); 39227c478bd9Sstevel@tonic-gate goto done; 39237c478bd9Sstevel@tonic-gate } 39247c478bd9Sstevel@tonic-gate break; 39257c478bd9Sstevel@tonic-gate } 39267c478bd9Sstevel@tonic-gate case CHUNK_ASCONF: 39277c478bd9Sstevel@tonic-gate ASSERT(fp != NULL); 39287c478bd9Sstevel@tonic-gate sctp_input_asconf(sctp, ch, fp); 39297c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 39307c478bd9Sstevel@tonic-gate break; 39317c478bd9Sstevel@tonic-gate case CHUNK_ASCONF_ACK: 39327c478bd9Sstevel@tonic-gate ASSERT(fp != NULL); 39337c478bd9Sstevel@tonic-gate sctp_faddr_alive(sctp, fp); 39347c478bd9Sstevel@tonic-gate sctp_input_asconf_ack(sctp, ch, fp); 39357c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 39367c478bd9Sstevel@tonic-gate break; 39377c478bd9Sstevel@tonic-gate case CHUNK_FORWARD_TSN: 39387c478bd9Sstevel@tonic-gate ASSERT(fp != NULL); 39397c478bd9Sstevel@tonic-gate sctp->sctp_lastdata = fp; 3940bd670b35SErik Nordmark sctp_process_forward_tsn(sctp, ch, fp, 3941bd670b35SErik Nordmark &ipp, ira); 39427c478bd9Sstevel@tonic-gate gotdata = 1; 39437c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 39447c478bd9Sstevel@tonic-gate break; 39457c478bd9Sstevel@tonic-gate default: 39467c478bd9Sstevel@tonic-gate if (sctp_strange_chunk(sctp, ch, fp) == 0) { 39477c478bd9Sstevel@tonic-gate goto nomorechunks; 39487c478bd9Sstevel@tonic-gate } /* else skip and continue processing */ 39497c478bd9Sstevel@tonic-gate break; 39507c478bd9Sstevel@tonic-gate } 39517c478bd9Sstevel@tonic-gate break; 39527c478bd9Sstevel@tonic-gate 39537c478bd9Sstevel@tonic-gate case SCTPS_LISTEN: 39547c478bd9Sstevel@tonic-gate switch (ch->sch_id) { 39557c478bd9Sstevel@tonic-gate case CHUNK_INIT: 3956bd670b35SErik Nordmark sctp_send_initack(sctp, sctph, ch, mp, ira); 39577c478bd9Sstevel@tonic-gate break; 39587c478bd9Sstevel@tonic-gate case CHUNK_COOKIE: { 39597c478bd9Sstevel@tonic-gate sctp_t *eager; 39607c478bd9Sstevel@tonic-gate 39617c478bd9Sstevel@tonic-gate if (sctp_process_cookie(sctp, ch, mp, &iack, 3962bd670b35SErik Nordmark sctph, &recv_adaptation, &peer_src, 3963bd670b35SErik Nordmark ira) == -1) { 39645dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, 39657c478bd9Sstevel@tonic-gate sctpInInvalidCookie); 39667c478bd9Sstevel@tonic-gate goto done; 39677c478bd9Sstevel@tonic-gate } 39687c478bd9Sstevel@tonic-gate 39697c478bd9Sstevel@tonic-gate /* 39707c478bd9Sstevel@tonic-gate * The cookie is good; ensure that 39717c478bd9Sstevel@tonic-gate * the peer used the verification 39727c478bd9Sstevel@tonic-gate * tag from the init ack in the header. 39737c478bd9Sstevel@tonic-gate */ 39747c478bd9Sstevel@tonic-gate if (iack->sic_inittag != sctph->sh_verf) 39757c478bd9Sstevel@tonic-gate goto done; 39767c478bd9Sstevel@tonic-gate 39777c478bd9Sstevel@tonic-gate eager = sctp_conn_request(sctp, mp, ifindex, 3978bd670b35SErik Nordmark ip_hdr_len, iack, ira); 39797c478bd9Sstevel@tonic-gate if (eager == NULL) { 39807c478bd9Sstevel@tonic-gate sctp_send_abort(sctp, sctph->sh_verf, 39817c478bd9Sstevel@tonic-gate SCTP_ERR_NO_RESOURCES, NULL, 0, mp, 3982bd670b35SErik Nordmark 0, B_FALSE, ira); 39837c478bd9Sstevel@tonic-gate goto done; 39847c478bd9Sstevel@tonic-gate } 39857c478bd9Sstevel@tonic-gate 39867c478bd9Sstevel@tonic-gate /* 39877c478bd9Sstevel@tonic-gate * If there were extra chunks 39887c478bd9Sstevel@tonic-gate * bundled with the cookie, 39897c478bd9Sstevel@tonic-gate * they must be processed 39907c478bd9Sstevel@tonic-gate * on the eager's queue. We 39917c478bd9Sstevel@tonic-gate * accomplish this by refeeding 39927c478bd9Sstevel@tonic-gate * the whole packet into the 39937c478bd9Sstevel@tonic-gate * state machine on the right 39947c478bd9Sstevel@tonic-gate * q. The packet (mp) gets 39957c478bd9Sstevel@tonic-gate * there via the eager's 39967c478bd9Sstevel@tonic-gate * cookie_mp field (overloaded 39977c478bd9Sstevel@tonic-gate * with the active open role). 39987c478bd9Sstevel@tonic-gate * This is picked up when 39997c478bd9Sstevel@tonic-gate * processing the null bind 40007c478bd9Sstevel@tonic-gate * request put on the eager's 40017c478bd9Sstevel@tonic-gate * q by sctp_accept(). We must 40027c478bd9Sstevel@tonic-gate * first revert the cookie 40037c478bd9Sstevel@tonic-gate * chunk's length field to network 40047c478bd9Sstevel@tonic-gate * byteorder so it can be 40057c478bd9Sstevel@tonic-gate * properly reprocessed on the 40067c478bd9Sstevel@tonic-gate * eager's queue. 40077c478bd9Sstevel@tonic-gate */ 40085dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpPassiveEstab); 40097c478bd9Sstevel@tonic-gate if (mlen > ntohs(ch->sch_len)) { 40107c478bd9Sstevel@tonic-gate eager->sctp_cookie_mp = dupb(mp); 40117c478bd9Sstevel@tonic-gate /* 40127c478bd9Sstevel@tonic-gate * If no mem, just let 40137c478bd9Sstevel@tonic-gate * the peer retransmit. 40147c478bd9Sstevel@tonic-gate */ 40157c478bd9Sstevel@tonic-gate } 40167c478bd9Sstevel@tonic-gate sctp_assoc_event(eager, SCTP_COMM_UP, 0, NULL); 4017558fbd03Skcpoon if (recv_adaptation) { 4018558fbd03Skcpoon eager->sctp_recv_adaptation = 1; 4019558fbd03Skcpoon eager->sctp_rx_adaptation_code = 4020558fbd03Skcpoon sctp->sctp_rx_adaptation_code; 4021558fbd03Skcpoon sctp_adaptation_event(eager); 40227c478bd9Sstevel@tonic-gate } 40237c478bd9Sstevel@tonic-gate 40247c478bd9Sstevel@tonic-gate eager->sctp_active = now; 40257c478bd9Sstevel@tonic-gate sctp_send_cookie_ack(eager); 40267c478bd9Sstevel@tonic-gate 40277c478bd9Sstevel@tonic-gate wake_eager = B_TRUE; 40287c478bd9Sstevel@tonic-gate 40297c478bd9Sstevel@tonic-gate /* 40307c478bd9Sstevel@tonic-gate * Process rest of the chunks with eager. 40317c478bd9Sstevel@tonic-gate */ 40327c478bd9Sstevel@tonic-gate sctp = eager; 40337c478bd9Sstevel@tonic-gate fp = sctp_lookup_faddr(sctp, &peer_src); 40347c478bd9Sstevel@tonic-gate /* 40357c478bd9Sstevel@tonic-gate * Confirm peer's original source. fp can 40367c478bd9Sstevel@tonic-gate * only be NULL if peer does not use the 40377c478bd9Sstevel@tonic-gate * original source as one of its addresses... 40387c478bd9Sstevel@tonic-gate */ 40397c478bd9Sstevel@tonic-gate if (fp == NULL) 40407c478bd9Sstevel@tonic-gate fp = sctp_lookup_faddr(sctp, &src); 40417c478bd9Sstevel@tonic-gate else 40427c478bd9Sstevel@tonic-gate sctp_faddr_alive(sctp, fp); 40437c478bd9Sstevel@tonic-gate 40447c478bd9Sstevel@tonic-gate /* 40457c478bd9Sstevel@tonic-gate * Validate the peer addresses. It also starts 40467c478bd9Sstevel@tonic-gate * the heartbeat timer. 40477c478bd9Sstevel@tonic-gate */ 40487c478bd9Sstevel@tonic-gate sctp_validate_peer(sctp); 40497c478bd9Sstevel@tonic-gate break; 40507c478bd9Sstevel@tonic-gate } 40517c478bd9Sstevel@tonic-gate /* Anything else is considered out-of-the-blue */ 40527c478bd9Sstevel@tonic-gate case CHUNK_ERROR: 40537c478bd9Sstevel@tonic-gate case CHUNK_ABORT: 40547c478bd9Sstevel@tonic-gate case CHUNK_COOKIE_ACK: 40557c478bd9Sstevel@tonic-gate case CHUNK_SHUTDOWN_COMPLETE: 40567c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 40577c478bd9Sstevel@tonic-gate goto done; 40587c478bd9Sstevel@tonic-gate default: 40597c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 40607c478bd9Sstevel@tonic-gate sctp_send_abort(sctp, sctph->sh_verf, 0, NULL, 4061bd670b35SErik Nordmark 0, mp, 0, B_TRUE, ira); 40627c478bd9Sstevel@tonic-gate goto done; 40637c478bd9Sstevel@tonic-gate } 40647c478bd9Sstevel@tonic-gate break; 40657c478bd9Sstevel@tonic-gate 40667c478bd9Sstevel@tonic-gate case SCTPS_COOKIE_WAIT: 40677c478bd9Sstevel@tonic-gate switch (ch->sch_id) { 40687c478bd9Sstevel@tonic-gate case CHUNK_INIT_ACK: 40697c478bd9Sstevel@tonic-gate sctp_stop_faddr_timers(sctp); 40707c478bd9Sstevel@tonic-gate sctp_faddr_alive(sctp, sctp->sctp_current); 4071bd670b35SErik Nordmark sctp_send_cookie_echo(sctp, ch, mp, ira); 40727c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 40737c478bd9Sstevel@tonic-gate break; 40747c478bd9Sstevel@tonic-gate case CHUNK_ABORT: 40757c478bd9Sstevel@tonic-gate sctp_process_abort(sctp, ch, ECONNREFUSED); 40767c478bd9Sstevel@tonic-gate goto done; 40777c478bd9Sstevel@tonic-gate case CHUNK_INIT: 4078bd670b35SErik Nordmark sctp_send_initack(sctp, sctph, ch, mp, ira); 40797c478bd9Sstevel@tonic-gate break; 40807c478bd9Sstevel@tonic-gate case CHUNK_COOKIE: 4081bd670b35SErik Nordmark cr = ira->ira_cred; 4082bd670b35SErik Nordmark cpid = ira->ira_cpid; 4083de8c4a14SErik Nordmark 40847c478bd9Sstevel@tonic-gate if (sctp_process_cookie(sctp, ch, mp, &iack, 4085bd670b35SErik Nordmark sctph, &recv_adaptation, NULL, ira) == -1) { 40865dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, 40877c478bd9Sstevel@tonic-gate sctpInInvalidCookie); 40887c478bd9Sstevel@tonic-gate break; 40897c478bd9Sstevel@tonic-gate } 40907c478bd9Sstevel@tonic-gate sctp_send_cookie_ack(sctp); 40917c478bd9Sstevel@tonic-gate sctp_stop_faddr_timers(sctp); 40927c478bd9Sstevel@tonic-gate if (!SCTP_IS_DETACHED(sctp)) { 40937f093707Skcpoon sctp->sctp_ulp_connected( 4094de8c4a14SErik Nordmark sctp->sctp_ulpd, 0, cr, cpid); 40957c478bd9Sstevel@tonic-gate sctp_set_ulp_prop(sctp); 4096de8c4a14SErik Nordmark 40977c478bd9Sstevel@tonic-gate } 40985dd46ab5SKacheong Poon SCTP_ASSOC_EST(sctps, sctp); 40995dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpActiveEstab); 41007c478bd9Sstevel@tonic-gate if (sctp->sctp_cookie_mp) { 41017c478bd9Sstevel@tonic-gate freemsg(sctp->sctp_cookie_mp); 41027c478bd9Sstevel@tonic-gate sctp->sctp_cookie_mp = NULL; 41037c478bd9Sstevel@tonic-gate } 41047c478bd9Sstevel@tonic-gate 41057c478bd9Sstevel@tonic-gate /* Validate the peer addresses. */ 41067c478bd9Sstevel@tonic-gate sctp->sctp_active = now; 41077c478bd9Sstevel@tonic-gate sctp_validate_peer(sctp); 41087c478bd9Sstevel@tonic-gate 41097c478bd9Sstevel@tonic-gate sctp_assoc_event(sctp, SCTP_COMM_UP, 0, NULL); 4110558fbd03Skcpoon if (recv_adaptation) { 4111558fbd03Skcpoon sctp->sctp_recv_adaptation = 1; 4112558fbd03Skcpoon sctp_adaptation_event(sctp); 41137c478bd9Sstevel@tonic-gate } 41147c478bd9Sstevel@tonic-gate /* Try sending queued data, or ASCONFs */ 41157c478bd9Sstevel@tonic-gate trysend = 1; 41167c478bd9Sstevel@tonic-gate break; 41177c478bd9Sstevel@tonic-gate default: 41187c478bd9Sstevel@tonic-gate if (sctp_strange_chunk(sctp, ch, fp) == 0) { 41197c478bd9Sstevel@tonic-gate goto nomorechunks; 41207c478bd9Sstevel@tonic-gate } /* else skip and continue processing */ 41217c478bd9Sstevel@tonic-gate break; 41227c478bd9Sstevel@tonic-gate } 41237c478bd9Sstevel@tonic-gate break; 41247c478bd9Sstevel@tonic-gate 41257c478bd9Sstevel@tonic-gate case SCTPS_COOKIE_ECHOED: 41267c478bd9Sstevel@tonic-gate switch (ch->sch_id) { 41277c478bd9Sstevel@tonic-gate case CHUNK_COOKIE_ACK: 4128bd670b35SErik Nordmark cr = ira->ira_cred; 4129bd670b35SErik Nordmark cpid = ira->ira_cpid; 4130de8c4a14SErik Nordmark 41317c478bd9Sstevel@tonic-gate if (!SCTP_IS_DETACHED(sctp)) { 41327f093707Skcpoon sctp->sctp_ulp_connected( 4133de8c4a14SErik Nordmark sctp->sctp_ulpd, 0, cr, cpid); 41347c478bd9Sstevel@tonic-gate sctp_set_ulp_prop(sctp); 41357c478bd9Sstevel@tonic-gate } 41367c478bd9Sstevel@tonic-gate if (sctp->sctp_unacked == 0) 41377c478bd9Sstevel@tonic-gate sctp_stop_faddr_timers(sctp); 41385dd46ab5SKacheong Poon SCTP_ASSOC_EST(sctps, sctp); 41395dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpActiveEstab); 41407c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 41417c478bd9Sstevel@tonic-gate if (sctp->sctp_cookie_mp) { 41427c478bd9Sstevel@tonic-gate freemsg(sctp->sctp_cookie_mp); 41437c478bd9Sstevel@tonic-gate sctp->sctp_cookie_mp = NULL; 41447c478bd9Sstevel@tonic-gate } 41457c478bd9Sstevel@tonic-gate sctp_faddr_alive(sctp, fp); 41467c478bd9Sstevel@tonic-gate /* Validate the peer addresses. */ 41477c478bd9Sstevel@tonic-gate sctp->sctp_active = now; 41487c478bd9Sstevel@tonic-gate sctp_validate_peer(sctp); 41497c478bd9Sstevel@tonic-gate 41507c478bd9Sstevel@tonic-gate /* Try sending queued data, or ASCONFs */ 41517c478bd9Sstevel@tonic-gate trysend = 1; 41527c478bd9Sstevel@tonic-gate sctp_assoc_event(sctp, SCTP_COMM_UP, 0, NULL); 4153558fbd03Skcpoon sctp_adaptation_event(sctp); 41547c478bd9Sstevel@tonic-gate break; 41557c478bd9Sstevel@tonic-gate case CHUNK_ABORT: 41567c478bd9Sstevel@tonic-gate sctp_process_abort(sctp, ch, ECONNREFUSED); 41577c478bd9Sstevel@tonic-gate goto done; 41587c478bd9Sstevel@tonic-gate case CHUNK_COOKIE: 4159bd670b35SErik Nordmark cr = ira->ira_cred; 4160bd670b35SErik Nordmark cpid = ira->ira_cpid; 4161de8c4a14SErik Nordmark 41627c478bd9Sstevel@tonic-gate if (sctp_process_cookie(sctp, ch, mp, &iack, 4163bd670b35SErik Nordmark sctph, &recv_adaptation, NULL, ira) == -1) { 41645dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, 41657c478bd9Sstevel@tonic-gate sctpInInvalidCookie); 41667c478bd9Sstevel@tonic-gate break; 41677c478bd9Sstevel@tonic-gate } 41687c478bd9Sstevel@tonic-gate sctp_send_cookie_ack(sctp); 41697c478bd9Sstevel@tonic-gate 41707c478bd9Sstevel@tonic-gate if (!SCTP_IS_DETACHED(sctp)) { 41717f093707Skcpoon sctp->sctp_ulp_connected( 4172de8c4a14SErik Nordmark sctp->sctp_ulpd, 0, cr, cpid); 41737c478bd9Sstevel@tonic-gate sctp_set_ulp_prop(sctp); 4174de8c4a14SErik Nordmark 41757c478bd9Sstevel@tonic-gate } 41767c478bd9Sstevel@tonic-gate if (sctp->sctp_unacked == 0) 41777c478bd9Sstevel@tonic-gate sctp_stop_faddr_timers(sctp); 41785dd46ab5SKacheong Poon SCTP_ASSOC_EST(sctps, sctp); 41795dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpActiveEstab); 41807c478bd9Sstevel@tonic-gate if (sctp->sctp_cookie_mp) { 41817c478bd9Sstevel@tonic-gate freemsg(sctp->sctp_cookie_mp); 41827c478bd9Sstevel@tonic-gate sctp->sctp_cookie_mp = NULL; 41837c478bd9Sstevel@tonic-gate } 41847c478bd9Sstevel@tonic-gate /* Validate the peer addresses. */ 41857c478bd9Sstevel@tonic-gate sctp->sctp_active = now; 41867c478bd9Sstevel@tonic-gate sctp_validate_peer(sctp); 41877c478bd9Sstevel@tonic-gate 41887c478bd9Sstevel@tonic-gate sctp_assoc_event(sctp, SCTP_COMM_UP, 0, NULL); 4189558fbd03Skcpoon if (recv_adaptation) { 4190558fbd03Skcpoon sctp->sctp_recv_adaptation = 1; 4191558fbd03Skcpoon sctp_adaptation_event(sctp); 41927c478bd9Sstevel@tonic-gate } 41937c478bd9Sstevel@tonic-gate /* Try sending queued data, or ASCONFs */ 41947c478bd9Sstevel@tonic-gate trysend = 1; 41957c478bd9Sstevel@tonic-gate break; 41967c478bd9Sstevel@tonic-gate case CHUNK_INIT: 4197bd670b35SErik Nordmark sctp_send_initack(sctp, sctph, ch, mp, ira); 41987c478bd9Sstevel@tonic-gate break; 41997c478bd9Sstevel@tonic-gate case CHUNK_ERROR: { 42007c478bd9Sstevel@tonic-gate sctp_parm_hdr_t *p; 42017c478bd9Sstevel@tonic-gate 42027c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 42037c478bd9Sstevel@tonic-gate /* check for a stale cookie */ 42047c478bd9Sstevel@tonic-gate if (ntohs(ch->sch_len) >= 42057c478bd9Sstevel@tonic-gate (sizeof (*p) + sizeof (*ch)) + 42067c478bd9Sstevel@tonic-gate sizeof (uint32_t)) { 42077c478bd9Sstevel@tonic-gate 42087c478bd9Sstevel@tonic-gate p = (sctp_parm_hdr_t *)(ch + 1); 42097c478bd9Sstevel@tonic-gate if (p->sph_type == 42107c478bd9Sstevel@tonic-gate htons(SCTP_ERR_STALE_COOKIE)) { 42115dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, 42127c478bd9Sstevel@tonic-gate sctpAborted); 42138dfac042SAnil udupa sctp_error_event(sctp, 42148dfac042SAnil udupa ch, B_FALSE); 4215c9da23f8Skcpoon sctp_assoc_event(sctp, 4216c9da23f8Skcpoon SCTP_COMM_LOST, 0, NULL); 42177c478bd9Sstevel@tonic-gate sctp_clean_death(sctp, 42187c478bd9Sstevel@tonic-gate ECONNREFUSED); 42197c478bd9Sstevel@tonic-gate goto done; 42207c478bd9Sstevel@tonic-gate } 42217c478bd9Sstevel@tonic-gate } 42227c478bd9Sstevel@tonic-gate break; 42237c478bd9Sstevel@tonic-gate } 42247c478bd9Sstevel@tonic-gate case CHUNK_HEARTBEAT: 42257f093707Skcpoon if (!hb_already) { 42267c478bd9Sstevel@tonic-gate sctp_return_heartbeat(sctp, ch, mp); 42277f093707Skcpoon hb_already = B_TRUE; 42287f093707Skcpoon } 42297c478bd9Sstevel@tonic-gate break; 42307c478bd9Sstevel@tonic-gate default: 42317c478bd9Sstevel@tonic-gate if (sctp_strange_chunk(sctp, ch, fp) == 0) { 42327c478bd9Sstevel@tonic-gate goto nomorechunks; 42337c478bd9Sstevel@tonic-gate } /* else skip and continue processing */ 42347c478bd9Sstevel@tonic-gate } /* switch (ch->sch_id) */ 42357c478bd9Sstevel@tonic-gate break; 42367c478bd9Sstevel@tonic-gate 42377c478bd9Sstevel@tonic-gate case SCTPS_SHUTDOWN_ACK_SENT: 42387c478bd9Sstevel@tonic-gate switch (ch->sch_id) { 42397c478bd9Sstevel@tonic-gate case CHUNK_ABORT: 42407c478bd9Sstevel@tonic-gate /* Pass gathered wisdom to IP for keeping */ 4241bd670b35SErik Nordmark sctp_update_dce(sctp); 42427c478bd9Sstevel@tonic-gate sctp_process_abort(sctp, ch, 0); 42437c478bd9Sstevel@tonic-gate goto done; 42447c478bd9Sstevel@tonic-gate case CHUNK_SHUTDOWN_COMPLETE: 42457c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 42465dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpShutdowns); 42477c478bd9Sstevel@tonic-gate sctp_assoc_event(sctp, SCTP_SHUTDOWN_COMP, 0, 42487c478bd9Sstevel@tonic-gate NULL); 42497c478bd9Sstevel@tonic-gate 42507c478bd9Sstevel@tonic-gate /* Pass gathered wisdom to IP for keeping */ 4251bd670b35SErik Nordmark sctp_update_dce(sctp); 42527c478bd9Sstevel@tonic-gate sctp_clean_death(sctp, 0); 42537c478bd9Sstevel@tonic-gate goto done; 42547c478bd9Sstevel@tonic-gate case CHUNK_SHUTDOWN_ACK: 42557c478bd9Sstevel@tonic-gate sctp_shutdown_complete(sctp); 42567c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 42575dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpShutdowns); 42587c478bd9Sstevel@tonic-gate sctp_assoc_event(sctp, SCTP_SHUTDOWN_COMP, 0, 42597c478bd9Sstevel@tonic-gate NULL); 42607c478bd9Sstevel@tonic-gate sctp_clean_death(sctp, 0); 42617c478bd9Sstevel@tonic-gate goto done; 42627c478bd9Sstevel@tonic-gate case CHUNK_COOKIE: 42637c478bd9Sstevel@tonic-gate (void) sctp_shutdown_received(sctp, NULL, 426477c67f2fSkcpoon B_TRUE, B_FALSE, fp); 42657c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 42667c478bd9Sstevel@tonic-gate break; 42677c478bd9Sstevel@tonic-gate case CHUNK_HEARTBEAT: 42687f093707Skcpoon if (!hb_already) { 42697c478bd9Sstevel@tonic-gate sctp_return_heartbeat(sctp, ch, mp); 42707f093707Skcpoon hb_already = B_TRUE; 42717f093707Skcpoon } 42727c478bd9Sstevel@tonic-gate break; 42737c478bd9Sstevel@tonic-gate default: 42747c478bd9Sstevel@tonic-gate if (sctp_strange_chunk(sctp, ch, fp) == 0) { 42757c478bd9Sstevel@tonic-gate goto nomorechunks; 42767c478bd9Sstevel@tonic-gate } /* else skip and continue processing */ 42777c478bd9Sstevel@tonic-gate break; 42787c478bd9Sstevel@tonic-gate } 42797c478bd9Sstevel@tonic-gate break; 42807c478bd9Sstevel@tonic-gate 42817c478bd9Sstevel@tonic-gate case SCTPS_SHUTDOWN_RECEIVED: 42827c478bd9Sstevel@tonic-gate switch (ch->sch_id) { 42837c478bd9Sstevel@tonic-gate case CHUNK_SHUTDOWN: 42847c478bd9Sstevel@tonic-gate trysend = sctp_shutdown_received(sctp, ch, 428577c67f2fSkcpoon B_FALSE, B_FALSE, fp); 42863e1dae9fSAnil udupa /* 42873e1dae9fSAnil udupa * shutdown_ack_needed may have been set as 42883e1dae9fSAnil udupa * mentioned in the case CHUNK_SACK below. 42893e1dae9fSAnil udupa * If sctp_shutdown_received() above found 42903e1dae9fSAnil udupa * the xmit queue empty the SHUTDOWN ACK chunk 42913e1dae9fSAnil udupa * has already been sent (or scheduled to be 42923e1dae9fSAnil udupa * sent on the timer) and the SCTP state 42933e1dae9fSAnil udupa * changed, so reset shutdown_ack_needed. 42943e1dae9fSAnil udupa */ 42953e1dae9fSAnil udupa if (shutdown_ack_needed && (sctp->sctp_state == 42963e1dae9fSAnil udupa SCTPS_SHUTDOWN_ACK_SENT)) 42973e1dae9fSAnil udupa shutdown_ack_needed = B_FALSE; 42987c478bd9Sstevel@tonic-gate break; 42997c478bd9Sstevel@tonic-gate case CHUNK_SACK: 43007c478bd9Sstevel@tonic-gate trysend = sctp_got_sack(sctp, ch); 43011d8c4025Svi117747 if (trysend < 0) { 43021d8c4025Svi117747 sctp_send_abort(sctp, sctph->sh_verf, 4303bd670b35SErik Nordmark 0, NULL, 0, mp, 0, B_FALSE, ira); 43041d8c4025Svi117747 sctp_assoc_event(sctp, 43051d8c4025Svi117747 SCTP_COMM_LOST, 0, NULL); 43061d8c4025Svi117747 sctp_clean_death(sctp, 43071d8c4025Svi117747 ECONNABORTED); 43081d8c4025Svi117747 goto done; 43091d8c4025Svi117747 } 43103e1dae9fSAnil udupa 43113e1dae9fSAnil udupa /* 43123e1dae9fSAnil udupa * All data acknowledgement after a shutdown 43133e1dae9fSAnil udupa * should be done with SHUTDOWN chunk. 43143e1dae9fSAnil udupa * However some peer SCTP do not conform with 43153e1dae9fSAnil udupa * this and can unexpectedly send a SACK chunk. 43163e1dae9fSAnil udupa * If all data are acknowledged, set 43173e1dae9fSAnil udupa * shutdown_ack_needed here indicating that 43183e1dae9fSAnil udupa * SHUTDOWN ACK needs to be sent later by 43193e1dae9fSAnil udupa * sctp_send_shutdown_ack(). 43203e1dae9fSAnil udupa */ 43213e1dae9fSAnil udupa if ((sctp->sctp_xmit_head == NULL) && 43223e1dae9fSAnil udupa (sctp->sctp_xmit_unsent == NULL)) 43233e1dae9fSAnil udupa shutdown_ack_needed = B_TRUE; 43247c478bd9Sstevel@tonic-gate break; 43257c478bd9Sstevel@tonic-gate case CHUNK_ABORT: 43267c478bd9Sstevel@tonic-gate sctp_process_abort(sctp, ch, ECONNRESET); 43277c478bd9Sstevel@tonic-gate goto done; 43287c478bd9Sstevel@tonic-gate case CHUNK_HEARTBEAT: 43297f093707Skcpoon if (!hb_already) { 43307c478bd9Sstevel@tonic-gate sctp_return_heartbeat(sctp, ch, mp); 43317f093707Skcpoon hb_already = B_TRUE; 43327f093707Skcpoon } 43337c478bd9Sstevel@tonic-gate break; 43347c478bd9Sstevel@tonic-gate default: 43357c478bd9Sstevel@tonic-gate if (sctp_strange_chunk(sctp, ch, fp) == 0) { 43367c478bd9Sstevel@tonic-gate goto nomorechunks; 43377c478bd9Sstevel@tonic-gate } /* else skip and continue processing */ 43387c478bd9Sstevel@tonic-gate break; 43397c478bd9Sstevel@tonic-gate } 43407c478bd9Sstevel@tonic-gate break; 43417c478bd9Sstevel@tonic-gate 43427c478bd9Sstevel@tonic-gate default: 4343769b977dSvi117747 /* 4344769b977dSvi117747 * The only remaining states are SCTPS_IDLE and 4345769b977dSvi117747 * SCTPS_BOUND, and we should not be getting here 4346769b977dSvi117747 * for these. 4347769b977dSvi117747 */ 4348769b977dSvi117747 ASSERT(0); 43497c478bd9Sstevel@tonic-gate } /* switch (sctp->sctp_state) */ 43507c478bd9Sstevel@tonic-gate 43517c478bd9Sstevel@tonic-gate ch = sctp_next_chunk(ch, &mlen); 43527c478bd9Sstevel@tonic-gate if (ch != NULL && !sctp_check_input(sctp, ch, mlen, 0)) 43537c478bd9Sstevel@tonic-gate goto done; 43547c478bd9Sstevel@tonic-gate } while (ch != NULL); 43557c478bd9Sstevel@tonic-gate 43567c478bd9Sstevel@tonic-gate /* Finished processing all chunks in packet */ 43577c478bd9Sstevel@tonic-gate 43587c478bd9Sstevel@tonic-gate nomorechunks: 43593e1dae9fSAnil udupa 43603e1dae9fSAnil udupa if (shutdown_ack_needed) 43613e1dae9fSAnil udupa sctp_send_shutdown_ack(sctp, fp, B_FALSE); 43623e1dae9fSAnil udupa 43637c478bd9Sstevel@tonic-gate /* SACK if necessary */ 43647c478bd9Sstevel@tonic-gate if (gotdata) { 43657f093707Skcpoon boolean_t sack_sent; 43667f093707Skcpoon 43677c478bd9Sstevel@tonic-gate (sctp->sctp_sack_toggle)++; 43687f093707Skcpoon sack_sent = sctp_sack(sctp, dups); 43697c478bd9Sstevel@tonic-gate dups = NULL; 43707c478bd9Sstevel@tonic-gate 43717f093707Skcpoon /* If a SACK is sent, no need to restart the timer. */ 43727f093707Skcpoon if (!sack_sent && !sctp->sctp_ack_timer_running) { 43737c478bd9Sstevel@tonic-gate sctp->sctp_ack_timer_running = B_TRUE; 43747c478bd9Sstevel@tonic-gate sctp_timer(sctp, sctp->sctp_ack_mp, 4375f4b3ec61Sdh155122 MSEC_TO_TICK(sctps->sctps_deferred_ack_interval)); 43767c478bd9Sstevel@tonic-gate } 43777c478bd9Sstevel@tonic-gate } 43787c478bd9Sstevel@tonic-gate 43797c478bd9Sstevel@tonic-gate if (trysend) { 438012f47623Skcpoon sctp_output(sctp, UINT_MAX); 43817c478bd9Sstevel@tonic-gate if (sctp->sctp_cxmit_list != NULL) 43827c478bd9Sstevel@tonic-gate sctp_wput_asconf(sctp, NULL); 43837c478bd9Sstevel@tonic-gate } 438492baa190SGeorge Shepherd /* 438592baa190SGeorge Shepherd * If there is unsent data, make sure a timer is running, check 438692baa190SGeorge Shepherd * timer_mp, if sctp_closei_local() ran the timers may be free. 438792baa190SGeorge Shepherd */ 43886be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (sctp->sctp_unsent > 0 && !sctp->sctp_current->sf_timer_running && 43896be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp->sctp_current->sf_timer_mp != NULL) { 43907c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, sctp->sctp_current, 43916be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp->sctp_current->sf_rto); 43927c478bd9Sstevel@tonic-gate } 43937c478bd9Sstevel@tonic-gate 43947c478bd9Sstevel@tonic-gate done: 43957c478bd9Sstevel@tonic-gate if (dups != NULL) 43967c478bd9Sstevel@tonic-gate freeb(dups); 43977c478bd9Sstevel@tonic-gate freemsg(mp); 43987c478bd9Sstevel@tonic-gate 43997f093707Skcpoon if (sctp->sctp_err_chunks != NULL) 44007f093707Skcpoon sctp_process_err(sctp); 44017f093707Skcpoon 44027c478bd9Sstevel@tonic-gate if (wake_eager) { 44037c478bd9Sstevel@tonic-gate /* 44047c478bd9Sstevel@tonic-gate * sctp points to newly created control block, need to 4405bd670b35SErik Nordmark * release it before exiting. 44067c478bd9Sstevel@tonic-gate */ 44077c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 44087c478bd9Sstevel@tonic-gate } 44097c478bd9Sstevel@tonic-gate } 44107c478bd9Sstevel@tonic-gate 44117c478bd9Sstevel@tonic-gate /* 4412*a215d4ebSKacheong Poon * Some amount of data got removed from ULP's receive queue and we can 4413*a215d4ebSKacheong Poon * push messages up if we are flow controlled before. Reset the receive 4414*a215d4ebSKacheong Poon * window to full capacity (conn_rcvbuf) and check if we should send a 4415*a215d4ebSKacheong Poon * window update. 44167c478bd9Sstevel@tonic-gate */ 44177c478bd9Sstevel@tonic-gate void 44187c478bd9Sstevel@tonic-gate sctp_recvd(sctp_t *sctp, int len) 44197c478bd9Sstevel@tonic-gate { 4420f4b3ec61Sdh155122 sctp_stack_t *sctps = sctp->sctp_sctps; 4421*a215d4ebSKacheong Poon conn_t *connp = sctp->sctp_connp; 4422*a215d4ebSKacheong Poon boolean_t send_sack = B_FALSE; 44237c478bd9Sstevel@tonic-gate 44247c478bd9Sstevel@tonic-gate ASSERT(sctp != NULL); 44257c478bd9Sstevel@tonic-gate RUN_SCTP(sctp); 44267c478bd9Sstevel@tonic-gate 4427*a215d4ebSKacheong Poon sctp->sctp_flowctrld = B_FALSE; 4428*a215d4ebSKacheong Poon /* This is the amount of data queued in ULP. */ 4429*a215d4ebSKacheong Poon sctp->sctp_ulp_rxqueued = connp->conn_rcvbuf - len; 4430c3c17166SGeorge Shepherd 4431*a215d4ebSKacheong Poon if (connp->conn_rcvbuf - sctp->sctp_arwnd >= sctp->sctp_mss) 4432*a215d4ebSKacheong Poon send_sack = B_TRUE; 4433*a215d4ebSKacheong Poon sctp->sctp_rwnd = connp->conn_rcvbuf; 44347c478bd9Sstevel@tonic-gate 4435*a215d4ebSKacheong Poon if (sctp->sctp_state >= SCTPS_ESTABLISHED && send_sack) { 44367c478bd9Sstevel@tonic-gate sctp->sctp_force_sack = 1; 44375dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpOutWinUpdate); 44387f093707Skcpoon (void) sctp_sack(sctp, NULL); 44397c478bd9Sstevel@tonic-gate } 44407c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 44417c478bd9Sstevel@tonic-gate } 4442