From 57c49bea03a4e37f49ea548a874cfa7d4cdfa73a Mon Sep 17 00:00:00 2001 From: rrs Date: Fri, 27 Feb 2009 20:54:45 +0000 Subject: 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 --- sys/netinet/sctp_input.c | 107 ++++++++++++++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 38 deletions(-) (limited to 'sys/netinet/sctp_input.c') diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c index a9f3dfc..494929b 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); + } } -- cgit v1.1