changeset 3845:cbc537e53089

6521543 recv may return fragmented messages on SCTP sockets on S10 when it need not
author vi117747
date Fri, 16 Mar 2007 17:42:01 -0700
parents 8c345d3f2fd4
children 64a25284bab5
files usr/src/cmd/mdb/common/modules/sctp/sctp.c usr/src/uts/common/inet/sctp/sctp.c usr/src/uts/common/inet/sctp/sctp_conn.c usr/src/uts/common/inet/sctp/sctp_impl.h usr/src/uts/common/inet/sctp/sctp_input.c usr/src/uts/common/inet/sctp/sctp_opt_data.c
diffstat 6 files changed, 252 insertions(+), 250 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/mdb/common/modules/sctp/sctp.c	Fri Mar 16 16:11:15 2007 -0700
+++ b/usr/src/cmd/mdb/common/modules/sctp/sctp.c	Fri Mar 16 17:42:01 2007 -0700
@@ -949,12 +949,14 @@
 		    "family\t\t%?u\tipversion\t%?hu\n"
 		    "hb_interval\t%?u\tautoclose\t%?d\n"
 		    "active\t\t%?ld\ttx_adaption_code%?x\n"
-		    "rx_adaption_code%?x\ttimer_mp\t%?p\n",
+		    "rx_adaption_code%?x\ttimer_mp\t%?p\n"
+		    "partial_delivery_point\t%?d\n",
 		    sctp.sctp_bound_if, sctp.sctp_heartbeat_mp,
 		    sctp.sctp_family, sctp.sctp_ipversion,
 		    sctp.sctp_hb_interval, sctp.sctp_autoclose,
 		    sctp.sctp_active, sctp.sctp_tx_adaption_code,
-		    sctp.sctp_rx_adaption_code, sctp.sctp_timer_mp);
+		    sctp.sctp_rx_adaption_code, sctp.sctp_timer_mp,
+		    sctp.sctp_pd_point);
 	}
 
 	if (opts & MDB_SCTP_SHOW_EXT) {
--- a/usr/src/uts/common/inet/sctp/sctp.c	Fri Mar 16 16:11:15 2007 -0700
+++ b/usr/src/uts/common/inet/sctp/sctp.c	Fri Mar 16 17:42:01 2007 -0700
@@ -954,7 +954,7 @@
 		sctp->sctp_cwnd_max = psctp->sctp_cwnd_max;
 		sctp->sctp_rwnd = psctp->sctp_rwnd;
 		sctp->sctp_irwnd = psctp->sctp_rwnd;
-
+		sctp->sctp_pd_point = psctp->sctp_pd_point;
 		sctp->sctp_rto_max = psctp->sctp_rto_max;
 		sctp->sctp_init_rto_max = psctp->sctp_init_rto_max;
 		sctp->sctp_rto_min = psctp->sctp_rto_min;
@@ -1015,6 +1015,7 @@
 		sctp->sctp_cwnd_max = sctps->sctps_cwnd_max_;
 		sctp->sctp_rwnd = sctps->sctps_recv_hiwat;
 		sctp->sctp_irwnd = sctp->sctp_rwnd;
+		sctp->sctp_pd_point = sctp->sctp_rwnd;
 		sctp->sctp_rto_max = MSEC_TO_TICK(sctps->sctps_rto_maxg);
 		sctp->sctp_init_rto_max = sctp->sctp_rto_max;
 		sctp->sctp_rto_min = MSEC_TO_TICK(sctps->sctps_rto_ming);
--- a/usr/src/uts/common/inet/sctp/sctp_conn.c	Fri Mar 16 16:11:15 2007 -0700
+++ b/usr/src/uts/common/inet/sctp/sctp_conn.c	Fri Mar 16 17:42:01 2007 -0700
@@ -151,6 +151,7 @@
 	 */
 	acceptor->sctp_rwnd = listener->sctp_rwnd;
 	acceptor->sctp_irwnd = acceptor->sctp_rwnd;
+	acceptor->sctp_pd_point = acceptor->sctp_rwnd;
 	bcopy(&listener->sctp_upcalls, &acceptor->sctp_upcalls,
 	    sizeof (sctp_upcalls_t));
 
--- a/usr/src/uts/common/inet/sctp/sctp_impl.h	Fri Mar 16 16:11:15 2007 -0700
+++ b/usr/src/uts/common/inet/sctp/sctp_impl.h	Fri Mar 16 17:42:01 2007 -0700
@@ -423,7 +423,13 @@
 	uint16_t	ssn;
 	uint16_t	needed;
 	uint16_t	got;
+	uint16_t	msglen;		/* len of consecutive fragments */
+					/* from the begining (B-bit) */
 	mblk_t		*tail;
+	boolean_t	hasBchunk;	/* If the fragment list begins with */
+					/* a B-bit set chunk */
+	uint32_t	nexttsn;	/* TSN of the next fragment we */
+					/* are expecting */
 	boolean_t	partial_delivered;
 } sctp_reass_t;
 
