Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_input.c
Show First 20 Lines • Show All 94 Lines • ▼ Show 20 Lines | |||||
#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/in6_var.h> | #include <netinet6/in6_var.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.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> | |||||
#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,589 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 (to.to_flags & TOF_FASTOPEN) | |||||
tcp_fastopen_update_cache(tp, to.to_mss, | |||||
to.to_tfo_len, to.to_tfo_cookie); | |||||
else | |||||
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))) { | ||||
log(LOG_DEBUG, "%s; %s: Timestamp missing, " | log(LOG_DEBUG, "%s; %s: Timestamp missing, " | ||||
▲ Show 20 Lines • Show All 293 Lines • ▼ Show 20 Lines | case TCPS_SYN_SENT: | ||||
if (thflags & TH_RST) | if (thflags & TH_RST) | ||||
goto drop; | goto drop; | ||||
if (!(thflags & TH_SYN)) | if (!(thflags & TH_SYN)) | ||||
goto drop; | goto drop; | ||||
tp->irs = th->th_seq; | tp->irs = th->th_seq; | ||||
tcp_rcvseqinit(tp); | tcp_rcvseqinit(tp); | ||||
if (thflags & TH_ACK) { | if (thflags & TH_ACK) { | ||||
int tfo_partial_ack = 0; | |||||
TCPSTAT_INC(tcps_connects); | TCPSTAT_INC(tcps_connects); | ||||
soisconnected(so); | soisconnected(so); | ||||
#ifdef MAC | #ifdef MAC | ||||
mac_socketpeer_set_from_mbuf(m, so); | mac_socketpeer_set_from_mbuf(m, so); | ||||
#endif | #endif | ||||
/* Do window scaling on this connection? */ | /* Do window scaling on this connection? */ | ||||
if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == | if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == | ||||
(TF_RCVD_SCALE|TF_REQ_SCALE)) { | (TF_RCVD_SCALE|TF_REQ_SCALE)) { | ||||
tp->rcv_scale = tp->request_r_scale; | tp->rcv_scale = tp->request_r_scale; | ||||
} | } | ||||
tp->rcv_adv += min(tp->rcv_wnd, | tp->rcv_adv += min(tp->rcv_wnd, | ||||
TCP_MAXWIN << tp->rcv_scale); | TCP_MAXWIN << tp->rcv_scale); | ||||
tp->snd_una++; /* SYN is acked */ | tp->snd_una++; /* SYN is acked */ | ||||
/* | /* | ||||
* If not all the data that was sent in the TFO SYN | |||||
* has been acked, resend the remainder right away. | |||||
*/ | |||||
if (IS_FASTOPEN(tp->t_flags) && | |||||
(tp->snd_una != tp->snd_max)) { | |||||
tp->snd_nxt = th->th_ack; | |||||
tfo_partial_ack = 1; | |||||
} | |||||
/* | |||||
* If there's data, delay ACK; if there's also a FIN | * If there's data, delay ACK; if there's also a FIN | ||||
* ACKNOW will be turned on later. | * ACKNOW will be turned on later. | ||||
*/ | */ | ||||
if (DELAY_ACK(tp, tlen) && tlen != 0) | if (DELAY_ACK(tp, tlen) && tlen != 0 && !tfo_partial_ack) | ||||
tcp_timer_activate(tp, TT_DELACK, | tcp_timer_activate(tp, TT_DELACK, | ||||
tcp_delacktime); | tcp_delacktime); | ||||
else | else | ||||
tp->t_flags |= TF_ACKNOW; | tp->t_flags |= TF_ACKNOW; | ||||
if ((thflags & TH_ECE) && V_tcp_do_ecn) { | if ((thflags & TH_ECE) && V_tcp_do_ecn) { | ||||
tp->t_flags |= TF_ECN_PERMIT; | tp->t_flags |= TF_ECN_PERMIT; | ||||
TCPSTAT_INC(tcps_ecn_shs); | TCPSTAT_INC(tcps_ecn_shs); | ||||
▲ Show 20 Lines • Show All 1,360 Lines • ▼ Show 20 Lines | case TCPOPT_SACK: | ||||
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 | #ifdef TCP_RFC7413 | ||||
case TCPOPT_FAST_OPEN: | case TCPOPT_FAST_OPEN: | ||||
if ((optlen != TCPOLEN_FAST_OPEN_EMPTY) && | /* | ||||
tuexen: I guess the above condition should read:
```
if ((optlen != TCPOLEN_FAST_OPEN_EMPTY) &&… | |||||
Not Done Inline ActionsOr maybe the answer is to minimize further or remove this check/continue altogether as the full validation/ignore is really part of the cookie checking code. pkelsey: Or maybe the answer is to minimize further or remove this check/continue altogether as the full… | |||||
Not Done Inline ActionsThat can also be done. I saw redundant code in the cookie handling. Then you only need to make sure that optlen >= 2. tuexen: That can also be done. I saw redundant code in the cookie handling. Then you only need to make… | |||||
(optlen < TCPOLEN_FAST_OPEN_MIN) && | * Cookie length validation is performed by the | ||||
(optlen > TCPOLEN_FAST_OPEN_MAX)) | * server side cookie checking code or the client | ||||
continue; | * side cookie cache update code. | ||||
*/ | |||||
if (!(flags & TO_SYN)) | if (!(flags & TO_SYN)) | ||||
continue; | continue; | ||||
if (!V_tcp_fastopen_enabled) | if (!V_tcp_fastopen_client_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 | #endif | ||||
default: | default: | ||||
continue; | continue; | ||||
▲ Show 20 Lines • Show All 451 Lines • Show Last 20 Lines |
I guess the above condition should read:
since TCP FO options with invalid length MUST be ignored. So there is a logical error in the condition and the test for the length being odd was missing.