Changeset View
Changeset View
Standalone View
Standalone View
head/sys/netinet/tcp_input.c
Show First 20 Lines • Show All 224 Lines • ▼ Show 20 Lines | |||||
SYSCTL_INT(_net_inet_tcp, OID_AUTO, recvbuf_max, CTLFLAG_VNET | CTLFLAG_RW, | SYSCTL_INT(_net_inet_tcp, OID_AUTO, recvbuf_max, CTLFLAG_VNET | CTLFLAG_RW, | ||||
&VNET_NAME(tcp_autorcvbuf_max), 0, | &VNET_NAME(tcp_autorcvbuf_max), 0, | ||||
"Max size of automatic receive buffer"); | "Max size of automatic receive buffer"); | ||||
VNET_DEFINE(struct inpcbhead, tcb); | VNET_DEFINE(struct inpcbhead, tcb); | ||||
#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); | |||||
static void tcp_do_segment(struct mbuf *, struct tcphdr *, | |||||
struct socket *, struct tcpcb *, int, int, uint8_t, | |||||
int); | |||||
static void tcp_dropwithreset(struct mbuf *, struct tcphdr *, | |||||
struct tcpcb *, int, int); | |||||
static void tcp_pulloutofband(struct socket *, | |||||
struct tcphdr *, struct mbuf *, int); | |||||
static void tcp_xmit_timer(struct tcpcb *, int); | |||||
static void tcp_newreno_partial_ack(struct tcpcb *, struct tcphdr *); | |||||
static void inline cc_ack_received(struct tcpcb *tp, struct tcphdr *th, | |||||
uint16_t type); | |||||
static void inline cc_conn_init(struct tcpcb *tp); | |||||
static void inline cc_post_recovery(struct tcpcb *tp, struct tcphdr *th); | |||||
static void inline hhook_run_tcp_est_in(struct tcpcb *tp, | |||||
struct tcphdr *th, struct tcpopt *to); | |||||
/* | /* | ||||
* TCP statistics are stored in an "array" of counter(9)s. | * TCP statistics are stored in an "array" of counter(9)s. | ||||
*/ | */ | ||||
VNET_PCPUSTAT_DEFINE(struct tcpstat, tcpstat); | VNET_PCPUSTAT_DEFINE(struct tcpstat, tcpstat); | ||||
VNET_PCPUSTAT_SYSINIT(tcpstat); | VNET_PCPUSTAT_SYSINIT(tcpstat); | ||||
SYSCTL_VNET_PCPUSTAT(_net_inet_tcp, TCPCTL_STATS, stats, struct tcpstat, | SYSCTL_VNET_PCPUSTAT(_net_inet_tcp, TCPCTL_STATS, stats, struct tcpstat, | ||||
tcpstat, "TCP statistics (struct tcpstat, netinet/tcp_var.h)"); | tcpstat, "TCP statistics (struct tcpstat, netinet/tcp_var.h)"); | ||||
Show All 9 Lines | |||||
{ | { | ||||
counter_u64_add(VNET(tcpstat)[statnum], 1); | counter_u64_add(VNET(tcpstat)[statnum], 1); | ||||
} | } | ||||
/* | /* | ||||
* 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; | ||||
if (V_tcp_hhh[HHOOK_TCP_EST_IN]->hhh_nhooks > 0) { | if (V_tcp_hhh[HHOOK_TCP_EST_IN]->hhh_nhooks > 0) { | ||||
hhook_data.tp = tp; | hhook_data.tp = tp; | ||||
hhook_data.th = th; | hhook_data.th = th; | ||||
hhook_data.to = to; | hhook_data.to = to; | ||||
hhook_run_hooks(V_tcp_hhh[HHOOK_TCP_EST_IN], &hhook_data, | hhook_run_hooks(V_tcp_hhh[HHOOK_TCP_EST_IN], &hhook_data, | ||||
tp->osd); | tp->osd); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* 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); | ||||
tp->ccv->bytes_this_ack = BYTES_THIS_ACK(tp, th); | tp->ccv->bytes_this_ack = BYTES_THIS_ACK(tp, th); | ||||
if (tp->snd_cwnd <= tp->snd_wnd) | if (tp->snd_cwnd <= tp->snd_wnd) | ||||
tp->ccv->flags |= CCF_CWND_LIMITED; | tp->ccv->flags |= CCF_CWND_LIMITED; | ||||
else | else | ||||
Show All 15 Lines | cc_ack_received(struct tcpcb *tp, struct tcphdr *th, uint16_t type) | ||||
if (CC_ALGO(tp)->ack_received != NULL) { | if (CC_ALGO(tp)->ack_received != NULL) { | ||||
/* XXXLAS: Find a way to live without this */ | /* XXXLAS: Find a way to live without this */ | ||||
tp->ccv->curack = th->th_ack; | tp->ccv->curack = th->th_ack; | ||||
CC_ALGO(tp)->ack_received(tp->ccv, type); | CC_ALGO(tp)->ack_received(tp->ccv, type); | ||||
} | } | ||||
} | } | ||||
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; | ||||
struct inpcb *inp = tp->t_inpcb; | struct inpcb *inp = tp->t_inpcb; | ||||
int rtt; | int rtt; | ||||
INP_WLOCK_ASSERT(tp->t_inpcb); | INP_WLOCK_ASSERT(tp->t_inpcb); | ||||
▲ Show 20 Lines • Show All 107 Lines • ▼ Show 20 Lines | cc_cong_signal(struct tcpcb *tp, struct tcphdr *th, uint32_t type) | ||||
if (CC_ALGO(tp)->cong_signal != NULL) { | if (CC_ALGO(tp)->cong_signal != NULL) { | ||||
if (th != NULL) | if (th != NULL) | ||||
tp->ccv->curack = th->th_ack; | tp->ccv->curack = th->th_ack; | ||||
CC_ALGO(tp)->cong_signal(tp->ccv, type); | CC_ALGO(tp)->cong_signal(tp->ccv, type); | ||||
} | } | ||||
} | } | ||||
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); | ||||
/* XXXLAS: KASSERT that we're in recovery? */ | /* XXXLAS: KASSERT that we're in recovery? */ | ||||
if (CC_ALGO(tp)->post_recovery != NULL) { | if (CC_ALGO(tp)->post_recovery != NULL) { | ||||
tp->ccv->curack = th->th_ack; | tp->ccv->curack = th->th_ack; | ||||
▲ Show 20 Lines • Show All 138 Lines • ▼ Show 20 Lines | #ifdef INET6 | ||||
struct ip6_hdr *ip6 = NULL; | struct ip6_hdr *ip6 = NULL; | ||||
int isipv6; | int isipv6; | ||||
#else | #else | ||||
const void *ip6 = NULL; | const void *ip6 = NULL; | ||||
#endif /* INET6 */ | #endif /* INET6 */ | ||||
struct tcpopt to; /* options in this segment */ | struct tcpopt to; /* options in this segment */ | ||||
char *s = NULL; /* address and port logging */ | char *s = NULL; /* address and port logging */ | ||||
int ti_locked; | int ti_locked; | ||||
#define TI_UNLOCKED 1 | |||||
#define TI_RLOCKED 2 | |||||
#ifdef TCPDEBUG | #ifdef TCPDEBUG | ||||
/* | /* | ||||
* The size of tcp_saveipgen must be the size of the max ip header, | * The size of tcp_saveipgen must be the size of the max ip header, | ||||
* now IPv6. | * now IPv6. | ||||
*/ | */ | ||||
u_char tcp_saveipgen[IP6_HDR_LEN]; | u_char tcp_saveipgen[IP6_HDR_LEN]; | ||||
struct tcphdr tcp_savetcp; | struct tcphdr tcp_savetcp; | ||||
short ostate = 0; | short ostate = 0; | ||||
▲ Show 20 Lines • Show All 555 Lines • ▼ Show 20 Lines | #ifdef TCP_SIGNATURE | ||||
} | } | ||||
#endif | #endif | ||||
/* | /* | ||||
* Process the segment and the data it | * Process the segment and the data it | ||||
* 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->tfb_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); | ||||
} | } | ||||
/* | /* | ||||
* Segment flag validation for new connection attempts: | * Segment flag validation for new connection attempts: | ||||
* | * | ||||
* Our (SYN|ACK) response was rejected. | * Our (SYN|ACK) response was rejected. | ||||
▲ Show 20 Lines • Show All 229 Lines • ▼ Show 20 Lines | #endif | ||||
TCP_PROBE5(receive, NULL, tp, mtod(m, const char *), tp, th); | TCP_PROBE5(receive, NULL, tp, mtod(m, const char *), tp, th); | ||||
/* | /* | ||||
* Segment belongs to a connection in SYN_SENT, ESTABLISHED or later | * Segment belongs to a connection in SYN_SENT, ESTABLISHED or later | ||||
* 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); | tp->t_fb->tfb_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); | ||||
dropwithreset: | dropwithreset: | ||||
TCP_PROBE5(receive, NULL, tp, mtod(m, const char *), tp, th); | TCP_PROBE5(receive, NULL, tp, mtod(m, const char *), tp, th); | ||||
if (ti_locked == TI_RLOCKED) { | if (ti_locked == TI_RLOCKED) { | ||||
INP_INFO_RUNLOCK(&V_tcbinfo); | INP_INFO_RUNLOCK(&V_tcbinfo); | ||||
Show All 38 Lines | drop: | ||||
INP_INFO_UNLOCK_ASSERT(&V_tcbinfo); | INP_INFO_UNLOCK_ASSERT(&V_tcbinfo); | ||||
if (s != NULL) | if (s != NULL) | ||||
free(s, M_TCPLOG); | free(s, M_TCPLOG); | ||||
if (m != NULL) | if (m != NULL) | ||||
m_freem(m); | m_freem(m); | ||||
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) | ||||
{ | { | ||||
int thflags, acked, ourfinisacked, needoutput = 0, sack_changed; | int thflags, acked, ourfinisacked, needoutput = 0, sack_changed; | ||||
int rstreason, todrop, win; | int rstreason, todrop, win; | ||||
u_long tiwin; | u_long tiwin; | ||||
char *s; | char *s; | ||||
▲ Show 20 Lines • Show All 295 Lines • ▼ Show 20 Lines | #endif | ||||
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); | 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, | 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->tfb_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 && | ||||
tlen <= sbspace(&so->so_rcv)) { | tlen <= sbspace(&so->so_rcv)) { | ||||
int newsize = 0; /* automatic sockbuf scaling */ | int newsize = 0; /* automatic sockbuf scaling */ | ||||
/* | /* | ||||
* This is a pure, in-sequence data packet with | * This is a pure, in-sequence data packet with | ||||
▲ Show 20 Lines • Show All 102 Lines • ▼ Show 20 Lines | */ | ||||
sbappendstream_locked(&so->so_rcv, m, 0); | sbappendstream_locked(&so->so_rcv, m, 0); | ||||
} | } | ||||
/* NB: sorwakeup_locked() does an implicit unlock. */ | /* NB: sorwakeup_locked() does an implicit unlock. */ | ||||
sorwakeup_locked(so); | sorwakeup_locked(so); | ||||
if (DELAY_ACK(tp, tlen)) { | if (DELAY_ACK(tp, tlen)) { | ||||
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->tfb_tcp_output(tp); | ||||
} | } | ||||
goto check_delack; | goto check_delack; | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Calculate amount of space in receive window, | * Calculate amount of space in receive window, | ||||
* and then do TCP input processing. | * and then do TCP input processing. | ||||
▲ Show 20 Lines • Show All 598 Lines • ▼ Show 20 Lines | if (SEQ_LEQ(th->th_ack, tp->snd_una)) { | ||||
if (awnd < tp->snd_ssthresh) { | if (awnd < tp->snd_ssthresh) { | ||||
tp->snd_cwnd += tp->t_maxseg; | tp->snd_cwnd += tp->t_maxseg; | ||||
if (tp->snd_cwnd > tp->snd_ssthresh) | if (tp->snd_cwnd > tp->snd_ssthresh) | ||||
tp->snd_cwnd = tp->snd_ssthresh; | tp->snd_cwnd = tp->snd_ssthresh; | ||||
} | } | ||||
} else | } else | ||||
tp->snd_cwnd += tp->t_maxseg; | tp->snd_cwnd += tp->t_maxseg; | ||||
(void) tcp_output(tp); | (void) tp->t_fb->tfb_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; | ||||
/* | /* | ||||
* If we're doing sack, check to | * If we're doing sack, check to | ||||
* see if we're already in sack | * see if we're already in sack | ||||
* recovery. If we're not doing sack, | * recovery. If we're not doing sack, | ||||
Show All 17 Lines | if (SEQ_LEQ(th->th_ack, tp->snd_una)) { | ||||
cc_ack_received(tp, th, CC_DUPACK); | cc_ack_received(tp, th, CC_DUPACK); | ||||
tcp_timer_activate(tp, TT_REXMT, 0); | 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( | ||||
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->tfb_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->tfb_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__)); | ||||
tp->snd_cwnd = tp->snd_ssthresh + | tp->snd_cwnd = tp->snd_ssthresh + | ||||
tp->t_maxseg * | tp->t_maxseg * | ||||
(tp->t_dupacks - tp->snd_limited); | (tp->t_dupacks - tp->snd_limited); | ||||
if (SEQ_GT(onxt, tp->snd_nxt)) | if (SEQ_GT(onxt, tp->snd_nxt)) | ||||
tp->snd_nxt = onxt; | tp->snd_nxt = onxt; | ||||
Show All 30 Lines | if (SEQ_LEQ(th->th_ack, tp->snd_una)) { | ||||
* is new data available to be sent. | * is new data available to be sent. | ||||
* Otherwise we would send pure ACKs. | * Otherwise we would send pure ACKs. | ||||
*/ | */ | ||||
SOCKBUF_LOCK(&so->so_snd); | SOCKBUF_LOCK(&so->so_snd); | ||||
avail = sbavail(&so->so_snd) - | avail = sbavail(&so->so_snd) - | ||||
(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->tfb_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 && | ||||
tp->snd_limited == 0) || | tp->snd_limited == 0) || | ||||
(sent == tp->t_maxseg + 1 && | (sent == tp->t_maxseg + 1 && | ||||
tp->t_flags & TF_SENTFIN), | tp->t_flags & TF_SENTFIN), | ||||
("%s: sent too much", | ("%s: sent too much", | ||||
__func__)); | __func__)); | ||||
▲ Show 20 Lines • Show All 449 Lines • ▼ Show 20 Lines | tcp_trace(TA_INPUT, ostate, tp, (void *)tcp_saveipgen, | ||||
&tcp_savetcp, 0); | &tcp_savetcp, 0); | ||||
#endif | #endif | ||||
TCP_PROBE3(debug__input, tp, th, mtod(m, const char *)); | TCP_PROBE3(debug__input, tp, th, mtod(m, const char *)); | ||||
/* | /* | ||||
* 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->tfb_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", | ||||
__func__, ti_locked)); | __func__, ti_locked)); | ||||
INP_INFO_UNLOCK_ASSERT(&V_tcbinfo); | INP_INFO_UNLOCK_ASSERT(&V_tcbinfo); | ||||
INP_WLOCK_ASSERT(tp->t_inpcb); | INP_WLOCK_ASSERT(tp->t_inpcb); | ||||
if (tp->t_flags & TF_DELACK) { | if (tp->t_flags & TF_DELACK) { | ||||
Show All 31 Lines | tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, | ||||
&tcp_savetcp, 0); | &tcp_savetcp, 0); | ||||
#endif | #endif | ||||
TCP_PROBE3(debug__input, tp, th, mtod(m, const char *)); | TCP_PROBE3(debug__input, tp, th, mtod(m, const char *)); | ||||
if (ti_locked == TI_RLOCKED) | if (ti_locked == TI_RLOCKED) | ||||
INP_INFO_RUNLOCK(&V_tcbinfo); | INP_INFO_RUNLOCK(&V_tcbinfo); | ||||
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->tfb_tcp_output(tp); | ||||
INP_WUNLOCK(tp->t_inpcb); | INP_WUNLOCK(tp->t_inpcb); | ||||
m_freem(m); | m_freem(m); | ||||
return; | return; | ||||
dropwithreset: | dropwithreset: | ||||
if (ti_locked == TI_RLOCKED) | if (ti_locked == TI_RLOCKED) | ||||
INP_INFO_RUNLOCK(&V_tcbinfo); | INP_INFO_RUNLOCK(&V_tcbinfo); | ||||
ti_locked = TI_UNLOCKED; | ti_locked = TI_UNLOCKED; | ||||
Show All 29 Lines | #endif | ||||
m_freem(m); | m_freem(m); | ||||
} | } | ||||
/* | /* | ||||
* Issue RST and make ACK acceptable to originator of segment. | * Issue RST and make ACK acceptable to originator of segment. | ||||
* 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) | ||||
{ | { | ||||
#ifdef INET | #ifdef INET | ||||
struct ip *ip; | struct ip *ip; | ||||
#endif | #endif | ||||
#ifdef INET6 | #ifdef INET6 | ||||
struct ip6_hdr *ip6; | struct ip6_hdr *ip6; | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | #endif | ||||
return; | return; | ||||
drop: | drop: | ||||
m_freem(m); | m_freem(m); | ||||
} | } | ||||
/* | /* | ||||
* 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; | ||||
to->to_flags = 0; | to->to_flags = 0; | ||||
for (; cnt > 0; cnt -= optlen, cp += optlen) { | for (; cnt > 0; cnt -= optlen, cp += optlen) { | ||||
opt = cp[0]; | opt = cp[0]; | ||||
if (opt == TCPOPT_EOL) | if (opt == TCPOPT_EOL) | ||||
▲ Show 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/* | /* | ||||
* Pull out of band byte out of a segment so | * Pull out of band byte out of a segment so | ||||
* it doesn't appear in the user's data queue. | * it doesn't appear in the user's data queue. | ||||
* 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) | ||||
{ | { | ||||
int cnt = off + th->th_urp - 1; | int cnt = off + th->th_urp - 1; | ||||
while (cnt >= 0) { | while (cnt >= 0) { | ||||
if (m->m_len > cnt) { | if (m->m_len > cnt) { | ||||
char *cp = mtod(m, caddr_t) + cnt; | char *cp = mtod(m, caddr_t) + cnt; | ||||
Show All 16 Lines | tcp_pulloutofband(struct socket *so, struct tcphdr *th, struct mbuf *m, | ||||
} | } | ||||
panic("tcp_pulloutofband"); | panic("tcp_pulloutofband"); | ||||
} | } | ||||
/* | /* | ||||
* 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; | ||||
INP_WLOCK_ASSERT(tp->t_inpcb); | INP_WLOCK_ASSERT(tp->t_inpcb); | ||||
TCPSTAT_INC(tcps_rttupdated); | TCPSTAT_INC(tcps_rttupdated); | ||||
tp->t_rttupdated++; | tp->t_rttupdated++; | ||||
▲ Show 20 Lines • Show All 363 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* On a partial ack arrives, force the retransmission of the | * On a partial ack arrives, force the retransmission of the | ||||
* next unacknowledged segment. Do not clear tp->t_dupacks. | * next unacknowledged segment. Do not clear tp->t_dupacks. | ||||
* 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; | ||||
u_long ocwnd = tp->snd_cwnd; | u_long ocwnd = tp->snd_cwnd; | ||||
INP_WLOCK_ASSERT(tp->t_inpcb); | INP_WLOCK_ASSERT(tp->t_inpcb); | ||||
tcp_timer_activate(tp, TT_REXMT, 0); | 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; | ||||
/* | /* | ||||
* Set snd_cwnd to one segment beyond acknowledged offset. | * Set snd_cwnd to one segment beyond acknowledged offset. | ||||
* (tp->snd_una has not yet been updated when this function is called.) | * (tp->snd_una has not yet been updated when this function is called.) | ||||
*/ | */ | ||||
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->tfb_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; | ||||
/* | /* | ||||
* Partial window deflation. Relies on fact that tp->snd_una | * Partial window deflation. Relies on fact that tp->snd_una | ||||
* not updated yet. | * not updated yet. | ||||
*/ | */ | ||||
if (tp->snd_cwnd > BYTES_THIS_ACK(tp, th)) | if (tp->snd_cwnd > BYTES_THIS_ACK(tp, th)) | ||||
Show All 13 Lines |