summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctp_usrreq.c
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2009-02-27 20:54:45 +0000
committerrrs <rrs@FreeBSD.org>2009-02-27 20:54:45 +0000
commit57c49bea03a4e37f49ea548a874cfa7d4cdfa73a (patch)
tree915dcbdc5a8a9a013baf1f350b5bf6e37cabb3df /sys/netinet/sctp_usrreq.c
parent90499e3f8eb3ad46cecd13f6219e89c28e330a34 (diff)
downloadFreeBSD-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.c53
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);
OpenPOWER on IntegriCloud