X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/0a7de7458d150b5d4dffc935ba399be265ef0a1a..HEAD:/bsd/netinet/tcp_usrreq.c diff --git a/bsd/netinet/tcp_usrreq.c b/bsd/netinet/tcp_usrreq.c index ef53f55b9..861c9f71d 100644 --- a/bsd/netinet/tcp_usrreq.c +++ b/bsd/netinet/tcp_usrreq.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2019 Apple Inc. All rights reserved. + * Copyright (c) 2000-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -67,12 +67,11 @@ #include #include #include -#if INET6 #include -#endif /* INET6 */ -#if !CONFIG_EMBEDDED +#if XNU_TARGET_OS_OSX #include -#endif +#endif /* XNU_TARGET_OS_OSX */ +#include #include #include #include @@ -82,21 +81,16 @@ #include #include #include +#include #include #include -#if INET6 #include -#endif #include -#if INET6 #include -#endif #include #include -#if INET6 #include -#endif #include #include #include @@ -104,6 +98,7 @@ #include #include #include +#include #include #if TCPDEBUG #include @@ -125,19 +120,16 @@ errno_t tcp_fill_info_for_info_tuple(struct info_tuple *, struct tcp_info *); int tcp_sysctl_info(struct sysctl_oid *, void *, int, struct sysctl_req *); static void tcp_connection_fill_info(struct tcpcb *tp, struct tcp_connection_info *tci); +static int tcp_get_mpkl_send_info(struct mbuf *, struct so_mpkl_send_info *); /* * TCP protocol interface to socket abstraction. */ -extern char *tcpstates[]; /* XXX ??? */ - static int tcp_attach(struct socket *, struct proc *); static int tcp_connect(struct tcpcb *, struct sockaddr *, struct proc *); -#if INET6 static int tcp6_connect(struct tcpcb *, struct sockaddr *, struct proc *); static int tcp6_usr_connect(struct socket *, struct sockaddr *, struct proc *); -#endif /* INET6 */ static struct tcpcb *tcp_disconnect(struct tcpcb *); static struct tcpcb *tcp_usrclosed(struct tcpcb *); extern void tcp_sbrcv_trim(struct tcpcb *tp, struct sockbuf *sb); @@ -187,7 +179,7 @@ tcp_usr_attach(struct socket *so, __unused int proto, struct proc *p) } if ((so->so_options & SO_LINGER) && so->so_linger == 0) { - so->so_linger = TCP_LINGERTIME * hz; + so->so_linger = (short)(TCP_LINGERTIME * hz); } tp = sototcpcb(so); out: @@ -230,18 +222,18 @@ out: } #if NECP -#define COMMON_START() TCPDEBUG0; \ +#define COMMON_START_ALLOW_FLOW_DIVERT(allow) TCPDEBUG0; \ do { \ if (inp == NULL || inp->inp_state == INPCB_STATE_DEAD) \ return (EINVAL); \ - if (necp_socket_should_use_flow_divert(inp)) \ + if (!(allow) && necp_socket_should_use_flow_divert(inp)) \ return (EPROTOTYPE); \ tp = intotcpcb(inp); \ TCPDEBUG1(); \ calculate_tcp_clock(); \ } while (0) #else /* NECP */ -#define COMMON_START() TCPDEBUG0; \ +#define COMMON_START_ALLOW_FLOW_DIVERT(allow) TCPDEBUG0; \ do { \ if (inp == NULL || inp->inp_state == INPCB_STATE_DEAD) \ return (EINVAL); \ @@ -251,6 +243,7 @@ do { \ } while (0) #endif /* !NECP */ +#define COMMON_START() COMMON_START_ALLOW_FLOW_DIVERT(false) #define COMMON_END(req) out: TCPDEBUG2(req); return error; goto out @@ -276,7 +269,7 @@ tcp_usr_bind(struct socket *so, struct sockaddr *nam, struct proc *p) struct tcpcb *tp; struct sockaddr_in *sinp; - COMMON_START(); + COMMON_START_ALLOW_FLOW_DIVERT(true); if (nam->sa_family != 0 && nam->sa_family != AF_INET) { error = EAFNOSUPPORT; @@ -311,7 +304,6 @@ tcp_usr_bind(struct socket *so, struct sockaddr *nam, struct proc *p) COMMON_END(PRU_BIND); } -#if INET6 static int tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct proc *p) { @@ -320,7 +312,7 @@ tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct proc *p) struct tcpcb *tp; struct sockaddr_in6 *sin6p; - COMMON_START(); + COMMON_START_ALLOW_FLOW_DIVERT(true); if (nam->sa_family != 0 && nam->sa_family != AF_INET6) { error = EAFNOSUPPORT; @@ -358,7 +350,6 @@ tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct proc *p) } COMMON_END(PRU_BIND); } -#endif /* INET6 */ /* * Prepare to accept connections. @@ -380,17 +371,17 @@ tcp_usr_listen(struct socket *so, struct proc *p) struct inpcb *inp = sotoinpcb(so); struct tcpcb *tp; - COMMON_START(); + COMMON_START_ALLOW_FLOW_DIVERT(true); if (inp->inp_lport == 0) { error = in_pcbbind(inp, NULL, p); } if (error == 0) { tp->t_state = TCPS_LISTEN; } + TCP_LOG_LISTEN(tp, error); COMMON_END(PRU_LISTEN); } -#if INET6 static int tcp6_usr_listen(struct socket *so, struct proc *p) { @@ -398,7 +389,7 @@ tcp6_usr_listen(struct socket *so, struct proc *p) struct inpcb *inp = sotoinpcb(so); struct tcpcb *tp; - COMMON_START(); + COMMON_START_ALLOW_FLOW_DIVERT(true); if (inp->inp_lport == 0) { inp->inp_vflag &= ~INP_IPV4; if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { @@ -409,9 +400,9 @@ tcp6_usr_listen(struct socket *so, struct proc *p) if (error == 0) { tp->t_state = TCPS_LISTEN; } + TCP_LOG_LISTEN(tp, error); COMMON_END(PRU_LISTEN); } -#endif /* INET6 */ static int tcp_connect_complete(struct socket *so) @@ -422,7 +413,8 @@ tcp_connect_complete(struct socket *so) /* TFO delays the tcp_output until later, when the app calls write() */ if (so->so_flags1 & SOF1_PRECONNECT_DATA) { - if (!necp_socket_is_allowed_to_send_recv(sotoinpcb(so), NULL, NULL, NULL)) { + if (!necp_socket_is_allowed_to_send_recv(sotoinpcb(so), NULL, 0, NULL, NULL, NULL, NULL)) { + TCP_LOG_DROP_NECP(NULL, NULL, tp, true); return EHOSTUNREACH; } @@ -474,27 +466,21 @@ tcp_usr_connect(struct socket *so, struct sockaddr *nam, struct proc *p) } } #if NECP -#if FLOW_DIVERT - else if (necp_socket_should_use_flow_divert(inp)) { - uint32_t fd_ctl_unit = necp_socket_get_flow_divert_control_unit(inp); - if (fd_ctl_unit > 0) { - error = flow_divert_pcb_init(so, fd_ctl_unit); - if (error == 0) { - error = flow_divert_connect_out(so, nam, p); - } - } else { - error = ENETDOWN; - } - - return error; - } -#endif /* FLOW_DIVERT */ #if CONTENT_FILTER - error = cfil_sock_attach(so); + error = cfil_sock_attach(so, NULL, nam, CFS_CONNECTION_DIR_OUT); if (error != 0) { return error; } #endif /* CONTENT_FILTER */ +#if FLOW_DIVERT + if (necp_socket_should_use_flow_divert(inp)) { + error = flow_divert_pcb_init(so); + if (error == 0) { + error = flow_divert_connect_out(so, nam, p); + } + return error; + } +#endif /* FLOW_DIVERT */ #endif /* NECP */ tp = intotcpcb(inp); TCPDEBUG1(); @@ -516,11 +502,14 @@ tcp_usr_connect(struct socket *so, struct sockaddr *nam, struct proc *p) } if ((error = tcp_connect(tp, nam, p)) != 0) { + TCP_LOG_CONNECT(tp, true, error); goto out; } error = tcp_connect_complete(so); + TCP_LOG_CONNECT(tp, true, error); + COMMON_END(PRU_CONNECT); } @@ -572,11 +561,9 @@ tcp_usr_connectx_common(struct socket *so, int af, case AF_INET: error = tcp_usr_connect(so, dst, p); break; -#if INET6 case AF_INET6: error = tcp6_usr_connect(so, dst, p); break; -#endif /* INET6 */ default: VERIFY(0); /* NOTREACHED */ @@ -636,7 +623,6 @@ tcp_usr_connectx(struct socket *so, struct sockaddr *src, pcid, flags, arg, arglen, uio, bytes_written); } -#if INET6 static int tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct proc *p) { @@ -658,27 +644,21 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct proc *p) } } #if NECP -#if FLOW_DIVERT - else if (necp_socket_should_use_flow_divert(inp)) { - uint32_t fd_ctl_unit = necp_socket_get_flow_divert_control_unit(inp); - if (fd_ctl_unit > 0) { - error = flow_divert_pcb_init(so, fd_ctl_unit); - if (error == 0) { - error = flow_divert_connect_out(so, nam, p); - } - } else { - error = ENETDOWN; - } - - return error; - } -#endif /* FLOW_DIVERT */ #if CONTENT_FILTER - error = cfil_sock_attach(so); + error = cfil_sock_attach(so, NULL, nam, CFS_CONNECTION_DIR_OUT); if (error != 0) { return error; } #endif /* CONTENT_FILTER */ +#if FLOW_DIVERT + if (necp_socket_should_use_flow_divert(inp)) { + error = flow_divert_pcb_init(so); + if (error == 0) { + error = flow_divert_connect_out(so, nam, p); + } + return error; + } +#endif /* FLOW_DIVERT */ #endif /* NECP */ tp = intotcpcb(inp); @@ -705,13 +685,22 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct proc *p) struct sockaddr_in sin; if ((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0) { - return EINVAL; + error = EINVAL; + goto out; } in6_sin6_2_sin(&sin, sin6p); + /* + * Must disallow TCP ``connections'' to multicast addresses. + */ + if (IN_MULTICAST(ntohl(sin.sin_addr.s_addr))) { + error = EAFNOSUPPORT; + goto out; + } inp->inp_vflag |= INP_IPV4; inp->inp_vflag &= ~INP_IPV6; if ((error = tcp_connect(tp, (struct sockaddr *)&sin, p)) != 0) { + TCP_LOG_CONNECT(tp, true, error); goto out; } @@ -721,10 +710,14 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct proc *p) inp->inp_vflag &= ~INP_IPV4; inp->inp_vflag |= INP_IPV6; if ((error = tcp6_connect(tp, nam, p)) != 0) { + TCP_LOG_CONNECT(tp, true, error); goto out; } error = tcp_connect_complete(so); + + TCP_LOG_CONNECT(tp, true, error); + COMMON_END(PRU_CONNECT); } @@ -737,7 +730,6 @@ tcp6_usr_connectx(struct socket *so, struct sockaddr*src, return tcp_usr_connectx_common(so, AF_INET6, src, dst, p, ifscope, aid, pcid, flags, arg, arglen, uio, bytes_written); } -#endif /* INET6 */ /* * Initiate disconnect from peer. @@ -807,23 +799,19 @@ tcp_usr_accept(struct socket *so, struct sockaddr **nam) else if (necp_socket_should_use_flow_divert(inp)) { return EPROTOTYPE; } -#if CONTENT_FILTER - error = cfil_sock_attach(so); - if (error != 0) { - return error; - } -#endif /* CONTENT_FILTER */ + #endif /* NECP */ tp = intotcpcb(inp); TCPDEBUG1(); + TCP_LOG_ACCEPT(tp, 0); + calculate_tcp_clock(); COMMON_END(PRU_ACCEPT); } -#if INET6 static int tcp6_usr_accept(struct socket *so, struct sockaddr **nam) { @@ -843,23 +831,19 @@ tcp6_usr_accept(struct socket *so, struct sockaddr **nam) else if (necp_socket_should_use_flow_divert(inp)) { return EPROTOTYPE; } -#if CONTENT_FILTER - error = cfil_sock_attach(so); - if (error != 0) { - return error; - } -#endif /* CONTENT_FILTER */ + #endif /* NECP */ tp = intotcpcb(inp); TCPDEBUG1(); + TCP_LOG_ACCEPT(tp, 0); + calculate_tcp_clock(); in6_mapped_peeraddr(so, nam); COMMON_END(PRU_ACCEPT); } -#endif /* INET6 */ /* * Mark the connection as being incapable of further output. @@ -937,7 +921,7 @@ tcp_usr_shutdown(struct socket *so) * After a receive, possibly send window update to peer. */ static int -tcp_usr_rcvd(struct socket *so, __unused int flags) +tcp_usr_rcvd(struct socket *so, int flags) { int error = 0; struct inpcb *inp = sotoinpcb(so); @@ -950,6 +934,10 @@ tcp_usr_rcvd(struct socket *so, __unused int flags) } tcp_sbrcv_trim(tp, &so->so_rcv); + if (flags & MSG_WAITALL) { + tp->t_flags |= TF_ACKNOW; + } + /* * This tcp_output is solely there to trigger window-updates. * However, we really do not want these window-updates while we @@ -1004,10 +992,11 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m, int error = 0; struct inpcb *inp = sotoinpcb(so); struct tcpcb *tp; - uint32_t msgpri = MSG_PRI_DEFAULT; -#if INET6 + uint32_t mpkl_len = 0; /* length of mbuf chain */ + uint32_t mpkl_seq; /* sequence number where new data is added */ + struct so_mpkl_send_info mpkl_send_info = {}; + int isipv6; -#endif TCPDEBUG0; if (inp == NULL || inp->inp_state == INPCB_STATE_DEAD @@ -1037,19 +1026,33 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m, TCPDEBUG1(); goto out; } -#if INET6 isipv6 = nam && nam->sa_family == AF_INET6; -#endif /* INET6 */ tp = intotcpcb(inp); TCPDEBUG1(); calculate_tcp_clock(); + if (net_mpklog_enabled) { + mpkl_seq = tp->snd_una + so->so_snd.sb_cc; + if (m) { + mpkl_len = m_length(m); + } + if (so->so_flags1 & SOF1_MPKL_SEND_INFO) { + uuid_copy(mpkl_send_info.mpkl_uuid, so->so_mpkl_send_uuid); + mpkl_send_info.mpkl_proto = so->so_mpkl_send_proto; + } + } + if (control != NULL) { - if (so->so_flags & SOF_ENABLE_MSGS) { - /* Get the msg priority from control mbufs */ - error = tcp_get_msg_priority(control, &msgpri); - if (error) { + if (control->m_len > 0 && net_mpklog_enabled) { + error = tcp_get_mpkl_send_info(control, &mpkl_send_info); + /* + * Intepretation of the returned code: + * 0: client wants us to use value passed in SCM_MPKL_SEND_INFO + * 1: SCM_MPKL_SEND_INFO was not present + * other: failure + */ + if (error != 0 && error != ENOMSG) { m_freem(control); if (m != NULL) { m_freem(m); @@ -1058,27 +1061,12 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m, m = NULL; goto out; } - m_freem(control); - control = NULL; - } else if (control->m_len) { - /* - * if not unordered, TCP should not have - * control mbufs - */ - m_freem(control); - if (m != NULL) { - m_freem(m); - } - control = NULL; - m = NULL; - error = EINVAL; - goto out; } - } - - if (so->so_flags & SOF_ENABLE_MSGS) { - VERIFY(m->m_flags & M_PKTHDR); - m->m_pkthdr.msg_pri = msgpri; + /* + * Silently drop unsupported ancillary data messages + */ + m_freem(control); + control = NULL; } /* MPTCP sublow socket buffers must not be compressed */ @@ -1086,12 +1074,7 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m, (so->so_snd.sb_flags & SB_NOCOMPRESS)); if (!(flags & PRUS_OOB) || (so->so_flags1 & SOF1_PRECONNECT_DATA)) { - /* Call msg send if message delivery is enabled */ - if (so->so_flags & SOF_ENABLE_MSGS) { - sbappendmsg_snd(&so->so_snd, m); - } else { - sbappendstream(&so->so_snd, m); - } + sbappendstream(&so->so_snd, m); if (nam && tp->t_state < TCPS_SYN_SENT) { /* @@ -1100,18 +1083,23 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m, * initialize maxseg/maxopd using peer's cached * MSS. */ -#if INET6 if (isipv6) { error = tcp6_connect(tp, nam, p); - } else -#endif /* INET6 */ - error = tcp_connect(tp, nam, p); + } else { + error = tcp_connect(tp, nam, p); + } if (error) { + TCP_LOG_CONNECT(tp, true, error); goto out; } tp->snd_wnd = TTCP_CLIENT_SND_WND; tp->max_sndwnd = tp->snd_wnd; tcp_mss(tp, -1, IFSCOPE_NONE); + + TCP_LOG_CONNECT(tp, true, error); + + /* The sequence number of the data is past the SYN */ + mpkl_seq = tp->iss + 1; } if (flags & PRUS_EOF) { @@ -1155,18 +1143,20 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m, * initialize maxseg/maxopd using peer's cached * MSS. */ -#if INET6 if (isipv6) { error = tcp6_connect(tp, nam, p); - } else -#endif /* INET6 */ - error = tcp_connect(tp, nam, p); + } else { + error = tcp_connect(tp, nam, p); + } if (error) { + TCP_LOG_CONNECT(tp, true, error); goto out; } tp->snd_wnd = TTCP_CLIENT_SND_WND; tp->max_sndwnd = tp->snd_wnd; tcp_mss(tp, -1, IFSCOPE_NONE); + + TCP_LOG_CONNECT(tp, true, error); } tp->snd_up = tp->snd_una + so->so_snd.sb_cc; tp->t_flagsext |= TF_FORCE; @@ -1174,6 +1164,17 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m, tp->t_flagsext &= ~TF_FORCE; } + if (net_mpklog_enabled && (inp = tp->t_inpcb) != NULL && + ((inp->inp_last_outifp != NULL && + (inp->inp_last_outifp->if_xflags & IFXF_MPK_LOG)) || + (inp->inp_boundifp != NULL && + (inp->inp_boundifp->if_xflags & IFXF_MPK_LOG)))) { + MPKL_TCP_SEND(tcp_mpkl_log_object, + mpkl_send_info.mpkl_proto, mpkl_send_info.mpkl_uuid, + ntohs(inp->inp_lport), ntohs(inp->inp_fport), + mpkl_seq, mpkl_len, + so->last_pid, so->so_log_seqn++); + } /* * We wait for the socket to successfully connect before returning. @@ -1295,7 +1296,6 @@ struct pr_usrreqs tcp_usrreqs = { .pru_preconnect = tcp_usr_preconnect, }; -#if INET6 struct pr_usrreqs tcp6_usrreqs = { .pru_abort = tcp_usr_abort, .pru_accept = tcp6_usr_accept, @@ -1318,7 +1318,6 @@ struct pr_usrreqs tcp6_usrreqs = { .pru_soreceive = soreceive, .pru_preconnect = tcp_usr_preconnect, }; -#endif /* INET6 */ /* * Common subroutine to open a TCP connection to remote host specified @@ -1437,7 +1436,7 @@ skip_oinp: inp->inp_flowhash = inp_calc_flowhash(inp); } - tcp_set_max_rwinscale(tp, so, outif); + tcp_set_max_rwinscale(tp, so); soisconnecting(so); tcpstat.tcps_connattempt++; @@ -1445,10 +1444,13 @@ skip_oinp: tp->t_timer[TCPT_KEEP] = OFFSET_FROM_START(tp, TCP_CONN_KEEPINIT(tp)); tp->iss = tcp_new_isn(tp); tcp_sendseqinit(tp); + tp->t_connect_time = tcp_now; if (nstat_collect) { nstat_route_connect_attempt(inp->inp_route.ro_rt); } + tcp_add_fsw_flow(tp, outif); + done: if (outif != NULL) { ifnet_release(outif); @@ -1457,7 +1459,6 @@ done: return error; } -#if INET6 static int tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct proc *p) { @@ -1534,10 +1535,10 @@ tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct proc *p) if (inp->inp_flow == 0 && inp->in6p_flags & IN6P_AUTOFLOWLABEL) { inp->inp_flow &= ~IPV6_FLOWLABEL_MASK; inp->inp_flow |= - (htonl(inp->inp_flowhash) & IPV6_FLOWLABEL_MASK); + (htonl(ip6_randomflowlabel()) & IPV6_FLOWLABEL_MASK); } - tcp_set_max_rwinscale(tp, so, outif); + tcp_set_max_rwinscale(tp, so); soisconnecting(so); tcpstat.tcps_connattempt++; @@ -1546,10 +1547,13 @@ tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct proc *p) TCP_CONN_KEEPINIT(tp)); tp->iss = tcp_new_isn(tp); tcp_sendseqinit(tp); + tp->t_connect_time = tcp_now; if (nstat_collect) { nstat_route_connect_attempt(inp->inp_route.ro_rt); } + tcp_add_fsw_flow(tp, outif); + done: if (outif != NULL) { ifnet_release(outif); @@ -1557,7 +1561,6 @@ done: return error; } -#endif /* INET6 */ /* * Export TCP internal state information via a struct tcp_info @@ -1569,7 +1572,7 @@ tcp_fill_info(struct tcpcb *tp, struct tcp_info *ti) bzero(ti, sizeof(*ti)); - ti->tcpi_state = tp->t_state; + ti->tcpi_state = (uint8_t)tp->t_state; ti->tcpi_flowhash = inp->inp_flowhash; if (tp->t_state > TCPS_LISTEN) { @@ -1639,7 +1642,7 @@ tcp_fill_info(struct tcpcb *tp, struct tcp_info *ti) ti->tcpi_rxoutoforderbytes = tp->t_stat.rxoutoforderbytes; if (tp->t_state > TCPS_LISTEN) { - ti->tcpi_synrexmits = tp->t_stat.synrxtshift; + ti->tcpi_synrexmits = (uint8_t)tp->t_stat.rxmitsyns; } ti->tcpi_cell_rxpackets = inp->inp_cstat->rxpackets; ti->tcpi_cell_rxbytes = inp->inp_cstat->rxbytes; @@ -1749,13 +1752,13 @@ tcp_fill_info_for_info_tuple(struct info_tuple *itpl, struct tcp_info *ti) ina6_local = itpl->itpl_local_sin6.sin6_addr; if (IN6_IS_SCOPE_LINKLOCAL(&ina6_local) && itpl->itpl_local_sin6.sin6_scope_id) { - ina6_local.s6_addr16[1] = htons(itpl->itpl_local_sin6.sin6_scope_id); + ina6_local.s6_addr16[1] = htons((uint16_t)itpl->itpl_local_sin6.sin6_scope_id); } ina6_remote = itpl->itpl_remote_sin6.sin6_addr; if (IN6_IS_SCOPE_LINKLOCAL(&ina6_remote) && itpl->itpl_remote_sin6.sin6_scope_id) { - ina6_remote.s6_addr16[1] = htons(itpl->itpl_remote_sin6.sin6_scope_id); + ina6_remote.s6_addr16[1] = htons((uint16_t)itpl->itpl_remote_sin6.sin6_scope_id); } inp = in6_pcblookup_hash(pcbinfo, @@ -1790,7 +1793,7 @@ tcp_connection_fill_info(struct tcpcb *tp, struct tcp_connection_info *tci) struct inpcb *inp = tp->t_inpcb; bzero(tci, sizeof(*tci)); - tci->tcpi_state = tp->t_state; + tci->tcpi_state = (uint8_t)tp->t_state; if (tp->t_state > TCPS_LISTEN) { if (TSTMP_SUPPORTED(tp)) { tci->tcpi_options |= TCPCI_OPT_TIMESTAMPS; @@ -1856,44 +1859,6 @@ tcp_sysctl_info(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int error; struct tcp_info ti = {}; struct info_tuple itpl; -#if !CONFIG_EMBEDDED - proc_t caller = PROC_NULL; - proc_t caller_parent = PROC_NULL; - char command_name[MAXCOMLEN + 1] = ""; - char parent_name[MAXCOMLEN + 1] = ""; - - if ((caller = proc_self()) != PROC_NULL) { - /* get process name */ - strlcpy(command_name, caller->p_comm, sizeof(command_name)); - - /* get parent process name if possible */ - if ((caller_parent = proc_find(caller->p_ppid)) != PROC_NULL) { - strlcpy(parent_name, caller_parent->p_comm, - sizeof(parent_name)); - proc_rele(caller_parent); - } - - if ((escape_str(command_name, strlen(command_name) + 1, - sizeof(command_name)) == 0) && - (escape_str(parent_name, strlen(parent_name) + 1, - sizeof(parent_name)) == 0)) { - kern_asl_msg(LOG_DEBUG, "messagetracer", - 5, - "com.apple.message.domain", - "com.apple.kernel.tcpstat", /* 1 */ - "com.apple.message.signature", - "tcpinfo", /* 2 */ - "com.apple.message.signature2", command_name, /* 3 */ - "com.apple.message.signature3", parent_name, /* 4 */ - "com.apple.message.summarize", "YES", /* 5 */ - NULL); - } - } - - if (caller != PROC_NULL) { - proc_rele(caller); - } -#endif /* !CONFIG_EMBEDDED */ if (req->newptr == USER_ADDR_NULL) { return EINVAL; @@ -1965,6 +1930,90 @@ tcp_getconninfo(struct socket *so, struct conninfo_tcp *tcp_ci) tcp_fill_info(sototcpcb(so), &tcp_ci->tcpci_tcp_info); } +void +tcp_clear_keep_alive_offload(struct socket *so) +{ + struct inpcb *inp; + struct ifnet *ifp; + + inp = sotoinpcb(so); + if (inp == NULL) { + return; + } + + if ((inp->inp_flags2 & INP2_KEEPALIVE_OFFLOAD) == 0) { + return; + } + + ifp = inp->inp_boundifp != NULL ? inp->inp_boundifp : + inp->inp_last_outifp; + if (ifp == NULL) { + panic("%s: so %p inp %p ifp NULL", + __func__, so, inp); + } + + ifnet_lock_exclusive(ifp); + + if (ifp->if_tcp_kao_cnt == 0) { + panic("%s: so %p inp %p ifp %p if_tcp_kao_cnt == 0", + __func__, so, inp, ifp); + } + ifp->if_tcp_kao_cnt--; + inp->inp_flags2 &= ~INP2_KEEPALIVE_OFFLOAD; + + ifnet_lock_done(ifp); +} + +static int +tcp_set_keep_alive_offload(struct socket *so, struct proc *proc) +{ + int error = 0; + struct inpcb *inp; + struct ifnet *ifp; + + inp = sotoinpcb(so); + if (inp == NULL) { + return ECONNRESET; + } + if ((inp->inp_flags2 & INP2_KEEPALIVE_OFFLOAD) != 0) { + return 0; + } + + ifp = inp->inp_boundifp != NULL ? inp->inp_boundifp : + inp->inp_last_outifp; + if (ifp == NULL) { + error = ENXIO; + os_log_info(OS_LOG_DEFAULT, + "%s: error %d for proc %s[%u] out ifp is not set\n", + __func__, error, + proc != NULL ? proc->p_comm : "kernel", + proc != NULL ? proc->p_pid : 0); + return ENXIO; + } + + error = if_get_tcp_kao_max(ifp); + if (error != 0) { + return error; + } + + ifnet_lock_exclusive(ifp); + if (ifp->if_tcp_kao_cnt < ifp->if_tcp_kao_max) { + ifp->if_tcp_kao_cnt++; + inp->inp_flags2 |= INP2_KEEPALIVE_OFFLOAD; + } else { + error = ETOOMANYREFS; + os_log_info(OS_LOG_DEFAULT, + "%s: error %d for proc %s[%u] if_tcp_kao_max %u\n", + __func__, error, + proc != NULL ? proc->p_comm : "kernel", + proc != NULL ? proc->p_pid : 0, + ifp->if_tcp_kao_max); + } + ifnet_lock_done(ifp); + + return error; +} + /* * The new sockopt interface makes it possible for us to block in the * copyin/out step (if we take a page fault). Taking a page fault at @@ -1987,12 +2036,11 @@ tcp_ctloutput(struct socket *so, struct sockopt *sopt) if (sopt->sopt_level != IPPROTO_TCP && !(sopt->sopt_level == SOL_SOCKET && (sopt->sopt_name == SO_FLUSH || sopt->sopt_name == SO_TRAFFIC_MGT_BACKGROUND))) { -#if INET6 if (SOCK_CHECK_DOM(so, PF_INET6)) { error = ip6_ctloutput(so, sopt); - } else -#endif /* INET6 */ - error = ip_ctloutput(so, sopt); + } else { + error = ip_ctloutput(so, sopt); + } return error; } tp = intotcpcb(inp); @@ -2203,6 +2251,10 @@ tcp_ctloutput(struct socket *so, struct sockopt *sopt) break; case TCP_KEEPALIVE_OFFLOAD: + if ((error = priv_check_cred(kauth_cred_get(), + PRIV_NETINET_TCP_KA_OFFLOAD, 0)) != 0) { + break; + } error = sooptcopyin(sopt, &optval, sizeof(optval), sizeof(optval)); if (error) { @@ -2213,9 +2265,10 @@ tcp_ctloutput(struct socket *so, struct sockopt *sopt) break; } if (optval != 0) { - inp->inp_flags2 |= INP2_KEEPALIVE_OFFLOAD; + error = tcp_set_keep_alive_offload(so, + sopt->sopt_p); } else { - inp->inp_flags2 &= ~INP2_KEEPALIVE_OFFLOAD; + tcp_clear_keep_alive_offload(so); } break; @@ -2280,7 +2333,7 @@ tcp_ctloutput(struct socket *so, struct sockopt *sopt) mptcp_reset_keepalive(tp); } } else { - tp->t_adaptive_rtimo = optval; + tp->t_adaptive_rtimo = (uint8_t)optval; } break; case TCP_ADAPTIVE_WRITE_TIMEOUT: @@ -2294,50 +2347,7 @@ tcp_ctloutput(struct socket *so, struct sockopt *sopt) error = EINVAL; break; } else { - tp->t_adaptive_wtimo = optval; - } - break; - case TCP_ENABLE_MSGS: - error = sooptcopyin(sopt, &optval, sizeof(optval), - sizeof(optval)); - if (error) { - break; - } - if (optval < 0 || optval > 1) { - error = EINVAL; - } else if (optval == 1) { - /* - * Check if messages option is already - * enabled, if so return. - */ - if (so->so_flags & SOF_ENABLE_MSGS) { - VERIFY(so->so_msg_state != NULL); - break; - } - - /* - * allocate memory for storing message - * related state - */ - VERIFY(so->so_msg_state == NULL); - MALLOC(so->so_msg_state, - struct msg_state *, - sizeof(struct msg_state), - M_TEMP, M_WAITOK | M_ZERO); - if (so->so_msg_state == NULL) { - error = ENOMEM; - break; - } - - /* Enable message delivery */ - so->so_flags |= SOF_ENABLE_MSGS; - } else { - /* - * Can't disable message delivery on socket - * because of restrictions imposed by - * encoding/decoding - */ - error = EINVAL; + tp->t_adaptive_wtimo = (uint8_t)optval; } break; case TCP_SENDMOREACKS: @@ -2398,6 +2408,9 @@ tcp_ctloutput(struct socket *so, struct sockopt *sopt) } break; case TCP_FASTOPEN_FORCE_HEURISTICS: + + break; + case TCP_FASTOPEN_FORCE_ENABLE: error = sooptcopyin(sopt, &optval, sizeof(optval), sizeof(optval)); @@ -2414,9 +2427,9 @@ tcp_ctloutput(struct socket *so, struct sockopt *sopt) break; } if (optval) { - tp->t_flagsext |= TF_FASTOPEN_HEUR; + tp->t_flagsext |= TF_FASTOPEN_FORCE_ENABLE; } else { - tp->t_flagsext &= ~TF_FASTOPEN_HEUR; + tp->t_flagsext &= ~TF_FASTOPEN_FORCE_ENABLE; } break; @@ -2600,7 +2613,10 @@ tcp_ctloutput(struct socket *so, struct sockopt *sopt) optval = tfo_enabled(tp); break; case TCP_FASTOPEN_FORCE_HEURISTICS: - optval = (tp->t_flagsext & TF_FASTOPEN_HEUR) ? 1 : 0; + optval = 0; + break; + case TCP_FASTOPEN_FORCE_ENABLE: + optval = (tp->t_flagsext & TF_FASTOPEN_FORCE_ENABLE) ? 1 : 0; break; case TCP_MEASURE_SND_BW: optval = tp->t_flagsext & TF_MEASURESNDBW; @@ -2639,14 +2655,6 @@ tcp_ctloutput(struct socket *so, struct sockopt *sopt) optval = 0; } break; - - case TCP_ENABLE_MSGS: - if (so->so_flags & SOF_ENABLE_MSGS) { - optval = 1; - } else { - optval = 0; - } - break; case TCP_SENDMOREACKS: if (tp->t_flagsext & TF_NOSTRETCHACK) { optval = 1; @@ -2789,9 +2797,7 @@ tcp_attach(struct socket *so, struct proc *p) struct tcpcb *tp; struct inpcb *inp; int error; -#if INET6 int isipv6 = SOCK_CHECK_DOM(so, PF_INET6) != 0; -#endif error = in_pcballoc(so, &tcbinfo, p); if (error) { @@ -2818,24 +2824,22 @@ tcp_attach(struct socket *so, struct proc *p) so->so_snd.sb_flags |= SB_AUTOSIZE; } -#if INET6 if (isipv6) { inp->inp_vflag |= INP_IPV6; inp->in6p_hops = -1; /* use kernel default */ - } else -#endif /* INET6 */ - inp->inp_vflag |= INP_IPV4; + } else { + inp->inp_vflag |= INP_IPV4; + } tp = tcp_newtcpcb(inp); if (tp == NULL) { int nofd = so->so_state & SS_NOFDREF; /* XXX */ so->so_state &= ~SS_NOFDREF; /* don't free the socket yet */ -#if INET6 if (isipv6) { in6_pcbdetach(inp); - } else -#endif /* INET6 */ - in_pcbdetach(inp); + } else { + in_pcbdetach(inp); + } so->so_state |= nofd; return ENOBUFS; } @@ -2915,6 +2919,7 @@ tcp_usrclosed(struct tcpcb *tp) struct tcpcb *, tp, int32_t, TCPS_FIN_WAIT_1); tp->t_state = TCPS_FIN_WAIT_1; + TCP_LOG_CONNECTION_SUMMARY(tp); break; case TCPS_CLOSE_WAIT: @@ -2923,6 +2928,7 @@ tcp_usrclosed(struct tcpcb *tp) struct tcpcb *, tp, int32_t, TCPS_LAST_ACK); tp->t_state = TCPS_LAST_ACK; + TCP_LOG_CONNECTION_SUMMARY(tp); break; } if (tp && tp->t_state >= TCPS_FIN_WAIT_2) { @@ -2950,7 +2956,6 @@ tcp_out_cksum_stats(u_int32_t len) tcpstat.tcps_snd_swcsum_bytes += len; } -#if INET6 void tcp_in6_cksum_stats(u_int32_t len) { @@ -2965,33 +2970,32 @@ tcp_out6_cksum_stats(u_int32_t len) tcpstat.tcps_snd6_swcsum_bytes += len; } -/* - * When messages are enabled on a TCP socket, the message priority - * is sent as a control message. This function will extract it. - */ int -tcp_get_msg_priority(struct mbuf *control, uint32_t *msgpri) +tcp_get_mpkl_send_info(struct mbuf *control, + struct so_mpkl_send_info *mpkl_send_info) { struct cmsghdr *cm; - if (control == NULL) { + + if (control == NULL || mpkl_send_info == NULL) { return EINVAL; } - for (cm = M_FIRST_CMSGHDR(control); - is_cmsg_valid(control, cm); + for (cm = M_FIRST_CMSGHDR(control); cm; cm = M_NXT_CMSGHDR(control, cm)) { - if (cm->cmsg_level == SOL_SOCKET && - cm->cmsg_type == SCM_MSG_PRIORITY) { - if (cm->cmsg_len != CMSG_LEN(sizeof(uint32_t))) { - return EINVAL; - } - *msgpri = *(uint32_t *)(void *)CMSG_DATA(cm); - if (*msgpri < MSG_PRI_MIN || *msgpri > MSG_PRI_MAX) { - return EINVAL; - } - break; + if (cm->cmsg_len < sizeof(struct cmsghdr) || + cm->cmsg_len > control->m_len) { + return EINVAL; + } + if (cm->cmsg_level != SOL_SOCKET || + cm->cmsg_type != SCM_MPKL_SEND_INFO) { + continue; } + if (cm->cmsg_len != CMSG_LEN(sizeof(struct so_mpkl_send_info))) { + return EINVAL; + } + memcpy(mpkl_send_info, CMSG_DATA(cm), + sizeof(struct so_mpkl_send_info)); + return 0; } - return 0; + return ENOMSG; } -#endif /* INET6 */