diff options
author | rrs <rrs@FreeBSD.org> | 2006-11-11 22:44:12 +0000 |
---|---|---|
committer | rrs <rrs@FreeBSD.org> | 2006-11-11 22:44:12 +0000 |
commit | fb5651e047ba819adc96c9f9e76b4559123edf34 (patch) | |
tree | 7a67d3389c46e84245fca92a06dcb77f66dbafcb | |
parent | 26d0f2fab6f6582478cd2a21695844600a1bd490 (diff) | |
download | FreeBSD-src-fb5651e047ba819adc96c9f9e76b4559123edf34.zip FreeBSD-src-fb5651e047ba819adc96c9f9e76b4559123edf34.tar.gz |
In a true restart case, the send_lock was
not being aquired. This meant that when we cleanup
the outbound we may have one in transit to be
added with the old sequence number. This is bad
since then we loose a message :(
Also the report_outbound needed to have the right
lock when its called which it did not.. I added
the lock with of course a flag since we want to
have the lock before we call it in the restart
case.
This also fixed the FIX ME case where, in the cookie
collision case, we mark for retransmit any that
were bundled with the cookie that was dropped.
This also means changes to the output routine
so we can assure getting the COOKIE-ACK sent
BEFORE we retransmit the Data.
Approved by: gnn
-rw-r--r-- | sys/netinet/sctp_constants.h | 1 | ||||
-rw-r--r-- | sys/netinet/sctp_input.c | 50 | ||||
-rw-r--r-- | sys/netinet/sctp_output.c | 13 | ||||
-rw-r--r-- | sys/netinet/sctputil.c | 16 | ||||
-rw-r--r-- | sys/netinet/sctputil.h | 2 |
5 files changed, 62 insertions, 20 deletions
diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h index 3e927bb..d11d380 100644 --- a/sys/netinet/sctp_constants.h +++ b/sys/netinet/sctp_constants.h @@ -307,6 +307,7 @@ __FBSDID("$FreeBSD$"); #define SCTP_OUTPUT_FROM_EARLY_FR_TMR 11 #define SCTP_OUTPUT_FROM_STRRST_REQ 12 #define SCTP_OUTPUT_FROM_USR_RCVD 13 +#define SCTP_OUTPUT_FROM_COOKIE_ACK 14 /* SCTP chunk types are moved sctp.h for application (NAT, FW) use */ /* align to 32-bit sizes */ diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c index 86ed9f8..69d441c 100644 --- a/sys/netinet/sctp_input.c +++ b/sys/netinet/sctp_input.c @@ -701,7 +701,7 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp, if (!TAILQ_EMPTY(&asoc->send_queue) || !TAILQ_EMPTY(&asoc->sent_queue) || !TAILQ_EMPTY(&asoc->out_wheel)) { - sctp_report_all_outbound(stcb); + sctp_report_all_outbound(stcb, 0); } /* stop the timer */ sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, net); @@ -1092,6 +1092,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, int chk_length; int init_offset, initack_offset; int retval; + int spec_flag = 0; /* I know that the TCB is non-NULL from the caller */ asoc = &stcb->asoc; @@ -1271,18 +1272,31 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, NULL); } - /* - * FIX? Should we go out, in this case (if the seq numbers - * changed on the peer) and set any data to RETRANSMIT? - */ asoc->my_rwnd = ntohl(initack_cp->init.a_rwnd); - asoc->pre_open_streams = - ntohs(initack_cp->init.num_outbound_streams); + asoc->pre_open_streams = ntohs(initack_cp->init.num_outbound_streams); + + /* Note last_cwr_tsn? where is this used? */ asoc->last_cwr_tsn = asoc->init_seq_number - 1; - asoc->asconf_seq_in = asoc->last_acked_seq = asoc->init_seq_number - 1; - asoc->str_reset_seq_in = asoc->init_seq_number; - asoc->advanced_peer_ack_point = asoc->last_acked_seq; + if (ntohl(init_cp->init.initiate_tag) != asoc->peer_vtag) { + /* + * Ok the peer probably discarded our data (if we + * echoed a cookie+data). So anything on the + * sent_queue should be marked for retransmit, we + * may not get something to kick us so it COULD + * still take a timeout to move these.. but it can't + * hurt to mark them. + */ + struct sctp_tmit_chunk *chk; + + TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { + if (chk->sent < SCTP_DATAGRAM_RESEND) { + chk->sent = SCTP_DATAGRAM_RESEND; + stcb->asoc.sent_queue_retran_cnt++; + spec_flag++; + } + } + } /* process the INIT info (peer's info) */ retval = sctp_process_init(init_cp, stcb, net); if (retval < 0) { @@ -1316,6 +1330,16 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, } sctp_stop_all_cookie_timers(stcb); sctp_send_cookie_ack(stcb); + if (spec_flag) { + /* + * only if we have retrans set do we do this. What + * this call does is get only the COOKIE-ACK out and + * then when we return the normal call to + * sctp_chunk_output will get the retrans out behind + * this. + */ + sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_COOKIE_ACK); + } return (stcb); } if ((ntohl(initack_cp->init.initiate_tag) != asoc->my_vtag && @@ -1336,7 +1360,8 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, /* send up all the data */ - sctp_report_all_outbound(stcb); + SCTP_TCB_SEND_LOCK(stcb); + sctp_report_all_outbound(stcb, 1); /* process the INIT-ACK info (my info) */ asoc->my_vtag = ntohl(initack_cp->init.initiate_tag); @@ -1376,6 +1401,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, memset(asoc->mapping_array, 0, asoc->mapping_array_size); /* process the INIT info (peer's info) */ + SCTP_TCB_SEND_UNLOCK(stcb); retval = sctp_process_init(init_cp, stcb, net); if (retval < 0) { return (NULL); @@ -2356,7 +2382,7 @@ sctp_handle_shutdown_complete(struct sctp_shutdown_complete_chunk *cp, if (!TAILQ_EMPTY(&asoc->send_queue) || !TAILQ_EMPTY(&asoc->sent_queue) || !TAILQ_EMPTY(&asoc->out_wheel)) { - sctp_report_all_outbound(stcb); + sctp_report_all_outbound(stcb, 0); } } /* stop the timer */ diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 78b9a3e..e71e5ac 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -7164,7 +7164,6 @@ sctp_chunk_output(struct sctp_inpcb *inp, un_sent = (stcb->asoc.total_output_queue_size - stcb->asoc.total_flight); - if ((un_sent <= 0) && (TAILQ_EMPTY(&asoc->control_send_queue)) && (asoc->sent_queue_retran_cnt == 0)) { @@ -7184,7 +7183,17 @@ sctp_chunk_output(struct sctp_inpcb *inp, * Ok, it is retransmission time only, we send out only ONE * packet with a single call off to the retran code. */ - if (from_where != SCTP_OUTPUT_FROM_HB_TMR) { + if (from_where == SCTP_OUTPUT_FROM_COOKIE_ACK) { + /* + * Special hook for handling cookiess discarded by + * peer that carried data. Send cookie-ack only and + * then the next call with get the retran's. + */ + (void)sctp_med_chunk_output(inp, stcb, asoc, &num_out, &reason_code, 1, + &cwnd_full, from_where, + &now, &now_filled, frag_point); + return (0); + } else if (from_where != SCTP_OUTPUT_FROM_HB_TMR) { /* if its not from a HB then do it */ ret = sctp_chunk_retransmission(inp, stcb, asoc, &num_out, &now, &now_filled); } else { diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index f98a81e..0f8fa0b 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -3242,12 +3242,13 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb, } void -sctp_report_all_outbound(struct sctp_tcb *stcb) +sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock) { struct sctp_association *asoc; struct sctp_stream_out *outs; struct sctp_tmit_chunk *chk; struct sctp_stream_queue_pending *sp; + int i; asoc = &stcb->asoc; @@ -3257,9 +3258,12 @@ sctp_report_all_outbound(struct sctp_tcb *stcb) return; } /* now through all the gunk freeing chunks */ - - TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) { - /* now clean up any chunks here */ + if (holds_lock == 0) + SCTP_TCB_SEND_LOCK(stcb); + for (i = 0; i < stcb->asoc.streamoutcnt; i++) { + /* For each stream */ + outs = &stcb->asoc.strmout[i]; + /* clean up any sends there */ stcb->asoc.locked_on_sending = NULL; sp = TAILQ_FIRST(&outs->outqueue); while (sp) { @@ -3338,6 +3342,8 @@ sctp_report_all_outbound(struct sctp_tcb *stcb) chk = TAILQ_FIRST(&asoc->sent_queue); } } + if (holds_lock == 0) + SCTP_TCB_SEND_UNLOCK(stcb); } void @@ -3350,7 +3356,7 @@ sctp_abort_notification(struct sctp_tcb *stcb, int error) return; } /* Tell them we lost the asoc */ - sctp_report_all_outbound(stcb); + sctp_report_all_outbound(stcb, 1); if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED))) { diff --git a/sys/netinet/sctputil.h b/sys/netinet/sctputil.h index ef0e9a4..06f6218 100644 --- a/sys/netinet/sctputil.h +++ b/sys/netinet/sctputil.h @@ -131,7 +131,7 @@ sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp, void sctp_stop_timers_for_shutdown(struct sctp_tcb *); -void sctp_report_all_outbound(struct sctp_tcb *); +void sctp_report_all_outbound(struct sctp_tcb *, int); int sctp_expand_mapping_array(struct sctp_association *); |