Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 17 Dec 2016 22:31:30 +0000 (UTC)
From:      Michael Tuexen <tuexen@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r310193 - head/sys/netinet
Message-ID:  <201612172231.uBHMVUv6017320@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: tuexen
Date: Sat Dec 17 22:31:30 2016
New Revision: 310193
URL: https://svnweb.freebsd.org/changeset/base/310193

Log:
  Fix the handling of buffered messages in stream reset deferred handling.
  
  Thanks to Eugen-Andrei Gavriloaie for reporting the issue and providing
  substantial help in nailing down the issue.
  
  MFC after:	1 week

Modified:
  head/sys/netinet/sctp_indata.c

Modified: head/sys/netinet/sctp_indata.c
==============================================================================
--- head/sys/netinet/sctp_indata.c	Sat Dec 17 18:35:17 2016	(r310192)
+++ head/sys/netinet/sctp_indata.c	Sat Dec 17 22:31:30 2016	(r310193)
@@ -472,7 +472,6 @@ sctp_clean_up_control(struct sctp_tcb *s
  */
 static void
 sctp_queue_data_to_stream(struct sctp_tcb *stcb,
-    struct sctp_stream_in *strm,
     struct sctp_association *asoc,
     struct sctp_queued_to_read *control, int *abort_flag, int *need_reasm)
 {
@@ -498,16 +497,17 @@ sctp_queue_data_to_stream(struct sctp_tc
 	int queue_needed;
 	uint32_t nxt_todel;
 	struct mbuf *op_err;
+	struct sctp_stream_in *strm;
 	char msg[SCTP_DIAG_INFO_LEN];
 
+	strm = &asoc->strmin[control->sinfo_stream];
 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
 		sctp_log_strm_del(control, NULL, SCTP_STR_LOG_FROM_INTO_STRD);
 	}
 	if (SCTP_MID_GT((asoc->idata_supported), strm->last_mid_delivered, control->mid)) {
 		/* The incoming sseq is behind where we last delivered? */
 		SCTPDBG(SCTP_DEBUG_INDATA1, "Duplicate S-SEQ: %u delivered: %u from peer, Abort association\n",
-		    control->mid, strm->last_mid_delivered);
-protocol_error:
+		    strm->last_mid_delivered, control->mid);
 		/*
 		 * throw it in the stream so it gets cleaned up in
 		 * association destruction
@@ -531,9 +531,6 @@ protocol_error:
 		return;
 
 	}
-	if ((SCTP_TSN_GE(asoc->cumulative_tsn, control->sinfo_tsn)) && (asoc->idata_supported == 0)) {
-		goto protocol_error;
-	}
 	queue_needed = 1;
 	asoc->size_on_all_streams += control->length;
 	sctp_ucount_incr(asoc->cnt_on_all_streams);
@@ -1041,7 +1038,7 @@ sctp_deliver_reasm_check(struct sctp_tcb
 	}
 	control = TAILQ_FIRST(&strm->uno_inqueue);
 
-	if ((control) &&
+	if ((control != NULL) &&
 	    (asoc->idata_supported == 0)) {
 		/* Special handling needed for "old" data format */
 		if (sctp_handle_old_unordered_data(stcb, asoc, strm, control, pd_point, inp_read_lock_held)) {
@@ -1280,7 +1277,6 @@ sctp_add_chk_to_control(struct sctp_queu
  */
 static void
 sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
-    struct sctp_stream_in *strm,
     struct sctp_queued_to_read *control,
     struct sctp_tmit_chunk *chk,
     int created_control,
@@ -1288,8 +1284,10 @@ sctp_queue_data_for_reasm(struct sctp_tc
 {
 	uint32_t next_fsn;
 	struct sctp_tmit_chunk *at, *nat;
+	struct sctp_stream_in *strm;
 	int do_wakeup, unordered;
 
+	strm = &asoc->strmin[control->sinfo_stream];
 	/*
 	 * For old un-ordered data chunks.
 	 */
@@ -1582,7 +1580,6 @@ sctp_process_a_data_chunk(struct sctp_tc
 	uint32_t ppid;
 	uint8_t chk_flags;
 	struct sctp_stream_reset_list *liste;
-	struct sctp_stream_in *strm;
 	int ordered;
 	size_t clen;
 	int created_control = 0;
@@ -1733,7 +1730,6 @@ sctp_process_a_data_chunk(struct sctp_tc
 		}
 		return (0);
 	}
-	strm = &asoc->strmin[sid];
 	/*
 	 * If its a fragmented message, lets see if we can find the control
 	 * on the reassembly queues.
@@ -1750,7 +1746,7 @@ sctp_process_a_data_chunk(struct sctp_tc
 		    mid, chk_flags);
 		goto err_out;
 	}
-	control = sctp_find_reasm_entry(strm, mid, ordered, asoc->idata_supported);
+	control = sctp_find_reasm_entry(&asoc->strmin[sid], mid, ordered, asoc->idata_supported);
 	SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags:0x%x look for control on queues %p\n",
 	    chk_flags, control);
 	if ((chk_flags & SCTP_DATA_NOT_FRAG) != SCTP_DATA_NOT_FRAG) {
@@ -2020,7 +2016,7 @@ sctp_process_a_data_chunk(struct sctp_tc
 
 		if ((chk_flags & SCTP_DATA_UNORDERED) == 0) {
 			/* for ordered, bump what we delivered */
-			strm->last_mid_delivered++;
+			asoc->strmin[sid].last_mid_delivered++;
 		}
 		SCTP_STAT_INCR(sctps_recvexpress);
 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
@@ -2130,7 +2126,7 @@ sctp_process_a_data_chunk(struct sctp_tc
 		} else {
 			SCTPDBG(SCTP_DEBUG_XXX, "Queue control: %p for reordering MID: %u\n", control,
 			    mid);
-			sctp_queue_data_to_stream(stcb, strm, asoc, control, abort_flag, &need_reasm_check);
+			sctp_queue_data_to_stream(stcb, asoc, control, abort_flag, &need_reasm_check);
 			if (*abort_flag) {
 				if (last_chunk) {
 					*m = NULL;
@@ -2145,7 +2141,7 @@ sctp_process_a_data_chunk(struct sctp_tc
 	SCTPDBG(SCTP_DEBUG_XXX,
 	    "Queue data to stream for reasm control: %p MID: %u\n",
 	    control, mid);
-	sctp_queue_data_for_reasm(stcb, asoc, strm, control, chk, created_control, abort_flag, tsn);
+	sctp_queue_data_for_reasm(stcb, asoc, control, chk, created_control, abort_flag, tsn);
 	if (*abort_flag) {
 		/*
 		 * the assoc is now gone and chk was put onto the reasm
@@ -2179,6 +2175,10 @@ finish_express_del:
 		sctp_log_map(asoc->mapping_array_base_tsn, asoc->cumulative_tsn,
 		    asoc->highest_tsn_inside_map, SCTP_MAP_PREPARE_SLIDE);
 	}
+	if (need_reasm_check) {
+		(void)sctp_deliver_reasm_check(stcb, asoc, &asoc->strmin[sid], SCTP_READ_LOCK_NOT_HELD);
+		need_reasm_check = 0;
+	}
 	/* check the special flag for stream resets */
 	if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) &&
 	    SCTP_TSN_GE(asoc->cumulative_tsn, liste->tsn)) {
@@ -2200,10 +2200,14 @@ finish_express_del:
 			/* All can be removed */
 			TAILQ_FOREACH_SAFE(ctl, &asoc->pending_reply_queue, next, nctl) {
 				TAILQ_REMOVE(&asoc->pending_reply_queue, ctl, next);
-				sctp_queue_data_to_stream(stcb, strm, asoc, ctl, abort_flag, &need_reasm_check);
+				sctp_queue_data_to_stream(stcb, asoc, ctl, abort_flag, &need_reasm_check);
 				if (*abort_flag) {
 					return (0);
 				}
+				if (need_reasm_check) {
+					(void)sctp_deliver_reasm_check(stcb, asoc, &asoc->strmin[ctl->sinfo_stream], SCTP_READ_LOCK_NOT_HELD);
+					need_reasm_check = 0;
+				}
 			}
 		} else {
 			TAILQ_FOREACH_SAFE(ctl, &asoc->pending_reply_queue, next, nctl) {
@@ -2216,22 +2220,16 @@ finish_express_del:
 				 * ctl->sinfo_tsn > liste->tsn
 				 */
 				TAILQ_REMOVE(&asoc->pending_reply_queue, ctl, next);
-				sctp_queue_data_to_stream(stcb, strm, asoc, ctl, abort_flag, &need_reasm_check);
+				sctp_queue_data_to_stream(stcb, asoc, ctl, abort_flag, &need_reasm_check);
 				if (*abort_flag) {
 					return (0);
 				}
+				if (need_reasm_check) {
+					(void)sctp_deliver_reasm_check(stcb, asoc, &asoc->strmin[ctl->sinfo_stream], SCTP_READ_LOCK_NOT_HELD);
+					need_reasm_check = 0;
+				}
 			}
 		}
-		/*
-		 * Now service re-assembly to pick up anything that has been
-		 * held on reassembly queue?
-		 */
-		(void)sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_NOT_HELD);
-		need_reasm_check = 0;
-	}
-	if (need_reasm_check) {
-		/* Another one waits ? */
-		(void)sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_NOT_HELD);
 	}
 	return (1);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201612172231.uBHMVUv6017320>