aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet/sctp_input.c
diff options
context:
space:
mode:
authorRandall Stewart <rrs@FreeBSD.org>2009-02-27 20:54:45 +0000
committerRandall Stewart <rrs@FreeBSD.org>2009-02-27 20:54:45 +0000
commit8aae94933f9ba7055a74355a3f48e3e920e59d17 (patch)
tree915dcbdc5a8a9a013baf1f350b5bf6e37cabb3df /sys/netinet/sctp_input.c
parentc72ae1423b6f824552d0a855eba3d5b08e46a062 (diff)
downloadsrc-8aae94933f9ba7055a74355a3f48e3e920e59d17.tar.gz
src-8aae94933f9ba7055a74355a3f48e3e920e59d17.zip
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
Notes
Notes: svn path=/head/; revision=189121
Diffstat (limited to 'sys/netinet/sctp_input.c')
-rw-r--r--sys/netinet/sctp_input.c107
1 files changed, 69 insertions, 38 deletions
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index a9f3dfcf98e0..494929bc0feb 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -3442,6 +3442,8 @@ sctp_handle_stream_reset_response(struct sctp_tcb *stcb,
}
} else if (type == SCTP_STR_RESET_ADD_STREAMS) {
/* Ok we now may have more streams */
+ 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;
@@ -3730,50 +3732,79 @@ sctp_handle_str_reset_add_strm(struct sctp_tcb *stcb, struct sctp_tmit_chunk *ch
*/
uint16_t num_stream, i;
uint32_t seq;
+ struct sctp_association *asoc = &stcb->asoc;
+ struct sctp_queued_to_read *ctl;
/* Get the number. */
seq = ntohl(str_add->request_seq);
num_stream = ntohs(str_add->number_of_streams);
/* Now what would be the new total? */
- num_stream += stcb->asoc.streamincnt;
- if (num_stream > stcb->asoc.max_inbound_streams) {
- /* 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;
- } else {
- /* Ok, we can do that :-) */
- struct sctp_stream_in *oldstrm;
-
- /* save off the old */
- oldstrm = stcb->asoc.strmin;
- SCTP_MALLOC(stcb->asoc.strmin, struct sctp_stream_in *,
- (num_stream * sizeof(struct sctp_stream_in)),
- SCTP_M_STRMI);
- if (stcb->asoc.strmin == NULL) {
- stcb->asoc.strmin = oldstrm;
- goto denied;
- }
- /* copy off the old data */
- memcpy(stcb->asoc.strmin, oldstrm,
- (stcb->asoc.streamincnt * sizeof(struct sctp_stream_in)));
- /* Init the new streams */
- for (i = stcb->asoc.streamincnt; i < num_stream; i++) {
- TAILQ_INIT(&stcb->asoc.strmin[i].inqueue);
- stcb->asoc.strmin[i].stream_no = i;
- stcb->asoc.strmin[i].last_sequence_delivered = 0xffff;
- stcb->asoc.strmin[i].delivery_started = 0;
+ if (asoc->str_reset_seq_in == seq) {
+ num_stream += stcb->asoc.streamincnt;
+ if (num_stream > stcb->asoc.max_inbound_streams) {
+ /* 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;
+ } else {
+ /* Ok, we can do that :-) */
+ struct sctp_stream_in *oldstrm;
+
+ /* save off the old */
+ oldstrm = stcb->asoc.strmin;
+ SCTP_MALLOC(stcb->asoc.strmin, struct sctp_stream_in *,
+ (num_stream * sizeof(struct sctp_stream_in)),
+ SCTP_M_STRMI);
+ if (stcb->asoc.strmin == NULL) {
+ stcb->asoc.strmin = oldstrm;
+ goto denied;
+ }
+ /* copy off the old data */
+ for (i = 0; i < stcb->asoc.streamincnt; i++) {
+ TAILQ_INIT(&stcb->asoc.strmin[i].inqueue);
+ stcb->asoc.strmin[i].stream_no = i;
+ stcb->asoc.strmin[i].last_sequence_delivered = oldstrm[i].last_sequence_delivered;
+ stcb->asoc.strmin[i].delivery_started = oldstrm[i].delivery_started;
+ /* now anything on those queues? */
+ while (TAILQ_EMPTY(&oldstrm[i].inqueue) == 0) {
+ ctl = TAILQ_FIRST(&oldstrm[i].inqueue);
+ TAILQ_REMOVE(&oldstrm[i].inqueue, ctl, next);
+ TAILQ_INSERT_TAIL(&stcb->asoc.strmin[i].inqueue, ctl, next);
+ }
+ }
+ /* Init the new streams */
+ for (i = stcb->asoc.streamincnt; i < num_stream; i++) {
+ TAILQ_INIT(&stcb->asoc.strmin[i].inqueue);
+ stcb->asoc.strmin[i].stream_no = i;
+ stcb->asoc.strmin[i].last_sequence_delivered = 0xffff;
+ stcb->asoc.strmin[i].delivery_started = 0;
+ }
+ 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_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);
+ } 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);
+
}
}