Index: sys/netinet/tcp_input.c =================================================================== --- sys/netinet/tcp_input.c +++ sys/netinet/tcp_input.c @@ -1465,6 +1465,19 @@ return (newsize); } +void +tcp_handle_wakeup(struct socket *so, int read_wakeup, int write_wakeup) +{ + if (read_wakeup != 0) { + SOCKBUF_UNLOCK_ASSERT(&so->so_rcv); + sorwakeup(so); + } + if (write_wakeup != 0) { + SOCKBUF_UNLOCK_ASSERT(&so->so_snd); + sowwakeup(so); + } +} + void tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, struct tcpcb *tp, int drop_hdrlen, int tlen, uint8_t iptos) @@ -1478,6 +1491,8 @@ struct mbuf *mfree; struct tcpopt to; int tfo_syn; + int read_wakeup = 0; + int write_wakeup = 0; #ifdef TCPDEBUG /* @@ -1805,7 +1820,7 @@ else if (!tcp_timer_active(tp, TT_PERSIST)) tcp_timer_activate(tp, TT_REXMT, tp->t_rxtcur); - sowwakeup(so); + write_wakeup = 1; if (sbavail(&so->so_snd)) (void) tp->t_fb->tfb_tcp_output(tp); goto check_delack; @@ -1861,8 +1876,8 @@ m_adj(m, drop_hdrlen); /* delayed header drop */ sbappendstream_locked(&so->so_rcv, m, 0); } - /* NB: sorwakeup_locked() does an implicit unlock. */ - sorwakeup_locked(so); + SOCKBUF_UNLOCK(&so->so_rcv); + read_wakeup = 1; if (DELAY_ACK(tp, tlen)) { tp->t_flags |= TF_DELACK; } else { @@ -2405,7 +2420,7 @@ */ if (tlen == 0 && (thflags & TH_FIN) == 0) (void) tcp_reass(tp, (struct tcphdr *)0, NULL, 0, - (struct mbuf *)0); + (struct mbuf *)0, &read_wakeup); tp->snd_wl1 = th->th_seq - 1; /* FALLTHROUGH */ @@ -2783,8 +2798,8 @@ tp->snd_wnd = 0; ourfinisacked = 0; } - /* NB: sowwakeup_locked() does an implicit unlock. */ - sowwakeup_locked(so); + SOCKBUF_UNLOCK(&so->so_snd); + write_wakeup = 1; m_freem(mfree); /* Detect una wraparound. */ if (!IN_RECOVERY(tp->t_flags) && @@ -2997,8 +3012,8 @@ m_freem(m); else sbappendstream_locked(&so->so_rcv, m, 0); - /* NB: sorwakeup_locked() does an implicit unlock. */ - sorwakeup_locked(so); + SOCKBUF_UNLOCK(&so->so_rcv); + read_wakeup = 1; } else { /* * XXX: Due to the header drop above "th" is @@ -3007,7 +3022,14 @@ * when trimming from the head. */ tcp_seq temp = save_start; - thflags = tcp_reass(tp, th, &temp, &tlen, m); + /* + * Bracketing tcp_reass here to prevent + * sending of window updates, excessive + * (duplicate) ACKs or data packets + * which may contain outdated TCP options. + */ + thflags = tcp_reass(tp, th, &temp, &tlen, m, + &read_wakeup); tp->t_flags |= TF_ACKNOW; } if ((tp->t_flags & TF_SACK_PERMIT) && (save_tlen > 0)) { @@ -3130,6 +3152,7 @@ tcp_timer_activate(tp, TT_DELACK, tcp_delacktime); } INP_WUNLOCK(tp->t_inpcb); + tcp_handle_wakeup(so, read_wakeup, write_wakeup); return; dropafterack: @@ -3162,6 +3185,7 @@ TCP_PROBE3(debug__input, tp, th, m); tp->t_flags |= TF_ACKNOW; (void) tp->t_fb->tfb_tcp_output(tp); + tcp_handle_wakeup(so, read_wakeup, write_wakeup); INP_WUNLOCK(tp->t_inpcb); m_freem(m); return; @@ -3169,6 +3193,7 @@ dropwithreset: if (tp != NULL) { tcp_dropwithreset(m, th, tp, tlen, rstreason); + tcp_handle_wakeup(so, read_wakeup, write_wakeup); INP_WUNLOCK(tp->t_inpcb); } else tcp_dropwithreset(m, th, NULL, tlen, rstreason); @@ -3184,8 +3209,10 @@ &tcp_savetcp, 0); #endif TCP_PROBE3(debug__input, tp, th, m); - if (tp != NULL) + if (tp != NULL) { + tcp_handle_wakeup(so, read_wakeup, write_wakeup); INP_WUNLOCK(tp->t_inpcb); + } m_freem(m); } Index: sys/netinet/tcp_reass.c =================================================================== --- sys/netinet/tcp_reass.c +++ sys/netinet/tcp_reass.c @@ -526,7 +526,7 @@ */ int tcp_reass(struct tcpcb *tp, struct tcphdr *th, tcp_seq *seq_start, - int *tlenp, struct mbuf *m) + int *tlenp, struct mbuf *m, int *read_wakeup) { struct tseg_qent *q, *last, *first; struct tseg_qent *p = NULL; @@ -961,7 +961,8 @@ } else { sbappendstream_locked(&so->so_rcv, m, 0); } - sorwakeup_locked(so); + SOCKBUF_UNLOCK(&so->so_rcv); + *read_wakeup = 1; return (flags); } if (tcp_new_limits) { @@ -1109,6 +1110,7 @@ #ifdef TCP_REASS_LOGGING tcp_reass_log_dump(tp); #endif - sorwakeup_locked(so); + SOCKBUF_UNLOCK(&so->so_rcv); + *read_wakeup = 1; return (flags); } Index: sys/netinet/tcp_stacks/bbr.c =================================================================== --- sys/netinet/tcp_stacks/bbr.c +++ sys/netinet/tcp_stacks/bbr.c @@ -8331,6 +8331,7 @@ uint16_t nsegs; int32_t tfo_syn; struct tcp_bbr *bbr; + int read_wakeup = 0; bbr = (struct tcp_bbr *)tp->t_fb_ptr; INP_WLOCK_ASSERT(tp->t_inpcb); @@ -8518,8 +8519,8 @@ appended = #endif sbappendstream_locked(&so->so_rcv, m, 0); - /* NB: sorwakeup_locked() does an implicit unlock. */ - sorwakeup_locked(so); + SOCKBUF_UNLOCK(&so->so_rcv); + read_wakeup = 1; #ifdef NETFLIX_SB_LIMITS if (so->so_rcv.sb_shlim && appended != mcnt) counter_fo_release(so->so_rcv.sb_shlim, @@ -8533,7 +8534,8 @@ * trimming from the head. */ tcp_seq temp = save_start; - thflags = tcp_reass(tp, th, &temp, &tlen, m); + thflags = tcp_reass(tp, th, &temp, &tlen, m, + &read_wakeup); tp->t_flags |= TF_ACKNOW; } if ((tp->t_flags & TF_SACK_PERMIT) && (save_tlen > 0)) { @@ -8637,6 +8639,7 @@ (sbavail(&so->so_snd) > ctf_outstanding(tp))) { bbr->r_wanted_output = 1; } + tcp_handle_wakeup(so, read_wakeup, 0); INP_WLOCK_ASSERT(tp->t_inpcb); return (0); } @@ -9200,6 +9203,7 @@ int32_t ourfinisacked = 0; int32_t ret_val; struct tcp_bbr *bbr; + int read_wakeup = 0; bbr = (struct tcp_bbr *)tp->t_fb_ptr; ctf_calc_rwin(so, tp); @@ -9356,9 +9360,11 @@ * If segment contains data or ACK, will call tcp_reass() later; if * not, do so now to pass queued data to user. */ - if (tlen == 0 && (thflags & TH_FIN) == 0) + if (tlen == 0 && (thflags & TH_FIN) == 0) { (void)tcp_reass(tp, (struct tcphdr *)0, NULL, 0, - (struct mbuf *)0); + (struct mbuf *)0, &read_wakeup); + tcp_handle_wakeup(so, read_wakeup, 0); + } tp->snd_wl1 = th->th_seq - 1; if (bbr_process_ack(m, th, so, tp, to, tiwin, tlen, &ourfinisacked, thflags, &ret_val)) { return (ret_val); Index: sys/netinet/tcp_stacks/rack.c =================================================================== --- sys/netinet/tcp_stacks/rack.c +++ sys/netinet/tcp_stacks/rack.c @@ -5575,6 +5575,7 @@ int32_t nsegs; int32_t tfo_syn; struct tcp_rack *rack; + int read_wakeup = 0; rack = (struct tcp_rack *)tp->t_fb_ptr; INP_WLOCK_ASSERT(tp->t_inpcb); @@ -5763,8 +5764,8 @@ appended = #endif sbappendstream_locked(&so->so_rcv, m, 0); - /* NB: sorwakeup_locked() does an implicit unlock. */ - sorwakeup_locked(so); + SOCKBUF_UNLOCK(&so->so_rcv); + read_wakeup = 1; #ifdef NETFLIX_SB_LIMITS if (so->so_rcv.sb_shlim && appended != mcnt) counter_fo_release(so->so_rcv.sb_shlim, @@ -5778,7 +5779,8 @@ * trimming from the head. */ tcp_seq temp = save_start; - thflags = tcp_reass(tp, th, &temp, &tlen, m); + thflags = tcp_reass(tp, th, &temp, &tlen, m, + &read_wakeup); tp->t_flags |= TF_ACKNOW; } if ((tp->t_flags & TF_SACK_PERMIT) && (save_tlen > 0)) { @@ -5884,6 +5886,7 @@ (sbavail(&so->so_snd) > (tp->snd_max - tp->snd_una))) { rack->r_wanted_output++; } + tcp_handle_wakeup(so, read_wakeup, 0); INP_WLOCK_ASSERT(tp->t_inpcb); return (0); } @@ -6431,6 +6434,7 @@ struct tcp_rack *rack; int32_t ret_val = 0; int32_t ourfinisacked = 0; + int read_wakeup = 0; ctf_calc_rwin(so, tp); if ((thflags & TH_ACK) && @@ -6566,9 +6570,11 @@ * If segment contains data or ACK, will call tcp_reass() later; if * not, do so now to pass queued data to user. */ - if (tlen == 0 && (thflags & TH_FIN) == 0) + if (tlen == 0 && (thflags & TH_FIN) == 0) { (void) tcp_reass(tp, (struct tcphdr *)0, NULL, 0, - (struct mbuf *)0); + (struct mbuf *)0, &read_wakeup); + tcp_handle_wakeup(so, read_wakeup, 0); + } tp->snd_wl1 = th->th_seq - 1; /* For syn-recv we need to possibly update the rtt */ if ((to->to_flags & TOF_TS) != 0 && to->to_tsecr) { Index: sys/netinet/tcp_var.h =================================================================== --- sys/netinet/tcp_var.h +++ sys/netinet/tcp_var.h @@ -879,7 +879,8 @@ const void *); char *tcp_log_vain(struct in_conninfo *, struct tcphdr *, void *, const void *); -int tcp_reass(struct tcpcb *, struct tcphdr *, tcp_seq *, int *, struct mbuf *); +int tcp_reass(struct tcpcb *, struct tcphdr *, tcp_seq *, int *, + struct mbuf *, int *); void tcp_reass_global_init(void); void tcp_reass_flush(struct tcpcb *); void tcp_dooptions(struct tcpopt *, u_char *, int, int); @@ -903,6 +904,7 @@ int tcp_input(struct mbuf **, int *, int); int tcp_autorcvbuf(struct mbuf *, struct tcphdr *, struct socket *, struct tcpcb *, int); +void tcp_handle_wakeup(struct socket *, int, int); void tcp_do_segment(struct mbuf *, struct tcphdr *, struct socket *, struct tcpcb *, int, int, uint8_t);