Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 29 Apr 2012 16:10:25 +0000 (UTC)
From:      Michael Tuexen <tuexen@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org
Subject:   svn commit: r234790 - stable/9/sys/netinet
Message-ID:  <201204291610.q3TGAP4r021164@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: tuexen
Date: Sun Apr 29 16:10:24 2012
New Revision: 234790
URL: http://svn.freebsd.org/changeset/base/234790

Log:
  MFC r233660:
  
  Make stream our stream reset implementation
  compliant to RFC6525.
  From rrs@.

Modified:
  stable/9/sys/netinet/sctp.h
  stable/9/sys/netinet/sctp_constants.h
  stable/9/sys/netinet/sctp_header.h
  stable/9/sys/netinet/sctp_input.c
  stable/9/sys/netinet/sctp_output.c
  stable/9/sys/netinet/sctp_output.h
  stable/9/sys/netinet/sctp_pcb.h
  stable/9/sys/netinet/sctp_peeloff.c
  stable/9/sys/netinet/sctp_structs.h
  stable/9/sys/netinet/sctp_uio.h
  stable/9/sys/netinet/sctp_usrreq.c
  stable/9/sys/netinet/sctputil.c
  stable/9/sys/netinet/sctputil.h
Directory Properties:
  stable/9/sys/   (props changed)

Modified: stable/9/sys/netinet/sctp.h
==============================================================================
--- stable/9/sys/netinet/sctp.h	Sun Apr 29 15:54:40 2012	(r234789)
+++ stable/9/sys/netinet/sctp.h	Sun Apr 29 16:10:24 2012	(r234790)
@@ -155,8 +155,22 @@ struct sctp_paramhdr {
  * field.
  */
 
-/* these should probably go into sockets API */
-#define SCTP_RESET_STREAMS		0x00001004	/* wo */
+#define SCTP_ENABLE_STREAM_RESET	0x00000900	/* struct
+							 * sctp_assoc_value */
+#define SCTP_RESET_STREAMS		0x00000901	/* struct
+							 * sctp_reset_streams */
+#define SCTP_RESET_ASSOC		0x00000902	/* sctp_assoc_t */
+#define SCTP_ADD_STREAMS		0x00000903	/* struct
+							 * sctp_add_streams */
+
+/* For enable stream reset */
+#define SCTP_ENABLE_RESET_STREAM_REQ 	0x00000001
+#define SCTP_ENABLE_RESET_ASSOC_REQ 	0x00000002
+#define SCTP_ENABLE_CHANGE_ASSOC_REQ 	0x00000004
+#define SCTP_ENABLE_VALUE_MASK		0x00000007
+/* For reset streams */
+#define SCTP_STREAM_RESET_INCOMING	0x00000001
+#define SCTP_STREAM_RESET_OUTGOING	0x00000002
 
 
 /* here on down are more implementation specific */

Modified: stable/9/sys/netinet/sctp_constants.h
==============================================================================
--- stable/9/sys/netinet/sctp_constants.h	Sun Apr 29 15:54:40 2012	(r234789)
+++ stable/9/sys/netinet/sctp_constants.h	Sun Apr 29 16:10:24 2012	(r234790)
@@ -418,7 +418,8 @@ __FBSDID("$FreeBSD$");
 #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_STR_RESET_ADD_OUT_STREAMS	0x0011
+#define SCTP_STR_RESET_ADD_IN_STREAMS   0x0012
 
 #define SCTP_MAX_RESET_PARAMS 2
 #define SCTP_STREAM_RESET_TSN_DELTA    0x1000

Modified: stable/9/sys/netinet/sctp_header.h
==============================================================================
--- stable/9/sys/netinet/sctp_header.h	Sun Apr 29 15:54:40 2012	(r234789)
+++ stable/9/sys/netinet/sctp_header.h	Sun Apr 29 16:10:24 2012	(r234790)
@@ -501,7 +501,7 @@ struct sctp_stream_reset_add_strm {
 
 #define SCTP_STREAM_RESET_NOTHING   0x00000000	/* Nothing for me to do */
 #define SCTP_STREAM_RESET_PERFORMED 0x00000001	/* Did it */
-#define SCTP_STREAM_RESET_DENIED    0x00000002	/* refused to do it */
+#define SCTP_STREAM_RESET_REJECT    0x00000002	/* refused to do it */
 #define SCTP_STREAM_RESET_ERROR_STR 0x00000003	/* bad Stream no */
 #define SCTP_STREAM_RESET_TRY_LATER 0x00000004	/* collision, try again */
 #define SCTP_STREAM_RESET_BAD_SEQNO 0x00000005	/* bad str-reset seq no */

Modified: stable/9/sys/netinet/sctp_input.c
==============================================================================
--- stable/9/sys/netinet/sctp_input.c	Sun Apr 29 15:54:40 2012	(r234789)
+++ stable/9/sys/netinet/sctp_input.c	Sun Apr 29 16:10:24 2012	(r234790)
@@ -2790,6 +2790,7 @@ sctp_handle_cookie_echo(struct mbuf *m, 
 			inp->sctp_ecn_enable = (*inp_p)->sctp_ecn_enable;
 			inp->partial_delivery_point = (*inp_p)->partial_delivery_point;
 			inp->sctp_context = (*inp_p)->sctp_context;
+			inp->local_strreset_support = (*inp_p)->local_strreset_support;
 			inp->inp_starting_point_for_iterator = NULL;
 			/*
 			 * copy in the authentication parameters from the
@@ -3612,20 +3613,35 @@ sctp_handle_stream_reset_response(struct
 				if (asoc->stream_reset_outstanding)
 					asoc->stream_reset_outstanding--;
 				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);
+					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) {
+			} else if (type == SCTP_STR_RESET_ADD_OUT_STREAMS) {
 				/* Ok we now may have more streams */
+				int num_stream;
+
+				num_stream = stcb->asoc.strm_pending_add_size;
+				if (num_stream > (stcb->asoc.strm_realoutsize - stcb->asoc.streamoutcnt)) {
+					/* TSNH */
+					num_stream = stcb->asoc.strm_realoutsize - stcb->asoc.streamoutcnt;
+				}
+				stcb->asoc.strm_pending_add_size = 0;
 				if (asoc->stream_reset_outstanding)
 					asoc->stream_reset_outstanding--;
 				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);
+					stcb->asoc.streamoutcnt += num_stream;
+					sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt, 0);
 				} else {
-					sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_ADD_FAIL, stcb,
-					    (uint32_t) stcb->asoc.streamoutcnt, NULL, SCTP_SO_NOT_LOCKED);
+					sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt,
+					    SCTP_STREAM_CHANGED_DENIED);
+				}
+			} else if (type == SCTP_STR_RESET_ADD_IN_STREAMS) {
+				if (asoc->stream_reset_outstanding)
+					asoc->stream_reset_outstanding--;
+				if (action != SCTP_STREAM_RESET_PERFORMED) {
+					sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt,
+					    SCTP_STREAM_CHANGED_DENIED);
 				}
 			} else if (type == SCTP_STR_RESET_TSN_REQUEST) {
 				/**
@@ -3667,7 +3683,10 @@ sctp_handle_stream_reset_response(struct
 
 					sctp_reset_out_streams(stcb, 0, (uint16_t *) NULL);
 					sctp_reset_in_stream(stcb, 0, (uint16_t *) NULL);
-
+					sctp_notify_stream_reset_tsn(stcb, stcb->asoc.sending_seq, (stcb->asoc.mapping_array_base_tsn + 1), 0);
+				} else {
+					sctp_notify_stream_reset_tsn(stcb, stcb->asoc.sending_seq, (stcb->asoc.mapping_array_base_tsn + 1),
+					    SCTP_STREAM_RESET_FAILED);
 				}
 			}
 			/* get rid of the request and get the request flags */
@@ -3700,8 +3719,7 @@ sctp_handle_str_reset_request_in(struct 
 		if (trunc) {
 			/* Can't do it, since they exceeded our buffer size  */
 			asoc->last_reset_action[1] = asoc->last_reset_action[0];
-			asoc->last_reset_action[0] = SCTP_STREAM_RESET_DENIED;
-			sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]);
+			asoc->last_reset_action[0] = SCTP_STREAM_RESET_REJECT;
 		} else if (stcb->asoc.stream_reset_out_is_outstanding == 0) {
 			len = ntohs(req->ph.param_length);
 			number_entries = ((len - sizeof(struct sctp_stream_reset_in_request)) / sizeof(uint16_t));
@@ -3723,8 +3741,8 @@ sctp_handle_str_reset_request_in(struct 
 			/* Can't do it, since we have sent one out */
 			asoc->last_reset_action[1] = asoc->last_reset_action[0];
 			asoc->last_reset_action[0] = SCTP_STREAM_RESET_TRY_LATER;
-			sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]);
 		}
