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
sctp_free_set(sctp_set_t * s)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
sctp_ack_add(sctp_set_t ** head,uint32_t tsn,int * num)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
sctp_ack_rem(sctp_set_t ** head,uint32_t end,int * num)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
sctp_sets_init()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
sctp_sets_fini()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 *
sctp_first_chunk(uchar_t * rptr,ssize_t remaining)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 *
sctp_next_chunk(sctp_chunk_hdr_t * ch,ssize_t * remaining)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
sctp_input_add_ancillary(sctp_t * sctp,mblk_t ** mp,sctp_data_hdr_t * dcp,sctp_faddr_t * fp,ip_pkt_t * ipp,ip_recv_attr_t * ira)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
sctp_free_reass(sctp_instr_t * sip)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 *
sctp_uodata_frag(sctp_t * sctp,mblk_t * dmp,sctp_data_hdr_t ** dc)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 *
sctp_try_partial_delivery(sctp_t * sctp,mblk_t * hmp,sctp_reass_t * srp,sctp_data_hdr_t ** dc)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 *
sctp_data_frag(sctp_t * sctp,mblk_t * dmp,sctp_data_hdr_t ** dc,int * error,sctp_instr_t * sip,boolean_t * tpfinished)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
sctp_add_dup(uint32_t tsn,mblk_t ** dups)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
sctp_data_chunk(sctp_t * sctp,sctp_chunk_hdr_t * ch,mblk_t * mp,mblk_t ** dups,sctp_faddr_t * fp,ip_pkt_t * ipp,ip_recv_attr_t * ira)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
sctp_fill_sack(sctp_t * sctp,unsigned char * dst,int sacklen)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 *
sctp_make_sack(sctp_t * sctp,sctp_faddr_t * sendto,mblk_t * dups)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
sctp_sack(sctp_t * sctp,mblk_t * dups)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
sctp_check_abandoned_msg(sctp_t * sctp,mblk_t * meta)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
sctp_cumack(sctp_t * sctp,uint32_t tsn,mblk_t ** first_unacked)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
sctp_set_frwnd(sctp_t * sctp,uint32_t frwnd)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
sctp_ftsn_check_uo_frag(sctp_t * sctp,uint32_t ftsn)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
sctp_ftsn_check_frag(sctp_t * sctp,uint16_t ssn,sctp_instr_t * sip)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
sctp_process_forward_tsn(sctp_t * sctp,sctp_chunk_hdr_t * ch,sctp_faddr_t * fp,ip_pkt_t * ipp,ip_recv_attr_t * ira)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
sctp_check_abandoned_data(sctp_t * sctp,sctp_faddr_t * fp)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
sctp_process_uo_gaps(sctp_t * sctp,uint32_t ctsn,sctp_sack_frag_t * ssf,int num_gaps,mblk_t * umphead,mblk_t * mphead,int * trysend,boolean_t * fast_recovery,uint32_t fr_xtsn)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
sctp_got_sack(sctp_t * sctp,sctp_chunk_hdr_t * sch)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
sctp_strange_chunk(sctp_t * sctp,sctp_chunk_hdr_t * ch,sctp_faddr_t * fp)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
sctp_check_input(sctp_t * sctp,sctp_chunk_hdr_t * ch,ssize_t len,int first)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 *
sctp_check_in_policy(mblk_t * mp,ip_recv_attr_t * ira,ip_stack_t * ipst)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
sctp_ootb_input(mblk_t * mp,ip_recv_attr_t * ira,ip_stack_t * ipst)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
sctp_input(conn_t * connp,ipha_t * ipha,ip6_t * ip6h,mblk_t * mp,ip_recv_attr_t * ira)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
sctp_process_abort(sctp_t * sctp,sctp_chunk_hdr_t * ch,int err)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
sctp_input_data(sctp_t * sctp,mblk_t * mp,ip_recv_attr_t * ira)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
sctp_recvd(sctp_t * sctp,int len)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