svn commit: r188854 - head/sys/netinet

Randall Stewart rrs at FreeBSD.org
Fri Feb 20 07:03:56 PST 2009


Author: rrs
Date: Fri Feb 20 15:03:54 2009
New Revision: 188854
URL: http://svn.freebsd.org/changeset/base/188854

Log:
  Add the add-stream capability. Still needs more
  testing..
  
  MFC after:	1 month

Modified:
  head/sys/netinet/sctp_constants.h
  head/sys/netinet/sctp_header.h
  head/sys/netinet/sctp_input.c
  head/sys/netinet/sctp_output.c
  head/sys/netinet/sctp_output.h
  head/sys/netinet/sctp_pcb.c
  head/sys/netinet/sctp_structs.h
  head/sys/netinet/sctp_uio.h
  head/sys/netinet/sctp_usrreq.c
  head/sys/netinet/sctputil.c

Modified: head/sys/netinet/sctp_constants.h
==============================================================================
--- head/sys/netinet/sctp_constants.h	Fri Feb 20 14:53:49 2009	(r188853)
+++ head/sys/netinet/sctp_constants.h	Fri Feb 20 15:03:54 2009	(r188854)
@@ -418,11 +418,12 @@ __FBSDID("$FreeBSD$");
 #define SCTP_HOSTNAME_ADDRESS		0x000b
 #define SCTP_SUPPORTED_ADDRTYPE		0x000c
 
-/* draft-ietf-stewart-strreset-xxx */
+/* draft-ietf-stewart-tsvwg-strreset-xxx */
 #define SCTP_STR_RESET_OUT_REQUEST	0x000d
 #define SCTP_STR_RESET_IN_REQUEST	0x000e
 #define SCTP_STR_RESET_TSN_REQUEST	0x000f
 #define SCTP_STR_RESET_RESPONSE		0x0010
+#define SCTP_STR_RESET_ADD_STREAMS  0x0011
 
 #define SCTP_MAX_RESET_PARAMS 2
 #define SCTP_STREAM_RESET_TSN_DELTA    0x1000
@@ -794,7 +795,11 @@ __FBSDID("$FreeBSD$");
 #define SCTP_NOTIFY_SPECIAL_SP_FAIL             27
 #define SCTP_NOTIFY_NO_PEER_AUTH                28
 #define SCTP_NOTIFY_SENDER_DRY                  29
-#define SCTP_NOTIFY_MAX                         29
+#define SCTP_NOTIFY_STR_RESET_ADD_OK            30
+#define SCTP_NOTIFY_STR_RESET_ADD_FAIL          31
+#define SCTP_NOTIFY_STR_RESET_INSTREAM_ADD_OK   32
+#define SCTP_NOTIFY_MAX                         32
+
 
 /* This is the value for messages that are NOT completely
  * copied down where we will start to split the message.

Modified: head/sys/netinet/sctp_header.h
==============================================================================
--- head/sys/netinet/sctp_header.h	Fri Feb 20 14:53:49 2009	(r188853)
+++ head/sys/netinet/sctp_header.h	Fri Feb 20 15:03:54 2009	(r188854)
@@ -498,7 +498,12 @@ struct sctp_stream_reset_response_tsn {
 	uint32_t receivers_next_tsn;
 }                              SCTP_PACKED;
 
-
+struct sctp_stream_reset_add_strm {
+	struct sctp_paramhdr ph;
+	uint32_t request_seq;
+	uint16_t number_of_streams;
+	uint16_t reserved;
+};
 
 #define SCTP_STREAM_RESET_NOTHING   0x00000000	/* Nothing for me to do */
 #define SCTP_STREAM_RESET_PERFORMED 0x00000001	/* Did it */

Modified: head/sys/netinet/sctp_input.c
==============================================================================
--- head/sys/netinet/sctp_input.c	Fri Feb 20 14:53:49 2009	(r188853)
+++ head/sys/netinet/sctp_input.c	Fri Feb 20 15:03:54 2009	(r188854)
@@ -314,7 +314,7 @@ sctp_process_init(struct sctp_init_chunk
 		asoc->pre_open_streams = newcnt;
 	}
 	SCTP_TCB_SEND_UNLOCK(stcb);
