diff options
Diffstat (limited to 'sys/netinet/sctp_indata.c')
-rw-r--r-- | sys/netinet/sctp_indata.c | 309 |
1 files changed, 198 insertions, 111 deletions
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c index 5786782..462013e 100644 --- a/sys/netinet/sctp_indata.c +++ b/sys/netinet/sctp_indata.c @@ -3201,7 +3201,9 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, if (stcb->asoc.peer_supports_prsctp) { if ((PR_SCTP_TTL_ENABLED(tp1->flags)) && tp1->sent < SCTP_DATAGRAM_ACKED) { /* Is it expired? */ - if (timevalcmp(&now, &tp1->rec.data.timetodrop, >)) { + if ( + (timevalcmp(&now, &tp1->rec.data.timetodrop, >)) + ) { /* Yes so drop it */ if (tp1->data != NULL) { sctp_release_pr_sctp_chunk(stcb, tp1, @@ -3285,7 +3287,9 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, tp1->sent, SCTP_FR_LOG_STRIKE_CHUNK); #endif - tp1->sent++; + if (tp1->sent < SCTP_DATAGRAM_RESEND) { + tp1->sent++; + } if (sctp_cmt_on_off && sctp_cmt_use_dac) { /* * CMT DAC algorithm: If SACK flag is set to @@ -3296,7 +3300,11 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, * not between two sacked TSNs, then mark by * one more. */ - if ((tp1->sent != SCTP_DATAGRAM_RESEND) && (num_dests_sacked == 1) && + /* + * Jana FIX, does this mean you strike it + * twice (see code above?) + */ + if ((tp1->sent < SCTP_DATAGRAM_RESEND) && (num_dests_sacked == 1) && compare_with_wrap(this_sack_lowest_newack, tp1->rec.data.TSN_seq, MAX_TSN)) { #ifdef SCTP_FR_LOGGING sctp_log_fr(16 + num_dests_sacked, @@ -3314,6 +3322,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, * biggest_newly_acked must be higher than the * sending_seq at the time we did the FR. */ + if ( #ifdef SCTP_FR_TO_ALTERNATE /* * If FR's go to new networks, then we must only do @@ -3321,11 +3330,12 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, * go to the same network (Armando's work) then its * ok to FR multiple times. */ - if (asoc->numnets < 2) + (asoc->numnets < 2) #else - if (1) + (1) #endif - { + ) { + if ((compare_with_wrap(biggest_tsn_newly_acked, tp1->rec.data.fast_retran_tsn, MAX_TSN)) || (biggest_tsn_newly_acked == @@ -3341,7 +3351,9 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, tp1->sent, SCTP_FR_LOG_STRIKE_CHUNK); #endif - tp1->sent++; + if (tp1->sent < SCTP_DATAGRAM_RESEND) { + tp1->sent++; + } strike_flag = 1; if (sctp_cmt_on_off && sctp_cmt_use_dac) { /* @@ -3357,15 +3369,20 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, * sacked TSNs, then mark by * one more. */ - if ((tp1->sent != SCTP_DATAGRAM_RESEND) && (num_dests_sacked == 1) && - compare_with_wrap(this_sack_lowest_newack, tp1->rec.data.TSN_seq, MAX_TSN)) { + if ((tp1->sent < SCTP_DATAGRAM_RESEND) && + (num_dests_sacked == 1) && + compare_with_wrap(this_sack_lowest_newack, + tp1->rec.data.TSN_seq, MAX_TSN)) { #ifdef SCTP_FR_LOGGING sctp_log_fr(32 + num_dests_sacked, tp1->rec.data.TSN_seq, tp1->sent, SCTP_FR_LOG_STRIKE_CHUNK); #endif - tp1->sent++; + if (tp1->sent < SCTP_DATAGRAM_RESEND) { + tp1->sent++; + + } } } } @@ -3390,7 +3407,9 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, tp1->sent, SCTP_FR_LOG_STRIKE_CHUNK); #endif - tp1->sent++; + if (tp1->sent < SCTP_DATAGRAM_RESEND) { + tp1->sent++; + } if (sctp_cmt_on_off && sctp_cmt_use_dac) { /* * CMT DAC algorithm: If SACK flag is set to @@ -3401,7 +3420,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, * not between two sacked TSNs, then mark by * one more. */ - if ((tp1->sent != SCTP_DATAGRAM_RESEND) && (num_dests_sacked == 1) && + if ((tp1->sent < SCTP_DATAGRAM_RESEND) && (num_dests_sacked == 1) && compare_with_wrap(this_sack_lowest_newack, tp1->rec.data.TSN_seq, MAX_TSN)) { #ifdef SCTP_FR_LOGGING sctp_log_fr(48 + num_dests_sacked, @@ -3426,8 +3445,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, /* This is a subsequent FR */ SCTP_STAT_INCR(sctps_sendmultfastretrans); } - sctp_ucount_incr(asoc->sent_queue_retran_cnt); - + sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); if (sctp_cmt_on_off) { /* * CMT: Using RTX_SSTHRESH policy for CMT. @@ -4061,10 +4079,16 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, struct sctp_nets *net; struct sctp_association *asoc; struct sctp_tmit_chunk *tp1, *tp2; + uint32_t old_rwnd; + int win_probe_recovery = 0; int j; SCTP_TCB_LOCK_ASSERT(stcb); asoc = &stcb->asoc; + if (compare_with_wrap(asoc->last_acked_seq, cumack, MAX_TSN)) { + /* old ack */ + return; + } /* First setup for CC stuff */ TAILQ_FOREACH(net, &asoc->nets, sctp_next) { net->prev_cwnd = net->cwnd; @@ -4116,118 +4140,126 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, #endif } } + old_rwnd = asoc->peers_rwnd; asoc->this_sack_highest_gap = cumack; stcb->asoc.overall_error_count = 0; - /* process the new consecutive TSN first */ - tp1 = TAILQ_FIRST(&asoc->sent_queue); - while (tp1) { - tp2 = TAILQ_NEXT(tp1, sctp_next); - if (compare_with_wrap(cumack, tp1->rec.data.TSN_seq, - MAX_TSN) || - cumack == tp1->rec.data.TSN_seq) { - if (tp1->sent != SCTP_DATAGRAM_UNSENT) { - /* - * ECN Nonce: Add the nonce to the sender's - * nonce sum - */ - asoc->nonce_sum_expect_base += tp1->rec.data.ect_nonce; - if (tp1->sent < SCTP_DATAGRAM_ACKED) { + if (compare_with_wrap(cumack, asoc->last_acked_seq, MAX_TSN)) { + /* process the new consecutive TSN first */ + tp1 = TAILQ_FIRST(&asoc->sent_queue); + while (tp1) { + tp2 = TAILQ_NEXT(tp1, sctp_next); + if (compare_with_wrap(cumack, tp1->rec.data.TSN_seq, + MAX_TSN) || + cumack == tp1->rec.data.TSN_seq) { + if (tp1->sent != SCTP_DATAGRAM_UNSENT) { /* - * If it is less than ACKED, it is - * now no-longer in flight. Higher - * values may occur during marking + * ECN Nonce: Add the nonce to the + * sender's nonce sum */ + asoc->nonce_sum_expect_base += tp1->rec.data.ect_nonce; + if (tp1->sent < SCTP_DATAGRAM_ACKED) { + /* + * If it is less than ACKED, + * it is now no-longer in + * flight. Higher values may + * occur during marking + */ #ifdef SCTP_FLIGHT_LOGGING - sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN, - tp1->whoTo->flight_size, - tp1->book_size, - (uintptr_t) stcb, - tp1->rec.data.TSN_seq); + sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN, + tp1->whoTo->flight_size, + tp1->book_size, + (uintptr_t) stcb, + tp1->rec.data.TSN_seq); #endif - if (tp1->whoTo->flight_size >= tp1->book_size) { - tp1->whoTo->flight_size -= tp1->book_size; - } else { - tp1->whoTo->flight_size = 0; - } + if (tp1->whoTo->flight_size >= tp1->book_size) { + tp1->whoTo->flight_size -= tp1->book_size; + } else { + tp1->whoTo->flight_size = 0; + } - if (asoc->total_flight >= tp1->book_size) { - asoc->total_flight -= tp1->book_size; - if (asoc->total_flight_count > 0) - asoc->total_flight_count--; - } else { - asoc->total_flight = 0; - asoc->total_flight_count = 0; - } - tp1->whoTo->net_ack += tp1->send_size; - if (tp1->snd_count < 2) { + if (asoc->total_flight >= tp1->book_size) { + asoc->total_flight -= tp1->book_size; + if (asoc->total_flight_count > 0) + asoc->total_flight_count--; + } else { + asoc->total_flight = 0; + asoc->total_flight_count = 0; + } + tp1->whoTo->net_ack += tp1->send_size; + if (tp1->snd_count < 2) { + /* + * True + * non-retransmited + * chunk + */ + tp1->whoTo->net_ack2 += + tp1->send_size; + + /* update RTO too? */ + if (tp1->do_rtt) { + tp1->whoTo->RTO = + sctp_calculate_rto(stcb, + asoc, tp1->whoTo, + &tp1->sent_rcv_time); + tp1->do_rtt = 0; + } + } /* - * True non-retransmited - * chunk + * CMT: CUCv2 algorithm. + * From the cumack'd TSNs, + * for each TSN being acked + * for the first time, set + * the following variables + * for the corresp + * destination. + * new_pseudo_cumack will + * trigger a cwnd update. + * find_(rtx_)pseudo_cumack + * will trigger search for + * the next expected + * (rtx-)pseudo-cumack. */ - tp1->whoTo->net_ack2 += - tp1->send_size; - - /* update RTO too? */ - if (tp1->do_rtt) { - tp1->whoTo->RTO = - sctp_calculate_rto(stcb, - asoc, tp1->whoTo, - &tp1->sent_rcv_time); - tp1->do_rtt = 0; - } - } - /* - * CMT: CUCv2 algorithm. From the - * cumack'd TSNs, for each TSN being - * acked for the first time, set the - * following variables for the - * corresp destination. - * new_pseudo_cumack will trigger a - * cwnd update. - * find_(rtx_)pseudo_cumack will - * trigger search for the next - * expected (rtx-)pseudo-cumack. - */ - tp1->whoTo->new_pseudo_cumack = 1; - tp1->whoTo->find_pseudo_cumack = 1; - tp1->whoTo->find_rtx_pseudo_cumack = 1; + tp1->whoTo->new_pseudo_cumack = 1; + tp1->whoTo->find_pseudo_cumack = 1; + tp1->whoTo->find_rtx_pseudo_cumack = 1; #ifdef SCTP_CWND_LOGGING - sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.TSN_seq, SCTP_CWND_LOG_FROM_SACK); + sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.TSN_seq, SCTP_CWND_LOG_FROM_SACK); #endif + } + if (tp1->sent == SCTP_DATAGRAM_RESEND) { + sctp_ucount_decr(asoc->sent_queue_retran_cnt); + } + if (tp1->rec.data.chunk_was_revoked) { + /* deflate the cwnd */ + tp1->whoTo->cwnd -= tp1->book_size; + tp1->rec.data.chunk_was_revoked = 0; + } + tp1->sent = SCTP_DATAGRAM_ACKED; } - if (tp1->sent == SCTP_DATAGRAM_RESEND) { - sctp_ucount_decr(asoc->sent_queue_retran_cnt); - } - if (tp1->rec.data.chunk_was_revoked) { - /* deflate the cwnd */ - tp1->whoTo->cwnd -= tp1->book_size; - tp1->rec.data.chunk_was_revoked = 0; - } - tp1->sent = SCTP_DATAGRAM_ACKED; + } else { + break; + } + TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next); + if (tp1->data) { + sctp_free_bufspace(stcb, asoc, tp1, 1); + sctp_m_freem(tp1->data); } - } else { - break; - } - TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next); - if (tp1->data) { - sctp_free_bufspace(stcb, asoc, tp1, 1); - sctp_m_freem(tp1->data); - } #ifdef SCTP_SACK_LOGGING - sctp_log_sack(asoc->last_acked_seq, - cumack, - tp1->rec.data.TSN_seq, - 0, - 0, - SCTP_LOG_FREE_SENT); + sctp_log_sack(asoc->last_acked_seq, + cumack, + tp1->rec.data.TSN_seq, + 0, + 0, + SCTP_LOG_FREE_SENT); #endif - tp1->data = NULL; - asoc->sent_queue_cnt--; - sctp_free_remote_addr(tp1->whoTo); - sctp_free_a_chunk(stcb, tp1); - tp1 = tp2; + tp1->data = NULL; + asoc->sent_queue_cnt--; + sctp_free_remote_addr(tp1->whoTo); + sctp_free_a_chunk(stcb, tp1); + tp1 = tp2; + } } if (stcb->sctp_socket) { SOCKBUF_LOCK(&stcb->sctp_socket->so_snd); @@ -4241,9 +4273,12 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, #endif } + if (asoc->last_acked_seq != cumack) sctp_cwnd_update(stcb, asoc, 1, 0, 0); + asoc->last_acked_seq = cumack; + if (TAILQ_EMPTY(&asoc->sent_queue)) { /* nothing left in-flight */ TAILQ_FOREACH(net, &asoc->nets, sctp_next) { @@ -4312,10 +4347,35 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, /* SWS sender side engages */ asoc->peers_rwnd = 0; } + if (asoc->peers_rwnd > old_rwnd) { + win_probe_recovery = 1; + } /* Now assure a timer where data is queued at */ again: j = 0; TAILQ_FOREACH(net, &asoc->nets, sctp_next) { + if (win_probe_recovery && (net->window_probe)) { + net->window_probe = 0; + /* + * Find first chunk that was used with window probe + * and clear the sent + */ + TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) { + if (tp1->window_probe) { + /* move back to data send queue */ + tp1->sent = SCTP_DATAGRAM_UNSENT; + tp1->window_probe = 0; + net->flight_size -= tp1->book_size; + asoc->total_flight -= tp1->book_size; + TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next); + TAILQ_INSERT_HEAD(&asoc->send_queue, tp1, sctp_next); + asoc->sent_queue_cnt--; + asoc->send_queue_cnt++; + asoc->total_flight_count--; + break; + } + } + } if (net->flight_size) { int to_ticks; @@ -4474,7 +4534,8 @@ sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb, long j; int accum_moved = 0; int will_exit_fast_recovery = 0; - uint32_t a_rwnd; + uint32_t a_rwnd, old_rwnd; + int win_probe_recovery = 0; struct sctp_nets *net = NULL; int nonce_sum_flag, ecn_seg_sums = 0; uint8_t reneged_all = 0; @@ -4526,7 +4587,7 @@ sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb, cmt_dac_flag = ch->ch.chunk_flags & SCTP_SACK_CMT_DAC; num_dup = ntohs(sack->num_dup_tsns); - + old_rwnd = stcb->asoc.peers_rwnd; stcb->asoc.overall_error_count = 0; asoc = &stcb->asoc; #ifdef SCTP_SACK_LOGGING @@ -5323,6 +5384,9 @@ done_with_it: /* SWS sender side engages */ asoc->peers_rwnd = 0; } + if (asoc->peers_rwnd > old_rwnd) { + win_probe_recovery = 1; + } /* * Now we must setup so we have a timer up for anyone with * outstanding data. @@ -5330,6 +5394,29 @@ done_with_it: again: j = 0; TAILQ_FOREACH(net, &asoc->nets, sctp_next) { + if (win_probe_recovery && (net->window_probe)) { + net->window_probe = 0; + /*- + * Find first chunk that was used with + * window probe and clear the event. Put + * it back into the send queue as if has + * not been sent. + */ + TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) { + if (tp1->window_probe) { + tp1->sent = SCTP_DATAGRAM_UNSENT; + tp1->window_probe = 0; + net->flight_size -= tp1->book_size; + asoc->total_flight -= tp1->book_size; + TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next); + TAILQ_INSERT_HEAD(&asoc->send_queue, tp1, sctp_next); + asoc->sent_queue_cnt--; + asoc->send_queue_cnt++; + asoc->total_flight_count--; + break; + } + } + } if (net->flight_size) { j++; sctp_timer_start(SCTP_TIMER_TYPE_SEND, |