@@ -920,6 +926,8 @@
 	uint_t		sctp_v6label_len;	/* length of cached v6 label */
 	uint32_t	sctp_rxt_nxttsn;	/* Next TSN to be rexmitted */
 	uint32_t	sctp_rxt_maxtsn;	/* Max TSN sent at time out */
+
+	int		sctp_pd_point;		/* Partial delivery point */
 } sctp_t;
 
 #endif	/* (defined(_KERNEL) || defined(_KMEMUSER)) */
--- a/usr/src/uts/common/inet/sctp/sctp_input.c	Fri Mar 16 16:11:15 2007 -0700
+++ b/usr/src/uts/common/inet/sctp/sctp_input.c	Fri Mar 16 17:42:01 2007 -0700
@@ -772,55 +772,148 @@
 #endif
 	return (begin);
 }
+
+/*
+ * Try partial delivery.
+ */
+static mblk_t *
+sctp_try_partial_delivery(sctp_t *sctp, mblk_t *hmp, sctp_reass_t *srp,
+    sctp_data_hdr_t **dc)
+{
+	mblk_t		*first_mp;
+	mblk_t		*mp;
+	mblk_t		*dmp;
+	mblk_t		*qmp;
+	mblk_t		*prev;
+	sctp_data_hdr_t	*qdc;
+	uint32_t	tsn;
+
+	ASSERT(DB_TYPE(hmp) == M_CTL);
+
+	dprint(4, ("trypartial: got=%d, needed=%d\n",
+	    (int)(srp->got), (int)(srp->needed)));
+
+	first_mp = hmp->b_cont;
+	mp = first_mp;
+	qdc = (sctp_data_hdr_t *)mp->b_rptr;
+
+	ASSERT(SCTP_DATA_GET_BBIT(qdc) && srp->hasBchunk);
+
+	tsn = ntohl(qdc->sdh_tsn) + 1;
+
+	/*
+	 * This loop has two exit conditions: the
+	 * end of received chunks has been reached, or
+	 * there is a break in the sequence. We want
+	 * to chop the reassembly list as follows (the
+	 * numbers are TSNs):
+	 *   10 -> 11 -> 	(end of chunks)
+	 *   10 -> 11 -> | 13   (break in sequence)
+	 */
+	prev = mp;
+	mp = mp->b_cont;
+	while (mp != NULL) {
+		qdc = (sctp_data_hdr_t *)mp->b_rptr;
+		if (ntohl(qdc->sdh_tsn) != tsn)
+			break;
+		prev = mp;
+		mp = mp->b_cont;
+		tsn++;
+	}
+	/*
+	 * We are sending all the fragments upstream, we have to retain
+	 * the srp info for further fragments.
+	 */
+	if (mp == NULL) {
+		dmp = hmp->b_cont;
+		hmp->b_cont = NULL;
+		srp->nexttsn = tsn;
+		srp->msglen = 0;
+		srp->needed = 0;
+		srp->got = 0;
+		srp->partial_delivered = B_TRUE;
+		srp->tail = NULL;
+	} else {
+		dmp = hmp->b_cont;
+		hmp->b_cont = mp;
+	}
+	srp->hasBchunk = B_FALSE;
+	/*
+	 * mp now points at the last chunk in the sequence,
+	 * and prev points to mp's previous in the list.
+	 * We chop the list at prev, and convert mp into the
+	 * new list head by setting the B bit. Subsequence
+	 * fragment deliveries will follow the normal reassembly
+	 * path.
+	 */
+	prev->b_cont = NULL;
+	srp->partial_delivered = B_TRUE;
+
+	dprint(4, ("trypartial: got some, got=%d, needed=%d\n",
+	    (int)(srp->got), (int)(srp->needed)));
+
+	/*
+	 * Adjust all mblk's except the lead so their rptr's point to the
+	 * payload. sctp_data_chunk() will need to process the lead's
+	 * data chunk section, so leave it's rptr pointing at the data chunk.
+	 */
+	*dc = (sctp_data_hdr_t *)dmp->b_rptr;
+	if (srp->tail != NULL) {
+		srp->got--;
+		ASSERT(srp->got != 0);
+		if (srp->needed != 0) {
+			srp->needed--;
+			ASSERT(srp->needed != 0);
+		}
+		srp->msglen -= ntohs((*dc)->sdh_len);
+	}
+	for (qmp = dmp->b_cont; qmp != NULL; qmp = qmp->b_cont) {
+		qdc = (sctp_data_hdr_t *)qmp->b_rptr;
+		qmp->b_rptr = (uchar_t *)(qdc + 1);
+
+		/*
+		 * Deduct the balance from got and needed here, now that
+		 * we know we are actually delivering these data.
+		 */
+		if (srp->tail != NULL) {
+			srp->got--;
+			ASSERT(srp->got != 0);
+			if (srp->needed != 0) {
+				srp->needed--;
+				ASSERT(srp->needed != 0);
+			}
+			srp->msglen -= ntohs(qdc->sdh_len);
+		}
+	}
+	ASSERT(srp->msglen == 0);
+	BUMP_LOCAL(sctp->sctp_reassmsgs);
+
+	return (dmp);
+}
+
 /*
  * Fragment list for ordered messages.
  * If no error occures, error is set to 0. If we run out of memory, error
  * is set to 1. If the peer commits a fatal error (like using different
  * sequence numbers for the same data fragment series), the association is
- * aborted and error is set to 2.
+ * aborted and error is set to 2. tpfinished indicates whether we have
+ * assembled a complete message, this is used in sctp_data_chunk() to
+ * see if we can try to send any queued message for this stream.
  */
 static mblk_t *
 sctp_data_frag(sctp_t *sctp, mblk_t *dmp, sctp_data_hdr_t **dc, int *error,
-    sctp_instr_t *sip, int trypartial, int *tpfinished)
+    sctp_instr_t *sip, boolean_t *tpfinished)
 {
 	mblk_t		*hmp;
 	mblk_t		*pmp;
 	mblk_t		*qmp;
-	mblk_t		*mp;
-	mblk_t		*prev;
-	mblk_t		*prevprev;
 	mblk_t		*first_mp;
 	sctp_reass_t	*srp;
 	sctp_data_hdr_t	*qdc;
 	sctp_data_hdr_t	*bdc;
 	sctp_data_hdr_t	*edc;
 	uint32_t	tsn;
-
-	/*
-	 * We can overwrite the Link Layer + IP header here, I suppose.
-	 * The M_CTL does not leave this function. We need to check
-	 * DB_REF(dmp) before using DB_BASE(dmp), since there could be
-	 * two fragments for different ssns in the same mblk.
-	 */
-#define	SCTP_NEW_REASS(nmp, dmp, srp, seterror)				\
-	if ((DB_REF(dmp) == 2) && (MBLKHEAD(dmp) >= 			\
-	    (sizeof (*(srp)) + sizeof (sctp_hdr_t))) &&			\
-	    (IS_P2ALIGNED(DB_BASE(dmp), sizeof (uintptr_t)))) {		\
-		(nmp) = (dmp);						\
-	} else {							\
-		(nmp) = allocb(sizeof (*(srp)), BPRI_MED); 		\
-		if ((nmp) == NULL) {					\
-			switch (seterror) {				\
-			case B_TRUE:					\
-				*error = 1;				\
-				break;					\
-			}						\
-			return (NULL);					\
-		}							\
-		DB_TYPE(nmp) = M_CTL;					\
-		(nmp)->b_cont = dmp;					\
-	}								\
-	(srp) = (sctp_reass_t *)DB_BASE(nmp);
+	uint16_t	fraglen = 0;
 
 	*error = 0;
 
@@ -835,12 +928,17 @@
 		qmp = hmp;
 	}
 
