diff options
author | rrs <rrs@FreeBSD.org> | 2010-07-29 11:37:04 +0000 |
---|---|---|
committer | rrs <rrs@FreeBSD.org> | 2010-07-29 11:37:04 +0000 |
commit | c9a735e2e795174cacdb32cf78185bc3c8fde78c (patch) | |
tree | 03cffd00fe5726c24c8cca36c9801d3dc3ff5732 /sys/netinet/sctp_timer.c | |
parent | a871a4e0159f3433c4ca560a62d1e6fbd89b4477 (diff) | |
download | FreeBSD-src-c9a735e2e795174cacdb32cf78185bc3c8fde78c.zip FreeBSD-src-c9a735e2e795174cacdb32cf78185bc3c8fde78c.tar.gz |
PR SCTP Bugs. Basically a full sized frame of
PR SCTP FWD-TSN's would not be sent and thus
cause a stalled connection. Also the rwnd
Calculation was also off on the receiver side for
PR-SCTP.
MFC after: 1 month
Diffstat (limited to 'sys/netinet/sctp_timer.c')
-rw-r--r-- | sys/netinet/sctp_timer.c | 38 |
1 files changed, 25 insertions, 13 deletions
diff --git a/sys/netinet/sctp_timer.c b/sys/netinet/sctp_timer.c index d4faaa4..2921272 100644 --- a/sys/netinet/sctp_timer.c +++ b/sys/netinet/sctp_timer.c @@ -545,7 +545,7 @@ static void sctp_backoff_on_timeout(struct sctp_tcb *stcb, struct sctp_nets *net, int win_probe, - int num_marked) + int num_marked, int num_abandoned) { if (net->RTO == 0) { net->RTO = stcb->asoc.minrto; @@ -554,7 +554,7 @@ sctp_backoff_on_timeout(struct sctp_tcb *stcb, if (net->RTO > stcb->asoc.maxrto) { net->RTO = stcb->asoc.maxrto; } - if ((win_probe == 0) && num_marked) { + if ((win_probe == 0) && (num_marked || num_abandoned)) { /* We don't apply penalty to window probe scenarios */ /* JRS - Use the congestion control given in the CC module */ stcb->asoc.cc_functions.sctp_cwnd_update_after_timeout(stcb, net); @@ -612,7 +612,8 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb, struct sctp_nets *net, struct sctp_nets *alt, int window_probe, - int *num_marked) + int *num_marked, + int *num_abandoned) { /* @@ -621,10 +622,11 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb, * We only mark chunks that have been outstanding long enough to * have received feed-back. */ - struct sctp_tmit_chunk *chk, *tp2, *could_be_sent = NULL; + struct sctp_tmit_chunk *chk, *tp2; struct sctp_nets *lnets; struct timeval now, min_wait, tv; int cur_rtt; + int cnt_abandoned; int audit_tf, num_mk, fir; unsigned int cnt_mk; uint32_t orig_flight, orig_tf; @@ -680,6 +682,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb, net->fast_retran_ip = 0; /* Now on to each chunk */ + cnt_abandoned = 0; num_mk = cnt_mk = 0; tsnfirst = tsnlast = 0; #ifndef INVARIANTS @@ -768,6 +771,7 @@ start_again: chk, (SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT), SCTP_SO_NOT_LOCKED); + cnt_abandoned++; } continue; } @@ -780,6 +784,7 @@ start_again: chk, (SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT), SCTP_SO_NOT_LOCKED); + cnt_abandoned++; } continue; } @@ -841,9 +846,11 @@ start_again: if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 1) { chk->no_fr_allowed = 1; } +#ifdef THIS_SHOULD_NOT_BE_DONE } else if (chk->sent == SCTP_DATAGRAM_ACKED) { /* remember highest acked one */ could_be_sent = chk; +#endif } if (chk->sent == SCTP_DATAGRAM_RESEND) { cnt_mk++; @@ -870,6 +877,7 @@ start_again: } #endif *num_marked = num_mk; + *num_abandoned = cnt_abandoned; /* * Now check for a ECN Echo that may be stranded And include the * cnt_mk'd to have all resends in the control queue. @@ -890,12 +898,14 @@ start_again: atomic_add_int(&alt->ref_count, 1); } } +#ifdef THIS_SHOULD_NOT_BE_DONE if ((stcb->asoc.sent_queue_retran_cnt == 0) && (could_be_sent)) { /* fix it so we retransmit the highest acked anyway */ sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); cnt_mk++; could_be_sent->sent = SCTP_DATAGRAM_RESEND; } +#endif if (stcb->asoc.sent_queue_retran_cnt != cnt_mk) { #ifdef INVARIANTS SCTP_PRINTF("Local Audit says there are %d for retran asoc cnt:%d we marked:%d this time\n", @@ -996,7 +1006,7 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp, struct sctp_nets *net) { struct sctp_nets *alt; - int win_probe, num_mk; + int win_probe, num_mk, num_abandoned; if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { sctp_log_fr(0, 0, 0, SCTP_FR_T3_TIMEOUT); @@ -1055,8 +1065,10 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp, } else { /* CMT is OFF */ alt = sctp_find_alternate_net(stcb, net, 0); } - - (void)sctp_mark_all_for_resend(stcb, net, alt, win_probe, &num_mk); + num_mk = 0; + num_abandoned = 0; + (void)sctp_mark_all_for_resend(stcb, net, alt, win_probe, + &num_mk, &num_abandoned); /* FR Loss recovery just ended with the T3. */ stcb->asoc.fast_retran_loss_recovery = 0; @@ -1070,7 +1082,7 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp, stcb->asoc.sat_t3_recovery_tsn = stcb->asoc.sending_seq; /* Backoff the timer and cwnd */ - sctp_backoff_on_timeout(stcb, net, win_probe, num_mk); + sctp_backoff_on_timeout(stcb, net, win_probe, num_mk, num_abandoned); if (win_probe == 0) { /* We don't do normal threshold management on window probes */ if (sctp_threshold_management(inp, stcb, net, @@ -1221,7 +1233,7 @@ sctp_t1init_timer(struct sctp_inpcb *inp, return (1); } stcb->asoc.dropped_special_cnt = 0; - sctp_backoff_on_timeout(stcb, stcb->asoc.primary_destination, 1, 0); + sctp_backoff_on_timeout(stcb, stcb->asoc.primary_destination, 1, 0, 0); if (stcb->asoc.initial_init_rto_max < net->RTO) { net->RTO = stcb->asoc.initial_init_rto_max; } @@ -1302,7 +1314,7 @@ sctp_cookie_timer(struct sctp_inpcb *inp, * an alternate */ stcb->asoc.dropped_special_cnt = 0; - sctp_backoff_on_timeout(stcb, cookie->whoTo, 1, 0); + sctp_backoff_on_timeout(stcb, cookie->whoTo, 1, 0, 0); alt = sctp_find_alternate_net(stcb, cookie->whoTo, 0); if (alt != cookie->whoTo) { sctp_free_remote_addr(cookie->whoTo); @@ -1347,7 +1359,7 @@ sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, * cleared theshold management now lets backoff the address & select * an alternate */ - sctp_backoff_on_timeout(stcb, strrst->whoTo, 1, 0); + sctp_backoff_on_timeout(stcb, strrst->whoTo, 1, 0, 0); alt = sctp_find_alternate_net(stcb, strrst->whoTo, 0); sctp_free_remote_addr(strrst->whoTo); strrst->whoTo = alt; @@ -1426,7 +1438,7 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, * cleared threshold management, so now backoff the net and * select an alternate */ - sctp_backoff_on_timeout(stcb, asconf->whoTo, 1, 0); + sctp_backoff_on_timeout(stcb, asconf->whoTo, 1, 0, 0); alt = sctp_find_alternate_net(stcb, asconf->whoTo, 0); if (asconf->whoTo != alt) { sctp_free_remote_addr(asconf->whoTo); @@ -1643,7 +1655,7 @@ sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, net->ro._s_addr = NULL; net->src_addr_selected = 0; } - sctp_backoff_on_timeout(stcb, net, 1, 0); + sctp_backoff_on_timeout(stcb, net, 1, 0, 0); } /* Zero PBA, if it needs it */ if (net->partial_bytes_acked) { |