Changeset View
Changeset View
Standalone View
Standalone View
head/sys/netinet/tcp_output.c
Show First 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | |||||
#include <netinet/in_pcb.h> | #include <netinet/in_pcb.h> | ||||
#include <netinet/ip_var.h> | #include <netinet/ip_var.h> | ||||
#include <netinet/ip_options.h> | #include <netinet/ip_options.h> | ||||
#ifdef INET6 | #ifdef INET6 | ||||
#include <netinet6/in6_pcb.h> | #include <netinet6/in6_pcb.h> | ||||
#include <netinet/ip6.h> | #include <netinet/ip6.h> | ||||
#include <netinet6/ip6_var.h> | #include <netinet6/ip6_var.h> | ||||
#endif | #endif | ||||
#ifdef TCP_RFC7413 | |||||
#include <netinet/tcp_fastopen.h> | |||||
#endif | |||||
#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> | ||||
#ifdef TCPPCAP | #ifdef TCPPCAP | ||||
#include <netinet/tcp_pcap.h> | #include <netinet/tcp_pcap.h> | ||||
▲ Show 20 Lines • Show All 120 Lines • ▼ Show 20 Lines | #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 | |||||
* SYN|ACK and those sent by the retransmit timer. | |||||
*/ | |||||
if ((tp->t_flags & TF_FASTOPEN) && | |||||
(tp->t_state == TCPS_SYN_RECEIVED) && | |||||
SEQ_GT(tp->snd_max, tp->snd_una) && /* inital SYN|ACK sent */ | |||||
(tp->snd_nxt != tp->snd_una)) /* not a retransmit */ | |||||
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) | ||||
cc_after_idle(tp); | cc_after_idle(tp); | ||||
▲ 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, | |||||
* do not include the SYN bit. | |||||
*/ | |||||
if ((tp->t_flags & TF_FASTOPEN) && | |||||
(tp->t_state == TCPS_SYN_RECEIVED)) | |||||
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 | |||||
/* | |||||
* When retransmitting SYN|ACK on a passively-created TFO socket, | |||||
* don't include data, as the presence of data may have caused the | |||||
* original SYN|ACK to have been dropped by a middlebox. | |||||
*/ | |||||
if ((tp->t_flags & TF_FASTOPEN) && | |||||
(((tp->t_state == TCPS_SYN_RECEIVED) && (tp->t_rxtshift > 0)) || | |||||
(flags & TH_RST))) | |||||
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 306 Lines • ▼ Show 20 Lines | #endif | ||||
*/ | */ | ||||
if ((tp->t_flags & TF_NOOPT) == 0) { | if ((tp->t_flags & TF_NOOPT) == 0) { | ||||
to.to_flags = 0; | to.to_flags = 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 | |||||
/* | |||||
* Only include the TFO option on the first | |||||
* transmission of the SYN|ACK on a | |||||
* passively-created TFO socket, as the presence of | |||||
* the TFO option may have caused the original | |||||
* SYN|ACK to have been dropped by a middlebox. | |||||
*/ | |||||
if ((tp->t_flags & TF_FASTOPEN) && | |||||
(tp->t_state == TCPS_SYN_RECEIVED) && | |||||
(tp->t_rxtshift == 0)) { | |||||
to.to_tfo_len = TCP_FASTOPEN_COOKIE_LEN; | |||||
to.to_tfo_cookie = (u_char *)&tp->t_tfo_cookie; | |||||
to.to_flags |= TOF_FASTOPEN; | |||||
} | } | ||||
#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) || | ||||
((flags & TH_SYN) && (tp->t_flags & TF_REQ_TSTMP))) { | ((flags & TH_SYN) && (tp->t_flags & TF_REQ_TSTMP))) { | ||||
▲ Show 20 Lines • Show All 262 Lines • ▼ Show 20 Lines | #endif | ||||
} | } | ||||
/* | /* | ||||
* If we're sending everything we've got, set PUSH. | * If we're sending everything we've got, set PUSH. | ||||
* (This will keep happy those implementations which only | * (This will keep happy those implementations which only | ||||
* give data to the user when a buffer fills or | * give data to the user when a buffer fills or | ||||
* a PUSH comes in.) | * a PUSH comes in.) | ||||
*/ | */ | ||||
if (off + len == sbused(&so->so_snd)) | if ((off + len == sbused(&so->so_snd)) && !(flags & TH_SYN)) | ||||
flags |= TH_PUSH; | flags |= TH_PUSH; | ||||
SOCKBUF_UNLOCK(&so->so_snd); | SOCKBUF_UNLOCK(&so->so_snd); | ||||
} else { | } else { | ||||
SOCKBUF_UNLOCK(&so->so_snd); | SOCKBUF_UNLOCK(&so->so_snd); | ||||
if (tp->t_flags & TF_ACKNOW) | if (tp->t_flags & TF_ACKNOW) | ||||
TCPSTAT_INC(tcps_sndacks); | TCPSTAT_INC(tcps_sndacks); | ||||
else if (flags & (TH_SYN|TH_FIN|TH_RST)) | else if (flags & (TH_SYN|TH_FIN|TH_RST)) | ||||
TCPSTAT_INC(tcps_sndctrl); | TCPSTAT_INC(tcps_sndctrl); | ||||
▲ Show 20 Lines • Show All 690 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: | |||||
{ | |||||
int total_len; | |||||
/* XXX is there any point to aligning this option? */ | |||||
total_len = TCPOLEN_FAST_OPEN_EMPTY + to->to_tfo_len; | |||||
if (TCP_MAXOLEN - optlen < total_len) | |||||
continue; | |||||
*optp++ = TCPOPT_FAST_OPEN; | |||||
*optp++ = total_len; | |||||
if (to->to_tfo_len > 0) { | |||||
bcopy(to->to_tfo_cookie, optp, to->to_tfo_len); | |||||
optp += to->to_tfo_len; | |||||
} | |||||
optlen += total_len; | |||||
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 All 17 Lines |