+		sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]);
 		asoc->str_reset_seq_in++;
 	} else if (asoc->str_reset_seq_in - 1 == seq) {
 		sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]);
@@ -3786,7 +3804,7 @@ sctp_handle_str_reset_request_tsn(struct
 		sctp_reset_in_stream(stcb, 0, (uint16_t *) NULL);
 		stcb->asoc.last_reset_action[1] = stcb->asoc.last_reset_action[0];
 		stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_PERFORMED;
-
+		sctp_notify_stream_reset_tsn(stcb, stcb->asoc.sending_seq, (stcb->asoc.mapping_array_base_tsn + 1), 0);
 		asoc->str_reset_seq_in++;
 	} else if (asoc->str_reset_seq_in - 1 == seq) {
 		sctp_add_stream_reset_result_tsn(chk, seq, asoc->last_reset_action[0],
@@ -3831,12 +3849,10 @@ sctp_handle_str_reset_request_out(struct
 		/* move the reset action back one */
 		asoc->last_reset_action[1] = asoc->last_reset_action[0];
 		if (trunc) {
-			sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_DENIED);
-			asoc->last_reset_action[0] = SCTP_STREAM_RESET_DENIED;
+			asoc->last_reset_action[0] = SCTP_STREAM_RESET_REJECT;
 		} else if (SCTP_TSN_GE(asoc->cumulative_tsn, tsn)) {
 			/* we can do it now */
 			sctp_reset_in_stream(stcb, number_entries, req->list_of_streams);
-			sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_PERFORMED);
 			asoc->last_reset_action[0] = SCTP_STREAM_RESET_PERFORMED;
 		} else {
 			/*
@@ -3851,8 +3867,8 @@ sctp_handle_str_reset_request_out(struct
 			    siz, SCTP_M_STRESET);
 			if (liste == NULL) {
 				/* gak out of memory */
-				sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_DENIED);
-				asoc->last_reset_action[0] = SCTP_STREAM_RESET_DENIED;
+				sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_REJECT);
+				asoc->last_reset_action[0] = SCTP_STREAM_RESET_REJECT;
 				return;
 			}
 			liste->tsn = tsn;
