Changeset View
Changeset View
Standalone View
Standalone View
head/sys/netinet/tcp_input.c
Show First 20 Lines • Show All 92 Lines • ▼ Show 20 Lines | |||||
#include <netinet/icmp_var.h> /* for ICMP_BANDLIM */ | #include <netinet/icmp_var.h> /* for ICMP_BANDLIM */ | ||||
#include <netinet/ip_var.h> | #include <netinet/ip_var.h> | ||||
#include <netinet/ip_options.h> | #include <netinet/ip_options.h> | ||||
#include <netinet/ip6.h> | #include <netinet/ip6.h> | ||||
#include <netinet/icmp6.h> | #include <netinet/icmp6.h> | ||||
#include <netinet6/in6_pcb.h> | #include <netinet6/in6_pcb.h> | ||||
#include <netinet6/ip6_var.h> | #include <netinet6/ip6_var.h> | ||||
#include <netinet6/nd6.h> | #include <netinet6/nd6.h> | ||||
#ifdef TCP_RFC7413 | |||||
#include <netinet/tcp_fastopen.h> | |||||
#endif | |||||
#include <netinet/tcp_fsm.h> | #include <netinet/tcp_fsm.h> | ||||
#include <netinet/tcp_seq.h> | #include <netinet/tcp_seq.h> | ||||
#include <netinet/tcp_timer.h> | #include <netinet/tcp_timer.h> | ||||
#include <netinet/tcp_var.h> | #include <netinet/tcp_var.h> | ||||
#include <netinet6/tcp6_var.h> | #include <netinet6/tcp6_var.h> | ||||
#include <netinet/tcpip.h> | #include <netinet/tcpip.h> | ||||
#ifdef TCPPCAP | #ifdef TCPPCAP | ||||
#include <netinet/tcp_pcap.h> | #include <netinet/tcp_pcap.h> | ||||
▲ Show 20 Lines • Show All 885 Lines • ▼ Show 20 Lines | #endif | ||||
* relock, we have to jump back to 'relocked' as the connection might | * relock, we have to jump back to 'relocked' as the connection might | ||||
* now be in TIMEWAIT. | * now be in TIMEWAIT. | ||||
*/ | */ | ||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
if ((thflags & (TH_FIN | TH_RST)) != 0) | if ((thflags & (TH_FIN | TH_RST)) != 0) | ||||
INP_INFO_RLOCK_ASSERT(&V_tcbinfo); | INP_INFO_RLOCK_ASSERT(&V_tcbinfo); | ||||
#endif | #endif | ||||
if (!((tp->t_state == TCPS_ESTABLISHED && (thflags & TH_SYN) == 0) || | if (!((tp->t_state == TCPS_ESTABLISHED && (thflags & TH_SYN) == 0) || | ||||
(tp->t_state == TCPS_LISTEN && (thflags & TH_SYN)))) { | (tp->t_state == TCPS_LISTEN && (thflags & TH_SYN) && | ||||
!(tp->t_flags & TF_FASTOPEN)))) { | |||||
if (ti_locked == TI_UNLOCKED) { | if (ti_locked == TI_UNLOCKED) { | ||||
if (INP_INFO_TRY_RLOCK(&V_tcbinfo) == 0) { | if (INP_INFO_TRY_RLOCK(&V_tcbinfo) == 0) { | ||||
in_pcbref(inp); | in_pcbref(inp); | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
INP_INFO_RLOCK(&V_tcbinfo); | INP_INFO_RLOCK(&V_tcbinfo); | ||||
ti_locked = TI_RLOCKED; | ti_locked = TI_RLOCKED; | ||||
INP_WLOCK(inp); | INP_WLOCK(inp); | ||||
if (in_pcbrele_wlocked(inp)) { | if (in_pcbrele_wlocked(inp)) { | ||||
▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | if ((thflags & (TH_RST|TH_ACK|TH_SYN)) == TH_ACK) { | ||||
* No syncache entry or ACK was not | * No syncache entry or ACK was not | ||||
* for our SYN/ACK. Send a RST. | * for our SYN/ACK. Send a RST. | ||||
* NB: syncache did its own logging | * NB: syncache did its own logging | ||||
* of the failure cause. | * of the failure cause. | ||||
*/ | */ | ||||
rstreason = BANDLIM_RST_OPENPORT; | rstreason = BANDLIM_RST_OPENPORT; | ||||
goto dropwithreset; | goto dropwithreset; | ||||
} | } | ||||
#ifdef TCP_RFC7413 | |||||
new_tfo_socket: | |||||
#endif | |||||
if (so == NULL) { | if (so == NULL) { | ||||
/* | /* | ||||
* We completed the 3-way handshake | * We completed the 3-way handshake | ||||
* but could not allocate a socket | * but could not allocate a socket | ||||
* either due to memory shortage, | * either due to memory shortage, | ||||
* listen queue length limits or | * listen queue length limits or | ||||
* global socket limits. Send RST | * global socket limits. Send RST | ||||
* or wait and have the remote end | * or wait and have the remote end | ||||
▲ Show 20 Lines • Show All 246 Lines • ▼ Show 20 Lines | #endif | ||||
*/ | */ | ||||
#ifdef TCPDEBUG | #ifdef TCPDEBUG | ||||
if (so->so_options & SO_DEBUG) | if (so->so_options & SO_DEBUG) | ||||
tcp_trace(TA_INPUT, ostate, tp, | tcp_trace(TA_INPUT, ostate, tp, | ||||
(void *)tcp_saveipgen, &tcp_savetcp, 0); | (void *)tcp_saveipgen, &tcp_savetcp, 0); | ||||
#endif | #endif | ||||
TCP_PROBE3(debug__input, tp, th, mtod(m, const char *)); | TCP_PROBE3(debug__input, tp, th, mtod(m, const char *)); | ||||
tcp_dooptions(&to, optp, optlen, TO_SYN); | tcp_dooptions(&to, optp, optlen, TO_SYN); | ||||
#ifdef TCP_RFC7413 | |||||
if (syncache_add(&inc, &to, th, inp, &so, m, NULL, NULL)) | |||||
goto new_tfo_socket; | |||||
#else | |||||
syncache_add(&inc, &to, th, inp, &so, m, NULL, NULL); | syncache_add(&inc, &to, th, inp, &so, m, NULL, NULL); | ||||
#endif | |||||
/* | /* | ||||
* Entry added to syncache and mbuf consumed. | * Entry added to syncache and mbuf consumed. | ||||
* Only the listen socket is unlocked by syncache_add(). | * Only the listen socket is unlocked by syncache_add(). | ||||
*/ | */ | ||||
if (ti_locked == TI_RLOCKED) { | if (ti_locked == TI_RLOCKED) { | ||||
INP_INFO_RUNLOCK(&V_tcbinfo); | INP_INFO_RUNLOCK(&V_tcbinfo); | ||||
ti_locked = TI_UNLOCKED; | ti_locked = TI_UNLOCKED; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 98 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
int thflags, acked, ourfinisacked, needoutput = 0, sack_changed; | int thflags, acked, ourfinisacked, needoutput = 0, sack_changed; | ||||
int rstreason, todrop, win; | int rstreason, todrop, win; | ||||
u_long tiwin; | u_long tiwin; | ||||
char *s; | char *s; | ||||
struct in_conninfo *inc; | struct in_conninfo *inc; | ||||
struct mbuf *mfree; | struct mbuf *mfree; | ||||
struct tcpopt to; | struct tcpopt to; | ||||
int tfo_syn; | |||||
#ifdef TCPDEBUG | #ifdef TCPDEBUG | ||||
/* | /* | ||||
* The size of tcp_saveipgen must be the size of the max ip header, | * The size of tcp_saveipgen must be the size of the max ip header, | ||||
* now IPv6. | * now IPv6. | ||||
*/ | */ | ||||
u_char tcp_saveipgen[IP6_HDR_LEN]; | u_char tcp_saveipgen[IP6_HDR_LEN]; | ||||
struct tcphdr tcp_savetcp; | struct tcphdr tcp_savetcp; | ||||
short ostate = 0; | short ostate = 0; | ||||
▲ Show 20 Lines • Show All 436 Lines • ▼ Show 20 Lines | #endif | ||||
*/ | */ | ||||
case TCPS_SYN_RECEIVED: | case TCPS_SYN_RECEIVED: | ||||
if ((thflags & TH_ACK) && | if ((thflags & TH_ACK) && | ||||
(SEQ_LEQ(th->th_ack, tp->snd_una) || | (SEQ_LEQ(th->th_ack, tp->snd_una) || | ||||
SEQ_GT(th->th_ack, tp->snd_max))) { | SEQ_GT(th->th_ack, tp->snd_max))) { | ||||
rstreason = BANDLIM_RST_OPENPORT; | rstreason = BANDLIM_RST_OPENPORT; | ||||
goto dropwithreset; | goto dropwithreset; | ||||
} | } | ||||
#ifdef TCP_RFC7413 | |||||
if (tp->t_flags & TF_FASTOPEN) { | |||||
/* | |||||
* When a TFO connection is in SYN_RECEIVED, the | |||||
* only valid packets are the initial SYN, a | |||||
* retransmit/copy of the initial SYN (possibly with | |||||
* a subset of the original data), a valid ACK, a | |||||
* FIN, or a RST. | |||||
*/ | |||||
if ((thflags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) { | |||||
rstreason = BANDLIM_RST_OPENPORT; | |||||
goto dropwithreset; | |||||
} else if (thflags & TH_SYN) { | |||||
/* non-initial SYN is ignored */ | |||||
if ((tcp_timer_active(tp, TT_DELACK) || | |||||
tcp_timer_active(tp, TT_REXMT))) | |||||
goto drop; | |||||
} else if (!(thflags & (TH_ACK|TH_FIN|TH_RST))) { | |||||
goto drop; | |||||
} | |||||
} | |||||
#endif | |||||
break; | break; | ||||
/* | /* | ||||
* If the state is SYN_SENT: | * If the state is SYN_SENT: | ||||
* if seg contains an ACK, but not for our SYN, drop the input. | * if seg contains an ACK, but not for our SYN, drop the input. | ||||
* if seg contains a RST, then drop the connection. | * if seg contains a RST, then drop the connection. | ||||
* if seg does not contain SYN, then drop it. | * if seg does not contain SYN, then drop it. | ||||
* Otherwise this is an acceptable SYN segment | * Otherwise this is an acceptable SYN segment | ||||
▲ Show 20 Lines • Show All 199 Lines • ▼ Show 20 Lines | if (thflags & TH_RST) { | ||||
} | } | ||||
goto drop; | goto drop; | ||||
} | } | ||||
/* | /* | ||||
* RFC5961 Section 4.2 | * RFC5961 Section 4.2 | ||||
* Send challenge ACK for any SYN in synchronized state. | * Send challenge ACK for any SYN in synchronized state. | ||||
*/ | */ | ||||
if ((thflags & TH_SYN) && tp->t_state != TCPS_SYN_SENT) { | if ((thflags & TH_SYN) && tp->t_state != TCPS_SYN_SENT && | ||||
tp->t_state != TCPS_SYN_RECEIVED) { | |||||
KASSERT(ti_locked == TI_RLOCKED, | KASSERT(ti_locked == TI_RLOCKED, | ||||
("tcp_do_segment: TH_SYN ti_locked %d", ti_locked)); | ("tcp_do_segment: TH_SYN ti_locked %d", ti_locked)); | ||||
INP_INFO_RLOCK_ASSERT(&V_tcbinfo); | INP_INFO_RLOCK_ASSERT(&V_tcbinfo); | ||||
TCPSTAT_INC(tcps_badsyn); | TCPSTAT_INC(tcps_badsyn); | ||||
if (V_tcp_insecure_syn && | if (V_tcp_insecure_syn && | ||||
SEQ_GEQ(th->th_seq, tp->last_ack_sent) && | SEQ_GEQ(th->th_seq, tp->last_ack_sent) && | ||||
SEQ_LT(th->th_seq, tp->last_ack_sent + tp->rcv_wnd)) { | SEQ_LT(th->th_seq, tp->last_ack_sent + tp->rcv_wnd)) { | ||||
▲ Show 20 Lines • Show All 177 Lines • ▼ Show 20 Lines | #endif | ||||
/* | /* | ||||
* If the ACK bit is off: if in SYN-RECEIVED state or SENDSYN | * If the ACK bit is off: if in SYN-RECEIVED state or SENDSYN | ||||
* flag is on (half-synchronized state), then queue data for | * flag is on (half-synchronized state), then queue data for | ||||
* later processing; else drop segment and return. | * later processing; else drop segment and return. | ||||
*/ | */ | ||||
if ((thflags & TH_ACK) == 0) { | if ((thflags & TH_ACK) == 0) { | ||||
if (tp->t_state == TCPS_SYN_RECEIVED || | if (tp->t_state == TCPS_SYN_RECEIVED || | ||||
(tp->t_flags & TF_NEEDSYN)) | (tp->t_flags & TF_NEEDSYN)) { | ||||
#ifdef TCP_RFC7413 | |||||
if (tp->t_state == TCPS_SYN_RECEIVED && | |||||
tp->t_flags & TF_FASTOPEN) { | |||||
tp->snd_wnd = tiwin; | |||||
cc_conn_init(tp); | |||||
} | |||||
#endif | |||||
goto step6; | goto step6; | ||||
else if (tp->t_flags & TF_ACKNOW) | } else if (tp->t_flags & TF_ACKNOW) | ||||
goto dropafterack; | goto dropafterack; | ||||
else | else | ||||
goto drop; | goto drop; | ||||
} | } | ||||
/* | /* | ||||
* Ack processing. | * Ack processing. | ||||
*/ | */ | ||||
Show All 22 Lines | case TCPS_SYN_RECEIVED: | ||||
tp->t_starttime = ticks; | tp->t_starttime = ticks; | ||||
if (tp->t_flags & TF_NEEDFIN) { | if (tp->t_flags & TF_NEEDFIN) { | ||||
tcp_state_change(tp, TCPS_FIN_WAIT_1); | tcp_state_change(tp, TCPS_FIN_WAIT_1); | ||||
tp->t_flags &= ~TF_NEEDFIN; | tp->t_flags &= ~TF_NEEDFIN; | ||||
} else { | } else { | ||||
tcp_state_change(tp, TCPS_ESTABLISHED); | tcp_state_change(tp, TCPS_ESTABLISHED); | ||||
TCP_PROBE5(accept__established, NULL, tp, | TCP_PROBE5(accept__established, NULL, tp, | ||||
mtod(m, const char *), tp, th); | mtod(m, const char *), tp, th); | ||||
#ifdef TCP_RFC7413 | |||||
if (tp->t_tfo_pending) { | |||||
tcp_fastopen_decrement_counter(tp->t_tfo_pending); | |||||
tp->t_tfo_pending = NULL; | |||||
/* | |||||
* Account for the ACK of our SYN prior to | |||||
* regular ACK processing below. | |||||
*/ | |||||
tp->snd_una++; | |||||
} | |||||
/* | |||||
* TFO connections call cc_conn_init() during SYN | |||||
* processing. Calling it again here for such | |||||
* connections is not harmless as it would undo the | |||||
* snd_cwnd reduction that occurs when a TFO SYN|ACK | |||||
* is retransmitted. | |||||
*/ | |||||
if (!(tp->t_flags & TF_FASTOPEN)) | |||||
#endif | |||||
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, 0, | ||||
▲ Show 20 Lines • Show All 531 Lines • ▼ Show 20 Lines | dodata: /* XXX */ | ||||
/* | /* | ||||
* Process the segment text, merging it into the TCP sequencing queue, | * Process the segment text, merging it into the TCP sequencing queue, | ||||
* and arranging for acknowledgment of receipt if necessary. | * and arranging for acknowledgment of receipt if necessary. | ||||
* This process logically involves adjusting tp->rcv_wnd as data | * This process logically involves adjusting tp->rcv_wnd as data | ||||
* is presented to the user (this happens in tcp_usrreq.c, | * is presented to the user (this happens in tcp_usrreq.c, | ||||
* case PRU_RCVD). If a FIN has already been received on this | * case PRU_RCVD). If a FIN has already been received on this | ||||
* connection then we just ignore the text. | * connection then we just ignore the text. | ||||
*/ | */ | ||||
if ((tlen || (thflags & TH_FIN)) && | tfo_syn = ((tp->t_state == TCPS_SYN_RECEIVED) && | ||||
(tp->t_flags & TF_FASTOPEN)); | |||||
if ((tlen || (thflags & TH_FIN) || tfo_syn) && | |||||
TCPS_HAVERCVDFIN(tp->t_state) == 0) { | TCPS_HAVERCVDFIN(tp->t_state) == 0) { | ||||
tcp_seq save_start = th->th_seq; | tcp_seq save_start = th->th_seq; | ||||
m_adj(m, drop_hdrlen); /* delayed header drop */ | m_adj(m, drop_hdrlen); /* delayed header drop */ | ||||
/* | /* | ||||
* Insert segment which includes th into TCP reassembly queue | * Insert segment which includes th into TCP reassembly queue | ||||
* with control block tp. Set thflags to whether reassembly now | * with control block tp. Set thflags to whether reassembly now | ||||
* includes a segment with FIN. This handles the common case | * includes a segment with FIN. This handles the common case | ||||
* inline (segment is the next to be received on an established | * inline (segment is the next to be received on an established | ||||
* 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) && | LIST_EMPTY(&tp->t_segq) && | ||||
TCPS_HAVEESTABLISHED(tp->t_state)) { | (TCPS_HAVEESTABLISHED(tp->t_state) || | ||||
if (DELAY_ACK(tp, tlen)) | tfo_syn)) { | ||||
if (DELAY_ACK(tp, tlen) || tfo_syn) | |||||
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); | ||||
▲ Show 20 Lines • Show All 338 Lines • ▼ Show 20 Lines | case TCPOPT_SACK: | ||||
continue; | continue; | ||||
if (flags & TO_SYN) | if (flags & TO_SYN) | ||||
continue; | continue; | ||||
to->to_flags |= TOF_SACK; | to->to_flags |= TOF_SACK; | ||||
to->to_nsacks = (optlen - 2) / TCPOLEN_SACK; | to->to_nsacks = (optlen - 2) / TCPOLEN_SACK; | ||||
to->to_sacks = cp + 2; | to->to_sacks = cp + 2; | ||||
TCPSTAT_INC(tcps_sack_rcv_blocks); | TCPSTAT_INC(tcps_sack_rcv_blocks); | ||||
break; | break; | ||||
#ifdef TCP_RFC7413 | |||||
case TCPOPT_FAST_OPEN: | |||||
if ((optlen != TCPOLEN_FAST_OPEN_EMPTY) && | |||||
(optlen < TCPOLEN_FAST_OPEN_MIN) && | |||||
(optlen > TCPOLEN_FAST_OPEN_MAX)) | |||||
continue; | |||||
if (!(flags & TO_SYN)) | |||||
continue; | |||||
if (!V_tcp_fastopen_enabled) | |||||
continue; | |||||
to->to_flags |= TOF_FASTOPEN; | |||||
to->to_tfo_len = optlen - 2; | |||||
to->to_tfo_cookie = to->to_tfo_len ? cp + 2 : NULL; | |||||
break; | |||||
#endif | |||||
default: | default: | ||||
continue; | continue; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Pull out of band byte out of a segment so | * Pull out of band byte out of a segment so | ||||
▲ Show 20 Lines • Show All 456 Lines • Show Last 20 Lines |