summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctp_usrreq.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/sctp_usrreq.c')
-rw-r--r--sys/netinet/sctp_usrreq.c61
1 files changed, 59 insertions, 2 deletions
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index 81a64a4..c64026b 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -3263,7 +3263,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
case SCTP_RESET_STREAMS:
{
struct sctp_stream_reset *strrst;
- uint8_t send_in = 0, send_tsn = 0, send_out = 0;
+ uint8_t send_in = 0, send_tsn = 0, send_out = 0,
+ addstream = 0;
+ uint16_t addstrmcnt = 0;
int i;
SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_stream_reset, optsize);
@@ -3301,6 +3303,60 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
send_out = 1;
} else if (strrst->strrst_flags == SCTP_RESET_TSN) {
send_tsn = 1;
+ } else if (strrst->strrst_flags == SCTP_RESET_ADD_STREAMS) {
+ if (send_tsn ||
+ send_in ||
+ send_out) {
+ /* We can't do that and add streams */
+ error = EINVAL;
+ goto skip_stuff;
+ }
+ if (stcb->asoc.stream_reset_outstanding) {
+ error = EBUSY;
+ goto skip_stuff;
+ }
+ addstream = 1;
+ /* We allocate here */
+ addstrmcnt = strrst->strrst_num_streams;
+ if ((int)(addstrmcnt + stcb->asoc.streamoutcnt) > 0xffff) {
+ /* You can't have more than 64k */
+ error = EINVAL;
+ goto skip_stuff;
+ }
+ if ((stcb->asoc.strm_realoutsize - stcb->asoc.streamoutcnt) < addstrmcnt) {
+ /* Need to allocate more */
+ struct sctp_stream_out *oldstream;
+
+ oldstream = stcb->asoc.strmout;
+ /* get some more */
+ SCTP_MALLOC(stcb->asoc.strmout, struct sctp_stream_out *,
+ ((stcb->asoc.streamoutcnt + addstrmcnt) * sizeof(struct sctp_stream_out)),
+ SCTP_M_STRMO);
+ if (stcb->asoc.strmout == NULL) {
+ stcb->asoc.strmout = oldstream;
+ error = ENOMEM;
+ goto skip_stuff;
+ }
+ /*
+ * Ok now we proceed with copying
+ * the old out stuff and
+ * initializing the new stuff.
+ */
+ memcpy(stcb->asoc.strmout, oldstream,
+ (stcb->asoc.streamoutcnt * sizeof(struct sctp_stream_out)));
+ /* now the new streams */
+ for (i = stcb->asoc.streamoutcnt; i < (stcb->asoc.streamoutcnt + addstrmcnt); i++) {
+ stcb->asoc.strmout[i].next_sequence_sent = 0x0;
+ TAILQ_INIT(&stcb->asoc.strmout[i].outqueue);
+ stcb->asoc.strmout[i].stream_no = i;
+ stcb->asoc.strmout[i].last_msg_incomplete = 0;
+ stcb->asoc.strmout[i].next_spoke.tqe_next = 0;
+ stcb->asoc.strmout[i].next_spoke.tqe_prev = 0;
+ }
+ stcb->asoc.strm_realoutsize = stcb->asoc.streamoutcnt + addstrmcnt;
+ SCTP_FREE(oldstream, SCTP_M_STRMO);
+ }
+ goto skip_stuff;
} else {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
@@ -3322,6 +3378,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
goto get_out;
}
}
+ skip_stuff:
if (error) {
get_out:
SCTP_TCB_UNLOCK(stcb);
@@ -3330,7 +3387,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
error = sctp_send_str_reset_req(stcb, strrst->strrst_num_streams,
strrst->strrst_list,
send_out, (stcb->asoc.str_reset_seq_in - 3),
- send_in, send_tsn);
+ send_in, send_tsn, addstream, addstrmcnt);
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
SCTP_TCB_UNLOCK(stcb);
OpenPOWER on IntegriCloud