Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_input.c
Context not available. | |||||
#define tcb6 tcb /* for KAME src sync over BSD*'s */ | #define tcb6 tcb /* for KAME src sync over BSD*'s */ | ||||
VNET_DEFINE(struct inpcbinfo, tcbinfo); | VNET_DEFINE(struct inpcbinfo, tcbinfo); | ||||
static void tcp_dooptions(struct tcpopt *, u_char *, int, int); | extern void tcp_dooptions(struct tcpopt *, u_char *, int, int); | ||||
jtl: This is already defined in tcp_var.h. Why add a non-static declaration to tcp_input.c? | |||||
Not Done Inline ActionsThat may have been a cut and paste error since I have no memory of rrs: That may have been a cut and paste error since I have no memory of
adding it explicitly :-) | |||||
static void tcp_do_segment(struct mbuf *, struct tcphdr *, | void tcp_dropwithreset(struct mbuf *, struct tcphdr *, | ||||
jtlUnsubmitted Not Done Inline ActionsShouldn't globally-visible functions normally go in a .h? jtl: Shouldn't globally-visible functions normally go in a .h? | |||||
struct socket *, struct tcpcb *, int, int, uint8_t, | |||||
int); | |||||
static void tcp_dropwithreset(struct mbuf *, struct tcphdr *, | |||||
struct tcpcb *, int, int); | struct tcpcb *, int, int); | ||||
static void tcp_pulloutofband(struct socket *, | void tcp_pulloutofband(struct socket *, | ||||
struct tcphdr *, struct mbuf *, int); | struct tcphdr *, struct mbuf *, int); | ||||
static void tcp_xmit_timer(struct tcpcb *, int); | void tcp_xmit_timer(struct tcpcb *, int); | ||||
static void tcp_newreno_partial_ack(struct tcpcb *, struct tcphdr *); | void tcp_newreno_partial_ack(struct tcpcb *, struct tcphdr *); | ||||
static void inline cc_ack_received(struct tcpcb *tp, struct tcphdr *th, | void cc_ack_received(struct tcpcb *tp, struct tcphdr *th, | ||||
uint16_t type); | uint16_t type); | ||||
static void inline cc_conn_init(struct tcpcb *tp); | void cc_conn_init(struct tcpcb *tp); | ||||
static void inline cc_post_recovery(struct tcpcb *tp, struct tcphdr *th); | void cc_post_recovery(struct tcpcb *tp, struct tcphdr *th); | ||||
static void inline hhook_run_tcp_est_in(struct tcpcb *tp, | void cc_cong_signal(struct tcpcb *tp, struct tcphdr *th, uint32_t type); | ||||
void hhook_run_tcp_est_in(struct tcpcb *tp, | |||||
struct tcphdr *th, struct tcpopt *to); | struct tcphdr *th, struct tcpopt *to); | ||||
void kmod_tcpstat_inc(int statnum); | |||||
/* | /* | ||||
* TCP statistics are stored in an "array" of counter(9)s. | * TCP statistics are stored in an "array" of counter(9)s. | ||||
*/ | */ | ||||
Context not available. | |||||
/* | /* | ||||
* Wrapper for the TCP established input helper hook. | * Wrapper for the TCP established input helper hook. | ||||
*/ | */ | ||||
static void inline | void | ||||
hhook_run_tcp_est_in(struct tcpcb *tp, struct tcphdr *th, struct tcpopt *to) | hhook_run_tcp_est_in(struct tcpcb *tp, struct tcphdr *th, struct tcpopt *to) | ||||
{ | { | ||||
struct tcp_hhook_data hhook_data; | struct tcp_hhook_data hhook_data; | ||||
Context not available. | |||||
/* | /* | ||||
* CC wrapper hook functions | * CC wrapper hook functions | ||||
*/ | */ | ||||
static void inline | void | ||||
cc_ack_received(struct tcpcb *tp, struct tcphdr *th, uint16_t type) | cc_ack_received(struct tcpcb *tp, struct tcphdr *th, uint16_t type) | ||||
{ | { | ||||
INP_WLOCK_ASSERT(tp->t_inpcb); | INP_WLOCK_ASSERT(tp->t_inpcb); | ||||
Context not available. | |||||
} | } | ||||
} | } | ||||
static void inline | void | ||||
cc_conn_init(struct tcpcb *tp) | cc_conn_init(struct tcpcb *tp) | ||||
{ | { | ||||
struct hc_metrics_lite metrics; | struct hc_metrics_lite metrics; | ||||
Context not available. | |||||
} | } | ||||
} | } | ||||
static void inline | void inline | ||||
cc_post_recovery(struct tcpcb *tp, struct tcphdr *th) | cc_post_recovery(struct tcpcb *tp, struct tcphdr *th) | ||||
{ | { | ||||
INP_WLOCK_ASSERT(tp->t_inpcb); | INP_WLOCK_ASSERT(tp->t_inpcb); | ||||
Context not available. | |||||
* connection. | * connection. | ||||
*/ | */ | ||||
#define DELAY_ACK(tp, tlen) \ | #define DELAY_ACK(tp, tlen) \ | ||||
((!tcp_timer_active(tp, TT_DELACK) && \ | ((!tp->t_fb->tcp_timer_active(tp, TT_DELACK) && \ | ||||
(tp->t_flags & TF_RXWIN0SENT) == 0) && \ | (tp->t_flags & TF_RXWIN0SENT) == 0) && \ | ||||
(tlen <= tp->t_maxopd) && \ | (tlen <= tp->t_maxopd) && \ | ||||
(V_tcp_delack_enabled || (tp->t_flags & TF_NEEDSYN))) | (V_tcp_delack_enabled || (tp->t_flags & TF_NEEDSYN))) | ||||
Context not available. | |||||
CC_ALGO(tp)->ecnpkt_handler(tp->ccv); | CC_ALGO(tp)->ecnpkt_handler(tp->ccv); | ||||
if (tp->ccv->flags & CCF_ACKNOW) | if (tp->ccv->flags & CCF_ACKNOW) | ||||
tcp_timer_activate(tp, TT_DELACK, tcp_delacktime); | tp->t_fb->tcp_timer_activate(tp, TT_DELACK, tcp_delacktime); | ||||
} | } | ||||
} | } | ||||
Context not available. | |||||
* contains. tcp_do_segment() consumes | * contains. tcp_do_segment() consumes | ||||
* the mbuf chain and unlocks the inpcb. | * the mbuf chain and unlocks the inpcb. | ||||
*/ | */ | ||||
tcp_do_segment(m, th, so, tp, drop_hdrlen, tlen, | tp->t_fb->tcp_do_segment(m, th, so, tp, drop_hdrlen, tlen, | ||||
iptos, ti_locked); | iptos, ti_locked); | ||||
INP_INFO_UNLOCK_ASSERT(&V_tcbinfo); | INP_INFO_UNLOCK_ASSERT(&V_tcbinfo); | ||||
return (IPPROTO_DONE); | return (IPPROTO_DONE); | ||||
Context not available. | |||||
* state. tcp_do_segment() always consumes the mbuf chain, unlocks | * state. tcp_do_segment() always consumes the mbuf chain, unlocks | ||||
* the inpcb, and unlocks pcbinfo. | * the inpcb, and unlocks pcbinfo. | ||||
*/ | */ | ||||
tcp_do_segment(m, th, so, tp, drop_hdrlen, tlen, iptos, ti_locked); | printf("Do segment call ti_locked:%d\n", ti_locked); | ||||
jtlUnsubmitted Not Done Inline ActionsThis should probably be converted to an appropriate debug statement. jtl: This should probably be converted to an appropriate debug statement. | |||||
rrsAuthorUnsubmitted Not Done Inline ActionsActually its a printf I forgot to purge.. it has been removed now :-) rrs: Actually its a printf I forgot to purge.. it has been removed now :-) | |||||
tp->t_fb->tcp_do_segment(m, th, so, tp, drop_hdrlen, tlen, iptos, ti_locked); | |||||
INP_INFO_UNLOCK_ASSERT(&V_tcbinfo); | INP_INFO_UNLOCK_ASSERT(&V_tcbinfo); | ||||
return (IPPROTO_DONE); | return (IPPROTO_DONE); | ||||
Context not available. | |||||
return (IPPROTO_DONE); | return (IPPROTO_DONE); | ||||
} | } | ||||
static void | void | ||||
tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, | tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, | ||||
struct tcpcb *tp, int drop_hdrlen, int tlen, uint8_t iptos, | struct tcpcb *tp, int drop_hdrlen, int tlen, uint8_t iptos, | ||||
int ti_locked) | int ti_locked) | ||||
Context not available. | |||||
*/ | */ | ||||
tp->t_rcvtime = ticks; | tp->t_rcvtime = ticks; | ||||
if (TCPS_HAVEESTABLISHED(tp->t_state)) | if (TCPS_HAVEESTABLISHED(tp->t_state)) | ||||
tcp_timer_activate(tp, TT_KEEP, TP_KEEPIDLE(tp)); | tp->t_fb->tcp_timer_activate(tp, TT_KEEP, TP_KEEPIDLE(tp)); | ||||
/* | /* | ||||
* Scale up the window into a 32-bit value. | * Scale up the window into a 32-bit value. | ||||
Not Done Inline ActionsIt looks like there is an accidental whitespace change here. jtl: It looks like there is an accidental whitespace change here. | |||||
Not Done Inline Actionsack rrs: ack | |||||
Context not available. | |||||
TCP_PROBE3(debug__input, tp, th, | TCP_PROBE3(debug__input, tp, th, | ||||
mtod(m, const char *)); | mtod(m, const char *)); | ||||
if (tp->snd_una == tp->snd_max) | if (tp->snd_una == tp->snd_max) | ||||
tcp_timer_activate(tp, TT_REXMT, 0); | tp->t_fb->tcp_timer_activate(tp, TT_REXMT, 0); | ||||
else if (!tcp_timer_active(tp, TT_PERSIST)) | else if (!tcp_timer_active(tp, TT_PERSIST)) | ||||
tcp_timer_activate(tp, TT_REXMT, | tp->t_fb->tcp_timer_activate(tp, TT_REXMT, | ||||
tp->t_rxtcur); | tp->t_rxtcur); | ||||
sowwakeup(so); | sowwakeup(so); | ||||
if (sbavail(&so->so_snd)) | if (sbavail(&so->so_snd)) | ||||
(void) tcp_output(tp); | (void) tp->t_fb->tcp_output(tp); | ||||
goto check_delack; | goto check_delack; | ||||
} | } | ||||
} else if (th->th_ack == tp->snd_una && | } else if (th->th_ack == tp->snd_una && | ||||
Context not available. | |||||
tp->t_flags |= TF_DELACK; | tp->t_flags |= TF_DELACK; | ||||
} else { | } else { | ||||
tp->t_flags |= TF_ACKNOW; | tp->t_flags |= TF_ACKNOW; | ||||
tcp_output(tp); | tp->t_fb->tcp_output(tp); | ||||
} | } | ||||
goto check_delack; | goto check_delack; | ||||
} | } | ||||
Context not available. | |||||
* 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) | ||||
tcp_timer_activate(tp, TT_DELACK, | tp->t_fb->tcp_timer_activate(tp, TT_DELACK, | ||||
tcp_delacktime); | tcp_delacktime); | ||||
else | else | ||||
tp->t_flags |= TF_ACKNOW; | tp->t_flags |= TF_ACKNOW; | ||||
Context not available. | |||||
TCP_PROBE5(connect__established, NULL, tp, | TCP_PROBE5(connect__established, NULL, tp, | ||||
mtod(m, const char *), tp, th); | mtod(m, const char *), tp, th); | ||||
cc_conn_init(tp); | cc_conn_init(tp); | ||||
tcp_timer_activate(tp, TT_KEEP, | tp->t_fb->tcp_timer_activate(tp, TT_KEEP, | ||||
TP_KEEPIDLE(tp)); | TP_KEEPIDLE(tp)); | ||||
} | } | ||||
} else { | } else { | ||||
Context not available. | |||||
* SYN-SENT* -> SYN-RECEIVED* | * SYN-SENT* -> SYN-RECEIVED* | ||||
*/ | */ | ||||
tp->t_flags |= (TF_ACKNOW | TF_NEEDSYN); | tp->t_flags |= (TF_ACKNOW | TF_NEEDSYN); | ||||
tcp_timer_activate(tp, TT_REXMT, 0); | tp->t_fb->tcp_timer_activate(tp, TT_REXMT, 0); | ||||
tcp_state_change(tp, TCPS_SYN_RECEIVED); | tcp_state_change(tp, TCPS_SYN_RECEIVED); | ||||
} | } | ||||
Context not available. | |||||
TCP_PROBE5(accept__established, NULL, tp, | TCP_PROBE5(accept__established, NULL, tp, | ||||
mtod(m, const char *), tp, th); | mtod(m, const char *), tp, th); | ||||
cc_conn_init(tp); | cc_conn_init(tp); | ||||
tcp_timer_activate(tp, TT_KEEP, TP_KEEPIDLE(tp)); | tp->t_fb->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() | ||||
Context not available. | |||||
* When using TCP ECN, notify the peer that | * When using TCP ECN, notify the peer that | ||||
* we reduced the cwnd. | * we reduced the cwnd. | ||||
*/ | */ | ||||
if (!tcp_timer_active(tp, TT_REXMT) || | if (!tp->t_fb->tcp_timer_active(tp, TT_REXMT) || | ||||
th->th_ack != tp->snd_una) | th->th_ack != tp->snd_una) | ||||
tp->t_dupacks = 0; | tp->t_dupacks = 0; | ||||
else if (++tp->t_dupacks > tcprexmtthresh || | else if (++tp->t_dupacks > tcprexmtthresh || | ||||
Context not available. | |||||
} | } | ||||
} else | } else | ||||
tp->snd_cwnd += tp->t_maxseg; | tp->snd_cwnd += tp->t_maxseg; | ||||
(void) tcp_output(tp); | (void) tp->t_fb->tcp_output(tp); | ||||
goto drop; | goto drop; | ||||
} else if (tp->t_dupacks == tcprexmtthresh) { | } else if (tp->t_dupacks == tcprexmtthresh) { | ||||
tcp_seq onxt = tp->snd_nxt; | tcp_seq onxt = tp->snd_nxt; | ||||
Context not available. | |||||
/* Congestion signal before ack. */ | /* Congestion signal before ack. */ | ||||
cc_cong_signal(tp, th, CC_NDUPACK); | cc_cong_signal(tp, th, CC_NDUPACK); | ||||
cc_ack_received(tp, th, CC_DUPACK); | cc_ack_received(tp, th, CC_DUPACK); | ||||
tcp_timer_activate(tp, TT_REXMT, 0); | tp->t_fb->tcp_timer_activate(tp, TT_REXMT, 0); | ||||
tp->t_rtttime = 0; | tp->t_rtttime = 0; | ||||
if (tp->t_flags & TF_SACK_PERMIT) { | if (tp->t_flags & TF_SACK_PERMIT) { | ||||
TCPSTAT_INC( | TCPSTAT_INC( | ||||
Context not available. | |||||
tcps_sack_recovery_episode); | tcps_sack_recovery_episode); | ||||
tp->sack_newdata = tp->snd_nxt; | tp->sack_newdata = tp->snd_nxt; | ||||
tp->snd_cwnd = tp->t_maxseg; | tp->snd_cwnd = tp->t_maxseg; | ||||
(void) tcp_output(tp); | (void) tp->t_fb->tcp_output(tp); | ||||
goto drop; | goto drop; | ||||
} | } | ||||
tp->snd_nxt = th->th_ack; | tp->snd_nxt = th->th_ack; | ||||
tp->snd_cwnd = tp->t_maxseg; | tp->snd_cwnd = tp->t_maxseg; | ||||
(void) tcp_output(tp); | (void) tp->t_fb->tcp_output(tp); | ||||
KASSERT(tp->snd_limited <= 2, | KASSERT(tp->snd_limited <= 2, | ||||
("%s: tp->snd_limited too big", | ("%s: tp->snd_limited too big", | ||||
__func__)); | __func__)); | ||||
Context not available. | |||||
(tp->snd_nxt - tp->snd_una); | (tp->snd_nxt - tp->snd_una); | ||||
SOCKBUF_UNLOCK(&so->so_snd); | SOCKBUF_UNLOCK(&so->so_snd); | ||||
if (avail > 0) | if (avail > 0) | ||||
(void) tcp_output(tp); | (void) tp->t_fb->tcp_output(tp); | ||||
sent = tp->snd_max - oldsndmax; | sent = tp->snd_max - oldsndmax; | ||||
if (sent > tp->t_maxseg) { | if (sent > tp->t_maxseg) { | ||||
KASSERT((tp->t_dupacks == 2 && | KASSERT((tp->t_dupacks == 2 && | ||||
Context not available. | |||||
* timer, using current (possibly backed-off) value. | * timer, using current (possibly backed-off) value. | ||||
*/ | */ | ||||
if (th->th_ack == tp->snd_max) { | if (th->th_ack == tp->snd_max) { | ||||
tcp_timer_activate(tp, TT_REXMT, 0); | tp->t_fb->tcp_timer_activate(tp, TT_REXMT, 0); | ||||
needoutput = 1; | needoutput = 1; | ||||
} else if (!tcp_timer_active(tp, TT_PERSIST)) | } else if (!tp->t_fb->tcp_timer_active(tp, TT_PERSIST)) | ||||
tcp_timer_activate(tp, TT_REXMT, tp->t_rxtcur); | tp->t_fb->tcp_timer_activate(tp, TT_REXMT, tp->t_rxtcur); | ||||
/* | /* | ||||
* If no data (only SYN) was ACK'd, | * If no data (only SYN) was ACK'd, | ||||
Context not available. | |||||
*/ | */ | ||||
if (so->so_rcv.sb_state & SBS_CANTRCVMORE) { | if (so->so_rcv.sb_state & SBS_CANTRCVMORE) { | ||||
soisdisconnected(so); | soisdisconnected(so); | ||||
tcp_timer_activate(tp, TT_2MSL, | tp->t_fb->tcp_timer_activate(tp, TT_2MSL, | ||||
(tcp_fast_finwait2_recycle ? | (tcp_fast_finwait2_recycle ? | ||||
tcp_finwait2_timeout : | tcp_finwait2_timeout : | ||||
TP_MAXIDLE(tp))); | TP_MAXIDLE(tp))); | ||||
Context not available. | |||||
* Return any desired output. | * Return any desired output. | ||||
*/ | */ | ||||
if (needoutput || (tp->t_flags & TF_ACKNOW)) | if (needoutput || (tp->t_flags & TF_ACKNOW)) | ||||
(void) tcp_output(tp); | (void) tp->t_fb->tcp_output(tp); | ||||
check_delack: | check_delack: | ||||
KASSERT(ti_locked == TI_UNLOCKED, ("%s: check_delack ti_locked %d", | KASSERT(ti_locked == TI_UNLOCKED, ("%s: check_delack ti_locked %d", | ||||
Context not available. | |||||
if (tp->t_flags & TF_DELACK) { | if (tp->t_flags & TF_DELACK) { | ||||
tp->t_flags &= ~TF_DELACK; | tp->t_flags &= ~TF_DELACK; | ||||
tcp_timer_activate(tp, TT_DELACK, tcp_delacktime); | tp->t_fb->tcp_timer_activate(tp, TT_DELACK, tcp_delacktime); | ||||
} | } | ||||
INP_WUNLOCK(tp->t_inpcb); | INP_WUNLOCK(tp->t_inpcb); | ||||
return; | return; | ||||
Context not available. | |||||
ti_locked = TI_UNLOCKED; | ti_locked = TI_UNLOCKED; | ||||
tp->t_flags |= TF_ACKNOW; | tp->t_flags |= TF_ACKNOW; | ||||
(void) tcp_output(tp); | (void) tp->t_fb->tcp_output(tp); | ||||
INP_WUNLOCK(tp->t_inpcb); | INP_WUNLOCK(tp->t_inpcb); | ||||
m_freem(m); | m_freem(m); | ||||
return; | return; | ||||
Context not available. | |||||
* 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. | ||||
*/ | */ | ||||
static void | void | ||||
tcp_dropwithreset(struct mbuf *m, struct tcphdr *th, struct tcpcb *tp, | tcp_dropwithreset(struct mbuf *m, struct tcphdr *th, struct tcpcb *tp, | ||||
int tlen, int rstreason) | int tlen, int rstreason) | ||||
{ | { | ||||
Context not available. | |||||
/* | /* | ||||
* Parse TCP options and place in tcpopt. | * Parse TCP options and place in tcpopt. | ||||
*/ | */ | ||||
static void | void | ||||
tcp_dooptions(struct tcpopt *to, u_char *cp, int cnt, int flags) | tcp_dooptions(struct tcpopt *to, u_char *cp, int cnt, int flags) | ||||
{ | { | ||||
int opt, optlen; | int opt, optlen; | ||||
Context not available. | |||||
* It is still reflected in the segment length for | * It is still reflected in the segment length for | ||||
* sequencing purposes. | * sequencing purposes. | ||||
*/ | */ | ||||
static void | void | ||||
tcp_pulloutofband(struct socket *so, struct tcphdr *th, struct mbuf *m, | tcp_pulloutofband(struct socket *so, struct tcphdr *th, struct mbuf *m, | ||||
int off) | int off) | ||||
{ | { | ||||
Context not available. | |||||
* Collect new round-trip time estimate | * Collect new round-trip time estimate | ||||
* and update averages and current timeout. | * and update averages and current timeout. | ||||
*/ | */ | ||||
static void | void | ||||
tcp_xmit_timer(struct tcpcb *tp, int rtt) | tcp_xmit_timer(struct tcpcb *tp, int rtt) | ||||
{ | { | ||||
int delta; | int delta; | ||||
Context not available. | |||||
* By setting snd_nxt to ti_ack, this forces retransmission timer to | * By setting snd_nxt to ti_ack, this forces retransmission timer to | ||||
* be started again. | * be started again. | ||||
*/ | */ | ||||
static void | void | ||||
tcp_newreno_partial_ack(struct tcpcb *tp, struct tcphdr *th) | tcp_newreno_partial_ack(struct tcpcb *tp, struct tcphdr *th) | ||||
{ | { | ||||
tcp_seq onxt = tp->snd_nxt; | tcp_seq onxt = tp->snd_nxt; | ||||
Context not available. | |||||
INP_WLOCK_ASSERT(tp->t_inpcb); | INP_WLOCK_ASSERT(tp->t_inpcb); | ||||
tcp_timer_activate(tp, TT_REXMT, 0); | tp->t_fb->tcp_timer_activate(tp, TT_REXMT, 0); | ||||
tp->t_rtttime = 0; | tp->t_rtttime = 0; | ||||
tp->snd_nxt = th->th_ack; | tp->snd_nxt = th->th_ack; | ||||
/* | /* | ||||
Context not available. | |||||
*/ | */ | ||||
tp->snd_cwnd = tp->t_maxseg + BYTES_THIS_ACK(tp, th); | tp->snd_cwnd = tp->t_maxseg + BYTES_THIS_ACK(tp, th); | ||||
tp->t_flags |= TF_ACKNOW; | tp->t_flags |= TF_ACKNOW; | ||||
(void) tcp_output(tp); | (void) tp->t_fb->tcp_output(tp); | ||||
tp->snd_cwnd = ocwnd; | tp->snd_cwnd = ocwnd; | ||||
if (SEQ_GT(onxt, tp->snd_nxt)) | if (SEQ_GT(onxt, tp->snd_nxt)) | ||||
tp->snd_nxt = onxt; | tp->snd_nxt = onxt; | ||||
Context not available. |
This is already defined in tcp_var.h. Why add a non-static declaration to tcp_input.c?