Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_subr.c
Show First 20 Lines • Show All 1,188 Lines • ▼ Show 20 Lines | if ((blk->tfb_tcp_output == NULL) || | ||||
(strlen(blk->tfb_tcp_block_name) == 0)) { | (strlen(blk->tfb_tcp_block_name) == 0)) { | ||||
/* | /* | ||||
* These functions are required and you | * These functions are required and you | ||||
* need a name. | * need a name. | ||||
*/ | */ | ||||
*num_names = 0; | *num_names = 0; | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
if (blk->tfb_tcp_timer_stop_all || | |||||
blk->tfb_tcp_timer_activate || | |||||
blk->tfb_tcp_timer_active || | |||||
blk->tfb_tcp_timer_stop) { | |||||
/* | |||||
* If you define one timer function you | |||||
* must have them all. | |||||
*/ | |||||
if ((blk->tfb_tcp_timer_stop_all == NULL) || | |||||
(blk->tfb_tcp_timer_activate == NULL) || | |||||
(blk->tfb_tcp_timer_active == NULL) || | |||||
(blk->tfb_tcp_timer_stop == NULL)) { | |||||
*num_names = 0; | |||||
return (EINVAL); | |||||
} | |||||
} | |||||
if (blk->tfb_flags & TCP_FUNC_BEING_REMOVED) { | if (blk->tfb_flags & TCP_FUNC_BEING_REMOVED) { | ||||
*num_names = 0; | *num_names = 0; | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
refcount_init(&blk->tfb_refcnt, 0); | refcount_init(&blk->tfb_refcnt, 0); | ||||
blk->tfb_id = atomic_fetchadd_int(&next_tcp_stack_id, 1); | blk->tfb_id = atomic_fetchadd_int(&next_tcp_stack_id, 1); | ||||
▲ Show 20 Lines • Show All 1,001 Lines • ▼ Show 20 Lines | #endif | ||||
TAILQ_INIT(&tp->t_segq); | TAILQ_INIT(&tp->t_segq); | ||||
tp->t_maxseg = | tp->t_maxseg = | ||||
#ifdef INET6 | #ifdef INET6 | ||||
isipv6 ? V_tcp_v6mssdflt : | isipv6 ? V_tcp_v6mssdflt : | ||||
#endif /* INET6 */ | #endif /* INET6 */ | ||||
V_tcp_mssdflt; | V_tcp_mssdflt; | ||||
/* Set up our timeouts. */ | callout_init_rw(&tp->t_callout, &inp->inp_lock, CALLOUT_RETURNUNLOCKED); | ||||
callout_init(&tp->tt_rexmt, 1); | for (int i = 0; i < TT_N; i++) | ||||
callout_init(&tp->tt_persist, 1); | tp->t_timers[i] = SBT_MAX; | ||||
callout_init(&tp->tt_keep, 1); | |||||
callout_init(&tp->tt_2msl, 1); | |||||
callout_init(&tp->tt_delack, 1); | |||||
switch (V_tcp_do_rfc1323) { | switch (V_tcp_do_rfc1323) { | ||||
case 0: | case 0: | ||||
break; | break; | ||||
default: | default: | ||||
case 1: | case 1: | ||||
tp->t_flags = (TF_REQ_SCALE|TF_REQ_TSTMP); | tp->t_flags = (TF_REQ_SCALE|TF_REQ_TSTMP); | ||||
break; | break; | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | #endif | ||||
} | } | ||||
#ifdef STATS | #ifdef STATS | ||||
if (V_tcp_perconn_stats_enable == 1) | if (V_tcp_perconn_stats_enable == 1) | ||||
tp->t_stats = stats_blob_alloc(V_tcp_perconn_stats_dflt_tpl, 0); | tp->t_stats = stats_blob_alloc(V_tcp_perconn_stats_dflt_tpl, 0); | ||||
#endif | #endif | ||||
if (V_tcp_do_lrd) | if (V_tcp_do_lrd) | ||||
tp->t_flags |= TF_LRD; | tp->t_flags |= TF_LRD; | ||||
/* | |||||
* XXXGL: this self-reference might be pointless. It will go away | |||||
* when the TCP timers are properly locked and could never fire after | |||||
* tcp_discardcb(). | |||||
*/ | |||||
in_pcbref(inp); | |||||
return (tp); | return (tp); | ||||
} | } | ||||
/* | /* | ||||
* Drop a TCP connection, reporting | * Drop a TCP connection, reporting | ||||
* the specified error. If connection is synchronized, | * the specified error. If connection is synchronized, | ||||
* then send a RST to peer. | * then send a RST to peer. | ||||
*/ | */ | ||||
Show All 17 Lines | tcp_drop(struct tcpcb *tp, int errno) | ||||
so->so_error = errno; | so->so_error = errno; | ||||
return (tcp_close(tp)); | return (tcp_close(tp)); | ||||
} | } | ||||
void | void | ||||
tcp_discardcb(struct tcpcb *tp) | tcp_discardcb(struct tcpcb *tp) | ||||
{ | { | ||||
struct inpcb *inp = tptoinpcb(tp); | struct inpcb *inp = tptoinpcb(tp); | ||||
struct socket *so = tptosocket(tp); | |||||
#ifdef INET6 | |||||
bool isipv6 = (inp->inp_vflag & INP_IPV6) != 0; | |||||
#endif | |||||
INP_WLOCK_ASSERT(inp); | INP_WLOCK_ASSERT(inp); | ||||
/* | tcp_timer_stop(tp); | ||||
* Make sure that all of our timers are stopped before we delete the | |||||
* PCB. | |||||
* | |||||
* If stopping a timer fails, we schedule a discard function in same | |||||
* callout, and the last discard function called will take care of | |||||
* deleting the tcpcb. | |||||
*/ | |||||
tp->tt_draincnt = 0; | |||||
tcp_timer_stop(tp, TT_REXMT); | |||||
tcp_timer_stop(tp, TT_PERSIST); | |||||
tcp_timer_stop(tp, TT_KEEP); | |||||
tcp_timer_stop(tp, TT_2MSL); | |||||
tcp_timer_stop(tp, TT_DELACK); | |||||
if (tp->t_fb->tfb_tcp_timer_stop_all) { | if (tp->t_fb->tfb_tcp_timer_stop_all) { | ||||
/* | |||||
* Call the stop-all function of the methods, | |||||
* this function should call the tcp_timer_stop() | |||||
* method with each of the function specific timeouts. | |||||
* That stop will be called via the tfb_tcp_timer_stop() | |||||
* which should use the async drain function of the | |||||
* callout system (see tcp_var.h). | |||||
*/ | |||||
tp->t_fb->tfb_tcp_timer_stop_all(tp); | tp->t_fb->tfb_tcp_timer_stop_all(tp); | ||||
} | } | ||||
/* free the reassembly queue, if any */ | /* free the reassembly queue, if any */ | ||||
tcp_reass_flush(tp); | tcp_reass_flush(tp); | ||||
#ifdef TCP_OFFLOAD | #ifdef TCP_OFFLOAD | ||||
/* Disconnect offload device, if any. */ | /* Disconnect offload device, if any. */ | ||||
Show All 19 Lines | |||||
#ifdef TCP_HHOOK | #ifdef TCP_HHOOK | ||||
khelp_destroy_osd(&tp->t_osd); | khelp_destroy_osd(&tp->t_osd); | ||||
#endif | #endif | ||||
#ifdef STATS | #ifdef STATS | ||||
stats_blob_destroy(tp->t_stats); | stats_blob_destroy(tp->t_stats); | ||||
#endif | #endif | ||||
CC_ALGO(tp) = NULL; | CC_ALGO(tp) = NULL; | ||||
if (tp->tt_draincnt == 0) | |||||
tcp_freecb(tp); | |||||
} | |||||
bool | |||||
tcp_freecb(struct tcpcb *tp) | |||||
{ | |||||
struct inpcb *inp = tptoinpcb(tp); | |||||
struct socket *so = tptosocket(tp); | |||||
#ifdef INET6 | |||||
bool isipv6 = (inp->inp_vflag & INP_IPV6) != 0; | |||||
#endif | |||||
INP_WLOCK_ASSERT(inp); | |||||
MPASS(tp->tt_draincnt == 0); | |||||
/* We own the last reference on tcpcb, let's free it. */ | |||||
#ifdef TCP_BLACKBOX | #ifdef TCP_BLACKBOX | ||||
tcp_log_tcpcbfini(tp); | tcp_log_tcpcbfini(tp); | ||||
#endif | #endif | ||||
TCPSTATES_DEC(tp->t_state); | TCPSTATES_DEC(tp->t_state); | ||||
if (tp->t_fb->tfb_tcp_fb_fini) | if (tp->t_fb->tfb_tcp_fb_fini) | ||||
(*tp->t_fb->tfb_tcp_fb_fini)(tp, 1); | (*tp->t_fb->tfb_tcp_fb_fini)(tp, 1); | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | #endif | ||||
metrics.rmx_cwnd = tp->snd_cwnd; | metrics.rmx_cwnd = tp->snd_cwnd; | ||||
metrics.rmx_sendpipe = 0; | metrics.rmx_sendpipe = 0; | ||||
metrics.rmx_recvpipe = 0; | metrics.rmx_recvpipe = 0; | ||||
tcp_hc_update(&inp->inp_inc, &metrics); | tcp_hc_update(&inp->inp_inc, &metrics); | ||||
} | } | ||||
refcount_release(&tp->t_fb->tfb_refcnt); | refcount_release(&tp->t_fb->tfb_refcnt); | ||||
return (in_pcbrele_wlocked(inp)); | |||||
} | } | ||||
/* | /* | ||||
* Attempt to close a TCP control block, marking it as dropped, and freeing | * Attempt to close a TCP control block, marking it as dropped, and freeing | ||||
* the socket if we hold the only reference. | * the socket if we hold the only reference. | ||||
*/ | */ | ||||
struct tcpcb * | struct tcpcb * | ||||
tcp_close(struct tcpcb *tp) | tcp_close(struct tcpcb *tp) | ||||
▲ Show 20 Lines • Show All 1,433 Lines • ▼ Show 20 Lines | tcp_inptoxtp(const struct inpcb *inp, struct xtcpcb *xt) | ||||
xt->t_dsack_bytes = tp->t_dsack_bytes; | xt->t_dsack_bytes = tp->t_dsack_bytes; | ||||
xt->t_dsack_tlp_bytes = tp->t_dsack_tlp_bytes; | xt->t_dsack_tlp_bytes = tp->t_dsack_tlp_bytes; | ||||
xt->t_dsack_pack = tp->t_dsack_pack; | xt->t_dsack_pack = tp->t_dsack_pack; | ||||
xt->t_maxseg = tp->t_maxseg; | xt->t_maxseg = tp->t_maxseg; | ||||
xt->xt_ecn = (tp->t_flags2 & TF2_ECN_PERMIT) ? 1 : 0 + | xt->xt_ecn = (tp->t_flags2 & TF2_ECN_PERMIT) ? 1 : 0 + | ||||
(tp->t_flags2 & TF2_ACE_PERMIT) ? 2 : 0; | (tp->t_flags2 & TF2_ACE_PERMIT) ? 2 : 0; | ||||
now = getsbinuptime(); | now = getsbinuptime(); | ||||
#define COPYTIMER(ttt) do { \ | #define COPYTIMER(which,where) do { \ | ||||
if (callout_active(&tp->ttt)) \ | if (tp->t_timers[which] != SBT_MAX) \ | ||||
xt->ttt = (tp->ttt.c_time - now) / SBT_1MS; \ | xt->where = (tp->t_timers[which] - now) / SBT_1MS; \ | ||||
else \ | else \ | ||||
xt->ttt = 0; \ | xt->where = 0; \ | ||||
} while (0) | } while (0) | ||||
COPYTIMER(tt_delack); | COPYTIMER(TT_DELACK, tt_delack); | ||||
COPYTIMER(tt_rexmt); | COPYTIMER(TT_REXMT, tt_rexmt); | ||||
COPYTIMER(tt_persist); | COPYTIMER(TT_PERSIST, tt_persist); | ||||
COPYTIMER(tt_keep); | COPYTIMER(TT_KEEP, tt_keep); | ||||
COPYTIMER(tt_2msl); | COPYTIMER(TT_2MSL, tt_2msl); | ||||
#undef COPYTIMER | #undef COPYTIMER | ||||
xt->t_rcvtime = 1000 * (ticks - tp->t_rcvtime) / hz; | xt->t_rcvtime = 1000 * (ticks - tp->t_rcvtime) / hz; | ||||
xt->xt_encaps_port = tp->t_port; | xt->xt_encaps_port = tp->t_port; | ||||
bcopy(tp->t_fb->tfb_tcp_block_name, xt->xt_stack, | bcopy(tp->t_fb->tfb_tcp_block_name, xt->xt_stack, | ||||
TCP_FUNCTION_NAME_LEN_MAX); | TCP_FUNCTION_NAME_LEN_MAX); | ||||
bcopy(CC_ALGO(tp)->name, xt->xt_cc, TCP_CA_NAME_MAX); | bcopy(CC_ALGO(tp)->name, xt->xt_cc, TCP_CA_NAME_MAX); | ||||
#ifdef TCP_BLACKBOX | #ifdef TCP_BLACKBOX | ||||
▲ Show 20 Lines • Show All 70 Lines • Show Last 20 Lines |