Index: sys/netinet/tcp_reass.c =================================================================== --- sys/netinet/tcp_reass.c +++ sys/netinet/tcp_reass.c @@ -936,47 +936,61 @@ * is understood. */ new_entry: - if (tcp_new_limits) { - if ((tp->t_segqlen > tcp_reass_queue_guard) && - (*tlenp < MSIZE)) { - /* - * This is really a lie, we are not full but - * are getting a segment that is above - * guard threshold. If it is and its below - * a mbuf size (256) we drop it if it - * can't fill in some place. - */ - TCPSTAT_INC(tcps_rcvreassfull); - *tlenp = 0; - if ((s = tcp_log_addrs(&tp->t_inpcb->inp_inc, th, NULL, NULL))) { - log(LOG_DEBUG, "%s; %s: queue limit reached, " - "segment dropped\n", s, __func__); - free(s, M_TCPLOG); - } - m_freem(m); + if (th->th_seq != tp->rcv_nxt || !TCPS_HAVEESTABLISHED(tp->t_state)) { + if (tcp_new_limits) { + if ((tp->t_segqlen > tcp_reass_queue_guard) && + (*tlenp < MSIZE)) { + /* + * This is really a lie, we are not full but + * are getting a segment that is above + * guard threshold. If it is and its below + * a mbuf size (256) we drop it if it + * can't fill in some place. + */ + TCPSTAT_INC(tcps_rcvreassfull); + *tlenp = 0; + if ((s = tcp_log_addrs(&tp->t_inpcb->inp_inc, th, NULL, NULL))) { + log(LOG_DEBUG, "%s; %s: queue limit reached, " + "segment dropped\n", s, __func__); + free(s, M_TCPLOG); + } + m_freem(m); #ifdef TCP_REASS_LOGGING - tcp_reass_log_dump(tp); + tcp_reass_log_dump(tp); #endif - return (0); - } - } else { - - if ((th->th_seq != tp->rcv_nxt || !TCPS_HAVEESTABLISHED(tp->t_state)) && - tp->t_segqlen >= min((so->so_rcv.sb_hiwat / tp->t_maxseg) + 1, - tcp_reass_maxqueuelen)) { - TCPSTAT_INC(tcps_rcvreassfull); - *tlenp = 0; - if ((s = tcp_log_addrs(&tp->t_inpcb->inp_inc, th, NULL, NULL))) { - log(LOG_DEBUG, "%s; %s: queue limit reached, " - "segment dropped\n", s, __func__); - free(s, M_TCPLOG); + return (0); } - m_freem(m); + } else { + if (tp->t_segqlen >= min((so->so_rcv.sb_hiwat / tp->t_maxseg) + 1, + tcp_reass_maxqueuelen)) { + TCPSTAT_INC(tcps_rcvreassfull); + *tlenp = 0; + if ((s = tcp_log_addrs(&tp->t_inpcb->inp_inc, th, NULL, NULL))) { + log(LOG_DEBUG, "%s; %s: queue limit reached, " + "segment dropped\n", s, __func__); + free(s, M_TCPLOG); + } + m_freem(m); #ifdef TCP_REASS_LOGGING - tcp_reass_log_dump(tp); + tcp_reass_log_dump(tp); #endif - return (0); + return (0); + } } + } + if (th->th_seq == tp->rcv_nxt && TCPS_HAVEESTABLISHED(tp->t_state)) { + tp->rcv_nxt += *tlenp; + flags = th->th_flags & TH_FIN; + TCPSTAT_INC(tcps_rcvoopack); + TCPSTAT_ADD(tcps_rcvoobyte, *tlenp); + SOCKBUF_LOCK(&so->so_rcv); + if (so->so_rcv.sb_state & SBS_CANTRCVMORE) { + m_freem(m); + } else { + sbappendstream_locked(&so->so_rcv, m, 0); + } + sorwakeup_locked(so); + return (flags); } /* * Allocate a new queue entry. If we can't, or hit the zone limit