Changeset View
Changeset View
Standalone View
Standalone View
head/sys/netinet/tcp_output.c
Show First 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | |||||
#include <netinet/tcp.h> | #include <netinet/tcp.h> | ||||
#define TCPOUTFLAGS | #define TCPOUTFLAGS | ||||
#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 <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 | ||||
#ifdef TCPDEBUG | #ifdef TCPDEBUG | ||||
#include <netinet/tcp_debug.h> | #include <netinet/tcp_debug.h> | ||||
#endif | #endif | ||||
#ifdef TCP_OFFLOAD | #ifdef TCP_OFFLOAD | ||||
#include <netinet/tcp_offload.h> | #include <netinet/tcp_offload.h> | ||||
▲ Show 20 Lines • Show All 114 Lines • ▼ Show 20 Lines | |||||
#if defined(IPSEC) || defined(IPSEC_SUPPORT) | #if defined(IPSEC) || defined(IPSEC_SUPPORT) | ||||
unsigned ipsec_optlen = 0; | unsigned ipsec_optlen = 0; | ||||
#endif | #endif | ||||
int idle, sendalot; | int idle, sendalot; | ||||
int sack_rxmit, sack_bytes_rxmt; | int sack_rxmit, sack_bytes_rxmt; | ||||
struct sackhole *p; | struct sackhole *p; | ||||
int tso, mtu; | int tso, mtu; | ||||
struct tcpopt to; | struct tcpopt to; | ||||
#ifdef TCP_RFC7413 | |||||
unsigned int wanted_cookie = 0; | unsigned int wanted_cookie = 0; | ||||
unsigned int dont_sendalot = 0; | unsigned int dont_sendalot = 0; | ||||
#endif | |||||
#if 0 | #if 0 | ||||
int maxburst = TCP_MAXBURST; | int maxburst = TCP_MAXBURST; | ||||
#endif | #endif | ||||
#ifdef INET6 | #ifdef INET6 | ||||
struct ip6_hdr *ip6 = NULL; | struct ip6_hdr *ip6 = NULL; | ||||
int isipv6; | int isipv6; | ||||
isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV6) != 0; | isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV6) != 0; | ||||
#endif | #endif | ||||
INP_WLOCK_ASSERT(tp->t_inpcb); | INP_WLOCK_ASSERT(tp->t_inpcb); | ||||
#ifdef TCP_OFFLOAD | #ifdef TCP_OFFLOAD | ||||
if (tp->t_flags & TF_TOE) | if (tp->t_flags & TF_TOE) | ||||
return (tcp_offload_output(tp)); | return (tcp_offload_output(tp)); | ||||
#endif | #endif | ||||
#ifdef TCP_RFC7413 | |||||
/* | /* | ||||
* For TFO connections in SYN_RECEIVED, only allow the initial | * For TFO connections in SYN_RECEIVED, only allow the initial | ||||
* SYN|ACK and those sent by the retransmit timer. | * SYN|ACK and those sent by the retransmit timer. | ||||
*/ | */ | ||||
if (IS_FASTOPEN(tp->t_flags) && | if (IS_FASTOPEN(tp->t_flags) && | ||||
(tp->t_state == TCPS_SYN_RECEIVED) && | (tp->t_state == TCPS_SYN_RECEIVED) && | ||||
SEQ_GT(tp->snd_max, tp->snd_una) && /* initial SYN|ACK sent */ | SEQ_GT(tp->snd_max, tp->snd_una) && /* initial SYN|ACK sent */ | ||||
(tp->snd_nxt != tp->snd_una)) /* not a retransmit */ | (tp->snd_nxt != tp->snd_una)) /* not a retransmit */ | ||||
return (0); | return (0); | ||||
#endif | |||||
/* | /* | ||||
* Determine length of data that should be transmitted, | * Determine length of data that should be transmitted, | ||||
* and flags that will be used. | * and flags that will be used. | ||||
* If there is some data or critical controls (SYN, RST) | * If there is some data or critical controls (SYN, RST) | ||||
* to send, then transmit; otherwise, investigate further. | * to send, then transmit; otherwise, investigate further. | ||||
*/ | */ | ||||
idle = (tp->t_flags & TF_LASTIDLE) || (tp->snd_max == tp->snd_una); | idle = (tp->t_flags & TF_LASTIDLE) || (tp->snd_max == tp->snd_una); | ||||
if (idle && ticks - tp->t_rcvtime >= tp->t_rxtcur) | if (idle && ticks - tp->t_rcvtime >= tp->t_rxtcur) | ||||
▲ Show 20 Lines • Show All 169 Lines • ▼ Show 20 Lines | after_sack_rexmit: | ||||
/* | /* | ||||
* Lop off SYN bit if it has already been sent. However, if this | * Lop off SYN bit if it has already been sent. However, if this | ||||
* is SYN-SENT state and if segment contains data and if we don't | * is SYN-SENT state and if segment contains data and if we don't | ||||
* know that foreign host supports TAO, suppress sending segment. | * know that foreign host supports TAO, suppress sending segment. | ||||
*/ | */ | ||||
if ((flags & TH_SYN) && SEQ_GT(tp->snd_nxt, tp->snd_una)) { | if ((flags & TH_SYN) && SEQ_GT(tp->snd_nxt, tp->snd_una)) { | ||||
if (tp->t_state != TCPS_SYN_RECEIVED) | if (tp->t_state != TCPS_SYN_RECEIVED) | ||||
flags &= ~TH_SYN; | flags &= ~TH_SYN; | ||||
#ifdef TCP_RFC7413 | |||||
/* | /* | ||||
* When sending additional segments following a TFO SYN|ACK, | * When sending additional segments following a TFO SYN|ACK, | ||||
* do not include the SYN bit. | * do not include the SYN bit. | ||||
*/ | */ | ||||
if (IS_FASTOPEN(tp->t_flags) && | if (IS_FASTOPEN(tp->t_flags) && | ||||
(tp->t_state == TCPS_SYN_RECEIVED)) | (tp->t_state == TCPS_SYN_RECEIVED)) | ||||
flags &= ~TH_SYN; | flags &= ~TH_SYN; | ||||
#endif | |||||
off--, len++; | off--, len++; | ||||
} | } | ||||
/* | /* | ||||
* Be careful not to send data and/or FIN on SYN segments. | * Be careful not to send data and/or FIN on SYN segments. | ||||
* This measure is needed to prevent interoperability problems | * This measure is needed to prevent interoperability problems | ||||
* with not fully conformant TCP implementations. | * with not fully conformant TCP implementations. | ||||
*/ | */ | ||||
if ((flags & TH_SYN) && (tp->t_flags & TF_NOOPT)) { | if ((flags & TH_SYN) && (tp->t_flags & TF_NOOPT)) { | ||||
len = 0; | len = 0; | ||||
flags &= ~TH_FIN; | flags &= ~TH_FIN; | ||||
} | } | ||||
#ifdef TCP_RFC7413 | |||||
/* | /* | ||||
* On TFO sockets, ensure no data is sent in the following cases: | * On TFO sockets, ensure no data is sent in the following cases: | ||||
* | * | ||||
* - When retransmitting SYN|ACK on a passively-created socket | * - When retransmitting SYN|ACK on a passively-created socket | ||||
* | * | ||||
* - When retransmitting SYN on an actively created socket | * - When retransmitting SYN on an actively created socket | ||||
* | * | ||||
* - When sending a zero-length cookie (cookie request) on an | * - When sending a zero-length cookie (cookie request) on an | ||||
* actively created socket | * actively created socket | ||||
* | * | ||||
* - When the socket is in the CLOSED state (RST is being sent) | * - When the socket is in the CLOSED state (RST is being sent) | ||||
*/ | */ | ||||
if (IS_FASTOPEN(tp->t_flags) && | if (IS_FASTOPEN(tp->t_flags) && | ||||
(((flags & TH_SYN) && (tp->t_rxtshift > 0)) || | (((flags & TH_SYN) && (tp->t_rxtshift > 0)) || | ||||
((tp->t_state == TCPS_SYN_SENT) && | ((tp->t_state == TCPS_SYN_SENT) && | ||||
(tp->t_tfo_client_cookie_len == 0)) || | (tp->t_tfo_client_cookie_len == 0)) || | ||||
(flags & TH_RST))) | (flags & TH_RST))) | ||||
len = 0; | len = 0; | ||||
#endif | |||||
if (len <= 0) { | if (len <= 0) { | ||||
/* | /* | ||||
* If FIN has been sent but not acked, | * If FIN has been sent but not acked, | ||||
* but we haven't been called to retransmit, | * but we haven't been called to retransmit, | ||||
* len will be < 0. Otherwise, window shrank | * len will be < 0. Otherwise, window shrank | ||||
* after we sent into it. If window shrank to 0, | * after we sent into it. If window shrank to 0, | ||||
* cancel pending retransmit, pull snd_nxt back | * cancel pending retransmit, pull snd_nxt back | ||||
* to (closed) window, and set the persist timer | * to (closed) window, and set the persist timer | ||||
▲ Show 20 Lines • Show All 287 Lines • ▼ Show 20 Lines | #endif | ||||
*/ | */ | ||||
to.to_flags = 0; | to.to_flags = 0; | ||||
if ((tp->t_flags & TF_NOOPT) == 0) { | if ((tp->t_flags & TF_NOOPT) == 0) { | ||||
/* Maximum segment size. */ | /* Maximum segment size. */ | ||||
if (flags & TH_SYN) { | if (flags & TH_SYN) { | ||||
tp->snd_nxt = tp->iss; | tp->snd_nxt = tp->iss; | ||||
to.to_mss = tcp_mssopt(&tp->t_inpcb->inp_inc); | to.to_mss = tcp_mssopt(&tp->t_inpcb->inp_inc); | ||||
to.to_flags |= TOF_MSS; | to.to_flags |= TOF_MSS; | ||||
#ifdef TCP_RFC7413 | |||||
/* | /* | ||||
* On SYN or SYN|ACK transmits on TFO connections, | * On SYN or SYN|ACK transmits on TFO connections, | ||||
* only include the TFO option if it is not a | * only include the TFO option if it is not a | ||||
* retransmit, as the presence of the TFO option may | * retransmit, as the presence of the TFO option may | ||||
* have caused the original SYN or SYN|ACK to have | * have caused the original SYN or SYN|ACK to have | ||||
* been dropped by a middlebox. | * been dropped by a middlebox. | ||||
*/ | */ | ||||
if (IS_FASTOPEN(tp->t_flags) && | if (IS_FASTOPEN(tp->t_flags) && | ||||
Show All 16 Lines | if (flags & TH_SYN) { | ||||
* send with the SYN than can fit in | * send with the SYN than can fit in | ||||
* one segment, don't send any more | * one segment, don't send any more | ||||
* until the SYN|ACK comes back from | * until the SYN|ACK comes back from | ||||
* the other end. | * the other end. | ||||
*/ | */ | ||||
dont_sendalot = 1; | dont_sendalot = 1; | ||||
} | } | ||||
} | } | ||||
#endif | |||||
} | } | ||||
/* Window scaling. */ | /* Window scaling. */ | ||||
if ((flags & TH_SYN) && (tp->t_flags & TF_REQ_SCALE)) { | if ((flags & TH_SYN) && (tp->t_flags & TF_REQ_SCALE)) { | ||||
to.to_wscale = tp->request_r_scale; | to.to_wscale = tp->request_r_scale; | ||||
to.to_flags |= TOF_SCALE; | to.to_flags |= TOF_SCALE; | ||||
} | } | ||||
/* Timestamps. */ | /* Timestamps. */ | ||||
if ((tp->t_flags & TF_RCVD_TSTMP) || | if ((tp->t_flags & TF_RCVD_TSTMP) || | ||||
Show All 27 Lines | #if defined(IPSEC_SUPPORT) || defined(TCP_SIGNATURE) | ||||
* account the size needed to set this TCP option. | * account the size needed to set this TCP option. | ||||
*/ | */ | ||||
if (tp->t_flags & TF_SIGNATURE) | if (tp->t_flags & TF_SIGNATURE) | ||||
to.to_flags |= TOF_SIGNATURE; | to.to_flags |= TOF_SIGNATURE; | ||||
#endif /* TCP_SIGNATURE */ | #endif /* TCP_SIGNATURE */ | ||||
/* Processing the options. */ | /* Processing the options. */ | ||||
hdrlen += optlen = tcp_addoptions(&to, opt); | hdrlen += optlen = tcp_addoptions(&to, opt); | ||||
#ifdef TCP_RFC7413 | |||||
/* | /* | ||||
* If we wanted a TFO option to be added, but it was unable | * If we wanted a TFO option to be added, but it was unable | ||||
* to fit, ensure no data is sent. | * to fit, ensure no data is sent. | ||||
*/ | */ | ||||
if (IS_FASTOPEN(tp->t_flags) && wanted_cookie && | if (IS_FASTOPEN(tp->t_flags) && wanted_cookie && | ||||
!(to.to_flags & TOF_FASTOPEN)) | !(to.to_flags & TOF_FASTOPEN)) | ||||
len = 0; | len = 0; | ||||
#endif | |||||
} | } | ||||
/* | /* | ||||
* Adjust data length if insertion of options will | * Adjust data length if insertion of options will | ||||
* bump the packet length beyond the t_maxseg length. | * bump the packet length beyond the t_maxseg length. | ||||
* Clear the FIN bit because we cut off the tail of | * Clear the FIN bit because we cut off the tail of | ||||
* the segment. | * the segment. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 128 Lines • ▼ Show 20 Lines | if (tso) { | ||||
* last segment. | * last segment. | ||||
*/ | */ | ||||
if (tp->t_flags & TF_NEEDFIN) | if (tp->t_flags & TF_NEEDFIN) | ||||
sendalot = 1; | sendalot = 1; | ||||
} else { | } else { | ||||
len = tp->t_maxseg - optlen - ipoptlen; | len = tp->t_maxseg - optlen - ipoptlen; | ||||
sendalot = 1; | sendalot = 1; | ||||
#ifdef TCP_RFC7413 | |||||
if (dont_sendalot) | if (dont_sendalot) | ||||
sendalot = 0; | sendalot = 0; | ||||
#endif | |||||
} | } | ||||
} else | } else | ||||
tso = 0; | tso = 0; | ||||
KASSERT(len + hdrlen + ipoptlen <= IP_MAXPACKET, | KASSERT(len + hdrlen + ipoptlen <= IP_MAXPACKET, | ||||
("%s: len > IP_MAXPACKET", __func__)); | ("%s: len > IP_MAXPACKET", __func__)); | ||||
/*#ifdef DIAGNOSTIC*/ | /*#ifdef DIAGNOSTIC*/ | ||||
▲ Show 20 Lines • Show All 787 Lines • ▼ Show 20 Lines | case TOF_SACK: | ||||
bcopy((u_char *)&sack_seq, optp, sizeof(sack_seq)); | bcopy((u_char *)&sack_seq, optp, sizeof(sack_seq)); | ||||
optp += sizeof(sack_seq); | optp += sizeof(sack_seq); | ||||
optlen += TCPOLEN_SACK; | optlen += TCPOLEN_SACK; | ||||
sack++; | sack++; | ||||
} | } | ||||
TCPSTAT_INC(tcps_sack_send_blocks); | TCPSTAT_INC(tcps_sack_send_blocks); | ||||
break; | break; | ||||
} | } | ||||
#ifdef TCP_RFC7413 | |||||
case TOF_FASTOPEN: | case TOF_FASTOPEN: | ||||
{ | { | ||||
int total_len; | int total_len; | ||||
/* XXX is there any point to aligning this option? */ | /* XXX is there any point to aligning this option? */ | ||||
total_len = TCPOLEN_FAST_OPEN_EMPTY + to->to_tfo_len; | total_len = TCPOLEN_FAST_OPEN_EMPTY + to->to_tfo_len; | ||||
if (TCP_MAXOLEN - optlen < total_len) { | if (TCP_MAXOLEN - optlen < total_len) { | ||||
to->to_flags &= ~TOF_FASTOPEN; | to->to_flags &= ~TOF_FASTOPEN; | ||||
continue; | continue; | ||||
} | } | ||||
*optp++ = TCPOPT_FAST_OPEN; | *optp++ = TCPOPT_FAST_OPEN; | ||||
*optp++ = total_len; | *optp++ = total_len; | ||||
if (to->to_tfo_len > 0) { | if (to->to_tfo_len > 0) { | ||||
bcopy(to->to_tfo_cookie, optp, to->to_tfo_len); | bcopy(to->to_tfo_cookie, optp, to->to_tfo_len); | ||||
optp += to->to_tfo_len; | optp += to->to_tfo_len; | ||||
} | } | ||||
optlen += total_len; | optlen += total_len; | ||||
break; | break; | ||||
} | } | ||||
#endif | |||||
default: | default: | ||||
panic("%s: unknown TCP option type", __func__); | panic("%s: unknown TCP option type", __func__); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
/* Terminate and pad TCP options to a 4 byte boundary. */ | /* Terminate and pad TCP options to a 4 byte boundary. */ | ||||
if (optlen % 4) { | if (optlen % 4) { | ||||
▲ Show 20 Lines • Show All 76 Lines • Show Last 20 Lines |