Author: rrs
Date: Thu Mar 29 13:36:53 2012
New Revision: 233660
URL: http://svn.freebsd.org/changeset/base/233660

Log:
  Make stream our stream reset implementation
  compliant to RFC6525.
  
  MFC after:    1 month

Modified:
  head/sys/netinet/sctp.h
  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.h
  head/sys/netinet/sctp_peeloff.c
  head/sys/netinet/sctp_structs.h
  head/sys/netinet/sctp_uio.h
  head/sys/netinet/sctp_usrreq.c
  head/sys/netinet/sctputil.c
  head/sys/netinet/sctputil.h

Modified: head/sys/netinet/sctp.h
==============================================================================
--- head/sys/netinet/sctp.h     Thu Mar 29 13:01:29 2012        (r233659)
+++ head/sys/netinet/sctp.h     Thu Mar 29 13:36:53 2012        (r233660)
@@ -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: head/sys/netinet/sctp_constants.h
==============================================================================
--- head/sys/netinet/sctp_constants.h   Thu Mar 29 13:01:29 2012        
(r233659)
+++ head/sys/netinet/sctp_constants.h   Thu Mar 29 13:36:53 2012        
(r233660)
@@ -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: head/sys/netinet/sctp_header.h
==============================================================================
--- head/sys/netinet/sctp_header.h      Thu Mar 29 13:01:29 2012        
(r233659)
+++ head/sys/netinet/sctp_header.h      Thu Mar 29 13:36:53 2012        
(r233660)
@@ -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: head/sys/netinet/sctp_input.c
==============================================================================
--- head/sys/netinet/sctp_input.c       Thu Mar 29 13:01:29 2012        
(r233659)
+++ head/sys/netinet/sctp_input.c       Thu Mar 29 13:36:53 2012        
(r233660)
@@ -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: head/sys/netinet/sctp_output.c
==============================================================================
--- head/sys/netinet/sctp_output.c      Thu Mar 29 13:01:29 2012        
(r233659)
+++ head/sys/netinet/sctp_output.c      Thu Mar 29 13:36:53 2012        
(r233660)
@@ -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: head/sys/netinet/sctp_output.h
==============================================================================
--- head/sys/netinet/sctp_output.h      Thu Mar 29 13:01:29 2012        
(r233659)
+++ head/sys/netinet/sctp_output.h      Thu Mar 29 13:36:53 2012        
(r233660)
@@ -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: head/sys/netinet/sctp_pcb.h
==============================================================================
--- head/sys/netinet/sctp_pcb.h Thu Mar 29 13:01:29 2012        (r233659)
+++ head/sys/netinet/sctp_pcb.h Thu Mar 29 13:36:53 2012        (r233660)
@@ -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: head/sys/netinet/sctp_peeloff.c
==============================================================================
--- head/sys/netinet/sctp_peeloff.c     Thu Mar 29 13:01:29 2012        
(r233659)
+++ head/sys/netinet/sctp_peeloff.c     Thu Mar 29 13:36:53 2012        
(r233660)
@@ -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: head/sys/netinet/sctp_structs.h
==============================================================================
--- head/sys/netinet/sctp_structs.h     Thu Mar 29 13:01:29 2012        
(r233659)
+++ head/sys/netinet/sctp_structs.h     Thu Mar 29 13:36:53 2012        
(r233660)
@@ -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: head/sys/netinet/sctp_uio.h
==============================================================================
--- head/sys/netinet/sctp_uio.h Thu Mar 29 13:01:29 2012        (r233659)
+++ head/sys/netinet/sctp_uio.h Thu Mar 29 13:36:53 2012        (r233660)
@@ -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: head/sys/netinet/sctp_usrreq.c
==============================================================================
--- head/sys/netinet/sctp_usrreq.c      Thu Mar 29 13:01:29 2012        
(r233659)
+++ head/sys/netinet/sctp_usrreq.c      Thu Mar 29 13:36:53 2012        
(r233660)
@@ -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 ***
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to