-	asoc->streamoutcnt = asoc->pre_open_streams;
+	asoc->strm_realoutsize = asoc->streamoutcnt = asoc->pre_open_streams;
 	/* init tsn's */
 	asoc->highest_tsn_inside_map = asoc->asconf_seq_in = ntohl(init->initial_tsn) - 1;
 	/* EY - nr_sack: initialize highest tsn in nr_mapping_array */
@@ -3440,6 +3440,17 @@ sctp_handle_stream_reset_response(struct
 				if (action != SCTP_STREAM_RESET_PERFORMED) {
 					sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_FAILED_IN, stcb, number_entries, srparam->list_of_streams, SCTP_SO_NOT_LOCKED);
 				}
+			} else if (type == SCTP_STR_RESET_ADD_STREAMS) {
+				/* Ok we now may have more streams */
+				if (action == SCTP_STREAM_RESET_PERFORMED) {
+					/* Put the new streams into effect */
+					stcb->asoc.streamoutcnt = stcb->asoc.strm_realoutsize;
+					sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_ADD_OK, stcb,
+					    (uint32_t) stcb->asoc.streamoutcnt, NULL, SCTP_SO_NOT_LOCKED);
+				} else {
+					sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_ADD_FAIL, stcb,
+					    (uint32_t) stcb->asoc.streamoutcnt, NULL, SCTP_SO_NOT_LOCKED);
+				}
 			} else if (type == SCTP_STR_RESET_TSN_REQUEST) {
 				/**
 				 * a) Adopt the new in tsn.
@@ -3709,6 +3720,63 @@ sctp_handle_str_reset_request_out(struct
 	}
 }
 
+static void
+sctp_handle_str_reset_add_strm(struct sctp_tcb *stcb, struct sctp_tmit_chunk *chk,
+    struct sctp_stream_reset_add_strm *str_add)
+{
+	/*
+	 * Peer is requesting to add more streams. If its within our
+	 * max-streams we will allow it.
+	 */
+	uint16_t num_stream, i;
+	uint32_t seq;
+
+	/* Get the number. */
+	seq = ntohl(str_add->request_seq);
+	num_stream = ntohs(str_add->number_of_streams);
+	/* Now what would be the new total? */
+	num_stream += stcb->asoc.streamincnt;
+	if (num_stream > stcb->asoc.max_inbound_streams) {
+		/* We must reject it they ask for to many */
+denied:
+		sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_DENIED);
+		stcb->asoc.last_reset_action[1] = stcb->asoc.last_reset_action[0];
+		stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_DENIED;
+	} else {
+		/* Ok, we can do that :-) */
+		struct sctp_stream_in *oldstrm;
+
+		/* save off the old */
+		oldstrm = stcb->asoc.strmin;
+		SCTP_MALLOC(stcb->asoc.strmin, struct sctp_stream_in *,
+		    (num_stream * sizeof(struct sctp_stream_in)),
+		    SCTP_M_STRMI);
+		if (stcb->asoc.strmin == NULL) {
+			stcb->asoc.strmin = oldstrm;
+			goto denied;
+		}
+		/* copy off the old data */
+		memcpy(stcb->asoc.strmin, oldstrm,
+		    (stcb->asoc.streamincnt * sizeof(struct sctp_stream_in)));
+		/* Init the new streams */
+		for (i = stcb->asoc.streamincnt; i < num_stream; i++) {
+			TAILQ_INIT(&stcb->asoc.strmin[i].inqueue);
+			stcb->asoc.strmin[i].stream_no = i;
+			stcb->asoc.strmin[i].last_sequence_delivered = 0xffff;
+			stcb->asoc.strmin[i].delivery_started = 0;
+		}
+		SCTP_FREE(oldstrm, SCTP_M_STRMI);
+		/* update the size */
+		stcb->asoc.streamincnt = num_stream;
+		/* Send the ack */
+		sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_PERFORMED);
+		stcb->asoc.last_reset_action[1] = stcb->asoc.last_reset_action[0];
+		stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_PERFORMED;
+		sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_INSTREAM_ADD_OK, stcb,
+		    (uint32_t) stcb->asoc.streamincnt, NULL, SCTP_SO_NOT_LOCKED);
+	}
+}
+
 #ifdef __GNUC__
 __attribute__((noinline))
 #endif
