diff options
Diffstat (limited to 'sys/netinet/sctp_usrreq.c')
-rw-r--r-- | sys/netinet/sctp_usrreq.c | 61 |
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); |