-	SCTP_NEW_REASS(pmp, dmp, srp, B_TRUE);
-	srp->ssn = ntohs((*dc)->sdh_ssn);
-	srp->needed = 0;
-	srp->got = 1;
-	srp->tail = dmp;
-	srp->partial_delivered = B_FALSE;
+	/*
+	 * Allocate a M_CTL that will contain information about this
+	 * fragmented message.
+	 */
+	if ((pmp = allocb(sizeof (*srp), BPRI_MED)) == NULL) {
+		*error = 1;
+		return (NULL);
+	}
+	DB_TYPE(pmp) = M_CTL;
+	srp = (sctp_reass_t *)DB_BASE(pmp);
+	pmp->b_cont = dmp;
 
 	if (hmp != NULL) {
 		if (sip->istr_reass == hmp) {
@@ -865,6 +963,28 @@
 		}
 		pmp->b_next = NULL;
 	}
+	srp->partial_delivered = B_FALSE;
+	srp->ssn = ntohs((*dc)->sdh_ssn);
+empty_srp:
+	srp->needed = 0;
+	srp->got = 1;
+	srp->tail = dmp;
+	if (SCTP_DATA_GET_BBIT(*dc)) {
+		srp->msglen = ntohs((*dc)->sdh_len);
+		srp->nexttsn = ntohl((*dc)->sdh_tsn) + 1;
+		srp->hasBchunk = B_TRUE;
+	} else if (srp->partial_delivered &&
+	    srp->nexttsn == ntohl((*dc)->sdh_tsn)) {
+		SCTP_DATA_SET_BBIT(*dc);
+		/* Last fragment */
+		if (SCTP_DATA_GET_EBIT(*dc)) {
+			srp->needed = 1;
+			goto frag_done;
+		}
+		srp->hasBchunk = B_TRUE;
+		srp->msglen = ntohs((*dc)->sdh_len);
+		srp->nexttsn++;
+	}
 	return (NULL);
 foundit:
 	/*
@@ -872,8 +992,18 @@
 	 * in the reassemble queue. Try the tail first, on the assumption
 	 * that the fragments are coming in in order.
 	 */