@@ -3803,6 +3871,12 @@ strres_nochunk:
 				}
 			}
 			sctp_handle_str_reset_request_out(stcb, chk, req_out, trunc);
+		} else if (ptype == SCTP_STR_RESET_ADD_STREAMS) {
+			struct sctp_stream_reset_add_strm *str_add;
+
+			str_add = (struct sctp_stream_reset_add_strm *)ph;
+			num_req++;
+			sctp_handle_str_reset_add_strm(stcb, chk, str_add);
 		} else if (ptype == SCTP_STR_RESET_IN_REQUEST) {
 			struct sctp_stream_reset_in_request *req_in;
 

Modified: head/sys/netinet/sctp_output.c
==============================================================================
--- head/sys/netinet/sctp_output.c	Fri Feb 20 14:53:49 2009	(r188853)
+++ head/sys/netinet/sctp_output.c	Fri Feb 20 15:03:54 2009	(r188854)
@@ -8620,13 +8620,12 @@ re_look:
 			sp->some_taken = 1;
 		}
 	} else {
-		to_move = sctp_can_we_split_this(stcb, length, goal_mtu,
-		    frag_point, eeor_mode);
+		to_move = sctp_can_we_split_this(stcb, length, goal_mtu, frag_point, eeor_mode);
 		if (to_move) {
 			/*-
-		         * We use a snapshot of length in case it
-		         * is expanding during the compare.
-		         */
+			 * We use a snapshot of length in case it
+			 * is expanding during the compare.
+			 */
 			uint32_t llen;
 
 			llen = length;
@@ -8634,9 +8633,9 @@ re_look:
 				to_move = llen;
 				if (send_lock_up == 0) {
 					/*-
-				         * We are taking all of an incomplete msg
-				         * thus we need a send lock.
-				         */
+					 * We are taking all of an incomplete msg
+					 * thus we need a send lock.
+					 */
 					SCTP_TCB_SEND_LOCK(stcb);
 					send_lock_up = 1;
 					if (sp->msg_is_complete) {
@@ -8836,8 +8835,7 @@ dont_do_it:
 		goto out_of;
 	}
 	sctp_snd_sb_alloc(stcb, sizeof(struct sctp_data_chunk));
-	chk->book_size = chk->send_size = (to_move +
-	    sizeof(struct sctp_data_chunk));
+	chk->book_size = chk->send_size = (to_move + sizeof(struct sctp_data_chunk));
 	chk->book_size_scale = 0;
 	chk->sent = SCTP_DATAGRAM_UNSENT;
 
@@ -13339,13 +13337,49 @@ sctp_add_stream_reset_result_tsn(struct 
 	return;
 }
 
+static void
+sctp_add_a_stream(struct sctp_tmit_chunk *chk,
+    uint32_t seq,
+    uint16_t adding)
+{
+	int len, old_len;
+	struct sctp_chunkhdr *ch;
+	struct sctp_stream_reset_add_strm *addstr;
+
+	ch = mtod(chk->data, struct sctp_chunkhdr *);
+	old_len = len = SCTP_SIZE32(ntohs(ch->chunk_length));
+
+	/* get to new offset for the param. */
+	addstr = (struct sctp_stream_reset_add_strm *)((caddr_t)ch + len);
+	/* now how long will this param be? */
+	len = sizeof(struct sctp_stream_reset_add_strm);
+
+	/* Fill it out. */
+	addstr->ph.param_type = htons(SCTP_STR_RESET_ADD_STREAMS);
+	addstr->ph.param_length = htons(len);
+	addstr->request_seq = htonl(seq);
+	addstr->number_of_streams = htons(adding);
+	addstr->reserved = 0;
+
+	/* now fix the chunk length */
+	ch->chunk_length = htons(len + old_len);
+	chk->send_size = len + old_len;
+	chk->book_size = SCTP_SIZE32(chk->send_size);
+	chk->book_size_scale = 0;
+	SCTP_BUF_LEN(chk->data) = SCTP_SIZE32(chk->send_size);
+	return;
+}
 
 int
 sctp_send_str_reset_req(struct sctp_tcb *stcb,
     int number_entries, uint16_t * list,
-    uint8_t send_out_req, uint32_t resp_seq,
+    uint8_t send_out_req,
+    uint32_t resp_seq,
     uint8_t send_in_req,
-    uint8_t send_tsn_req)
+    uint8_t send_tsn_req,
+    uint8_t add_stream,
+    uint16_t adding
+)
 {
 
 	struct sctp_association *asoc;
@@ -13361,7 +13395,8 @@ sctp_send_str_reset_req(struct sctp_tcb 
 		SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EBUSY);
 		return (EBUSY);
 	}
-	if ((send_out_req == 0) && (send_in_req == 0) && (send_tsn_req == 0)) {
+	if ((send_out_req == 0) && (send_in_req == 0) && (send_tsn_req == 0) &&
+	    (add_stream == 0)) {
 		/* nothing to do */
 		SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL);
 		return (EINVAL);
@@ -13412,6 +13447,11 @@ sctp_send_str_reset_req(struct sctp_tcb 
 		seq++;
 		asoc->stream_reset_outstanding++;
 	}
+	if (add_stream) {
+		sctp_add_a_stream(chk, seq, adding);
+		seq++;
+		asoc->stream_reset_outstanding++;
+	}
 	if (send_in_req) {
 		sctp_add_stream_reset_in(chk, number_entries, list, seq);
 		asoc->stream_reset_outstanding++;
@@ -14432,7 +14472,7 @@ sctp_lower_sosend(struct socket *so,
 						if (tmp_str != NULL) {
 							SCTP_FREE(asoc->strmout, SCTP_M_STRMO);
 							asoc->strmout = tmp_str;
-							asoc->streamoutcnt = asoc->pre_open_streams;
+							asoc->strm_realoutsize = asoc->streamoutcnt = asoc->pre_open_streams;
 						} else {
 							asoc->pre_open_streams = asoc->streamoutcnt;
 						}
@@ -15016,9 +15056,6 @@ skip_preblock:
 				    (stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk)));
 				if (net->flight_size > net->cwnd) {
 					queue_only = 1;
-					SCTP_STAT_INCR(sctps_send_burst_avoid);
-				} else if (net->flight_size > net->cwnd) {
-					queue_only = 1;
 					SCTP_STAT_INCR(sctps_send_cwnd_avoid);
 				} else {
 					queue_only = 0;
@@ -15293,9 +15330,6 @@ skip_out_eof:
 		    (stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk)));
 		if (net->flight_size > net->cwnd) {
 			queue_only = 1;
-			SCTP_STAT_INCR(sctps_send_burst_avoid);
-		} else if (net->flight_size > net->cwnd) {
-			queue_only = 1;
 			SCTP_STAT_INCR(sctps_send_cwnd_avoid);
 		} else {
 			queue_only = 0;

Modified: head/sys/netinet/sctp_output.h
==============================================================================
--- head/sys/netinet/sctp_output.h	Fri Feb 20 14:53:49 2009	(r188853)
+++ head/sys/netinet/sctp_output.h	Fri Feb 20 15:03:54 2009	(r188854)
@@ -192,10 +192,14 @@ sctp_add_stream_reset_result_tsn(struct 
 
 int
 sctp_send_str_reset_req(struct sctp_tcb *stcb,
-    int number_entries, uint16_t * list,
-    uint8_t send_out_req, uint32_t resp_seq,
+    int number_entries,
+    uint16_t * list,
+    uint8_t send_out_req,
+    uint32_t resp_seq,
     uint8_t send_in_req,
-    uint8_t send_tsn_req);
+    uint8_t send_tsn_req,
+    uint8_t add_str,
+    uint16_t adding);
 
 
 void

Modified: head/sys/netinet/sctp_pcb.c
==============================================================================
--- head/sys/netinet/sctp_pcb.c	Fri Feb 20 14:53:49 2009	(r188853)
+++ head/sys/netinet/sctp_pcb.c	Fri Feb 20 15:03:54 2009	(r188854)
@@ -4885,7 +4885,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, 
 		SCTP_FREE(asoc->strmout, SCTP_M_STRMO);
 		asoc->strmout = NULL;
 	}
-	asoc->streamoutcnt = 0;
+	asoc->strm_realoutsize = asoc->streamoutcnt = 0;
 	if (asoc->strmin) {
 		struct sctp_queued_to_read *ctl;
 

Modified: head/sys/netinet/sctp_structs.h
==============================================================================
--- head/sys/netinet/sctp_structs.h	Fri Feb 20 14:53:49 2009	(r188853)
+++ head/sys/netinet/sctp_structs.h	Fri Feb 20 15:03:54 2009	(r188854)
@@ -935,7 +935,7 @@ struct sctp_association {
 	/* could re-arrange to optimize space here. */
 	uint16_t streamincnt;
 	uint16_t streamoutcnt;
-
+	uint16_t strm_realoutsize;
 	/* my maximum number of retrans of INIT and SEND */
 	/* copied from SCTP but should be individually setable */
 	uint16_t max_init_times;

Modified: head/sys/netinet/sctp_uio.h
==============================================================================
--- head/sys/netinet/sctp_uio.h	Fri Feb 20 14:53:49 2009	(r188853)
+++ head/sys/netinet/sctp_uio.h	Fri Feb 20 15:03:54 2009	(r188854)
@@ -377,7 +377,7 @@ struct sctp_stream_reset_event {
 #define SCTP_STRRESET_ALL_STREAMS  0x0004
 #define SCTP_STRRESET_STREAM_LIST  0x0008
 #define SCTP_STRRESET_FAILED       0x0010
-
+#define SCTP_STRRESET_ADD_STREAM   0x0020
 
 /* SCTP notification event */
 struct sctp_tlv {
@@ -596,6 +596,7 @@ struct sctp_blk_args {
 #define SCTP_RESET_LOCAL_SEND  0x0002
 #define SCTP_RESET_BOTH        0x0003
 #define SCTP_RESET_TSN         0x0004
+#define SCTP_RESET_ADD_STREAMS 0x0005
 
 struct sctp_stream_reset {
 	sctp_assoc_t strrst_assoc_id;
@@ -941,9 +942,7 @@ struct sctpstat {
 	uint32_t sctps_cached_strmoq;	/* Number of cached stream oq's used */
 	uint32_t sctps_left_abandon;	/* Number of unread message abandonded
 					 * by close */
-	uint32_t sctps_send_burst_avoid;	/* Send burst avoidance,
-						 * already max burst inflight
-						 * to net */
+	uint32_t sctps_send_burst_avoid;	/* Unused */
 	uint32_t sctps_send_cwnd_avoid;	/* Send cwnd full  avoidance, already
 					 * max burst inflight to net */
 	uint32_t sctps_fwdtsn_map_over;	/* number of map array over-runs via

Modified: head/sys/netinet/sctp_usrreq.c
==============================================================================
--- head/sys/netinet/sctp_usrreq.c	Fri Feb 20 14:53:49 2009	(r188853)
+++ head/sys/netinet/sctp_usrreq.c	Fri Feb 20 15:03:54 2009	(r188854)
@@ -3263,7 +3263,9 @@ sctp_setopt(struct socket *so, int optna
 	case SCTP_RESET_STREAMS:
 		{
 			struct sctp_stream_reset *strrst;
-			uint8_t send_in = 0, send_tsn = 0, send_out = 0;
+			uint8_t send_in = 0, send_tsn = 0, send_out = 0,
+			        addstream = 0;
+			uint16_t addstrmcnt = 0;
 			int i;
 
 			SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_stream_reset, optsize);
@@ -3301,6 +3303,60 @@ sctp_setopt(struct socket *so, int optna
 				send_out = 1;
 			} else if (strrst->strrst_flags == SCTP_RESET_TSN) {
 				send_tsn = 1;
+			} else if (strrst->strrst_flags == SCTP_RESET_ADD_STREAMS) {
+				if (send_tsn ||
+				    send_in ||
+				    send_out) {
+					/* We can't do that and add streams */
+					error = EINVAL;
+					goto skip_stuff;
+				}
+				if (stcb->asoc.stream_reset_outstanding) {
+					error = EBUSY;
+					goto skip_stuff;
+				}
+				addstream = 1;
+				/* We allocate here */
+				addstrmcnt = strrst->strrst_num_streams;
+				if ((int)(addstrmcnt + stcb->asoc.streamoutcnt) > 0xffff) {
+					/* You can't have more than 64k */
+					error = EINVAL;
+					goto skip_stuff;
+				}
+				if ((stcb->asoc.strm_realoutsize - stcb->asoc.streamoutcnt) < addstrmcnt) {
+					/* Need to allocate more */
+					struct sctp_stream_out *oldstream;
+
+					oldstream = stcb->asoc.strmout;
+					/* get some more */
+					SCTP_MALLOC(stcb->asoc.strmout, struct sctp_stream_out *,
+					    ((stcb->asoc.streamoutcnt + addstrmcnt) * sizeof(struct sctp_stream_out)),
+					    SCTP_M_STRMO);
+					if (stcb->asoc.strmout == NULL) {
+						stcb->asoc.strmout = oldstream;
+						error = ENOMEM;
+						goto skip_stuff;
+					}
+					/*
+					 * Ok now we proceed with copying
+					 * the old out stuff and
+					 * initializing the new stuff.
+					 */
+					memcpy(stcb->asoc.strmout, oldstream,
+					    (stcb->asoc.streamoutcnt * sizeof(struct sctp_stream_out)));
+					/* now the new streams */
+					for (i = stcb->asoc.streamoutcnt; i < (stcb->asoc.streamoutcnt + addstrmcnt); i++) {
+						stcb->asoc.strmout[i].next_sequence_sent = 0x0;
+						TAILQ_INIT(&stcb->asoc.strmout[i].outqueue);
+						stcb->asoc.strmout[i].stream_no = i;
+						stcb->asoc.strmout[i].last_msg_incomplete = 0;
+						stcb->asoc.strmout[i].next_spoke.tqe_next = 0;
+						stcb->asoc.strmout[i].next_spoke.tqe_prev = 0;
+					}
+					stcb->asoc.strm_realoutsize = stcb->asoc.streamoutcnt + addstrmcnt;
+					SCTP_FREE(oldstream, SCTP_M_STRMO);
+				}
+				goto skip_stuff;
 			} else {
 				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
 				error = EINVAL;
@@ -3322,6 +3378,7 @@ sctp_setopt(struct socket *so, int optna
 					goto get_out;
 				}
 			}
+	skip_stuff:
 			if (error) {
 		get_out:
 				SCTP_TCB_UNLOCK(stcb);
@@ -3330,7 +3387,7 @@ sctp_setopt(struct socket *so, int optna
 			error = sctp_send_str_reset_req(stcb, strrst->strrst_num_streams,
 			    strrst->strrst_list,
 			    send_out, (stcb->asoc.str_reset_seq_in - 3),
-			    send_in, send_tsn);
+			    send_in, send_tsn, addstream, addstrmcnt);
 
 			sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
 			SCTP_TCB_UNLOCK(stcb);

Modified: head/sys/netinet/sctputil.c
==============================================================================
--- head/sys/netinet/sctputil.c	Fri Feb 20 14:53:49 2009	(r188853)
+++ head/sys/netinet/sctputil.c	Fri Feb 20 15:03:54 2009	(r188854)
@@ -1119,7 +1119,7 @@ sctp_init_asoc(struct sctp_inpcb *m, str
 	 * Now the stream parameters, here we allocate space for all streams
 	 * that we request by default.
 	 */
-	asoc->streamoutcnt = asoc->pre_open_streams =
+	asoc->strm_realoutsize = asoc->streamoutcnt = asoc->pre_open_streams =
 	    m->sctp_ep.pre_open_stream_count;
 	SCTP_MALLOC(asoc->strmout, struct sctp_stream_out *,
 	    asoc->streamoutcnt * sizeof(struct sctp_stream_out),
@@ -3351,6 +3351,63 @@ sctp_notify_sender_dry_event(struct sctp
 	    &stcb->sctp_socket->so_rcv, 1, so_locked);
 }
 
+
+static void
+sctp_notify_stream_reset_add(struct sctp_tcb *stcb, int number_entries, int flag)
+{
+	struct mbuf *m_notify;
+	struct sctp_queued_to_read *control;
+	struct sctp_stream_reset_event *strreset;
+	int len;
+
+	if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_STREAM_RESETEVNT)) {
+		/* event not enabled */
+		return;
+	}
+	m_notify = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_DONTWAIT, 1, MT_DATA);
+	if (m_notify == NULL)
+		/* no space left */
+		return;
+	SCTP_BUF_LEN(m_notify) = 0;
+	len = sizeof(struct sctp_stream_reset_event) + (number_entries * sizeof(uint16_t));
+	if (len > M_TRAILINGSPACE(m_notify)) {
+		/* never enough room */
+		sctp_m_freem(m_notify);
+		return;
+	}
+	strreset = mtod(m_notify, struct sctp_stream_reset_event *);
+	strreset->strreset_type = SCTP_STREAM_RESET_EVENT;
+	strreset->strreset_flags = SCTP_STRRESET_ADD_STREAM | flag;
+	strreset->strreset_length = len;
+	strreset->strreset_assoc_id = sctp_get_associd(stcb);
+	strreset->strreset_list[0] = number_entries;
+
+	SCTP_BUF_LEN(m_notify) = len;
+	SCTP_BUF_NEXT(m_notify) = NULL;
+	if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) {
+		/* no space */
+		sctp_m_freem(m_notify);
+		return;
+	}
+	/* append to socket */
+	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
+	    0, 0, 0, 0, 0, 0,
+	    m_notify);
+	if (control == NULL) {
+		/* no memory */
+		sctp_m_freem(m_notify);
+		return;
+	}
+	control->spec_flags = M_NOTIFICATION;
+	control->length = SCTP_BUF_LEN(m_notify);
+	/* not that we need this */
+	control->tail_mbuf = m_notify;
+	sctp_add_to_readq(stcb->sctp_ep, stcb,
+	    control,
+	    &stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
+}
+
+
 static void
 sctp_notify_stream_reset(struct sctp_tcb *stcb,
     int number_entries, uint16_t * list, int flag)
@@ -3528,6 +3585,16 @@ sctp_ulp_notify(uint32_t notification, s
 		break;
 	case SCTP_NOTIFY_HB_RESP:
 		break;
+	case SCTP_NOTIFY_STR_RESET_INSTREAM_ADD_OK:
+		sctp_notify_stream_reset_add(stcb, error, SCTP_STRRESET_INBOUND_STR);
+		break;
+	case SCTP_NOTIFY_STR_RESET_ADD_OK:
+		sctp_notify_stream_reset_add(stcb, error, SCTP_STRRESET_OUTBOUND_STR);
+		break;
+	case SCTP_NOTIFY_STR_RESET_ADD_FAIL:
+		sctp_notify_stream_reset_add(stcb, error, (SCTP_STRRESET_FAILED | SCTP_STRRESET_OUTBOUND_STR));
+		break;
+
 	case SCTP_NOTIFY_STR_RESET_SEND:
 		sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), SCTP_STRRESET_OUTBOUND_STR);
 		break;


More information about the svn-src-head mailing list