Changeset View
Changeset View
Standalone View
Standalone View
head/sys/netinet/tcp_stacks/rack.c
- This file is larger than 256 KB, so syntax highlighting is disabled by default.
Show First 20 Lines • Show All 2,077 Lines • ▼ Show 20 Lines | rack_timer_start(struct tcpcb *tp, struct tcp_rack *rack, uint32_t cts) | ||||
if (rack->t_timers_stopped) { | if (rack->t_timers_stopped) { | ||||
/* All timers have been stopped none are to run */ | /* All timers have been stopped none are to run */ | ||||
return (0); | return (0); | ||||
} | } | ||||
if (rack->rc_in_persist) { | if (rack->rc_in_persist) { | ||||
/* We can't start any timer in persists */ | /* We can't start any timer in persists */ | ||||
return (rack_get_persists_timer_val(tp, rack)); | return (rack_get_persists_timer_val(tp, rack)); | ||||
} | } | ||||
if (tp->t_state < TCPS_ESTABLISHED) | |||||
goto activate_rxt; | |||||
rsm = TAILQ_FIRST(&rack->r_ctl.rc_tmap); | rsm = TAILQ_FIRST(&rack->r_ctl.rc_tmap); | ||||
if (rsm == NULL) { | if (rsm == NULL) { | ||||
/* Nothing on the send map */ | /* Nothing on the send map */ | ||||
activate_rxt: | activate_rxt: | ||||
if (SEQ_LT(tp->snd_una, tp->snd_max) || sbavail(&(tp->t_inpcb->inp_socket->so_snd))) { | if (SEQ_LT(tp->snd_una, tp->snd_max) || sbavail(&(tp->t_inpcb->inp_socket->so_snd))) { | ||||
rack->r_ctl.rc_hpts_flags |= PACE_TMR_RXT; | rack->r_ctl.rc_hpts_flags |= PACE_TMR_RXT; | ||||
to = TICKS_2_MSEC(tp->t_rxtcur); | to = TICKS_2_MSEC(tp->t_rxtcur); | ||||
if (to == 0) | if (to == 0) | ||||
▲ Show 20 Lines • Show All 1,286 Lines • ▼ Show 20 Lines | #endif | ||||
if (th_flags & TH_FIN) { | if (th_flags & TH_FIN) { | ||||
rsm->r_flags = RACK_HAS_FIN; | rsm->r_flags = RACK_HAS_FIN; | ||||
} else { | } else { | ||||
rsm->r_flags = 0; | rsm->r_flags = 0; | ||||
} | } | ||||
rsm->r_tim_lastsent[0] = ts; | rsm->r_tim_lastsent[0] = ts; | ||||
rsm->r_rtr_cnt = 1; | rsm->r_rtr_cnt = 1; | ||||
rsm->r_rtr_bytes = 0; | rsm->r_rtr_bytes = 0; | ||||
if (th_flags & TH_SYN) { | |||||
/* The data space is one beyond snd_una */ | |||||
rsm->r_start = seq_out + 1; | |||||
rsm->r_end = rsm->r_start + (len - 1); | |||||
} else { | |||||
/* Normal case */ | |||||
rsm->r_start = seq_out; | rsm->r_start = seq_out; | ||||
rsm->r_end = rsm->r_start + len; | rsm->r_end = rsm->r_start + len; | ||||
} | |||||
rsm->r_sndcnt = 0; | rsm->r_sndcnt = 0; | ||||
TAILQ_INSERT_TAIL(&rack->r_ctl.rc_map, rsm, r_next); | TAILQ_INSERT_TAIL(&rack->r_ctl.rc_map, rsm, r_next); | ||||
TAILQ_INSERT_TAIL(&rack->r_ctl.rc_tmap, rsm, r_tnext); | TAILQ_INSERT_TAIL(&rack->r_ctl.rc_tmap, rsm, r_tnext); | ||||
rsm->r_in_tmap = 1; | rsm->r_in_tmap = 1; | ||||
return; | return; | ||||
} | } | ||||
/* | /* | ||||
* If we reach here its a retransmission and we need to find it. | * If we reach here its a retransmission and we need to find it. | ||||
▲ Show 20 Lines • Show All 1,254 Lines • ▼ Show 20 Lines | rack_process_data(struct mbuf *m, struct tcphdr *th, struct socket *so, | ||||
struct tcpcb *tp, int32_t drop_hdrlen, int32_t tlen, | struct tcpcb *tp, int32_t drop_hdrlen, int32_t tlen, | ||||
int32_t * ti_locked, uint32_t tiwin, int32_t thflags, int32_t nxt_pkt) | int32_t * ti_locked, uint32_t tiwin, int32_t thflags, int32_t nxt_pkt) | ||||
{ | { | ||||
/* | /* | ||||
* Update window information. Don't look at window if no ACK: TAC's | * Update window information. Don't look at window if no ACK: TAC's | ||||
* send garbage on first SYN. | * send garbage on first SYN. | ||||
*/ | */ | ||||
int32_t nsegs; | int32_t nsegs; | ||||
#ifdef TCP_RFC7413 | |||||
int32_t tfo_syn; | int32_t tfo_syn; | ||||
#else | |||||
#define tfo_syn (FALSE) | |||||
#endif | |||||
struct tcp_rack *rack; | struct tcp_rack *rack; | ||||
rack = (struct tcp_rack *)tp->t_fb_ptr; | rack = (struct tcp_rack *)tp->t_fb_ptr; | ||||
INP_WLOCK_ASSERT(tp->t_inpcb); | INP_WLOCK_ASSERT(tp->t_inpcb); | ||||
nsegs = max(1, m->m_pkthdr.lro_nsegs); | nsegs = max(1, m->m_pkthdr.lro_nsegs); | ||||
if ((thflags & TH_ACK) && | if ((thflags & TH_ACK) && | ||||
(SEQ_LT(tp->snd_wl1, th->th_seq) || | (SEQ_LT(tp->snd_wl1, th->th_seq) || | ||||
▲ Show 20 Lines • Show All 89 Lines • ▼ Show 20 Lines | dodata: /* XXX */ | ||||
/* | /* | ||||
* Process the segment text, merging it into the TCP sequencing | * Process the segment text, merging it into the TCP sequencing | ||||
* queue, and arranging for acknowledgment of receipt if necessary. | * queue, and arranging for acknowledgment of receipt if necessary. | ||||
* This process logically involves adjusting tp->rcv_wnd as data is | * This process logically involves adjusting tp->rcv_wnd as data is | ||||
* presented to the user (this happens in tcp_usrreq.c, case | * presented to the user (this happens in tcp_usrreq.c, case | ||||
* PRU_RCVD). If a FIN has already been received on this connection | * PRU_RCVD). If a FIN has already been received on this connection | ||||
* then we just ignore the text. | * 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) && | ||||
(tp->t_flags & TF_FASTOPEN)); | IS_FASTOPEN(tp->t_flags)); | ||||
#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 | * Insert segment which includes th into TCP reassembly | ||||
* queue with control block tp. Set thflags to whether | * queue with control block tp. Set thflags to whether | ||||
▲ Show 20 Lines • Show All 450 Lines • ▼ Show 20 Lines | rack_do_syn_sent(struct mbuf *m, struct tcphdr *th, struct socket *so, | ||||
} | } | ||||
if (!(thflags & TH_SYN)) { | if (!(thflags & TH_SYN)) { | ||||
rack_do_drop(m, tp, ti_locked); | rack_do_drop(m, tp, ti_locked); | ||||
return (1); | return (1); | ||||
} | } | ||||
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 = 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); | ||||
/* | /* | ||||
* 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 = 1; | |||||
} | |||||
/* | |||||
* If there's data, delay ACK; if there's also a FIN ACKNOW | * If there's data, delay ACK; if there's also a FIN ACKNOW | ||||
* will be turned on later. | * will be turned on later. | ||||
*/ | */ | ||||
if (DELAY_ACK(tp, tlen) && tlen != 0) { | if (DELAY_ACK(tp, tlen) && tlen != 0 && (tfo_partial == 0)) { | ||||
rack_timer_cancel(tp, (struct tcp_rack *)tp->t_fb_ptr, | rack_timer_cancel(tp, (struct tcp_rack *)tp->t_fb_ptr, | ||||
((struct tcp_rack *)tp->t_fb_ptr)->r_ctl.rc_rcvtime, __LINE__); | ((struct tcp_rack *)tp->t_fb_ptr)->r_ctl.rc_rcvtime, __LINE__); | ||||
tp->t_flags |= TF_DELACK; | tp->t_flags |= TF_DELACK; | ||||
} else { | } else { | ||||
((struct tcp_rack *)tp->t_fb_ptr)->r_wanted_output++; | ((struct tcp_rack *)tp->t_fb_ptr)->r_wanted_output++; | ||||
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); | ||||
} | } | ||||
if (SEQ_GT(th->th_ack, tp->snd_una)) { | |||||
/* | /* | ||||
* We advance snd_una for the | |||||
* fast open case. If th_ack is | |||||
* acknowledging data beyond | |||||
* snd_una we can't just call | |||||
* ack-processing since the | |||||
* data stream in our send-map | |||||
* will start at snd_una + 1 (one | |||||
* beyond the SYN). If its just | |||||
* equal we don't need to do that | |||||
* and there is no send_map. | |||||
*/ | |||||
tp->snd_una++; | |||||
} | |||||
/* | |||||
* Received <SYN,ACK> in SYN_SENT[*] state. Transitions: | * Received <SYN,ACK> in SYN_SENT[*] state. Transitions: | ||||
* SYN_SENT --> ESTABLISHED SYN_SENT* --> FIN_WAIT_1 | * SYN_SENT --> ESTABLISHED SYN_SENT* --> FIN_WAIT_1 | ||||
*/ | */ | ||||
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; | ||||
thflags &= ~TH_SYN; | thflags &= ~TH_SYN; | ||||
▲ Show 20 Lines • Show All 92 Lines • ▼ Show 20 Lines | rack_do_syn_recv(struct mbuf *m, struct tcphdr *th, struct socket *so, | ||||
rack_calc_rwin(so, tp); | rack_calc_rwin(so, tp); | ||||
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))) { | ||||
rack_do_dropwithreset(m, tp, th, ti_locked, BANDLIM_RST_OPENPORT, tlen); | rack_do_dropwithreset(m, tp, th, ti_locked, BANDLIM_RST_OPENPORT, tlen); | ||||
return (1); | return (1); | ||||
} | } | ||||
#ifdef TCP_RFC7413 | if (IS_FASTOPEN(tp->t_flags)) { | ||||
if (tp->t_flags & TF_FASTOPEN) { | |||||
/* | /* | ||||
* When a TFO connection is in SYN_RECEIVED, the only valid | * When a TFO connection is in SYN_RECEIVED, the | ||||
* packets are the initial SYN, a retransmit/copy of the | * only valid packets are the initial SYN, a | ||||
* initial SYN (possibly with a subset of the original | * retransmit/copy of the initial SYN (possibly with | ||||
* data), a valid ACK, a FIN, or a RST. | * a subset of the original data), a valid ACK, a | ||||
* FIN, or a RST. | |||||
*/ | */ | ||||
if ((thflags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) { | if ((thflags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) { | ||||
rack_do_dropwithreset(m, tp, th, ti_locked, BANDLIM_RST_OPENPORT, tlen); | rack_do_dropwithreset(m, tp, th, ti_locked, BANDLIM_RST_OPENPORT, tlen); | ||||
return (1); | return (1); | ||||
} else if (thflags & TH_SYN) { | } else if (thflags & TH_SYN) { | ||||
/* non-initial SYN is ignored */ | /* non-initial SYN is ignored */ | ||||
struct tcp_rack *rack; | struct tcp_rack *rack; | ||||
rack = (struct tcp_rack *)tp->t_fb_ptr; | rack = (struct tcp_rack *)tp->t_fb_ptr; | ||||
if ((rack->r_ctl.rc_hpts_flags & PACE_TMR_RXT) || | if ((rack->r_ctl.rc_hpts_flags & PACE_TMR_RXT) || | ||||
(rack->r_ctl.rc_hpts_flags & PACE_TMR_TLP) || | (rack->r_ctl.rc_hpts_flags & PACE_TMR_TLP) || | ||||
(rack->r_ctl.rc_hpts_flags & PACE_TMR_RACK)) { | (rack->r_ctl.rc_hpts_flags & PACE_TMR_RACK)) { | ||||
rack_do_drop(m, NULL, ti_locked); | rack_do_drop(m, NULL, ti_locked); | ||||
return (0); | return (0); | ||||
} | } | ||||
} else if (!(thflags & (TH_ACK | TH_FIN | TH_RST))) { | } else if (!(thflags & (TH_ACK | TH_FIN | TH_RST))) { | ||||
rack_do_drop(m, NULL, ti_locked); | rack_do_drop(m, NULL, ti_locked); | ||||
return (0); | return (0); | ||||
} | } | ||||
} | } | ||||
#endif | |||||
if (thflags & TH_RST) | if (thflags & TH_RST) | ||||
return (rack_process_rst(m, th, so, tp, ti_locked)); | return (rack_process_rst(m, th, so, tp, ti_locked)); | ||||
/* | /* | ||||
* RFC5961 Section 4.2 Send challenge ACK for any SYN in | * RFC5961 Section 4.2 Send challenge ACK for any SYN in | ||||
* synchronized state. | * synchronized state. | ||||
*/ | */ | ||||
if (thflags & TH_SYN) { | if (thflags & TH_SYN) { | ||||
rack_challenge_ack(m, th, tp, ti_locked, &ret_val); | rack_challenge_ack(m, th, tp, ti_locked, &ret_val); | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | if ((to->to_flags & TOF_TS) != 0 && | ||||
tp->ts_recent = to->to_tsval; | tp->ts_recent = to->to_tsval; | ||||
} | } | ||||
/* | /* | ||||
* If the ACK bit is off: if in SYN-RECEIVED state or SENDSYN flag | * If the ACK bit is off: if in SYN-RECEIVED state or SENDSYN flag | ||||
* is on (half-synchronized state), then queue data for later | * is on (half-synchronized state), then queue data for later | ||||
* processing; else drop segment and return. | * processing; else drop segment and return. | ||||
*/ | */ | ||||
if ((thflags & TH_ACK) == 0) { | if ((thflags & TH_ACK) == 0) { | ||||
#ifdef TCP_RFC7413 | if (IS_FASTOPEN(tp->t_flags)) { | ||||
if (tp->t_flags & TF_FASTOPEN) { | |||||
tp->snd_wnd = tiwin; | tp->snd_wnd = tiwin; | ||||
cc_conn_init(tp); | cc_conn_init(tp); | ||||
} | } | ||||
#endif | |||||
return (rack_process_data(m, th, so, tp, drop_hdrlen, tlen, | return (rack_process_data(m, th, so, tp, drop_hdrlen, tlen, | ||||
ti_locked, tiwin, thflags, nxt_pkt)); | ti_locked, tiwin, thflags, nxt_pkt)); | ||||
} | } | ||||
TCPSTAT_INC(tcps_connects); | TCPSTAT_INC(tcps_connects); | ||||
soisconnected(so); | soisconnected(so); | ||||
/* Do window scaling? */ | /* Do window scaling? */ | ||||
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->snd_wnd = tiwin; | tp->snd_wnd = tiwin; | ||||
} | } | ||||
/* | /* | ||||
* Make transitions: SYN-RECEIVED -> ESTABLISHED SYN-RECEIVED* -> | * Make transitions: SYN-RECEIVED -> ESTABLISHED SYN-RECEIVED* -> | ||||
* FIN-WAIT-1 | * FIN-WAIT-1 | ||||
*/ | */ | ||||
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 (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 regular | * Account for the ACK of our SYN prior to regular | ||||
* ACK processing below. | * 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 connections | * processing. Calling it again here for such connections | ||||
* is not harmless as it would undo the snd_cwnd reduction | * is not harmless as it would undo the snd_cwnd reduction | ||||
* that occurs when a TFO SYN|ACK is retransmitted. | * that occurs when a TFO SYN|ACK is retransmitted. | ||||
*/ | */ | ||||
if (!(tp->t_flags & TF_FASTOPEN)) | if (!IS_FASTOPEN(tp->t_flags)) | ||||
#endif | |||||
cc_conn_init(tp); | cc_conn_init(tp); | ||||
} | } | ||||
/* | /* | ||||
* If segment contains data or ACK, will call tcp_reass() later; if | * If segment contains data or ACK, will call tcp_reass() later; if | ||||
* not, do so now to pass queued data to user. | * 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 1,399 Lines • ▼ Show 20 Lines | rack_output(struct tcpcb *tp) | ||||
struct ip *ip = NULL; | struct ip *ip = NULL; | ||||
#ifdef TCPDEBUG | #ifdef TCPDEBUG | ||||
struct ipovly *ipov = NULL; | struct ipovly *ipov = NULL; | ||||
#endif | #endif | ||||
struct udphdr *udp = NULL; | struct udphdr *udp = NULL; | ||||
struct tcp_rack *rack; | struct tcp_rack *rack; | ||||
struct tcphdr *th; | struct tcphdr *th; | ||||
uint8_t pass = 0; | uint8_t pass = 0; | ||||
uint8_t wanted_cookie = 0; | |||||
u_char opt[TCP_MAXOLEN]; | u_char opt[TCP_MAXOLEN]; | ||||
unsigned ipoptlen, optlen, hdrlen, ulen=0; | unsigned ipoptlen, optlen, hdrlen, ulen=0; | ||||
uint32_t rack_seq; | uint32_t rack_seq; | ||||
#if defined(IPSEC) || defined(IPSEC_SUPPORT) | #if defined(IPSEC) || defined(IPSEC_SUPPORT) | ||||
unsigned ipsec_optlen = 0; | unsigned ipsec_optlen = 0; | ||||
#endif | #endif | ||||
Show All 25 Lines | #endif | ||||
do_a_prefetch = 1; | do_a_prefetch = 1; | ||||
INP_WLOCK_ASSERT(inp); | INP_WLOCK_ASSERT(inp); | ||||
#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 ((tp->t_flags & TF_FASTOPEN) && | 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) && /* inital SYN|ACK sent */ | SEQ_GT(tp->snd_max, tp->snd_una) && /* initial SYN|ACK sent */ | ||||
(tp->snd_nxt != tp->snd_una)) /* not a retransmit */ | (rack->r_ctl.rc_resend == NULL)) /* not a retransmit */ | ||||
return (0); | return (0); | ||||
#endif | |||||
#ifdef INET6 | #ifdef INET6 | ||||
if (rack->r_state) { | if (rack->r_state) { | ||||
/* Use the cache line loaded if possible */ | /* Use the cache line loaded if possible */ | ||||
isipv6 = rack->r_is_v6; | isipv6 = rack->r_is_v6; | ||||
} else { | } else { | ||||
isipv6 = (inp->inp_vflag & INP_IPV6) != 0; | isipv6 = (inp->inp_vflag & INP_IPV6) != 0; | ||||
} | } | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 273 Lines • ▼ Show 20 Lines | #endif | ||||
* | * | ||||
* If sack_rxmit is true we are retransmitting from the scoreboard | * If sack_rxmit is true we are retransmitting from the scoreboard | ||||
* in which case len is already set. | * in which case len is already set. | ||||
*/ | */ | ||||
if (sack_rxmit == 0) { | if (sack_rxmit == 0) { | ||||
uint32_t avail; | uint32_t avail; | ||||
avail = sbavail(sb); | avail = sbavail(sb); | ||||
if (SEQ_GT(tp->snd_nxt, tp->snd_una)) | if (SEQ_GT(tp->snd_nxt, tp->snd_una) && avail) | ||||
sb_offset = tp->snd_nxt - tp->snd_una; | sb_offset = tp->snd_nxt - tp->snd_una; | ||||
else | else | ||||
sb_offset = 0; | sb_offset = 0; | ||||
if (IN_RECOVERY(tp->t_flags) == 0) { | if (IN_RECOVERY(tp->t_flags) == 0) { | ||||
if (rack->r_ctl.rc_tlp_new_data) { | if (rack->r_ctl.rc_tlp_new_data) { | ||||
/* TLP is forcing out new data */ | /* TLP is forcing out new data */ | ||||
if (rack->r_ctl.rc_tlp_new_data > (uint32_t) (avail - sb_offset)) { | if (rack->r_ctl.rc_tlp_new_data > (uint32_t) (avail - sb_offset)) { | ||||
rack->r_ctl.rc_tlp_new_data = (uint32_t) (avail - sb_offset); | rack->r_ctl.rc_tlp_new_data = (uint32_t) (avail - sb_offset); | ||||
▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | if (prefetch_so_done == 0) { | ||||
kern_prefetch(so, &prefetch_so_done); | kern_prefetch(so, &prefetch_so_done); | ||||
prefetch_so_done = 1; | prefetch_so_done = 1; | ||||
} | } | ||||
/* | /* | ||||
* Lop off SYN bit if it has already been sent. However, if this is | * 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 know | * SYN-SENT state and if segment contains data and if we don't know | ||||
* that foreign host supports TAO, suppress sending segment. | * 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) && | ((sack_rxmit == 0) && (tp->t_rxtshift == 0))) { | ||||
(tp->t_state != TCPS_SYN_SENT)) | 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 ((tp->t_flags & TF_FASTOPEN) && | 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 | |||||
sb_offset--, len++; | sb_offset--, len++; | ||||
if (sbavail(sb) == 0) | |||||
len = 0; | |||||
} | } | ||||
/* | /* | ||||
* Be careful not to send data and/or FIN on SYN segments. This | * Be careful not to send data and/or FIN on SYN segments. This | ||||
* measure is needed to prevent interoperability problems with not | * measure is needed to prevent interoperability problems with not | ||||
* fully conformant TCP implementations. | * 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, | * On TFO sockets, ensure no data is sent in the following cases: | ||||
* don't include data, as the presence of data may have caused the | * | ||||
* original SYN|ACK to have been dropped by a middlebox. | * - When retransmitting SYN|ACK on a passively-created socket | ||||
* | |||||
* - When retransmitting SYN on an actively created socket | |||||
* | |||||
* - When sending a zero-length cookie (cookie request) on an | |||||
* actively created socket | |||||
* | |||||
* - When the socket is in the CLOSED state (RST is being sent) | |||||
*/ | */ | ||||
if ((tp->t_flags & TF_FASTOPEN) && | if (IS_FASTOPEN(tp->t_flags) && | ||||
((tp->t_state == TCPS_SYN_RECEIVED) && (tp->t_rxtshift > 0))) | (((flags & TH_SYN) && (tp->t_rxtshift > 0)) || | ||||
((tp->t_state == TCPS_SYN_SENT) && | |||||
(tp->t_tfo_client_cookie_len == 0)) || | |||||
(flags & TH_RST))) | |||||
len = 0; | len = 0; | ||||
#endif | /* Without fast-open there should never be data sent on a SYN */ | ||||
if ((flags & TH_SYN) && (!IS_FASTOPEN(tp->t_flags))) | |||||
len = 0; | |||||
if (len <= 0) { | if (len <= 0) { | ||||
/* | /* | ||||
* If FIN has been sent but not acked, but we haven't been | * If FIN has been sent but not acked, but we haven't been | ||||
* called to retransmit, len will be < 0. Otherwise, window | * called to retransmit, len will be < 0. Otherwise, window | ||||
* shrank after we sent into it. If window shrank to 0, | * shrank after we sent into it. If window shrank to 0, | ||||
* cancel pending retransmit, pull snd_nxt back to (closed) | * cancel pending retransmit, pull snd_nxt back to (closed) | ||||
* window, and set the persist timer if it isn't already | * window, and set the persist timer if it isn't already | ||||
* going. If the window didn't close completely, just wait | * going. If the window didn't close completely, just wait | ||||
▲ Show 20 Lines • Show All 299 Lines • ▼ Show 20 Lines | if ((tp->t_flags & TF_NOOPT) == 0) { | ||||
if (flags & TH_SYN) { | if (flags & TH_SYN) { | ||||
tp->snd_nxt = tp->iss; | tp->snd_nxt = tp->iss; | ||||
to.to_mss = tcp_mssopt(&inp->inp_inc); | to.to_mss = tcp_mssopt(&inp->inp_inc); | ||||
#ifdef NETFLIX_TCPOUDP | #ifdef NETFLIX_TCPOUDP | ||||
if (tp->t_port) | if (tp->t_port) | ||||
to.to_mss -= V_tcp_udp_tunneling_overhead; | to.to_mss -= V_tcp_udp_tunneling_overhead; | ||||
#endif | #endif | ||||
to.to_flags |= TOF_MSS; | to.to_flags |= TOF_MSS; | ||||
#ifdef TCP_RFC7413 | |||||
/* | /* | ||||
* Only include the TFO option on the first | * On SYN or SYN|ACK transmits on TFO connections, | ||||
* transmission of the SYN|ACK on a | * only include the TFO option if it is not a | ||||
* passively-created TFO socket, as the presence of | * retransmit, as the presence of the TFO option may | ||||
* the TFO option may have caused the original | * have caused the original SYN or SYN|ACK to have | ||||
* SYN|ACK to have been dropped by a middlebox. | * been dropped by a middlebox. | ||||
*/ | */ | ||||
if ((tp->t_flags & TF_FASTOPEN) && | if (IS_FASTOPEN(tp->t_flags) && | ||||
(tp->t_state == TCPS_SYN_RECEIVED) && | |||||
(tp->t_rxtshift == 0)) { | (tp->t_rxtshift == 0)) { | ||||
to.to_tfo_len = TCP_FASTOPEN_MAX_COOKIE_LEN; | if (tp->t_state == TCPS_SYN_RECEIVED) { | ||||
to.to_tfo_cookie = (u_char *)&tp->t_tfo_cookie; | to.to_tfo_len = TCP_FASTOPEN_COOKIE_LEN; | ||||
to.to_tfo_cookie = | |||||
(u_int8_t *)&tp->t_tfo_cookie.server; | |||||
to.to_flags |= TOF_FASTOPEN; | to.to_flags |= TOF_FASTOPEN; | ||||
wanted_cookie = 1; | |||||
} else if (tp->t_state == TCPS_SYN_SENT) { | |||||
to.to_tfo_len = | |||||
tp->t_tfo_client_cookie_len; | |||||
to.to_tfo_cookie = | |||||
tp->t_tfo_cookie.client; | |||||
to.to_flags |= TOF_FASTOPEN; | |||||
wanted_cookie = 1; | |||||
/* | |||||
* If we wind up having more data to | |||||
* send with the SYN than can fit in | |||||
* one segment, don't send any more | |||||
* until the SYN|ACK comes back from | |||||
* the other end. | |||||
*/ | |||||
sendalot = 0; | |||||
} | } | ||||
#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 All 17 Lines | |||||
#if defined(IPSEC_SUPPORT) || defined(TCP_SIGNATURE) | #if defined(IPSEC_SUPPORT) || defined(TCP_SIGNATURE) | ||||
/* TCP-MD5 (RFC2385). */ | /* TCP-MD5 (RFC2385). */ | ||||
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); | ||||
/* | |||||
* If we wanted a TFO option to be added, but it was unable | |||||
* to fit, ensure no data is sent. | |||||
*/ | |||||
if (IS_FASTOPEN(tp->t_flags) && wanted_cookie && | |||||
!(to.to_flags & TOF_FASTOPEN)) | |||||
len = 0; | |||||
} | } | ||||
#ifdef NETFLIX_TCPOUDP | #ifdef NETFLIX_TCPOUDP | ||||
if (tp->t_port) { | if (tp->t_port) { | ||||
if (V_tcp_udp_tunneling_port == 0) { | if (V_tcp_udp_tunneling_port == 0) { | ||||
/* The port was removed?? */ | /* The port was removed?? */ | ||||
SOCKBUF_UNLOCK(&so->so_snd); | SOCKBUF_UNLOCK(&so->so_snd); | ||||
return (EHOSTUNREACH); | return (EHOSTUNREACH); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,391 Lines • Show Last 20 Lines |