@@ -3860,9 +3876,9 @@ sctp_handle_str_reset_request_out(struct
 			memcpy(&liste->req, req,
 			    (sizeof(struct sctp_stream_reset_out_request) + (number_entries * sizeof(uint16_t))));
 			TAILQ_INSERT_TAIL(&asoc->resetHead, liste, next_resp);
-			sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_PERFORMED);
 			asoc->last_reset_action[0] = SCTP_STREAM_RESET_PERFORMED;
 		}
+		sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]);
 		asoc->str_reset_seq_in++;
 	} else if ((asoc->str_reset_seq_in - 1) == seq) {
 		/*
@@ -3889,7 +3905,7 @@ sctp_handle_str_reset_add_strm(struct sc
 	 * Peer is requesting to add more streams. If its within our
 	 * max-streams we will allow it.
 	 */
-	uint16_t num_stream, i;
+	uint32_t num_stream, i;
 	uint32_t seq;
 	struct sctp_association *asoc = &stcb->asoc;
 	struct sctp_queued_to_read *ctl, *nctl;
@@ -3900,12 +3916,12 @@ sctp_handle_str_reset_add_strm(struct sc
 	/* Now what would be the new total? */
 	if (asoc->str_reset_seq_in == seq) {
 		num_stream += stcb->asoc.streamincnt;
-		if (num_stream > stcb->asoc.max_inbound_streams) {
+		if ((num_stream > stcb->asoc.max_inbound_streams) ||
+		    (num_stream > 0xffff)) {
 			/* 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;
+			stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_REJECT;
 		} else {
 			/* Ok, we can do that :-) */
 			struct sctp_stream_in *oldstrm;
@@ -3941,13 +3957,12 @@ sctp_handle_str_reset_add_strm(struct sc
 			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);
+			sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt, 0);
 		}
+		sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]);
+		asoc->str_reset_seq_in++;
 	} else if ((asoc->str_reset_seq_in - 1) == seq) {
 		/*
 		 * one seq back, just echo back last action since my
@@ -3966,6 +3981,63 @@ sctp_handle_str_reset_add_strm(struct sc
 	}
 }
 
+static void
+sctp_handle_str_reset_add_out_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;
+	uint32_t seq;
+	struct sctp_association *asoc = &stcb->asoc;
+
+	/* Get the number. */
+	seq = ntohl(str_add->request_seq);
+	num_stream = ntohs(str_add->number_of_streams);
+	/* Now what would be the new total? */
+	if (asoc->str_reset_seq_in == seq) {
+		if (stcb->asoc.stream_reset_outstanding) {
+			/* We must reject it we have something pending */
+			stcb->asoc.last_reset_action[1] = stcb->asoc.last_reset_action[0];
+			stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_REJECT;
+		} else {
+			/* Ok, we can do that :-) */
+			int mychk;
+
+			mychk = stcb->asoc.streamoutcnt;
+			mychk += num_stream;
+			if (mychk < 0x10000) {
+				stcb->asoc.last_reset_action[1] = stcb->asoc.last_reset_action[0];
+				stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_PERFORMED;
+				if (sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 0, 1, num_stream, 0, 1)) {
+					stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_REJECT;
+				}
+			} else {
+				stcb->asoc.last_reset_action[1] = stcb->asoc.last_reset_action[0];
+				stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_REJECT;
+			}
+		}
+		sctp_add_stream_reset_result(chk, seq, stcb->asoc.last_reset_action[0]);
+		asoc->str_reset_seq_in++;
+	} else if ((asoc->str_reset_seq_in - 1) == seq) {
+		/*
+		 * one seq back, just echo back last action since my
+		 * response was lost.
+		 */
+		sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]);
+	} else if ((asoc->str_reset_seq_in - 2) == seq) {
+		/*
+		 * two seq back, just echo back last action since my
+		 * response was lost.
+		 */
+		sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[1]);
+	} else {
+		sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_BAD_SEQNO);
+	}
+}
+
 #ifdef __GNUC__
 __attribute__((noinline))
 #endif
@@ -3977,7 +4049,7 @@ __attribute__((noinline))
 	struct sctp_paramhdr pstore;
 	uint8_t cstore[SCTP_CHUNK_BUFFER_SIZE];
 
-	uint32_t seq;
+	uint32_t seq = 0;
 	int num_req = 0;
 	int trunc = 0;
 	struct sctp_tmit_chunk *chk;
@@ -4041,7 +4113,6 @@ strres_nochunk:
 		} else {
 			trunc = 0;
 		}
-
 		if (num_param > SCTP_MAX_RESET_PARAMS) {
 			/* hit the max of parameters already sorry.. */
 			break;
@@ -4059,26 +4130,29 @@ strres_nochunk:
 				}
 			}
 			sctp_handle_str_reset_request_out(stcb, chk, req_out, trunc);