-
 	qmp = srp->tail;
+
+	/*
+	 * This means the message was partially delivered.
+	 */
+	if (qmp == NULL) {
+		ASSERT(srp->got == 0 && srp->needed == 0 &&
+		    srp->partial_delivered);
+		ASSERT(hmp->b_cont == NULL);
+		hmp->b_cont = dmp;
+		goto empty_srp;
+	}
 	qdc = (sctp_data_hdr_t *)qmp->b_rptr;
 	ASSERT(qmp->b_cont == NULL);
 
@@ -887,46 +1017,24 @@
 		qmp->b_cont = dmp;
 		srp->tail = dmp;
 		dmp->b_cont = NULL;
+		if (srp->hasBchunk && srp->nexttsn == ntohl((*dc)->sdh_tsn)) {
+			srp->msglen += ntohs((*dc)->sdh_len);
+			srp->nexttsn++;
+		}
 		goto inserted;
 	}
 
 	/* Next check for insertion at the beginning */
-	qmp = (DB_TYPE(hmp) == M_DATA) ? hmp : hmp->b_cont;
+	qmp = hmp->b_cont;
 	qdc = (sctp_data_hdr_t *)qmp->b_rptr;
 	if (SEQ_LT(ntohl((*dc)->sdh_tsn), ntohl(qdc->sdh_tsn))) {
-		if (DB_TYPE(hmp) == M_DATA) {
-			sctp_reass_t	*srp1 = srp;
-
-			SCTP_NEW_REASS(pmp, dmp, srp, B_TRUE);
-			ASSERT(pmp->b_prev == NULL && pmp->b_next == NULL);
-			if (sip->istr_reass == hmp) {
-				sip->istr_reass = pmp;
-				if (hmp->b_next != NULL) {
-					hmp->b_next->b_prev = pmp;
-					pmp->b_next = hmp->b_next;
-				}
-			} else {
-				hmp->b_prev->b_next = pmp;
-				pmp->b_prev = hmp->b_prev;
-				if (hmp->b_next != NULL) {
-					hmp->b_next->b_prev = pmp;
-					pmp->b_next = hmp->b_next;
-				}
-			}
-			srp->ssn = srp1->ssn;
-			srp->needed = srp1->needed;
-			srp->got = srp1->got;
-			srp->tail = srp1->tail;
-			srp->partial_delivered = srp1->partial_delivered;
-			hmp->b_next = hmp->b_prev = NULL;
-			dmp->b_cont = hmp;
-			hmp = pmp;
-		} else {
-			ASSERT(DB_TYPE(hmp) == M_CTL);
-			dmp->b_cont = qmp;
-			hmp->b_cont = dmp;
+		dmp->b_cont = qmp;
+		hmp->b_cont = dmp;
+		if (SCTP_DATA_GET_BBIT(*dc)) {
+			srp->hasBchunk = B_TRUE;
+			srp->nexttsn = ntohl((*dc)->sdh_tsn);
 		}
-		goto inserted;
+		goto preinserted;
 	}
 
 	/* Insert somewhere in the middle */
@@ -943,148 +1051,71 @@
 		}
 		qmp = qmp->b_cont;
 	}
