diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -1529,7 +1529,7 @@ struct mbuf *mfree; struct tcpopt to; int tfo_syn; - u_int maxseg; + u_int maxseg = 0; thflags = tcp_get_flags(th); tp->sackhint.last_sack_ack = 0; @@ -2596,7 +2596,8 @@ if (V_tcp_do_prr && IN_FASTRECOVERY(tp->t_flags) && (tp->t_flags & TF_SACK_PERMIT)) { - tcp_do_prr_ack(tp, th, &to, sack_changed); + tcp_do_prr_ack(tp, th, &to, + sack_changed, &maxseg); } else if (tcp_is_sack_recovery(tp, &to) && IN_FASTRECOVERY(tp->t_flags)) { int awnd; @@ -2801,19 +2802,24 @@ */ if (IN_FASTRECOVERY(tp->t_flags)) { if (SEQ_LT(th->th_ack, tp->snd_recover)) { - if (tp->t_flags & TF_SACK_PERMIT) + if (tp->t_flags & TF_SACK_PERMIT) { if (V_tcp_do_prr && to.to_flags & TOF_SACK) { tcp_timer_activate(tp, TT_REXMT, 0); tp->t_rtttime = 0; - tcp_do_prr_ack(tp, th, &to, sack_changed); + tcp_do_prr_ack(tp, th, &to, + sack_changed, &maxseg); tp->t_flags |= TF_ACKNOW; (void) tcp_output(tp); - } else - tcp_sack_partialack(tp, th); - else + } else { + tcp_sack_partialack(tp, th, + &maxseg); + } + } else { tcp_newreno_partial_ack(tp, th); - } else + } + } else { cc_post_recovery(tp, th); + } } else if (IN_CONGRECOVERY(tp->t_flags)) { if (SEQ_LT(th->th_ack, tp->snd_recover)) { if (V_tcp_do_prr) { @@ -2823,11 +2829,13 @@ * During ECN cwnd reduction * always use PRR-SSRB */ - tcp_do_prr_ack(tp, th, &to, SACK_CHANGE); + tcp_do_prr_ack(tp, th, &to, SACK_CHANGE, + &maxseg); (void) tcp_output(tp); } - } else + } else { cc_post_recovery(tp, th); + } } /* * If we reach this point, ACK is not a duplicate, @@ -3946,13 +3954,18 @@ } void -tcp_do_prr_ack(struct tcpcb *tp, struct tcphdr *th, struct tcpopt *to, sackstatus_t sack_changed) +tcp_do_prr_ack(struct tcpcb *tp, struct tcphdr *th, struct tcpopt *to, + sackstatus_t sack_changed, u_int *maxsegp) { int snd_cnt = 0, limit = 0, del_data = 0, pipe = 0; - int maxseg = tcp_maxseg(tp); + u_int maxseg; INP_WLOCK_ASSERT(tptoinpcb(tp)); + if (*maxsegp == 0) { + *maxsegp = tcp_maxseg(tp); + } + maxseg = *maxsegp; /* * Compute the amount of data that this ACK is indicating * (del_data) and an estimate of how many bytes are in the diff --git a/sys/netinet/tcp_sack.c b/sys/netinet/tcp_sack.c --- a/sys/netinet/tcp_sack.c +++ b/sys/netinet/tcp_sack.c @@ -936,13 +936,18 @@ * the midst of sack recovery. */ void -tcp_sack_partialack(struct tcpcb *tp, struct tcphdr *th) +tcp_sack_partialack(struct tcpcb *tp, struct tcphdr *th, u_int *maxsegp) { struct sackhole *temp; int num_segs = 1; - u_int maxseg = tcp_maxseg(tp); + u_int maxseg; INP_WLOCK_ASSERT(tptoinpcb(tp)); + + if (*maxsegp == 0) { + *maxsegp = tcp_maxseg(tp); + } + maxseg = *maxsegp; tcp_timer_activate(tp, TT_REXMT, 0); tp->t_rtttime = 0; /* Send one or 2 segments based on how much new data was acked. */ diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -1481,14 +1481,16 @@ tcp_sack_doack(struct tcpcb *, struct tcpopt *, tcp_seq); int tcp_dsack_block_exists(struct tcpcb *); void tcp_update_dsack_list(struct tcpcb *, tcp_seq, tcp_seq); -void tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_laststart, tcp_seq rcv_lastend); +void tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_laststart, + tcp_seq rcv_lastend); void tcp_clean_dsack_blocks(struct tcpcb *tp); void tcp_clean_sackreport(struct tcpcb *tp); void tcp_sack_adjust(struct tcpcb *tp); struct sackhole *tcp_sack_output(struct tcpcb *tp, int *sack_bytes_rexmt); -void tcp_do_prr_ack(struct tcpcb *, struct tcphdr *, struct tcpopt *, sackstatus_t); +void tcp_do_prr_ack(struct tcpcb *, struct tcphdr *, struct tcpopt *, + sackstatus_t, u_int *); void tcp_lost_retransmission(struct tcpcb *, struct tcphdr *); -void tcp_sack_partialack(struct tcpcb *, struct tcphdr *); +void tcp_sack_partialack(struct tcpcb *, struct tcphdr *, u_int *); void tcp_resend_sackholes(struct tcpcb *tp); void tcp_free_sackholes(struct tcpcb *tp); void tcp_sack_lost_retransmission(struct tcpcb *, struct tcphdr *);