Changeset View
Changeset View
Standalone View
Standalone View
head/sys/netinet/tcp_input.c
Show First 20 Lines • Show All 102 Lines • ▼ Show 20 Lines | |||||
#include <netinet/tcp.h> | #include <netinet/tcp.h> | ||||
#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> | ||||
#include <netinet/cc/cc.h> | #include <netinet/cc/cc.h> | ||||
#ifdef TCP_RFC7413 | |||||
#include <netinet/tcp_fastopen.h> | #include <netinet/tcp_fastopen.h> | ||||
#endif | |||||
#ifdef TCPPCAP | #ifdef TCPPCAP | ||||
#include <netinet/tcp_pcap.h> | #include <netinet/tcp_pcap.h> | ||||
#endif | #endif | ||||
#include <netinet/tcp_syncache.h> | #include <netinet/tcp_syncache.h> | ||||
#ifdef TCPDEBUG | #ifdef TCPDEBUG | ||||
#include <netinet/tcp_debug.h> | #include <netinet/tcp_debug.h> | ||||
#endif /* TCPDEBUG */ | #endif /* TCPDEBUG */ | ||||
#ifdef TCP_OFFLOAD | #ifdef TCP_OFFLOAD | ||||
▲ Show 20 Lines • Show All 1,003 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 | |||||
tfo_socket_result: | tfo_socket_result: | ||||
#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 226 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, m); | TCP_PROBE3(debug__input, tp, th, m); | ||||
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)) | if (syncache_add(&inc, &to, th, inp, &so, m, NULL, NULL)) | ||||
goto tfo_socket_result; | goto tfo_socket_result; | ||||
#else | |||||
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 153 Lines • ▼ Show 20 Lines | tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, | ||||
int thflags, acked, ourfinisacked, needoutput = 0, sack_changed; | int thflags, acked, ourfinisacked, needoutput = 0, sack_changed; | ||||
int rstreason, todrop, win; | int rstreason, todrop, win; | ||||
uint32_t tiwin; | uint32_t tiwin; | ||||
uint16_t nsegs; | uint16_t nsegs; | ||||
char *s; | char *s; | ||||
struct in_conninfo *inc; | struct in_conninfo *inc; | ||||
struct mbuf *mfree; | struct mbuf *mfree; | ||||
struct tcpopt to; | struct tcpopt to; | ||||
#ifdef TCP_RFC7413 | |||||
int tfo_syn; | int tfo_syn; | ||||
#endif | |||||
#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; | ||||
▲ Show 20 Lines • Show All 148 Lines • ▼ Show 20 Lines | if (to.to_flags & TOF_TS) { | ||||
tp->ts_recent = to.to_tsval; | tp->ts_recent = to.to_tsval; | ||||
tp->ts_recent_age = tcp_ts_getticks(); | tp->ts_recent_age = tcp_ts_getticks(); | ||||
} | } | ||||
if (to.to_flags & TOF_MSS) | if (to.to_flags & TOF_MSS) | ||||
tcp_mss(tp, to.to_mss); | tcp_mss(tp, to.to_mss); | ||||
if ((tp->t_flags & TF_SACK_PERMIT) && | if ((tp->t_flags & TF_SACK_PERMIT) && | ||||
(to.to_flags & TOF_SACKPERM) == 0) | (to.to_flags & TOF_SACKPERM) == 0) | ||||
tp->t_flags &= ~TF_SACK_PERMIT; | tp->t_flags &= ~TF_SACK_PERMIT; | ||||
#ifdef TCP_RFC7413 | |||||
if (IS_FASTOPEN(tp->t_flags)) { | if (IS_FASTOPEN(tp->t_flags)) { | ||||
if (to.to_flags & TOF_FASTOPEN) | if (to.to_flags & TOF_FASTOPEN) | ||||
tcp_fastopen_update_cache(tp, to.to_mss, | tcp_fastopen_update_cache(tp, to.to_mss, | ||||
to.to_tfo_len, to.to_tfo_cookie); | to.to_tfo_len, to.to_tfo_cookie); | ||||
else | else | ||||
tcp_fastopen_disable_path(tp); | tcp_fastopen_disable_path(tp); | ||||
} | } | ||||
#endif | |||||
} | } | ||||
/* | /* | ||||
* If timestamps were negotiated during SYN/ACK they should | * If timestamps were negotiated during SYN/ACK they should | ||||
* appear on every segment during this session and vice versa. | * appear on every segment during this session and vice versa. | ||||
*/ | */ | ||||
if ((tp->t_flags & TF_RCVD_TSTMP) && !(to.to_flags & TOF_TS)) { | if ((tp->t_flags & TF_RCVD_TSTMP) && !(to.to_flags & TOF_TS)) { | ||||
if ((s = tcp_log_addrs(inc, th, NULL, NULL))) { | if ((s = tcp_log_addrs(inc, th, NULL, NULL))) { | ||||
▲ Show 20 Lines • Show All 241 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 (IS_FASTOPEN(tp->t_flags)) { | if (IS_FASTOPEN(tp->t_flags)) { | ||||
/* | /* | ||||
* When a TFO connection is in SYN_RECEIVED, the | * When a TFO connection is in SYN_RECEIVED, the | ||||
* only valid packets are the initial SYN, a | * only valid packets are the initial SYN, a | ||||
* retransmit/copy of the initial SYN (possibly with | * retransmit/copy of the initial SYN (possibly with | ||||
* a subset of the original data), a valid ACK, a | * a subset of the original data), a valid ACK, a | ||||
* FIN, or a RST. | * FIN, or a RST. | ||||
*/ | */ | ||||
if ((thflags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) { | if ((thflags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) { | ||||
rstreason = BANDLIM_RST_OPENPORT; | rstreason = BANDLIM_RST_OPENPORT; | ||||
goto dropwithreset; | goto dropwithreset; | ||||
} else if (thflags & TH_SYN) { | } else if (thflags & TH_SYN) { | ||||
/* non-initial SYN is ignored */ | /* non-initial SYN is ignored */ | ||||
if ((tcp_timer_active(tp, TT_DELACK) || | if ((tcp_timer_active(tp, TT_DELACK) || | ||||
tcp_timer_active(tp, TT_REXMT))) | tcp_timer_active(tp, TT_REXMT))) | ||||
goto drop; | goto drop; | ||||
} else if (!(thflags & (TH_ACK|TH_FIN|TH_RST))) { | } else if (!(thflags & (TH_ACK|TH_FIN|TH_RST))) { | ||||
goto drop; | goto drop; | ||||
} | } | ||||
} | } | ||||
#endif | |||||
break; | break; | ||||
/* | /* | ||||
* If the state is SYN_SENT: | * If the state is SYN_SENT: | ||||
* if seg contains a RST with valid ACK (SEQ.ACK has already | * if seg contains a RST with valid ACK (SEQ.ACK has already | ||||
* been verified), then drop the connection. | * been verified), then drop the connection. | ||||
* if seg contains a RST without an ACK, drop the seg. | * if seg contains a RST without an ACK, drop the seg. | ||||
* if seg does not contain SYN, then drop the seg. | * if seg does not contain SYN, then drop the seg. | ||||
▲ Show 20 Lines • Show All 402 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 && | if (tp->t_state == TCPS_SYN_RECEIVED && | ||||
IS_FASTOPEN(tp->t_flags)) { | IS_FASTOPEN(tp->t_flags)) { | ||||
tp->snd_wnd = tiwin; | tp->snd_wnd = tiwin; | ||||
cc_conn_init(tp); | 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; | ||||
} | } | ||||
/* | /* | ||||
Show All 24 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, | ||||
m, tp, th); | m, tp, th); | ||||
#ifdef TCP_RFC7413 | if (IS_FASTOPEN(tp->t_flags) && tp->t_tfo_pending) { | ||||
if (tp->t_tfo_pending) { | |||||
tcp_fastopen_decrement_counter(tp->t_tfo_pending); | tcp_fastopen_decrement_counter(tp->t_tfo_pending); | ||||
tp->t_tfo_pending = NULL; | tp->t_tfo_pending = NULL; | ||||
/* | /* | ||||
* Account for the ACK of our SYN prior to | * Account for the ACK of our SYN prior to | ||||
* regular ACK processing below. | * regular ACK processing below. | ||||
*/ | */ | ||||
tp->snd_una++; | tp->snd_una++; | ||||
} | } | ||||
/* | /* | ||||
* TFO connections call cc_conn_init() during SYN | * TFO connections call cc_conn_init() during SYN | ||||
* processing. Calling it again here for such | * processing. Calling it again here for such | ||||
* connections is not harmless as it would undo the | * connections is not harmless as it would undo the | ||||
* snd_cwnd reduction that occurs when a TFO SYN|ACK | * snd_cwnd reduction that occurs when a TFO SYN|ACK | ||||
* is retransmitted. | * is retransmitted. | ||||
*/ | */ | ||||
if (!IS_FASTOPEN(tp->t_flags)) | if (!IS_FASTOPEN(tp->t_flags)) | ||||
#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) | ||||
▲ Show 20 Lines • Show All 549 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. | ||||
*/ | */ | ||||
#ifdef TCP_RFC7413 | |||||
tfo_syn = ((tp->t_state == TCPS_SYN_RECEIVED) && | tfo_syn = ((tp->t_state == TCPS_SYN_RECEIVED) && | ||||
IS_FASTOPEN(tp->t_flags)); | IS_FASTOPEN(tp->t_flags)); | ||||
#else | |||||
#define tfo_syn (false) | |||||
#endif | |||||
if ((tlen || (thflags & TH_FIN) || tfo_syn) && | 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 | ||||
▲ Show 20 Lines • Show All 207 Lines • ▼ Show 20 Lines | #ifdef TCPDEBUG | ||||
if (tp == NULL || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) | if (tp == NULL || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) | ||||
tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, | tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, | ||||
&tcp_savetcp, 0); | &tcp_savetcp, 0); | ||||
#endif | #endif | ||||
TCP_PROBE3(debug__input, tp, th, m); | TCP_PROBE3(debug__input, tp, th, m); | ||||
if (tp != NULL) | if (tp != NULL) | ||||
INP_WUNLOCK(tp->t_inpcb); | INP_WUNLOCK(tp->t_inpcb); | ||||
m_freem(m); | m_freem(m); | ||||
#ifndef TCP_RFC7413 | |||||
#undef tfo_syn | |||||
#endif | |||||
} | } | ||||
/* | /* | ||||
* Issue RST and make ACK acceptable to originator of segment. | * Issue RST and make ACK acceptable to originator of segment. | ||||
* The mbuf must still include the original packet header. | * The mbuf must still include the original packet header. | ||||
* tp may be NULL. | * tp may be NULL. | ||||
*/ | */ | ||||
void | void | ||||
▲ Show 20 Lines • Show All 137 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: | case TCPOPT_FAST_OPEN: | ||||
/* | /* | ||||
* Cookie length validation is performed by the | * Cookie length validation is performed by the | ||||
* server side cookie checking code or the client | * server side cookie checking code or the client | ||||
* side cookie cache update code. | * side cookie cache update code. | ||||
*/ | */ | ||||
if (!(flags & TO_SYN)) | if (!(flags & TO_SYN)) | ||||
continue; | continue; | ||||
if (!V_tcp_fastopen_client_enable && | if (!V_tcp_fastopen_client_enable && | ||||
!V_tcp_fastopen_server_enable) | !V_tcp_fastopen_server_enable) | ||||
continue; | continue; | ||||
to->to_flags |= TOF_FASTOPEN; | to->to_flags |= TOF_FASTOPEN; | ||||
to->to_tfo_len = optlen - 2; | to->to_tfo_len = optlen - 2; | ||||
to->to_tfo_cookie = to->to_tfo_len ? cp + 2 : NULL; | to->to_tfo_cookie = to->to_tfo_len ? cp + 2 : NULL; | ||||
break; | 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 445 Lines • Show Last 20 Lines |