Changeset View
Changeset View
Standalone View
Standalone View
stable/11/sys/netinet/tcp_stacks/fastpath.c
Show First 20 Lines • Show All 925 Lines • ▼ Show 20 Lines | if (tp->t_flags & TF_NEEDFIN) { | ||||
cc_conn_init(tp); | cc_conn_init(tp); | ||||
tcp_timer_activate(tp, TT_KEEP, TP_KEEPIDLE(tp)); | tcp_timer_activate(tp, TT_KEEP, TP_KEEPIDLE(tp)); | ||||
} | } | ||||
/* | /* | ||||
* If segment contains data or ACK, will call tcp_reass() | * If segment contains data or ACK, will call tcp_reass() | ||||
* later; if not, do so now to pass queued data to user. | * 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, 0, | (void) tcp_reass(tp, (struct tcphdr *)0, NULL, 0, | ||||
(struct mbuf *)0); | (struct mbuf *)0); | ||||
tp->snd_wl1 = th->th_seq - 1; | tp->snd_wl1 = th->th_seq - 1; | ||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
/* | /* | ||||
* In ESTABLISHED state: drop duplicate ACKs; ACK out of range | * In ESTABLISHED state: drop duplicate ACKs; ACK out of range | ||||
* ACKs. If the ack is in the range | * ACKs. If the ack is in the range | ||||
* tp->snd_una < th->th_ack <= tp->snd_max | * tp->snd_una < th->th_ack <= tp->snd_max | ||||
▲ Show 20 Lines • Show All 516 Lines • ▼ Show 20 Lines | if ((tlen || (thflags & TH_FIN)) && | ||||
* connection, and the queue is empty), avoiding linkage into | * connection, and the queue is empty), avoiding linkage into | ||||
* and removal from the queue and repetition of various | * and removal from the queue and repetition of various | ||||
* conversions. | * conversions. | ||||
* Set DELACK for segments received in order, but ack | * Set DELACK for segments received in order, but ack | ||||
* immediately when segments are out of order (so | * immediately when segments are out of order (so | ||||
* fast retransmit can work). | * fast retransmit can work). | ||||
*/ | */ | ||||
if (th->th_seq == tp->rcv_nxt && | if (th->th_seq == tp->rcv_nxt && | ||||
LIST_EMPTY(&tp->t_segq) && | SEGQ_EMPTY(tp) && | ||||
TCPS_HAVEESTABLISHED(tp->t_state)) { | TCPS_HAVEESTABLISHED(tp->t_state)) { | ||||
if (DELAY_ACK(tp, tlen)) | if (DELAY_ACK(tp, tlen)) | ||||
tp->t_flags |= TF_DELACK; | tp->t_flags |= TF_DELACK; | ||||
else | else | ||||
tp->t_flags |= TF_ACKNOW; | tp->t_flags |= TF_ACKNOW; | ||||
tp->rcv_nxt += tlen; | tp->rcv_nxt += tlen; | ||||
thflags = th->th_flags & TH_FIN; | thflags = th->th_flags & TH_FIN; | ||||
TCPSTAT_INC(tcps_rcvpack); | TCPSTAT_INC(tcps_rcvpack); | ||||
TCPSTAT_ADD(tcps_rcvbyte, tlen); | TCPSTAT_ADD(tcps_rcvbyte, tlen); | ||||
SOCKBUF_LOCK(&so->so_rcv); | SOCKBUF_LOCK(&so->so_rcv); | ||||
if (so->so_rcv.sb_state & SBS_CANTRCVMORE) | if (so->so_rcv.sb_state & SBS_CANTRCVMORE) | ||||
m_freem(m); | m_freem(m); | ||||
else | else | ||||
sbappendstream_locked(&so->so_rcv, m, 0); | sbappendstream_locked(&so->so_rcv, m, 0); | ||||
/* NB: sorwakeup_locked() does an implicit unlock. */ | /* NB: sorwakeup_locked() does an implicit unlock. */ | ||||
sorwakeup_locked(so); | sorwakeup_locked(so); | ||||
} else { | } else { | ||||
/* | /* | ||||
* XXX: Due to the header drop above "th" is | * XXX: Due to the header drop above "th" is | ||||
* theoretically invalid by now. Fortunately | * theoretically invalid by now. Fortunately | ||||
* m_adj() doesn't actually frees any mbufs | * m_adj() doesn't actually frees any mbufs | ||||
* when trimming from the head. | * when trimming from the head. | ||||
*/ | */ | ||||
thflags = tcp_reass(tp, th, &tlen, m); | thflags = tcp_reass(tp, th, &save_start, &tlen, m); | ||||
tp->t_flags |= TF_ACKNOW; | tp->t_flags |= TF_ACKNOW; | ||||
} | } | ||||
if (tlen > 0 && (tp->t_flags & TF_SACK_PERMIT)) | if (tlen > 0 && (tp->t_flags & TF_SACK_PERMIT)) | ||||
tcp_update_sack_list(tp, save_start, save_start + tlen); | tcp_update_sack_list(tp, save_start, save_start + tlen); | ||||
#if 0 | #if 0 | ||||
/* | /* | ||||
* Note the amount of data that peer has sent into | * Note the amount of data that peer has sent into | ||||
* our window, in order to estimate the sender's | * our window, in order to estimate the sender's | ||||
▲ Show 20 Lines • Show All 400 Lines • ▼ Show 20 Lines | #endif | ||||
* be TH_NEEDSYN. | * be TH_NEEDSYN. | ||||
*/ | */ | ||||
if (__predict_true(tp->t_state == TCPS_ESTABLISHED && | if (__predict_true(tp->t_state == TCPS_ESTABLISHED && | ||||
th->th_seq == tp->rcv_nxt && | th->th_seq == tp->rcv_nxt && | ||||
(thflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK && | (thflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK && | ||||
tp->snd_nxt == tp->snd_max && | tp->snd_nxt == tp->snd_max && | ||||
can_enter && | can_enter && | ||||
((tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN)) == 0) && | ((tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN)) == 0) && | ||||
LIST_EMPTY(&tp->t_segq) && | SEGQ_EMPTY(tp) && | ||||
((to.to_flags & TOF_TS) == 0 || | ((to.to_flags & TOF_TS) == 0 || | ||||
TSTMP_GEQ(to.to_tsval, tp->ts_recent)))) { | TSTMP_GEQ(to.to_tsval, tp->ts_recent)))) { | ||||
if (__predict_true((tlen == 0) && | if (__predict_true((tlen == 0) && | ||||
(SEQ_LEQ(th->th_ack, tp->snd_max) && | (SEQ_LEQ(th->th_ack, tp->snd_max) && | ||||
!IN_RECOVERY(tp->t_flags) && | !IN_RECOVERY(tp->t_flags) && | ||||
(to.to_flags & TOF_SACK) == 0 && | (to.to_flags & TOF_SACK) == 0 && | ||||
TAILQ_EMPTY(&tp->snd_holes)))) { | TAILQ_EMPTY(&tp->snd_holes)))) { | ||||
/* We are done */ | /* We are done */ | ||||
▲ Show 20 Lines • Show All 435 Lines • ▼ Show 20 Lines | #endif | ||||
* Make sure that the hidden state-flags are also off. | * Make sure that the hidden state-flags are also off. | ||||
* Since we check for TCPS_ESTABLISHED first, it can only | * Since we check for TCPS_ESTABLISHED first, it can only | ||||
* be TH_NEEDSYN. | * be TH_NEEDSYN. | ||||
*/ | */ | ||||
if (__predict_true(tp->t_state == TCPS_ESTABLISHED) && | if (__predict_true(tp->t_state == TCPS_ESTABLISHED) && | ||||
__predict_true(((to.to_flags & TOF_SACK) == 0)) && | __predict_true(((to.to_flags & TOF_SACK) == 0)) && | ||||
__predict_true(tlen == 0) && | __predict_true(tlen == 0) && | ||||
__predict_true((thflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK) && | __predict_true((thflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK) && | ||||
__predict_true(LIST_EMPTY(&tp->t_segq)) && | __predict_true(SEGQ_EMPTY(tp)) && | ||||
__predict_true(th->th_seq == tp->rcv_nxt)) { | __predict_true(th->th_seq == tp->rcv_nxt)) { | ||||
if (tcp_fastack(m, th, so, tp, &to, drop_hdrlen, tlen, | if (tcp_fastack(m, th, so, tp, &to, drop_hdrlen, tlen, | ||||
ti_locked, tiwin)) { | ti_locked, tiwin)) { | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
tcp_do_slowpath(m, th, so, tp, &to, drop_hdrlen, tlen, | tcp_do_slowpath(m, th, so, tp, &to, drop_hdrlen, tlen, | ||||
ti_locked, tiwin, thflags); | ti_locked, tiwin, thflags); | ||||
▲ Show 20 Lines • Show All 63 Lines • Show Last 20 Lines |