summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet/tcp_subr.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/netinet/tcp_subr.c')
-rw-r--r--freebsd/sys/netinet/tcp_subr.c198
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