diff options
Diffstat (limited to 'freebsd/sys/netinet/tcp_subr.c')
-rw-r--r-- | freebsd/sys/netinet/tcp_subr.c | 198 |
1 files changed, 165 insertions, 33 deletions
diff --git a/freebsd/sys/netinet/tcp_subr.c b/freebsd/sys/netinet/tcp_subr.c index 52d2ca2a..223f33f7 100644 --- a/freebsd/sys/netinet/tcp_subr.c +++ b/freebsd/sys/netinet/tcp_subr.c @@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include <rtems/bsd/local/opt_inet.h> #include <rtems/bsd/local/opt_inet6.h> #include <rtems/bsd/local/opt_ipsec.h> +#include <rtems/bsd/local/opt_kern_tls.h> #include <rtems/bsd/local/opt_tcpdebug.h> #include <sys/param.h> @@ -56,6 +57,9 @@ __FBSDID("$FreeBSD$"); #ifdef TCP_HHOOK #include <sys/khelp.h> #endif +#ifdef KERN_TLS +#include <sys/ktls.h> +#endif #include <sys/sysctl.h> #include <sys/jail.h> #include <sys/malloc.h> @@ -201,6 +205,11 @@ SYSCTL_INT(_net_inet_tcp, TCPCTL_DO_RFC1323, rfc1323, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(tcp_do_rfc1323), 0, "Enable rfc1323 (high performance TCP) extensions"); +VNET_DEFINE(int, tcp_ts_offset_per_conn) = 1; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, ts_offset_per_conn, CTLFLAG_VNET | CTLFLAG_RW, + &VNET_NAME(tcp_ts_offset_per_conn), 0, + "Initialize TCP timestamps per connection instead of per host pair"); + static int tcp_log_debug = 0; SYSCTL_INT(_net_inet_tcp, OID_AUTO, log_debug, CTLFLAG_RW, &tcp_log_debug, 0, "Log errors caused by incoming TCP segments"); @@ -263,21 +272,10 @@ static struct tcp_function_block tcp_def_funcblk = { .tfb_tcp_fb_fini = tcp_default_fb_fini, }; -int t_functions_inited = 0; static int tcp_fb_cnt = 0; struct tcp_funchead t_functions; static struct tcp_function_block *tcp_func_set_ptr = &tcp_def_funcblk; -static void -init_tcp_functions(void) -{ - if (t_functions_inited == 0) { - TAILQ_INIT(&t_functions); - rw_init_flags(&tcp_function_lock, "tcp_func_lock" , 0); - t_functions_inited = 1; - } -} - static struct tcp_function_block * find_tcp_functions_locked(struct tcp_function_set *fs) { @@ -565,13 +563,10 @@ sysctl_net_inet_list_func_info(SYSCTL_HANDLER_ARGS) bzero(&tfi, sizeof(tfi)); tfi.tfi_refcnt = f->tf_fb->tfb_refcnt; tfi.tfi_id = f->tf_fb->tfb_id; - (void)strncpy(tfi.tfi_alias, f->tf_name, - TCP_FUNCTION_NAME_LEN_MAX); - tfi.tfi_alias[TCP_FUNCTION_NAME_LEN_MAX - 1] = '\0'; - (void)strncpy(tfi.tfi_name, - f->tf_fb->tfb_tcp_block_name, - TCP_FUNCTION_NAME_LEN_MAX); - tfi.tfi_name[TCP_FUNCTION_NAME_LEN_MAX - 1] = '\0'; + (void)strlcpy(tfi.tfi_alias, f->tf_name, + sizeof(tfi.tfi_alias)); + (void)strlcpy(tfi.tfi_name, + f->tf_fb->tfb_tcp_block_name, sizeof(tfi.tfi_name)); error = SYSCTL_OUT(req, &tfi, sizeof(tfi)); /* * Don't stop on error, as that is the @@ -787,10 +782,9 @@ register_tcp_functions_as_names(struct tcp_function_block *blk, int wait, KASSERT(names != NULL && *num_names > 0, ("%s: Called with 0-length name list", __func__)); KASSERT(names != NULL, ("%s: Called with NULL name list", __func__)); + KASSERT(rw_initialized(&tcp_function_lock), + ("%s: called too early", __func__)); - if (t_functions_inited == 0) { - init_tcp_functions(); - } if ((blk->tfb_tcp_output == NULL) || (blk->tfb_tcp_do_segment == NULL) || (blk->tfb_tcp_ctloutput == NULL) || @@ -819,8 +813,12 @@ register_tcp_functions_as_names(struct tcp_function_block *blk, int wait, } } + if (blk->tfb_flags & TCP_FUNC_BEING_REMOVED) { + *num_names = 0; + return (EINVAL); + } + refcount_init(&blk->tfb_refcnt, 0); - blk->tfb_flags = 0; blk->tfb_id = atomic_fetchadd_int(&next_tcp_stack_id, 1); for (i = 0; i < *num_names; i++) { n = malloc(sizeof(struct tcp_function), M_TCPFUNCTIONS, wait); @@ -830,9 +828,8 @@ register_tcp_functions_as_names(struct tcp_function_block *blk, int wait, } n->tf_fb = blk; - (void)strncpy(fs.function_set_name, names[i], - TCP_FUNCTION_NAME_LEN_MAX); - fs.function_set_name[TCP_FUNCTION_NAME_LEN_MAX - 1] = '\0'; + (void)strlcpy(fs.function_set_name, names[i], + sizeof(fs.function_set_name)); rw_wlock(&tcp_function_lock); if (find_tcp_functions_locked(&fs) != NULL) { /* Duplicate name space not allowed */ @@ -841,8 +838,7 @@ register_tcp_functions_as_names(struct tcp_function_block *blk, int wait, error = EALREADY; goto cleanup; } - (void)strncpy(n->tf_name, names[i], TCP_FUNCTION_NAME_LEN_MAX); - n->tf_name[TCP_FUNCTION_NAME_LEN_MAX - 1] = '\0'; + (void)strlcpy(n->tf_name, names[i], sizeof(n->tf_name)); TAILQ_INSERT_TAIL(&t_functions, n, tf_next); tcp_fb_cnt++; rw_wunlock(&tcp_function_lock); @@ -929,8 +925,8 @@ deregister_tcp_functions(struct tcp_function_block *blk, bool quiesce, bool force) { struct tcp_function *f; - - if (strcmp(blk->tfb_tcp_block_name, "default") == 0) { + + if (blk == &tcp_def_funcblk) { /* You can't un-register the default */ return (EPERM); } @@ -1088,6 +1084,9 @@ tcp_init(void) tcp_keepintvl = TCPTV_KEEPINTVL; tcp_maxpersistidle = TCPTV_KEEP_IDLE; tcp_msl = TCPTV_MSL; + tcp_rexmit_initial = TCPTV_RTOBASE; + if (tcp_rexmit_initial < 1) + tcp_rexmit_initial = 1; tcp_rexmit_min = TCPTV_MIN; if (tcp_rexmit_min < 1) tcp_rexmit_min = 1; @@ -1096,8 +1095,10 @@ tcp_init(void) tcp_rexmit_slop = TCPTV_CPU_VAR; tcp_finwait2_timeout = TCPTV_FINWAIT2_TIMEOUT; tcp_tcbhashsize = hashsize; + /* Setup the tcp function block list */ - init_tcp_functions(); + TAILQ_INIT(&t_functions); + rw_init(&tcp_function_lock, "tcp_func_lock"); register_tcp_functions(&tcp_def_funcblk, M_WAITOK); #ifdef TCP_BLACKBOX /* Initialize the TCP logging data. */ @@ -1130,6 +1131,13 @@ tcp_init(void) SHUTDOWN_PRI_DEFAULT); EVENTHANDLER_REGISTER(maxsockets_change, tcp_zone_change, NULL, EVENTHANDLER_PRI_ANY); + + tcp_inp_lro_direct_queue = counter_u64_alloc(M_WAITOK); + tcp_inp_lro_wokeup_queue = counter_u64_alloc(M_WAITOK); + tcp_inp_lro_compressed = counter_u64_alloc(M_WAITOK); + tcp_inp_lro_single_push = counter_u64_alloc(M_WAITOK); + tcp_inp_lro_locks_taken = counter_u64_alloc(M_WAITOK); + tcp_inp_lro_sack_wake = counter_u64_alloc(M_WAITOK); #ifdef TCPPCAP tcp_pcap_init(); #endif @@ -1666,9 +1674,9 @@ tcp_newtcpcb(struct inpcb *inp) * reasonable initial retransmit time. */ tp->t_srtt = TCPTV_SRTTBASE; - tp->t_rttvar = ((TCPTV_RTOBASE - TCPTV_SRTTBASE) << TCP_RTTVAR_SHIFT) / 4; + tp->t_rttvar = ((tcp_rexmit_initial - TCPTV_SRTTBASE) << TCP_RTTVAR_SHIFT) / 4; tp->t_rttmin = tcp_rexmit_min; - tp->t_rxtcur = TCPTV_RTOBASE; + tp->t_rxtcur = tcp_rexmit_initial; tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT; tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT; tp->t_rcvtime = ticks; @@ -2648,7 +2656,17 @@ tcp_keyed_hash(struct in_conninfo *inc, u_char *key, u_int len) uint32_t tcp_new_ts_offset(struct in_conninfo *inc) { - return (tcp_keyed_hash(inc, V_ts_offset_secret, + struct in_conninfo inc_store, *local_inc; + + if (!V_tcp_ts_offset_per_conn) { + memcpy(&inc_store, inc, sizeof(struct in_conninfo)); + inc_store.inc_lport = 0; + inc_store.inc_fport = 0; + local_inc = &inc_store; + } else { + local_inc = inc; + } + return (tcp_keyed_hash(local_inc, V_ts_offset_secret, sizeof(V_ts_offset_secret))); } @@ -3075,6 +3093,120 @@ SYSCTL_PROC(_net_inet_tcp, TCPCTL_DROP, drop, CTLFLAG_VNET | CTLTYPE_STRUCT | CTLFLAG_WR | CTLFLAG_SKIP, NULL, 0, sysctl_drop, "", "Drop TCP connection"); +#ifdef KERN_TLS +static int +sysctl_switch_tls(SYSCTL_HANDLER_ARGS) +{ + /* addrs[0] is a foreign socket, addrs[1] is a local one. */ + struct sockaddr_storage addrs[2]; + struct inpcb *inp; + struct sockaddr_in *fin, *lin; + struct epoch_tracker et; +#ifdef INET6 + struct sockaddr_in6 *fin6, *lin6; +#endif + int error; + + inp = NULL; + fin = lin = NULL; +#ifdef INET6 + fin6 = lin6 = NULL; +#endif + error = 0; + + if (req->oldptr != NULL || req->oldlen != 0) + return (EINVAL); + if (req->newptr == NULL) + return (EPERM); + if (req->newlen < sizeof(addrs)) + return (ENOMEM); + error = SYSCTL_IN(req, &addrs, sizeof(addrs)); + if (error) + return (error); + + switch (addrs[0].ss_family) { +#ifdef INET6 + case AF_INET6: + fin6 = (struct sockaddr_in6 *)&addrs[0]; + lin6 = (struct sockaddr_in6 *)&addrs[1]; + if (fin6->sin6_len != sizeof(struct sockaddr_in6) || + lin6->sin6_len != sizeof(struct sockaddr_in6)) + return (EINVAL); + if (IN6_IS_ADDR_V4MAPPED(&fin6->sin6_addr)) { + if (!IN6_IS_ADDR_V4MAPPED(&lin6->sin6_addr)) + return (EINVAL); + in6_sin6_2_sin_in_sock((struct sockaddr *)&addrs[0]); + in6_sin6_2_sin_in_sock((struct sockaddr *)&addrs[1]); + fin = (struct sockaddr_in *)&addrs[0]; + lin = (struct sockaddr_in *)&addrs[1]; + break; + } + error = sa6_embedscope(fin6, V_ip6_use_defzone); + if (error) + return (error); + error = sa6_embedscope(lin6, V_ip6_use_defzone); + if (error) + return (error); + break; +#endif +#ifdef INET + case AF_INET: + fin = (struct sockaddr_in *)&addrs[0]; + lin = (struct sockaddr_in *)&addrs[1]; + if (fin->sin_len != sizeof(struct sockaddr_in) || + lin->sin_len != sizeof(struct sockaddr_in)) + return (EINVAL); + break; +#endif + default: + return (EINVAL); + } + INP_INFO_RLOCK_ET(&V_tcbinfo, et); + switch (addrs[0].ss_family) { +#ifdef INET6 + case AF_INET6: + inp = in6_pcblookup(&V_tcbinfo, &fin6->sin6_addr, + fin6->sin6_port, &lin6->sin6_addr, lin6->sin6_port, + INPLOOKUP_WLOCKPCB, NULL); + break; +#endif +#ifdef INET + case AF_INET: + inp = in_pcblookup(&V_tcbinfo, fin->sin_addr, fin->sin_port, + lin->sin_addr, lin->sin_port, INPLOOKUP_WLOCKPCB, NULL); + break; +#endif + } + INP_INFO_RUNLOCK_ET(&V_tcbinfo, et); + if (inp != NULL) { + if ((inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) != 0 || + inp->inp_socket == NULL) { + error = ECONNRESET; + INP_WUNLOCK(inp); + } else { + struct socket *so; + + so = inp->inp_socket; + soref(so); + error = ktls_set_tx_mode(so, + arg2 == 0 ? TCP_TLS_MODE_SW : TCP_TLS_MODE_IFNET); + INP_WUNLOCK(inp); + SOCK_LOCK(so); + sorele(so); + } + } else + error = ESRCH; + return (error); +} + +SYSCTL_PROC(_net_inet_tcp, OID_AUTO, switch_to_sw_tls, + CTLFLAG_VNET | CTLTYPE_STRUCT | CTLFLAG_WR | CTLFLAG_SKIP, NULL, + 0, sysctl_switch_tls, "", "Switch TCP connection to SW TLS"); +SYSCTL_PROC(_net_inet_tcp, OID_AUTO, switch_to_ifnet_tls, + CTLFLAG_VNET | CTLTYPE_STRUCT | CTLFLAG_WR | CTLFLAG_SKIP, NULL, + 1, sysctl_switch_tls, "", "Switch TCP connection to ifnet TLS"); +#endif + /* * Generate a standardized TCP log line for use throughout the * tcp subsystem. Memory allocation is done with M_NOWAIT to |