summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctp_timer.c
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2010-07-29 11:37:04 +0000
committerrrs <rrs@FreeBSD.org>2010-07-29 11:37:04 +0000
commitc9a735e2e795174cacdb32cf78185bc3c8fde78c (patch)
tree03cffd00fe5726c24c8cca36c9801d3dc3ff5732 /sys/netinet/sctp_timer.c
parenta871a4e0159f3433c4ca560a62d1e6fbd89b4477 (diff)
downloadFreeBSD-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.c38
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) {
OpenPOWER on IntegriCloud