svn commit: r196260 - head/sys/netinet

Michael Tuexen tuexen at FreeBSD.org
Sat Aug 15 21:10:53 UTC 2009


Author: tuexen
Date: Sat Aug 15 21:10:52 2009
New Revision: 196260
URL: http://svn.freebsd.org/changeset/base/196260

Log:
  * Fix a bug where PR-SCTP settings are ignore when using implicit
    association setup.
  * Fix a bug where message with illegal stream ids are not deleted.
  * Fix a crash when reporting back unsent messages from the send_queue.
  * Fix a bug related to INIT retransmission when the socket is already
    closed.
  * Fix a bug where associations were stalled when partial delivery API
    was enabled.
  * Fix a bug where the receive buffer size was smaller than the
    partial_delivery_point.
  
  Approved by: re, rrs (mentor)
  MFC after: One day.

Modified:
  head/sys/netinet/sctp_indata.c
  head/sys/netinet/sctp_input.c
  head/sys/netinet/sctp_output.c
  head/sys/netinet/sctp_pcb.c
  head/sys/netinet/sctp_timer.c
  head/sys/netinet/sctputil.c
  head/sys/netinet/sctputil.h

Modified: head/sys/netinet/sctp_indata.c
==============================================================================
--- head/sys/netinet/sctp_indata.c	Sat Aug 15 19:48:14 2009	(r196259)
+++ head/sys/netinet/sctp_indata.c	Sat Aug 15 21:10:52 2009	(r196260)
@@ -900,7 +900,7 @@ sctp_deliver_reasm_check(struct sctp_tcb
 {
 	struct sctp_tmit_chunk *chk;
 	uint16_t nxt_todel;
-	uint32_t tsize;
+	uint32_t tsize, pd_point;
 
 doit_again:
 	chk = TAILQ_FIRST(&asoc->reasmqueue);
@@ -920,8 +920,13 @@ doit_again:
 			 * Yep the first one is here and its ok to deliver
 			 * but should we?
 			 */
-			if ((sctp_is_all_msg_on_reasm(asoc, &tsize) ||
-			    (tsize >= stcb->sctp_ep->partial_delivery_point))) {
+			if (stcb->sctp_socket) {
+				pd_point = min(SCTP_SB_LIMIT_RCV(stcb->sctp_socket) >> SCTP_PARTIAL_DELIVERY_SHIFT,
+				    stcb->sctp_ep->partial_delivery_point);
+			} else {
+				pd_point = stcb->sctp_ep->partial_delivery_point;
+			}
+			if (sctp_is_all_msg_on_reasm(asoc, &tsize) || (tsize >= pd_point)) {
 
 				/*
 				 * Yes, we setup to start reception, by
@@ -2824,7 +2829,7 @@ void
 sctp_service_queues(struct sctp_tcb *stcb, struct sctp_association *asoc)
 {
 	struct sctp_tmit_chunk *chk;
-	uint32_t tsize;
+	uint32_t tsize, pd_point;
 	uint16_t nxt_todel;
 
 	if (asoc->fragmented_delivery_inprogress) {
@@ -2860,8 +2865,13 @@ doit_again:
 		 * be here or 1/4 the socket buffer max or nothing on the
 		 * delivery queue and something can be delivered.
 		 */
-		if ((sctp_is_all_msg_on_reasm(asoc, &tsize) ||
-		    (tsize >= stcb->sctp_ep->partial_delivery_point))) {
+		if (stcb->sctp_socket) {
+			pd_point = min(SCTP_SB_LIMIT_RCV(stcb->sctp_socket) >> SCTP_PARTIAL_DELIVERY_SHIFT,
+			    stcb->sctp_ep->partial_delivery_point);
+		} else {
+			pd_point = stcb->sctp_ep->partial_delivery_point;
+		}
+		if (sctp_is_all_msg_on_reasm(asoc, &tsize) || (tsize >= pd_point)) {
 			asoc->fragmented_delivery_inprogress = 1;
 			asoc->tsn_last_delivered = chk->rec.data.TSN_seq - 1;
 			asoc->str_of_pdapi = chk->rec.data.stream_number;
@@ -5192,7 +5202,7 @@ skip_segments:
 			/* sa_ignore NO_NULL_CHK */
 			sctp_free_bufspace(stcb, asoc, tp1, 1);
 			sctp_m_freem(tp1->data);
-			if (PR_SCTP_BUF_ENABLED(tp1->flags)) {
+			if (asoc->peer_supports_prsctp && PR_SCTP_BUF_ENABLED(tp1->flags)) {
 				asoc->sent_queue_cnt_removeable--;
 			}
 		}
@@ -6289,10 +6299,11 @@ sctp_handle_forward_tsn(struct sctp_tcb 
 					ctl->pdapi_aborted = 1;
 					sv = stcb->asoc.control_pdapi;
 					stcb->asoc.control_pdapi = ctl;
-					sctp_notify_partial_delivery_indication(stcb,
+					sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION,
+					    stcb,
 					    SCTP_PARTIAL_DELIVERY_ABORTED,
-					    SCTP_HOLDS_LOCK,
-					    str_seq);
+					    (void *)&str_seq,
+					    SCTP_SO_NOT_LOCKED);
 					stcb->asoc.control_pdapi = sv;
 					break;
 				} else if ((ctl->sinfo_stream == stseq->stream) &&
@@ -7786,7 +7797,7 @@ skip_segments:
 			/* sa_ignore NO_NULL_CHK */
 			sctp_free_bufspace(stcb, asoc, tp1, 1);
 			sctp_m_freem(tp1->data);
-			if (PR_SCTP_BUF_ENABLED(tp1->flags)) {
+			if (asoc->peer_supports_prsctp && PR_SCTP_BUF_ENABLED(tp1->flags)) {
 				asoc->sent_queue_cnt_removeable--;
 			}
 		}

Modified: head/sys/netinet/sctp_input.c
==============================================================================
--- head/sys/netinet/sctp_input.c	Sat Aug 15 19:48:14 2009	(r196259)
+++ head/sys/netinet/sctp_input.c	Sat Aug 15 21:10:52 2009	(r196260)
@@ -278,18 +278,38 @@ sctp_process_init(struct sctp_init_chunk
 		unsigned int newcnt;
 		struct sctp_stream_out *outs;
 		struct sctp_stream_queue_pending *sp;
+		struct sctp_tmit_chunk *chk, *chk_next;
 
-		/* cut back on number of streams */
+		/* abandon the upper streams */
 		newcnt = ntohs(init->num_inbound_streams);
-		/* This if is probably not needed but I am cautious */
+		if (!TAILQ_EMPTY(&asoc->send_queue)) {
+			chk = TAILQ_FIRST(&asoc->send_queue);
+			while (chk) {
+				chk_next = TAILQ_NEXT(chk, sctp_next);
+				if (chk->rec.data.stream_number >= newcnt) {
+					TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next);
+					asoc->send_queue_cnt--;
+					if (chk->data != NULL) {
+						sctp_free_bufspace(stcb, asoc, chk, 1);
+						sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb,
+						    SCTP_NOTIFY_DATAGRAM_UNSENT, chk, SCTP_SO_NOT_LOCKED);
+						if (chk->data) {
+							sctp_m_freem(chk->data);
+							chk->data = NULL;
+						}
+					}
+					sctp_free_a_chunk(stcb, chk);
+					/* sa_ignore FREED_MEMORY */
+				}
+				chk = chk_next;
+			}
+		}
 		if (asoc->strmout) {
-			/* First make sure no data chunks are trapped */
 			for (i = newcnt; i < asoc->pre_open_streams; i++) {
 				outs = &asoc->strmout[i];
 				sp = TAILQ_FIRST(&outs->outqueue);
 				while (sp) {
-					TAILQ_REMOVE(&outs->outqueue, sp,
-					    next);
+					TAILQ_REMOVE(&outs->outqueue, sp, next);
 					asoc->stream_queue_cnt--;
 					sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL,
 					    stcb, SCTP_NOTIFY_DATAGRAM_UNSENT,
@@ -301,16 +321,13 @@ sctp_process_init(struct sctp_init_chunk
 					sctp_free_remote_addr(sp->net);
 					sp->net = NULL;
 					/* Free the chunk */
-					SCTP_PRINTF("sp:%p tcb:%p weird free case\n",
-					    sp, stcb);
-
 					sctp_free_a_strmoq(stcb, sp);
 					/* sa_ignore FREED_MEMORY */
 					sp = TAILQ_FIRST(&outs->outqueue);
 				}
 			}
 		}
-		/* cut back the count and abandon the upper streams */
+		/* cut back the count */
 		asoc->pre_open_streams = newcnt;
 	}
 	SCTP_TCB_SEND_UNLOCK(stcb);

Modified: head/sys/netinet/sctp_output.c
==============================================================================
--- head/sys/netinet/sctp_output.c	Sat Aug 15 19:48:14 2009	(r196259)
+++ head/sys/netinet/sctp_output.c	Sat Aug 15 21:10:52 2009	(r196260)
@@ -4200,7 +4200,7 @@ sctp_send_initiate(struct sctp_inpcb *in
 	/* place in my tag */
 	init->init.initiate_tag = htonl(stcb->asoc.my_vtag);
 	/* set up some of the credits. */
-	init->init.a_rwnd = htonl(max(SCTP_SB_LIMIT_RCV(inp->sctp_socket),
+	init->init.a_rwnd = htonl(max(inp->sctp_socket ? SCTP_SB_LIMIT_RCV(inp->sctp_socket) : 0,
 	    SCTP_MINIMAL_RWND));
 
 	init->init.num_outbound_streams = htons(stcb->asoc.pre_open_streams);
@@ -4411,7 +4411,6 @@ sctp_send_initiate(struct sctp_inpcb *in
 	    net->port, so_locked, NULL);
 	SCTPDBG(SCTP_DEBUG_OUTPUT4, "lowlevel_output - %d\n", ret);
 	SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
-	sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, net);
 	(void)SCTP_GETTIME_TIMEVAL(&net->last_sent_time);
 }
 
@@ -5786,61 +5785,58 @@ sctp_get_frag_point(struct sctp_tcb *stc
 }
 
 static void
-sctp_set_prsctp_policy(struct sctp_tcb *stcb,
-    struct sctp_stream_queue_pending *sp)
+sctp_set_prsctp_policy(struct sctp_stream_queue_pending *sp)
 {
 	sp->pr_sctp_on = 0;
-	if (stcb->asoc.peer_supports_prsctp) {
+	/*
+	 * We assume that the user wants PR_SCTP_TTL if the user provides a
+	 * positive lifetime but does not specify any PR_SCTP policy. This
+	 * is a BAD assumption and causes problems at least with the
+	 * U-Vancovers MPI folks. I will change this to be no policy means
+	 * NO PR-SCTP.
+	 */
+	if (PR_SCTP_ENABLED(sp->sinfo_flags)) {
+		sp->act_flags |= PR_SCTP_POLICY(sp->sinfo_flags);
+		sp->pr_sctp_on = 1;
+	} else {
+		return;
+	}
+	switch (PR_SCTP_POLICY(sp->sinfo_flags)) {
+	case CHUNK_FLAGS_PR_SCTP_BUF:
 		/*
-		 * We assume that the user wants PR_SCTP_TTL if the user
-		 * provides a positive lifetime but does not specify any
-		 * PR_SCTP policy. This is a BAD assumption and causes
-		 * problems at least with the U-Vancovers MPI folks. I will
-		 * change this to be no policy means NO PR-SCTP.
-		 */
-		if (PR_SCTP_ENABLED(sp->sinfo_flags)) {
-			sp->act_flags |= PR_SCTP_POLICY(sp->sinfo_flags);
-			sp->pr_sctp_on = 1;
-		} else {
-			return;
-		}
-		switch (PR_SCTP_POLICY(sp->sinfo_flags)) {
-		case CHUNK_FLAGS_PR_SCTP_BUF:
-			/*
-			 * Time to live is a priority stored in tv_sec when
-			 * doing the buffer drop thing.
-			 */
-			sp->ts.tv_sec = sp->timetolive;
-			sp->ts.tv_usec = 0;
-			break;
-		case CHUNK_FLAGS_PR_SCTP_TTL:
-			{
-				struct timeval tv;
-
-				(void)SCTP_GETTIME_TIMEVAL(&sp->ts);
-				tv.tv_sec = sp->timetolive / 1000;
-				tv.tv_usec = (sp->timetolive * 1000) % 1000000;
-				/*
-				 * TODO sctp_constants.h needs alternative
-				 * time macros when _KERNEL is undefined.
-				 */
-				timevaladd(&sp->ts, &tv);
-			}
-			break;
-		case CHUNK_FLAGS_PR_SCTP_RTX:
+		 * Time to live is a priority stored in tv_sec when doing
+		 * the buffer drop thing.
+		 */
+		sp->ts.tv_sec = sp->timetolive;
+		sp->ts.tv_usec = 0;
+		break;
+	case CHUNK_FLAGS_PR_SCTP_TTL:
+		{
+			struct timeval tv;
+
+			(void)SCTP_GETTIME_TIMEVAL(&sp->ts);
+			tv.tv_sec = sp->timetolive / 1000;
+			tv.tv_usec = (sp->timetolive * 1000) % 1000000;
 			/*
-			 * Time to live is a the number or retransmissions
-			 * stored in tv_sec.
+			 * TODO sctp_constants.h needs alternative time
+			 * macros when _KERNEL is undefined.
 			 */
-			sp->ts.tv_sec = sp->timetolive;
-			sp->ts.tv_usec = 0;
-			break;
-		default:
-			SCTPDBG(SCTP_DEBUG_USRREQ1,
-			    "Unknown PR_SCTP policy %u.\n",
-			    PR_SCTP_POLICY(sp->sinfo_flags));
-			break;
+			timevaladd(&sp->ts, &tv);
 		}
+		break;
+	case CHUNK_FLAGS_PR_SCTP_RTX:
+		/*
+		 * Time to live is a the number or retransmissions stored in
+		 * tv_sec.
+		 */
+		sp->ts.tv_sec = sp->timetolive;
+		sp->ts.tv_usec = 0;
+		break;
+	default:
+		SCTPDBG(SCTP_DEBUG_USRREQ1,
+		    "Unknown PR_SCTP policy %u.\n",
+		    PR_SCTP_POLICY(sp->sinfo_flags));
+		break;
 	}
 }
 
@@ -5911,7 +5907,7 @@ sctp_msg_append(struct sctp_tcb *stcb,
 	sp->tail_mbuf = NULL;
 	sp->length = 0;
 	at = m;
-	sctp_set_prsctp_policy(stcb, sp);
+	sctp_set_prsctp_policy(sp);
 	/*
 	 * We could in theory (for sendall) sifa the length in, but we would
 	 * still have to hunt through the chain since we need to setup the
@@ -7138,7 +7134,7 @@ dont_do_it:
 	}
 	/* We only re-set the policy if it is on */
 	if (sp->pr_sctp_on) {
-		sctp_set_prsctp_policy(stcb, sp);
+		sctp_set_prsctp_policy(sp);
 		asoc->pr_sctp_cnt++;
 		chk->pr_sctp_on = 1;
 	} else {
@@ -12285,7 +12281,7 @@ skip_copy:
 			sp->addr_over = 0;
 		}
 		atomic_add_int(&sp->net->ref_count, 1);
-		sctp_set_prsctp_policy(stcb, sp);
+		sctp_set_prsctp_policy(sp);
 	}
 out_now:
 	return (sp);

Modified: head/sys/netinet/sctp_pcb.c
==============================================================================
--- head/sys/netinet/sctp_pcb.c	Sat Aug 15 19:48:14 2009	(r196259)
+++ head/sys/netinet/sctp_pcb.c	Sat Aug 15 21:10:52 2009	(r196260)
@@ -4547,8 +4547,11 @@ sctp_free_assoc(struct sctp_inpcb *inp, 
 
 						stcb->asoc.control_pdapi = sq;
 						strseq = (sq->sinfo_stream << 16) | sq->sinfo_ssn;
-						sctp_notify_partial_delivery_indication(stcb,
-						    SCTP_PARTIAL_DELIVERY_ABORTED, 1, strseq);
+						sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION,
+						    stcb,
+						    SCTP_PARTIAL_DELIVERY_ABORTED,
+						    (void *)&strseq,
+						    SCTP_SO_LOCKED);
 						stcb->asoc.control_pdapi = NULL;
 					}
 				}

Modified: head/sys/netinet/sctp_timer.c
==============================================================================
--- head/sys/netinet/sctp_timer.c	Sat Aug 15 19:48:14 2009	(r196259)
+++ head/sys/netinet/sctp_timer.c	Sat Aug 15 21:10:52 2009	(r196260)
@@ -588,7 +588,7 @@ sctp_recover_sent_list(struct sctp_tcb *
 				/* sa_ignore NO_NULL_CHK */
 				sctp_free_bufspace(stcb, asoc, chk, 1);
 				sctp_m_freem(chk->data);
-				if (PR_SCTP_BUF_ENABLED(chk->flags)) {
+				if (asoc->peer_supports_prsctp && PR_SCTP_BUF_ENABLED(chk->flags)) {
 					asoc->sent_queue_cnt_removeable--;
 				}
 			}
@@ -757,7 +757,7 @@ start_again:
 					continue;
 				}
 			}
-			if (PR_SCTP_TTL_ENABLED(chk->flags)) {
+			if (stcb->asoc.peer_supports_prsctp && PR_SCTP_TTL_ENABLED(chk->flags)) {
 				/* Is it expired? */
 				if ((now.tv_sec > chk->rec.data.timetodrop.tv_sec) ||
 				    ((chk->rec.data.timetodrop.tv_sec == now.tv_sec) &&
@@ -772,7 +772,7 @@ start_again:
 					continue;
 				}
 			}
-			if (PR_SCTP_RTX_ENABLED(chk->flags)) {
+			if (stcb->asoc.peer_supports_prsctp && PR_SCTP_RTX_ENABLED(chk->flags)) {
 				/* Has it been retransmitted tv_sec times? */
 				if (chk->snd_count > chk->rec.data.timetodrop.tv_sec) {
 					if (chk->data) {

Modified: head/sys/netinet/sctputil.c
==============================================================================
--- head/sys/netinet/sctputil.c	Sat Aug 15 19:48:14 2009	(r196259)
+++ head/sys/netinet/sctputil.c	Sat Aug 15 21:10:52 2009	(r196260)
@@ -1484,6 +1484,7 @@ sctp_timeout_handler(void *t)
 		SCTP_INP_INCR_REF(inp);
 		if ((inp->sctp_socket == 0) &&
 		    ((tmr->type != SCTP_TIMER_TYPE_INPKILL) &&
+		    (tmr->type != SCTP_TIMER_TYPE_INIT) &&
 		    (tmr->type != SCTP_TIMER_TYPE_SEND) &&
 		    (tmr->type != SCTP_TIMER_TYPE_RECV) &&
 		    (tmr->type != SCTP_TIMER_TYPE_HEARTBEAT) &&
@@ -2984,8 +2985,6 @@ sctp_notify_send_failed(struct sctp_tcb 
 	ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb);
 	ssf->ssf_assoc_id = sctp_get_associd(stcb);
 
-	SCTP_BUF_NEXT(m_notify) = chk->data;
-	SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed);
 	if (chk->data) {
 		/*
 		 * trim off the sctp chunk header(it should be there)
@@ -2996,6 +2995,8 @@ sctp_notify_send_failed(struct sctp_tcb 
 			chk->send_size -= sizeof(struct sctp_data_chunk);
 		}
 	}
+	SCTP_BUF_NEXT(m_notify) = chk->data;
+	SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed);
 	/* Steal off the mbuf */
 	chk->data = NULL;
 	/*
@@ -3146,9 +3147,13 @@ sctp_notify_adaptation_layer(struct sctp
 }
 
 /* This always must be called with the read-queue LOCKED in the INP */
-void
+static void
 sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error,
-    int nolock, uint32_t val)
+    uint32_t val, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+    SCTP_UNUSED
+#endif
+)
 {
 	struct mbuf *m_notify;
 	struct sctp_pdapi_event *pdapi;
@@ -3189,9 +3194,6 @@ sctp_notify_partial_delivery_indication(
 	control->tail_mbuf = m_notify;
 	control->held_length = 0;
 	control->length = 0;
-	if (nolock == 0) {
-		SCTP_INP_READ_LOCK(stcb->sctp_ep);
-	}
 	sb = &stcb->sctp_socket->so_rcv;
 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
 		sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m_notify));
@@ -3208,12 +3210,30 @@ sctp_notify_partial_delivery_indication(
 		/* we really should not see this case */
 		TAILQ_INSERT_TAIL(&stcb->sctp_ep->read_queue, control, next);
 	}
-	if (nolock == 0) {
-		SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
-	}
 	if (stcb->sctp_ep && stcb->sctp_socket) {
 		/* This should always be the case */
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+		struct socket *so;
+
+		so = SCTP_INP_SO(stcb->sctp_ep);
+		if (!so_locked) {
+			atomic_add_int(&stcb->asoc.refcnt, 1);
+			SCTP_TCB_UNLOCK(stcb);
+			SCTP_SOCKET_LOCK(so, 1);
+			SCTP_TCB_LOCK(stcb);
+			atomic_subtract_int(&stcb->asoc.refcnt, 1);
+			if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
+				SCTP_SOCKET_UNLOCK(so, 1);
+				return;
+			}
+		}
+#endif
 		sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+		if (!so_locked) {
+			SCTP_SOCKET_UNLOCK(so, 1);
+		}
+#endif
 	}
 }
 
@@ -3540,9 +3560,9 @@ sctp_ulp_notify(uint32_t notification, s
 
 			val = *((uint32_t *) data);
 
-			sctp_notify_partial_delivery_indication(stcb, error, 0, val);
+			sctp_notify_partial_delivery_indication(stcb, error, val, so_locked);
+			break;
 		}
-		break;
 	case SCTP_NOTIFY_STRDATA_ERR:
 		break;
 	case SCTP_NOTIFY_ASSOC_ABORTED:
@@ -3585,11 +3605,9 @@ sctp_ulp_notify(uint32_t notification, s
 	case SCTP_NOTIFY_STR_RESET_FAILED_OUT:
 		sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), (SCTP_STRRESET_OUTBOUND_STR | SCTP_STRRESET_FAILED));
 		break;
-
 	case SCTP_NOTIFY_STR_RESET_FAILED_IN:
 		sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), (SCTP_STRRESET_INBOUND_STR | SCTP_STRRESET_FAILED));
 		break;
-
 	case SCTP_NOTIFY_ASCONF_ADD_IP:
 		sctp_notify_peer_addr_change(stcb, SCTP_ADDR_ADDED, data,
 		    error);
@@ -3671,8 +3689,10 @@ sctp_report_all_outbound(struct sctp_tcb
 				sctp_free_bufspace(stcb, asoc, chk, 1);
 				sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb,
 				    SCTP_NOTIFY_DATAGRAM_SENT, chk, so_locked);
-				sctp_m_freem(chk->data);
-				chk->data = NULL;
+				if (chk->data) {
+					sctp_m_freem(chk->data);
+					chk->data = NULL;
+				}
 			}
 			sctp_free_a_chunk(stcb, chk);
 			/* sa_ignore FREED_MEMORY */
@@ -3689,8 +3709,10 @@ sctp_report_all_outbound(struct sctp_tcb
 				sctp_free_bufspace(stcb, asoc, chk, 1);
 				sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb,
 				    SCTP_NOTIFY_DATAGRAM_UNSENT, chk, so_locked);
-				sctp_m_freem(chk->data);
-				chk->data = NULL;
+				if (chk->data) {
+					sctp_m_freem(chk->data);
+					chk->data = NULL;
+				}
 			}
 			sctp_free_a_chunk(stcb, chk);
 			/* sa_ignore FREED_MEMORY */
@@ -5346,6 +5368,38 @@ restart_nosblocks:
 		}
 		goto restart;
 	}
+	if ((control->length == 0) &&
+	    (control->end_added == 1)) {
+		/*
+		 * Do we also need to check for (control->pdapi_aborted ==
+		 * 1)?
+		 */
+		if (hold_rlock == 0) {
+			hold_rlock = 1;
+			SCTP_INP_READ_LOCK(inp);
+		}
+		TAILQ_REMOVE(&inp->read_queue, control, next);
+		if (control->data) {
+#ifdef INVARIANTS
+			panic("control->data not null but control->length == 0");
+#else
+			SCTP_PRINTF("Strange, data left in the control buffer. Cleaning up.\n");
+			sctp_m_freem(control->data);
+			control->data = NULL;
+#endif
+		}
+		if (control->aux_data) {
+			sctp_m_free(control->aux_data);
+			control->aux_data = NULL;
+		}
+		sctp_free_remote_addr(control->whoFrom);
+		sctp_free_a_readq(stcb, control);
+		if (hold_rlock) {
+			hold_rlock = 0;
+			SCTP_INP_READ_UNLOCK(inp);
+		}
+		goto restart;
+	}
 	if (control->length == 0) {
 		if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) &&
 		    (filling_sinfo)) {

Modified: head/sys/netinet/sctputil.h
==============================================================================
--- head/sys/netinet/sctputil.h	Sat Aug 15 19:48:14 2009	(r196259)
+++ head/sys/netinet/sctputil.h	Sat Aug 15 21:10:52 2009	(r196260)
@@ -234,10 +234,6 @@ int sctp_cmpaddr(struct sockaddr *, stru
 void sctp_print_address(struct sockaddr *);
 void sctp_print_address_pkt(struct ip *, struct sctphdr *);
 
-void
-sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb,
-    uint32_t error, int no_lock, uint32_t strseq);
-
 int
 sctp_release_pr_sctp_chunk(struct sctp_tcb *, struct sctp_tmit_chunk *,
     int, int


More information about the svn-src-head mailing list