From owner-svn-src-head@FreeBSD.ORG Fri Feb 27 20:54:46 2009 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 746F71065670; Fri, 27 Feb 2009 20:54:46 +0000 (UTC) (envelope-from rrs@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 616ED8FC1B; Fri, 27 Feb 2009 20:54:46 +0000 (UTC) (envelope-from rrs@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n1RKskYi082788; Fri, 27 Feb 2009 20:54:46 GMT (envelope-from rrs@svn.freebsd.org) Received: (from rrs@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n1RKskaU082783; Fri, 27 Feb 2009 20:54:46 GMT (envelope-from rrs@svn.freebsd.org) Message-Id: <200902272054.n1RKskaU082783@svn.freebsd.org> From: Randall Stewart Date: Fri, 27 Feb 2009 20:54:46 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r189121 - head/sys/netinet X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 27 Feb 2009 20:54:46 -0000 Author: rrs Date: Fri Feb 27 20:54:45 2009 New Revision: 189121 URL: http://svn.freebsd.org/changeset/base/189121 Log: 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 Modified: head/sys/netinet/sctp_crc32.c head/sys/netinet/sctp_input.c head/sys/netinet/sctp_output.c head/sys/netinet/sctp_output.h head/sys/netinet/sctp_usrreq.c Modified: head/sys/netinet/sctp_crc32.c ============================================================================== --- head/sys/netinet/sctp_crc32.c Fri Feb 27 20:00:15 2009 (r189120) +++ head/sys/netinet/sctp_crc32.c Fri Feb 27 20:54:45 2009 (r189121) @@ -40,7 +40,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include Modified: head/sys/netinet/sctp_input.c ============================================================================== --- head/sys/netinet/sctp_input.c Fri Feb 27 20:00:15 2009 (r189120) +++ head/sys/netinet/sctp_input.c Fri Feb 27 20:54:45 2009 (r189121) @@ -3442,6 +3442,8 @@ sctp_handle_stream_reset_response(struct } } 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 sc */ 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; + 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); + } + } 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 { - /* Ok, we can do that :-) */ - struct sctp_stream_in *oldstrm; + sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_BAD_SEQNO); - /* 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; - } - 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); } } Modified: head/sys/netinet/sctp_output.c ============================================================================== --- head/sys/netinet/sctp_output.c Fri Feb 27 20:00:15 2009 (r189120) +++ head/sys/netinet/sctp_output.c Fri Feb 27 20:54:45 2009 (r189121) @@ -7445,22 +7445,26 @@ outof_here: } } -static void +void sctp_remove_from_wheel(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_stream_out *strq) + struct sctp_stream_out *strq, + int holds_lock) { /* take off and then setup so we know it is not on the wheel */ - SCTP_TCB_SEND_LOCK(stcb); + if (holds_lock == 0) + SCTP_TCB_SEND_LOCK(stcb); if (TAILQ_FIRST(&strq->outqueue)) { /* more was added */ - SCTP_TCB_SEND_UNLOCK(stcb); + if (holds_lock == 0) + SCTP_TCB_SEND_UNLOCK(stcb); return; } TAILQ_REMOVE(&asoc->out_wheel, strq, next_spoke); strq->next_spoke.tqe_next = NULL; strq->next_spoke.tqe_prev = NULL; - SCTP_TCB_SEND_UNLOCK(stcb); + if (holds_lock == 0) + SCTP_TCB_SEND_UNLOCK(stcb); } static void @@ -9083,7 +9087,7 @@ sctp_fill_outqueue(struct sctp_tcb *stcb } } } - sctp_remove_from_wheel(stcb, asoc, strq); + sctp_remove_from_wheel(stcb, asoc, strq, 0); } if ((giveup) || bail) { break; Modified: head/sys/netinet/sctp_output.h ============================================================================== --- head/sys/netinet/sctp_output.h Fri Feb 27 20:00:15 2009 (r189120) +++ head/sys/netinet/sctp_output.h Fri Feb 27 20:54:45 2009 (r189121) @@ -101,6 +101,11 @@ void sctp_send_heartbeat_ack(struct sctp_tcb *, struct mbuf *, int, int, struct sctp_nets *); +void +sctp_remove_from_wheel(struct sctp_tcb *stcb, + struct sctp_association *asoc, + struct sctp_stream_out *strq, int holds_lock); + void sctp_send_shutdown(struct sctp_tcb *, struct sctp_nets *); Modified: head/sys/netinet/sctp_usrreq.c ============================================================================== --- head/sys/netinet/sctp_usrreq.c Fri Feb 27 20:00:15 2009 (r189120) +++ head/sys/netinet/sctp_usrreq.c Fri Feb 27 20:54:45 2009 (r189121) @@ -3326,6 +3326,8 @@ sctp_setopt(struct socket *so, int optna 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 optna * 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);