diff options
author | rrs <rrs@FreeBSD.org> | 2009-02-27 20:54:45 +0000 |
---|---|---|
committer | rrs <rrs@FreeBSD.org> | 2009-02-27 20:54:45 +0000 |
commit | 57c49bea03a4e37f49ea548a874cfa7d4cdfa73a (patch) | |
tree | 915dcbdc5a8a9a013baf1f350b5bf6e37cabb3df /sys/netinet/sctp_usrreq.c | |
parent | 90499e3f8eb3ad46cecd13f6219e89c28e330a34 (diff) | |
download | FreeBSD-src-57c49bea03a4e37f49ea548a874cfa7d4cdfa73a.zip FreeBSD-src-57c49bea03a4e37f49ea548a874cfa7d4cdfa73a.tar.gz |
Fix the add stream feature of strm-reset to really work:
- Fix the copy, we can't do a blind copy but must transfer
the data from the old to the new.
- Fix the ACK processing so we properly stop retransmitting
the thing.
- Fix it so if we get a retran we will properly reply with
the saved response without doing anything.
MFC after: 1 month
Diffstat (limited to 'sys/netinet/sctp_usrreq.c')
-rw-r--r-- | sys/netinet/sctp_usrreq.c | 53 |
1 files changed, 49 insertions, 4 deletions
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index c64026b..b3bfea5 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -3326,6 +3326,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, if ((stcb->asoc.strm_realoutsize - stcb->asoc.streamoutcnt) < addstrmcnt) { /* Need to allocate more */ struct sctp_stream_out *oldstream; + struct sctp_stream_queue_pending *sp; + int removed; oldstream = stcb->asoc.strmout; /* get some more */ @@ -3342,20 +3344,63 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, * the old out stuff and * initializing the new stuff. */ - memcpy(stcb->asoc.strmout, oldstream, - (stcb->asoc.streamoutcnt * sizeof(struct sctp_stream_out))); + SCTP_TCB_SEND_LOCK(stcb); + 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; + if (oldstream[i].next_spoke.tqe_next) { + sctp_remove_from_wheel(stcb, &stcb->asoc, &oldstream[i], 1); + stcb->asoc.strmout[i].next_spoke.tqe_next = NULL; + stcb->asoc.strmout[i].next_spoke.tqe_prev = NULL; + removed = 1; + } else { + /* not on out wheel */ + stcb->asoc.strmout[i].next_spoke.tqe_next = NULL; + stcb->asoc.strmout[i].next_spoke.tqe_prev = NULL; + removed = 0; + } + /* + * now anything on those + * queues? + */ + while (TAILQ_EMPTY(&oldstream[i].outqueue) == 0) { + sp = TAILQ_FIRST(&oldstream[i].outqueue); + TAILQ_REMOVE(&oldstream[i].outqueue, sp, next); + TAILQ_INSERT_TAIL(&stcb->asoc.strmout[i].outqueue, sp, next); + } + /* Did we disrupt the wheel? */ + if (removed) { + sctp_insert_on_wheel(stcb, + &stcb->asoc, + &stcb->asoc.strmout[i], + 1); + } + /* + * 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 */ 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.strmout[i].next_spoke.tqe_next = NULL; + stcb->asoc.strmout[i].next_spoke.tqe_prev = 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); |