-
+preinserted:
+	if (!srp->hasBchunk || ntohl((*dc)->sdh_tsn) != srp->nexttsn)
+		goto inserted;
+	/*
+	 * fraglen contains the length of consecutive chunks of fragments.
+	 * starting from the chunk inserted recently.
+	 */
+	tsn = srp->nexttsn;
+	for (qmp = dmp; qmp != NULL; qmp = qmp->b_cont) {
+		qdc = (sctp_data_hdr_t *)qmp->b_rptr;
+		if (tsn != ntohl(qdc->sdh_tsn))
+			break;
+		fraglen += ntohs(qdc->sdh_len);
+		tsn++;
+	}
+	srp->nexttsn = tsn;
+	srp->msglen += fraglen;
 inserted:
-	(srp->got)++;
-	first_mp = (DB_TYPE(hmp) == M_DATA) ? hmp : hmp->b_cont;
+	srp->got++;
+	first_mp = hmp->b_cont;
 	if (srp->needed == 0) {
 		/* check if we have the first and last fragments */
 		bdc = (sctp_data_hdr_t *)first_mp->b_rptr;
 		edc = (sctp_data_hdr_t *)srp->tail->b_rptr;
 
 		/* calculate how many fragments are needed, if possible  */
-		if (SCTP_DATA_GET_BBIT(bdc) && SCTP_DATA_GET_EBIT(edc))
+		if (SCTP_DATA_GET_BBIT(bdc) && SCTP_DATA_GET_EBIT(edc)) {
 			srp->needed = ntohl(edc->sdh_tsn) -
 			    ntohl(bdc->sdh_tsn) + 1;
-	}
-
-	if (srp->needed != srp->got) {
-		if (!trypartial)
-			return (NULL);
-		/*
-		 * Try partial delivery. We need a consecutive run of
-		 * at least two chunks, starting from the first chunk
-		 * (which may have been the last + 1 chunk from a
-		 * previous partial delivery).
-		 */
-		dprint(4, ("trypartial: got=%d, needed=%d\n",
-		    (int)(srp->got), (int)(srp->needed)));
-		mp = first_mp;
-		if (mp->b_cont == NULL) {
-			/* need at least two chunks */
-			dprint(4, ("trypartial: only 1 chunk\n"));
-			return (NULL);
-		}
-
-		qdc = (sctp_data_hdr_t *)mp->b_rptr;
-		if (!SCTP_DATA_GET_BBIT(qdc)) {
-			/* don't have first chunk; can't do it. */
-			dprint(4, ("trypartial: no beginning\n"));
-			return (NULL);
 		}
-
-		tsn = ntohl(qdc->sdh_tsn) + 1;
-
-		/*
-		 * This loop has two exit conditions: the
-		 * end of received chunks has been reached, or
-		 * there is a break in the sequence. We want
-		 * to chop the reassembly list as follows (the
-		 * numbers are TSNs):
-		 *   10 -> 11 -> | 12	(end of chunks)
-		 *   10 -> 11 -> | 12 -> 14 (break in sequence)
-		 */
-		prevprev = prev = mp;
-		mp = mp->b_cont;
-		while (mp != NULL) {
-			qdc = (sctp_data_hdr_t *)mp->b_rptr;
-			if (ntohl(qdc->sdh_tsn) != tsn) {
-				/*
-				 * break in sequence.
-				 * 1st and 2nd chunks are not sequntial.
-				 */
-				if (mp == first_mp->b_cont)
-					return (NULL);
-				/* Back up mp and prev */
-				mp = prev;
-				prev = prevprev;
-				break;
-			}
-
-			/* end of sequence */
-			if (mp->b_cont == NULL)
-				break;
-
-			prevprev = prev;
-			prev = mp;
-			mp = mp->b_cont;
-			tsn++;
+	}
+
+	/*
+	 * Try partial delivery if the message length has exceeded the
+	 * partial delivery point. Only do this if we can immediately
+	 * deliver the partially assembled message, and only partially
+	 * deliver one message at a time (i.e. messages cannot be
+	 * intermixed arriving at the upper layer). A simple way to
+	 * enforce this is to only try partial delivery if this TSN is
+	 * the next expected TSN. Partial Delivery not supported
+	 * for un-ordered message.
+	 */
+	if (srp->needed != srp->got) {
+		dmp = NULL;
+		if (ntohl((*dc)->sdh_tsn) == sctp->sctp_ftsn &&
+		    srp->msglen >= sctp->sctp_pd_point) {
+			dmp = sctp_try_partial_delivery(sctp, hmp, srp, dc);
+			*tpfinished = B_FALSE;
 		}
-		if (DB_TYPE(hmp) == M_DATA) {
-			sctp_reass_t	*srp1 = srp;
-
-			SCTP_NEW_REASS(pmp, mp, srp, B_FALSE);
-			ASSERT(pmp->b_prev == NULL && pmp->b_next == NULL);
-			if (sip->istr_reass == hmp) {
-				sip->istr_reass = pmp;
-				if (hmp->b_next != NULL) {
-					hmp->b_next->b_prev = pmp;
-					pmp->b_next = hmp->b_next;
-				}
-			} else {
-				hmp->b_prev->b_next = pmp;
-				pmp->b_prev = hmp->b_prev;
-				if (hmp->b_next != NULL) {
-					hmp->b_next->b_prev = pmp;
-					pmp->b_next = hmp->b_next;
-				}
-			}
-			srp->ssn = srp1->ssn;
-			srp->needed = srp1->needed;
-			srp->got = srp1->got;
-			srp->tail = srp1->tail;
-			hmp->b_next = hmp->b_prev = NULL;
-			dmp = hmp;
-			hmp = pmp;
-		} else {
-			ASSERT(DB_TYPE(hmp) == M_CTL);
-			dmp = hmp->b_cont;
-			hmp->b_cont = mp;
-		}
-		/*
-		 * mp now points at the last chunk in the sequence,
-		 * and prev points to mp's previous in the list.
-		 * We chop the list at prev, and convert mp into the
-		 * new list head by setting the B bit. Subsequence
-		 * fragment deliveries will follow the normal reassembly
-		 * path.
-		 */
-		prev->b_cont = NULL;
-		bdc = (sctp_data_hdr_t *)mp->b_rptr;
-		SCTP_DATA_SET_BBIT(bdc);
-		*tpfinished = 0;
-		srp->partial_delivered = B_TRUE;
-
-		dprint(4, ("trypartial: got some, got=%d, needed=%d\n",
-		    (int)(srp->got), (int)(srp->needed)));
-		goto fixup;
+		return (dmp);
 	}
-
+frag_done:
 	/*
 	 * else reassembly done; prepare the data for delivery.
 	 * First unlink hmp from the ssn list.
 	 */
 	if (sip->istr_reass == hmp) {
 		sip->istr_reass = hmp->b_next;
-		if (hmp->b_next) {
+		if (hmp->b_next)
 			hmp->b_next->b_prev = NULL;
-		}
 	} else {
 		ASSERT(hmp->b_prev != NULL);
 		hmp->b_prev->b_next = hmp->b_next;
-		if (hmp->b_next) {
+		if (hmp->b_next)
 			hmp->b_next->b_prev = hmp->b_prev;
-		}
 	}
 
 	/*
@@ -1095,51 +1126,25 @@
 	hmp->b_next = NULL;
 	hmp->b_prev = NULL;
 	dmp = hmp;
-	if (DB_TYPE(hmp) == M_CTL) {
-		dmp = dmp->b_cont;
-		hmp->b_cont = NULL;
-		freeb(hmp);
-	}
-	*tpfinished = 1;
-
-fixup:
+	dmp = dmp->b_cont;
+	hmp->b_cont = NULL;
+	freeb(hmp);
+	*tpfinished = B_TRUE;
+
 	/*
 	 * Adjust all mblk's except the lead so their rptr's point to the
 	 * payload. sctp_data_chunk() will need to process the lead's
 	 * data chunk section, so leave it's rptr pointing at the data chunk.
 	 */
 	*dc = (sctp_data_hdr_t *)dmp->b_rptr;
-	if (trypartial && !(*tpfinished)) {
-		(srp->got)--;
-		ASSERT(srp->got != 0);
-		if (srp->needed != 0) {
-			(srp->needed)--;
-			ASSERT(srp->needed != 0);
-		}
-	}
-	for (qmp = dmp->b_cont; qmp; qmp = qmp->b_cont) {
+	for (qmp = dmp->b_cont; qmp != NULL; qmp = qmp->b_cont) {
 		qdc = (sctp_data_hdr_t *)qmp->b_rptr;
 		qmp->b_rptr = (uchar_t *)(qdc + 1);
-
-		/*
-		 * If in partial delivery, deduct the balance from got
-		 * and needed here, now that we know we are actually
-		 * delivering these data.
-		 */
-		if (trypartial && !(*tpfinished)) {
-			(srp->got)--;
-			ASSERT(srp->got != 0);
-			if (srp->needed != 0) {
-				(srp->needed)--;
-				ASSERT(srp->needed != 0);
-			}
-		}
 	}
 	BUMP_LOCAL(sctp->sctp_reassmsgs);
 
 	return (dmp);
 }
-
 static void
 sctp_add_dup(uint32_t tsn, mblk_t **dups)
 {
@@ -1185,8 +1190,7 @@
 	boolean_t can_deliver = B_TRUE;
 	uint32_t tsn;
 	int dlen;
-	int trypartial = 0;
-	int tpfinished = 1;
+	boolean_t tpfinished = B_TRUE;
 	int32_t new_rwnd;
 	sctp_stack_t	*sctps = sctp->sctp_sctps;
 
@@ -1275,23 +1279,9 @@
 	/* Initialize the stream, if not yet used */
 	if (instr->sctp == NULL)
 		instr->sctp = sctp;
-	/*
-	 * If we are getting low on buffers set trypartial to try
-	 * a partial delivery if we are reassembling a fragmented
-	 * message. Only do this if we can immediately deliver the
-	 * partially assembled message, and only partially deliver
-	 * one message at a time (i.e. messages cannot be intermixed
-	 * arriving at the upper layer). A simple way to enforce
-	 * this is to only try partial delivery if this TSN is
-	 * the next expected TSN. Partial Delivery not supported
-	 * for un-ordered message.
-	 */
+
 	isfrag = !(SCTP_DATA_GET_BBIT(dc) && SCTP_DATA_GET_EBIT(dc));
 	ssn = ntohs(dc->sdh_ssn);
-	if ((sctp->sctp_rwnd - sctp->sctp_rxqueued < SCTP_RECV_LOWATER) &&
-	    !ubit && isfrag && (tsn == sctp->sctp_ftsn)) {
-		trypartial = 1;
-	}
 
 	dmp = dupb(mp);
 	if (dmp == NULL) {
@@ -1319,7 +1309,7 @@
 #endif
 		} else {
 			dmp = sctp_data_frag(sctp, dmp, &dc, &error, instr,
-			    trypartial, &tpfinished);
+			    &tpfinished);
 		}
 		if (error != 0) {
 			sctp->sctp_rxqueued -= dlen;
@@ -1352,7 +1342,7 @@
 		}
 	}
 
-	if (!ubit && !trypartial && ssn != instr->nextseq) {
+	if (!ubit && !isfrag && ssn != instr->nextseq) {
 		/* Adjust rptr to point at the data chunk for compares */
 		dmp->b_rptr = (uchar_t *)dc;
 
@@ -2004,12 +1994,11 @@
 		hmp->b_next = NULL;
 		ASSERT(hmp->b_prev == NULL);
 		dmp = hmp;
-		if (DB_TYPE(hmp) == M_CTL) {
-			dmp = hmp->b_cont;
-			hmp->b_cont = NULL;
-			freeb(hmp);
-			hmp = dmp;
-		}
+		ASSERT(DB_TYPE(hmp) == M_CTL);
+		dmp = hmp->b_cont;
+		hmp->b_cont = NULL;
+		freeb(hmp);
+		hmp = dmp;
 		while (dmp != NULL) {
 			dc = (sctp_data_hdr_t *)dmp->b_rptr;
 			dlen += ntohs(dc->sdh_len) - sizeof (*dc);
--- a/usr/src/uts/common/inet/sctp/sctp_opt_data.c	Fri Mar 16 16:11:15 2007 -0700
+++ b/usr/src/uts/common/inet/sctp/sctp_opt_data.c	Fri Mar 16 17:42:01 2007 -0700
@@ -1226,6 +1226,7 @@
 				    sctp->sctp_mss);
 				sctp->sctp_rwnd = *i1;
 				sctp->sctp_irwnd = sctp->sctp_rwnd;
+				sctp->sctp_pd_point = sctp->sctp_rwnd;
 			}
 			/*
 			 * XXX should we return the rwnd here