-		} else if (ptype == SCTP_STR_RESET_ADD_STREAMS) {
+		} else if (ptype == SCTP_STR_RESET_ADD_OUT_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_ADD_IN_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_out_strm(stcb, chk, str_add);
 		} else if (ptype == SCTP_STR_RESET_IN_REQUEST) {
 			struct sctp_stream_reset_in_request *req_in;
 
 			num_req++;
-
 			req_in = (struct sctp_stream_reset_in_request *)ph;
-
 			sctp_handle_str_reset_request_in(stcb, chk, req_in, trunc);
 		} else if (ptype == SCTP_STR_RESET_TSN_REQUEST) {
 			struct sctp_stream_reset_tsn_request *req_tsn;
 
 			num_req++;
 			req_tsn = (struct sctp_stream_reset_tsn_request *)ph;
-
 			if (sctp_handle_str_reset_request_tsn(stcb, chk, req_tsn)) {
 				ret_code = 1;
 				goto strres_nochunk;

Modified: stable/9/sys/netinet/sctp_output.c
==============================================================================
--- stable/9/sys/netinet/sctp_output.c	Sun Apr 29 15:54:40 2012	(r234789)
+++ stable/9/sys/netinet/sctp_output.c	Sun Apr 29 16:10:24 2012	(r234790)
@@ -11716,7 +11716,7 @@ sctp_add_stream_reset_result_tsn(struct 
 }
 
 static void
-sctp_add_a_stream(struct sctp_tmit_chunk *chk,
+sctp_add_an_out_stream(struct sctp_tmit_chunk *chk,
     uint32_t seq,
     uint16_t adding)
 {
@@ -11733,7 +11733,7 @@ sctp_add_a_stream(struct sctp_tmit_chunk
 	len = sizeof(struct sctp_stream_reset_add_strm);
 
 	/* Fill it out. */
-	addstr->ph.param_type = htons(SCTP_STR_RESET_ADD_STREAMS);
+	addstr->ph.param_type = htons(SCTP_STR_RESET_ADD_OUT_STREAMS);
 	addstr->ph.param_length = htons(len);
 	addstr->request_seq = htonl(seq);
 	addstr->number_of_streams = htons(adding);
@@ -11748,15 +11748,49 @@ sctp_add_a_stream(struct sctp_tmit_chunk
 	return;
 }
 
+static void
+sctp_add_an_in_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_IN_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_in_req,
     uint8_t send_tsn_req,
     uint8_t add_stream,
-    uint16_t adding
+    uint16_t adding_o,
+    uint16_t adding_i, uint8_t peer_asked
 )
 {
 
@@ -11823,18 +11857,86 @@ sctp_send_str_reset_req(struct sctp_tcb 
 	seq = stcb->asoc.str_reset_seq_out;
 	if (send_out_req) {
 		sctp_add_stream_reset_out(chk, number_entries, list,
-		    seq, resp_seq, (stcb->asoc.sending_seq - 1));
+		    seq, (stcb->asoc.str_reset_seq_in - 1), (stcb->asoc.sending_seq - 1));
 		asoc->stream_reset_out_is_outstanding = 1;
 		seq++;
 		asoc->stream_reset_outstanding++;
 	}
-	if (add_stream) {
-		sctp_add_a_stream(chk, seq, adding);
+	if ((add_stream & 1) &&
+	    ((stcb->asoc.strm_realoutsize - stcb->asoc.streamoutcnt) < adding_o)) {
+		/* Need to allocate more */
+		struct sctp_stream_out *oldstream;
+		struct sctp_stream_queue_pending *sp, *nsp;
+		int i;
+
+		oldstream = stcb->asoc.strmout;
+		/* get some more */
+		SCTP_MALLOC(stcb->asoc.strmout, struct sctp_stream_out *,
+		    ((stcb->asoc.streamoutcnt + adding_o) * sizeof(struct sctp_stream_out)),
+		    SCTP_M_STRMO);
+		if (stcb->asoc.strmout == NULL) {
+			uint8_t x;
+
+			stcb->asoc.strmout = oldstream;
+			/* Turn off the bit */
+			x = add_stream & 0xfe;
+			add_stream = x;
+			goto skip_stuff;
+		}
+		/*
+		 * Ok now we proceed with copying the old out stuff and
+		 * initializing the new stuff.
+		 */
+		SCTP_TCB_SEND_LOCK(stcb);
+		stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 0, 1);
+		for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
+			TAILQ_INIT(&stcb->asoc.strmout[i].outqueue);
+			stcb->asoc.strmout[i].next_sequence_sent = oldstream[i].next_sequence_sent;
+			stcb->asoc.strmout[i].last_msg_incomplete = oldstream[i].last_msg_incomplete;
+			stcb->asoc.strmout[i].stream_no = i;
+			stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], &oldstream[i]);
+			/* now anything on those queues? */
+			TAILQ_FOREACH_SAFE(sp, &oldstream[i].outqueue, next, nsp) {
+				TAILQ_REMOVE(&oldstream[i].outqueue, sp, next);
+				TAILQ_INSERT_TAIL(&stcb->asoc.strmout[i].outqueue, sp, next);
+			}
+			/* Now move assoc pointers too */
+			if (stcb->asoc.last_out_stream == &oldstream[i]) {
+				stcb->asoc.last_out_stream = &stcb->asoc.strmout[i];
+			}
+			if (stcb->asoc.locked_on_sending == &oldstream[i]) {
+				stcb->asoc.locked_on_sending = &stcb->asoc.strmout[i];
+			}
+		}
+		/* now the new streams */
+		stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
+		for (i = stcb->asoc.streamoutcnt; i < (stcb->asoc.streamoutcnt + adding_o); 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.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], NULL);
+		}
+		stcb->asoc.strm_realoutsize = stcb->asoc.streamoutcnt + adding_o;
+		SCTP_FREE(oldstream, SCTP_M_STRMO);
+		SCTP_TCB_SEND_UNLOCK(stcb);
+	}
+skip_stuff:
+	if ((add_stream & 1) && (adding_o > 0)) {
+		asoc->strm_pending_add_size = adding_o;
+		asoc->peer_req_out = peer_asked;
+		sctp_add_an_out_stream(chk, seq, adding_o);
+		seq++;
+		asoc->stream_reset_outstanding++;
+	}
+	if ((add_stream & 2) && (adding_i > 0)) {
+		sctp_add_an_in_stream(chk, seq, adding_i);
 		seq++;
 		asoc->stream_reset_outstanding++;
 	}
 	if (send_in_req) {
 		sctp_add_stream_reset_in(chk, number_entries, list, seq);
+		seq++;
 		asoc->stream_reset_outstanding++;
 	}
 	if (send_tsn_req) {
@@ -11842,7 +11944,6 @@ sctp_send_str_reset_req(struct sctp_tcb 
 		asoc->stream_reset_outstanding++;
 	}
 	asoc->str_reset = chk;
-
 	/* insert the chunk for sending */
 	TAILQ_INSERT_TAIL(&asoc->control_send_queue,
 	    chk,

Modified: stable/9/sys/netinet/sctp_output.h
==============================================================================
--- stable/9/sys/netinet/sctp_output.h	Sun Apr 29 15:54:40 2012	(r234789)
+++ stable/9/sys/netinet/sctp_output.h	Sun Apr 29 16:10:24 2012	(r234790)
@@ -194,15 +194,13 @@ sctp_add_stream_reset_result_tsn(struct 
 
 int
 sctp_send_str_reset_req(struct sctp_tcb *stcb,
-    int number_entries,
-    uint16_t * list,
+    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 add_str,
-    uint16_t adding);
-
+    uint8_t add_stream,
+    uint16_t adding_o,
+    uint16_t adding_i, uint8_t from_peer);
 
 void
 sctp_send_abort(struct mbuf *, int, struct sctphdr *, uint32_t,

Modified: stable/9/sys/netinet/sctp_pcb.h
==============================================================================
--- stable/9/sys/netinet/sctp_pcb.h	Sun Apr 29 15:54:40 2012	(r234789)
+++ stable/9/sys/netinet/sctp_pcb.h	Sun Apr 29 16:10:24 2012	(r234790)
@@ -399,6 +399,7 @@ struct sctp_inpcb {
 	uint32_t sctp_frag_point;
 	uint32_t partial_delivery_point;
 	uint32_t sctp_context;
+	uint8_t local_strreset_support;
 	uint32_t sctp_cmt_on_off;
 	uint32_t sctp_ecn_enable;
 	struct sctp_nonpad_sndrcvinfo def_send;

Modified: stable/9/sys/netinet/sctp_peeloff.c
==============================================================================
--- stable/9/sys/netinet/sctp_peeloff.c	Sun Apr 29 15:54:40 2012	(r234789)
+++ stable/9/sys/netinet/sctp_peeloff.c	Sun Apr 29 16:10:24 2012	(r234790)
@@ -127,6 +127,7 @@ sctp_do_peeloff(struct socket *head, str
 	n_inp->sctp_ecn_enable = inp->sctp_ecn_enable;
 	n_inp->partial_delivery_point = inp->partial_delivery_point;
 	n_inp->sctp_context = inp->sctp_context;
+	n_inp->local_strreset_support = inp->local_strreset_support;
 	n_inp->inp_starting_point_for_iterator = NULL;
 	/* copy in the authentication parameters from the original endpoint */
 	if (n_inp->sctp_ep.local_hmacs)
@@ -202,6 +203,7 @@ sctp_get_peeloff(struct socket *head, sc
 	n_inp->sctp_ecn_enable = inp->sctp_ecn_enable;
 	n_inp->partial_delivery_point = inp->partial_delivery_point;
 	n_inp->sctp_context = inp->sctp_context;
+	n_inp->local_strreset_support = inp->local_strreset_support;
 	n_inp->inp_starting_point_for_iterator = NULL;
 
 	/* copy in the authentication parameters from the original endpoint */

Modified: stable/9/sys/netinet/sctp_structs.h
==============================================================================
--- stable/9/sys/netinet/sctp_structs.h	Sun Apr 29 15:54:40 2012	(r234789)
+++ stable/9/sys/netinet/sctp_structs.h	Sun Apr 29 16:10:24 2012	(r234790)
@@ -1095,6 +1095,7 @@ struct sctp_association {
 	uint16_t streamincnt;
 	uint16_t streamoutcnt;
 	uint16_t strm_realoutsize;
+	uint16_t strm_pending_add_size;
 	/* my maximum number of retrans of INIT and SEND */
 	/* copied from SCTP but should be individually setable */
 	uint16_t max_init_times;
@@ -1156,6 +1157,9 @@ struct sctp_association {
 	/* Flag to tell if ECN is allowed */
 	uint8_t ecn_allowed;
 
+	/* Did the peer make the stream config (add out) request */
+	uint8_t peer_req_out;
+
 	/* flag to indicate if peer can do asconf */
 	uint8_t peer_supports_asconf;
 	/* EY - flag to indicate if peer can do nr_sack */
@@ -1166,6 +1170,7 @@ struct sctp_association {
 	uint8_t peer_supports_auth;
 	/* stream resets are supported by the peer */
 	uint8_t peer_supports_strreset;
+	uint8_t local_strreset_support;
 
 	uint8_t peer_supports_nat;
 	/*

Modified: stable/9/sys/netinet/sctp_uio.h
==============================================================================
--- stable/9/sys/netinet/sctp_uio.h	Sun Apr 29 15:54:40 2012	(r234789)
+++ stable/9/sys/netinet/sctp_uio.h	Sun Apr 29 16:10:24 2012	(r234790)
@@ -438,23 +438,51 @@ struct sctp_sender_dry_event {
 
 
 /*
- * stream reset event
+ * Stream reset event - subscribe to SCTP_STREAM_RESET_EVENT
  */
 struct sctp_stream_reset_event {
 	uint16_t strreset_type;
 	uint16_t strreset_flags;
 	uint32_t strreset_length;
 	sctp_assoc_t strreset_assoc_id;
-	uint16_t strreset_list[];
+	uint16_t strreset_stream_list[];
 };
 
-/* flags in strreset_flags field */
-#define SCTP_STRRESET_INBOUND_STR  0x0001
-#define SCTP_STRRESET_OUTBOUND_STR 0x0002
-#define SCTP_STRRESET_ALL_STREAMS  0x0004
-#define SCTP_STRRESET_STREAM_LIST  0x0008
-#define SCTP_STRRESET_FAILED       0x0010
-#define SCTP_STRRESET_ADD_STREAM   0x0020
+/* flags in stream_reset_event (strreset_flags) */
+#define SCTP_STREAM_RESET_DENIED        0x0004	/* SCTP_STRRESET_FAILED */
+#define SCTP_STREAM_RESET_FAILED        0x0008	/* SCTP_STRRESET_FAILED */
+#define SCTP_STREAM_CHANGED_DENIED	0x0010
+
+/*
+ * Assoc reset event - subscribe to SCTP_ASSOC_RESET_EVENT
+ */
+struct sctp_assoc_reset_event {
+	uint16_t assocreset_type;
+	uint16_t assocreset_flags;
+	uint32_t assocreset_length;
+	sctp_assoc_t assocreset_assoc_id;
+	uint32_t assocreset_local_tsn;
+	uint32_t assocreset_remote_tsn;
+};
+
+#define SCTP_ASSOC_RESET_DENIED		0x0004
+#define SCTP_ASSOC_RESET_FAILED		0x0008
+
+/*
+ * Stream change event - subscribe to SCTP_STREAM_CHANGE_EVENT
+ */
+struct sctp_stream_change_event {
+	uint16_t strchange_type;
+	uint16_t strchange_flags;
+	uint32_t strchange_length;
+	sctp_assoc_t strchange_assoc_id;
+	uint16_t strchange_instrms;
+	uint16_t strchange_outstrms;
+};
+
+#define SCTP_STREAM_CHANGE_DENIED	0x0004
+#define SCTP_STREAM_CHANGE_FAILED	0x0008
+
 
 /* SCTP notification event */
 struct sctp_tlv {
@@ -477,6 +505,9 @@ union sctp_notification {
 	struct sctp_authkey_event sn_auth_event;
 	struct sctp_sender_dry_event sn_sender_dry_event;
 	struct sctp_stream_reset_event sn_strreset_event;
+	struct sctp_assoc_reset_event sn_assocreset_event;
+	struct sctp_stream_change_event sn_strchange_event;
+
 };
 
 /* notification types */
@@ -493,6 +524,9 @@ union sctp_notification {
 #define SCTP_STREAM_RESET_EVENT			0x0009
 #define SCTP_SENDER_DRY_EVENT			0x000a
 #define SCTP_NOTIFICATIONS_STOPPED_EVENT	0x000b	/* we don't send this */
+#define SCTP_ASSOC_RESET_EVENT			0x000c
+#define SCTP_STREAM_CHANGE_EVENT		0x000d
+
 /*
  * socket option structs
  */
@@ -707,19 +741,18 @@ struct sctp_blk_args {
  */
 #define SCTP_MAX_EXPLICT_STR_RESET   1000
 
-#define SCTP_RESET_LOCAL_RECV  0x0001
-#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;
-	uint16_t strrst_flags;
-	uint16_t strrst_num_streams;	/* 0 == ALL */
-	uint16_t strrst_list[];	/* list if strrst_num_streams is not 0 */
+struct sctp_reset_streams {
+	sctp_assoc_t srs_assoc_id;
+	uint16_t srs_flags;
+	uint16_t srs_number_streams;	/* 0 == ALL */
+	uint16_t srs_stream_list[];	/* list if strrst_num_streams is not 0 */
 };
 
+struct sctp_add_streams {
+	sctp_assoc_t sas_assoc_id;
+	uint16_t sas_instrms;
+	uint16_t sas_outstrms;
+};
 
 struct sctp_get_nonce_values {
 	sctp_assoc_t gn_assoc_id;

Modified: stable/9/sys/netinet/sctp_usrreq.c
==============================================================================
--- stable/9/sys/netinet/sctp_usrreq.c	Sun Apr 29 15:54:40 2012	(r234789)
+++ stable/9/sys/netinet/sctp_usrreq.c	Sun Apr 29 16:10:24 2012	(r234790)
@@ -4088,17 +4088,52 @@ sctp_setopt(struct socket *so, int optna
 			}
 			break;
 		}
+	case SCTP_ENABLE_STREAM_RESET:
+		{
+			struct sctp_assoc_value *av;
+			uint8_t set_value = 0;
 
+			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
+			if (av->assoc_value & (~SCTP_ENABLE_VALUE_MASK)) {
+				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+				error = EINVAL;
+				break;
+			}
+			set_value = av->assoc_value & SCTP_ENABLE_VALUE_MASK;
+			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
+			if (stcb) {
+				stcb->asoc.local_strreset_support = set_value;
+				SCTP_TCB_UNLOCK(stcb);
+			} else {
+				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
+				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
+				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
+				    (av->assoc_id == SCTP_ALL_ASSOC)) {
+					SCTP_INP_WLOCK(inp);
+					inp->local_strreset_support = set_value;
+					SCTP_INP_WUNLOCK(inp);
+				}
+				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
+				    (av->assoc_id == SCTP_ALL_ASSOC)) {
+					SCTP_INP_RLOCK(inp);
+					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
+						SCTP_TCB_LOCK(stcb);
+						stcb->asoc.local_strreset_support = set_value;
+						SCTP_TCB_UNLOCK(stcb);
+					}
+					SCTP_INP_RUNLOCK(inp);
+				}
+			}
+			break;
+		}
 	case SCTP_RESET_STREAMS:
 		{
-			struct sctp_stream_reset *strrst;
-			uint8_t send_in = 0, send_tsn = 0, send_out = 0,
-			        addstream = 0;
-			uint16_t addstrmcnt = 0;
-			int i;
+			struct sctp_reset_streams *strrst;
+			int i, send_out = 0;
+			int send_in = 0;
 
-			SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_stream_reset, optsize);
-			SCTP_FIND_STCB(inp, stcb, strrst->strrst_assoc_id);
+			SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_reset_streams, optsize);
+			SCTP_FIND_STCB(inp, stcb, strrst->srs_assoc_id);
 
 			if (stcb == NULL) {
 				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
@@ -4107,13 +4142,19 @@ sctp_setopt(struct socket *so, int optna
 			}
 			if (stcb->asoc.peer_supports_strreset == 0) {
 				/*
-				 * Peer does not support it, we return
-				 * protocol not supported since this is true
-				 * for this feature and this peer, not the
-				 * socket request in general.
+				 * Peer does not support the chunk type.
 				 */
-				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPROTONOSUPPORT);
-				error = EPROTONOSUPPORT;
+				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
+				error = EOPNOTSUPP;
+				SCTP_TCB_UNLOCK(stcb);
+				break;
+			}
+			if (!(stcb->asoc.local_strreset_support & SCTP_ENABLE_RESET_STREAM_REQ)) {
+				/*
+				 * User did not enable the operation.
+				 */
+				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPERM);
+				error = EPERM;
 				SCTP_TCB_UNLOCK(stcb);
 				break;
 			}
@@ -4123,129 +4164,137 @@ sctp_setopt(struct socket *so, int optna
 				SCTP_TCB_UNLOCK(stcb);
 				break;
 			}
-			if (strrst->strrst_flags == SCTP_RESET_LOCAL_RECV) {
-				send_in = 1;
-			} else if (strrst->strrst_flags == SCTP_RESET_LOCAL_SEND) {
-				send_out = 1;
-			} else if (strrst->strrst_flags == SCTP_RESET_BOTH) {
+			if (strrst->srs_flags & SCTP_STREAM_RESET_INCOMING) {
 				send_in = 1;
+			}
+			if (strrst->srs_flags & SCTP_STREAM_RESET_OUTGOING) {
 				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 */
+			}
+			if ((send_in == 0) && (send_out == 0)) {
+				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+				error = EINVAL;
+				SCTP_TCB_UNLOCK(stcb);
+				break;
+			}
+			for (i = 0; i < strrst->srs_number_streams; i++) {
+				if ((send_in) &&
+				    (strrst->srs_stream_list[i] > stcb->asoc.streamincnt)) {
+					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
 					error = EINVAL;
-					goto skip_stuff;
+					break;
 				}
-				if (stcb->asoc.stream_reset_outstanding) {
-					error = EBUSY;
-					goto skip_stuff;
+				if ((send_out) &&
+				    (strrst->srs_stream_list[i] > stcb->asoc.streamoutcnt)) {
+					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+					error = EINVAL;
+					break;
 				}
+			}
+			if (error) {
+				SCTP_TCB_UNLOCK(stcb);
+				break;
+			}
+			error = sctp_send_str_reset_req(stcb, strrst->srs_number_streams,
+			    strrst->srs_stream_list,
+			    send_out, send_in, 0, 0, 0, 0, 0);
+
+			sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
+			SCTP_TCB_UNLOCK(stcb);
+			break;
+		}
+	case SCTP_ADD_STREAMS:
+		{
+			struct sctp_add_streams *stradd;
+			uint8_t addstream = 0;
+			uint16_t add_o_strmcnt = 0;
+			uint16_t add_i_strmcnt = 0;
+
+			SCTP_CHECK_AND_CAST(stradd, optval, struct sctp_add_streams, optsize);
+			SCTP_FIND_STCB(inp, stcb, stradd->sas_assoc_id);
+			if (stcb == NULL) {
+				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
+				error = ENOENT;
+				break;
+			}
+			if ((stradd->sas_outstrms == 0) &&
+			    (stradd->sas_instrms == 0)) {
+				error = EINVAL;
+				goto skip_stuff;
+			}
+			if (stradd->sas_outstrms) {
 				addstream = 1;
 				/* We allocate here */
-				addstrmcnt = strrst->strrst_num_streams;
-				if ((int)(addstrmcnt + stcb->asoc.streamoutcnt) > 0xffff) {
+				add_o_strmcnt = stradd->sas_outstrms;
+				if ((((int)add_o_strmcnt) + ((int)stcb->asoc.streamoutcnt)) > 0x0000ffff) {
 					/* 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;
-					struct sctp_stream_queue_pending *sp,
-					                         *nsp;
-
-					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.
-					 */
-					SCTP_TCB_SEND_LOCK(stcb);
-					stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 0, 1);
-					for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
-						TAILQ_INIT(&stcb->asoc.strmout[i].outqueue);
-						stcb->asoc.strmout[i].next_sequence_sent = oldstream[i].next_sequence_sent;
-						stcb->asoc.strmout[i].last_msg_incomplete = oldstream[i].last_msg_incomplete;
-						stcb->asoc.strmout[i].stream_no = i;
-						stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], &oldstream[i]);
-						/*
-						 * now anything on those
-						 * queues?
-						 */
-						TAILQ_FOREACH_SAFE(sp, &oldstream[i].outqueue, next, nsp) {
-							TAILQ_REMOVE(&oldstream[i].outqueue, sp, next);
-							TAILQ_INSERT_TAIL(&stcb->asoc.strmout[i].outqueue, sp, next);
-						}
-						/*
-						 * Now move assoc pointers
-						 * too
-						 */
-						if (stcb->asoc.last_out_stream == &oldstream[i]) {
-							stcb->asoc.last_out_stream = &stcb->asoc.strmout[i];
-						}
-						if (stcb->asoc.locked_on_sending == &oldstream[i]) {
-							stcb->asoc.locked_on_sending = &stcb->asoc.strmout[i];
-						}
-					}
-					/* now the new streams */
-					stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
-					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.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], NULL);
-					}
-					stcb->asoc.strm_realoutsize = stcb->asoc.streamoutcnt + addstrmcnt;
-					SCTP_FREE(oldstream, SCTP_M_STRMO);
-				}
-				SCTP_TCB_SEND_UNLOCK(stcb);
-				goto skip_stuff;
-			} else {
-				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
-				error = EINVAL;
-				SCTP_TCB_UNLOCK(stcb);
-				break;
 			}
-			for (i = 0; i < strrst->strrst_num_streams; i++) {
-				if ((send_in) &&
+			if (stradd->sas_instrms) {
+				int cnt;
 
-				    (strrst->strrst_list[i] > stcb->asoc.streamincnt)) {
-					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+				addstream |= 2;
+				/*
+				 * We allocate inside
+				 * sctp_send_str_reset_req()
+				 */
+				add_i_strmcnt = stradd->sas_instrms;
+				cnt = add_i_strmcnt;
+				cnt += stcb->asoc.streamincnt;
+				if (cnt > 0x0000ffff) {
+					/* You can't have more than 64k */
 					error = EINVAL;
-					goto get_out;
+					goto skip_stuff;
 				}
-				if ((send_out) &&
-				    (strrst->strrst_list[i] > stcb->asoc.streamoutcnt)) {
-					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+				if (cnt > (int)stcb->asoc.max_inbound_streams) {
+					/* More than you are allowed */
 					error = EINVAL;
-					goto get_out;
+					goto skip_stuff;
 				}
 			}
+			error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 0, addstream, add_o_strmcnt, add_i_strmcnt, 0);
+			sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
 	skip_stuff:
-			if (error) {
-		get_out:
+			SCTP_TCB_UNLOCK(stcb);
+			break;
+		}
+	case SCTP_RESET_ASSOC:
+		{
+			uint32_t *value;
+
+			SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize);
+			SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value);
+			if (stcb == NULL) {
+				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
+				error = ENOENT;
+				break;
+			}
+			if (stcb->asoc.peer_supports_strreset == 0) {
+				/*
+				 * Peer does not support the chunk type.
+				 */
+				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
+				error = EOPNOTSUPP;
 				SCTP_TCB_UNLOCK(stcb);
 				break;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



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