/*
- * Copyright (c) 2010-2018 Apple Inc. All rights reserved.
+ * Copyright (c) 2010-2020 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
xso->xso_len = sizeof(struct xsocket_n);
xso->xso_kind = XSO_SOCKET;
- if (so != NULL) {
- xso->xso_so = (uint64_t)VM_KERNEL_ADDRPERM(so);
- xso->so_type = so->so_type;
- xso->so_options = so->so_options;
- xso->so_linger = so->so_linger;
- xso->so_state = so->so_state;
- xso->so_pcb = (uint64_t)VM_KERNEL_ADDRPERM(so->so_pcb);
- if (so->so_proto) {
- xso->xso_protocol = SOCK_PROTO(so);
- xso->xso_family = SOCK_DOM(so);
- } else {
- xso->xso_protocol = xso->xso_family = 0;
- }
- xso->so_qlen = so->so_qlen;
- xso->so_incqlen = so->so_incqlen;
- xso->so_qlimit = so->so_qlimit;
- xso->so_timeo = so->so_timeo;
- xso->so_error = so->so_error;
- xso->so_pgid = so->so_pgid;
- xso->so_oobmark = so->so_oobmark;
- xso->so_uid = kauth_cred_getuid(so->so_cred);
- xso->so_last_pid = so->last_pid;
- xso->so_e_pid = so->e_pid;
+ if (so == NULL) {
+ return;
+ }
+
+ xso->xso_so = (uint64_t)VM_KERNEL_ADDRPERM(so);
+ xso->so_type = so->so_type;
+ xso->so_options = so->so_options;
+ xso->so_linger = so->so_linger;
+ xso->so_state = so->so_state;
+ xso->so_pcb = (uint64_t)VM_KERNEL_ADDRPERM(so->so_pcb);
+ if (so->so_proto) {
+ xso->xso_protocol = SOCK_PROTO(so);
+ xso->xso_family = SOCK_DOM(so);
+ } else {
+ xso->xso_protocol = xso->xso_family = 0;
}
+ xso->so_qlen = so->so_qlen;
+ xso->so_incqlen = so->so_incqlen;
+ xso->so_qlimit = so->so_qlimit;
+ xso->so_timeo = so->so_timeo;
+ xso->so_error = so->so_error;
+ xso->so_pgid = so->so_pgid;
+ xso->so_oobmark = so->so_oobmark;
+ xso->so_uid = kauth_cred_getuid(so->so_cred);
+ xso->so_last_pid = so->last_pid;
+ xso->so_e_pid = so->e_pid;
}
__private_extern__ void
sbtoxsockbuf_n(struct sockbuf *sb, struct xsockbuf_n *xsb)
{
xsb->xsb_len = sizeof(struct xsockbuf_n);
- xsb->xsb_kind = (sb->sb_flags & SB_RECV) ? XSO_RCVBUF : XSO_SNDBUF;
- if (sb != NULL) {
- xsb->sb_cc = sb->sb_cc;
- xsb->sb_hiwat = sb->sb_hiwat;
- xsb->sb_mbcnt = sb->sb_mbcnt;
- xsb->sb_mbmax = sb->sb_mbmax;
- xsb->sb_lowat = sb->sb_lowat;
- xsb->sb_flags = sb->sb_flags;
- xsb->sb_timeo = (short)(sb->sb_timeo.tv_sec * hz) +
- sb->sb_timeo.tv_usec / tick;
- if (xsb->sb_timeo == 0 && sb->sb_timeo.tv_usec != 0) {
- xsb->sb_timeo = 1;
- }
+ if (sb == NULL) {
+ return;
+ }
+
+ xsb->xsb_kind = (sb->sb_flags & SB_RECV) ? XSO_RCVBUF : XSO_SNDBUF;
+ xsb->sb_cc = sb->sb_cc;
+ xsb->sb_hiwat = sb->sb_hiwat;
+ xsb->sb_mbcnt = sb->sb_mbcnt;
+ xsb->sb_mbmax = sb->sb_mbmax;
+ xsb->sb_lowat = sb->sb_lowat;
+ xsb->sb_flags = (short)sb->sb_flags;
+ xsb->sb_timeo = (short)((sb->sb_timeo.tv_sec * hz) +
+ sb->sb_timeo.tv_usec / tick);
+ if (xsb->sb_timeo == 0 && sb->sb_timeo.tv_usec != 0) {
+ xsb->sb_timeo = 1;
}
}
xst->xst_len = sizeof(struct xsockstat_n);
xst->xst_kind = XSO_STATS;
+ if (so == NULL) {
+ return;
+ }
+
for (i = 0; i < SO_TC_STATS_MAX; i++) {
xst->xst_tc_stats[i].rxpackets = so->so_tc_stats[i].rxpackets;
xst->xst_tc_stats[i].rxbytes = so->so_tc_stats[i].rxbytes;
bool iswildcard, wildcardok, nowakeok;
bool recvanyifonly, extbgidleok;
bool activeonly;
+ bool anytcpstateok;
- wildcardok = ((flags & INPCB_GET_PORTS_USED_WILDCARDOK) != 0);
- nowakeok = ((flags & INPCB_GET_PORTS_USED_NOWAKEUPOK) != 0);
- recvanyifonly = ((flags & INPCB_GET_PORTS_USED_RECVANYIFONLY) != 0);
- extbgidleok = ((flags & INPCB_GET_PORTS_USED_EXTBGIDLEONLY) != 0);
- activeonly = ((flags & INPCB_GET_PORTS_USED_ACTIVEONLY) != 0);
+ wildcardok = ((flags & IFNET_GET_LOCAL_PORTS_WILDCARDOK) != 0);
+ nowakeok = ((flags & IFNET_GET_LOCAL_PORTS_NOWAKEUPOK) != 0);
+ recvanyifonly = ((flags & IFNET_GET_LOCAL_PORTS_RECVANYIFONLY) != 0);
+ extbgidleok = ((flags & IFNET_GET_LOCAL_PORTS_EXTBGIDLEONLY) != 0);
+ activeonly = ((flags & IFNET_GET_LOCAL_PORTS_ACTIVEONLY) != 0);
+ anytcpstateok = ((flags & IFNET_GET_LOCAL_PORTS_ANYTCPSTATEOK) != 0);
lck_rw_lock_shared(pcbinfo->ipi_lock);
gencnt = pcbinfo->ipi_gencnt;
for (inp = LIST_FIRST(pcbinfo->ipi_listhead); inp;
inp = LIST_NEXT(inp, inp_list)) {
- uint16_t port;
-
if (inp->inp_gencnt > gencnt ||
inp->inp_state == INPCB_STATE_DEAD ||
inp->inp_wantcnt == WNT_STOPUSING) {
continue;
}
- if ((so = inp->inp_socket) == NULL ||
- (so->so_state & SS_DEFUNCT) ||
- (so->so_state & SS_ISDISCONNECTED)) {
+ if ((so = inp->inp_socket) == NULL || inp->inp_lport == 0) {
+ continue;
+ }
+
+ /*
+ * ANYTCPSTATEOK means incoming packets cannot be filtered
+ * reception so cast a wide net of possibilities
+ */
+ if (!anytcpstateok &&
+ ((so->so_state & SS_DEFUNCT) ||
+ (so->so_state & SS_ISDISCONNECTED))) {
continue;
}
switch (tp->t_state) {
case TCPS_CLOSED:
+ if (anytcpstateok && inp->inp_fport != 0) {
+ /*
+ * A foreign port means we had a 4 tuple at
+ * least a connection attempt so packets
+ * may be received for the 4 tuple after the
+ * connection is gone
+ */
+ break;
+ }
continue;
/* NOT REACHED */
case TCPS_LISTEN:
case TCPS_FIN_WAIT_2:
/*
* In the closing states, the connection
- * is not idle when there is outgoing
+ * is active when there is outgoing
* data having to be acknowledged
*/
- if (activeonly && so->so_snd.sb_cc == 0) {
+ if (!anytcpstateok &&
+ (activeonly && so->so_snd.sb_cc == 0)) {
continue;
}
break;
case TCPS_TIME_WAIT:
+ if (anytcpstateok) {
+ /*
+ * Packets may still be received for the 4 tuple
+ * after the connection is gone
+ */
+ break;
+ }
continue;
/* NOT REACHED */
}
}
- /*
- * Final safeguard to exclude unspecified local port
- */
- port = ntohs(inp->inp_lport);
- if (port == 0) {
- continue;
- }
- bitstr_set(bitfield, port);
+
+ bitstr_set(bitfield, ntohs(inp->inp_lport));
if_ports_used_add_inpcb(ifindex, inp);
}
static int
shutdown_sockets_on_interface_proc_callout(proc_t p, void *arg)
{
- struct filedesc *fdp;
- int i;
+ struct fileproc *fp;
struct ifnet *ifp = (struct ifnet *)arg;
if (ifp == NULL) {
return PROC_RETURNED;
}
- proc_fdlock(p);
- fdp = p->p_fd;
- for (i = 0; i < fdp->fd_nfiles; i++) {
- struct fileproc *fp = fdp->fd_ofiles[i];
- struct fileglob *fg;
+ fdt_foreach(fp, p) {
+ struct fileglob *fg = fp->fp_glob;
struct socket *so;
struct inpcb *inp;
struct ifnet *inp_ifp;
int error;
- if (fp == NULL || (fdp->fd_ofileflags[i] & UF_RESERVED) != 0) {
- continue;
- }
-
- fg = fp->f_fglob;
if (FILEGLOB_DTYPE(fg) != DTYPE_SOCKET) {
continue;
}
- so = (struct socket *)fp->f_fglob->fg_data;
+ so = (struct socket *)fp->fp_glob->fg_data;
if (SOCK_DOM(so) != PF_INET && SOCK_DOM(so) != PF_INET6) {
continue;
}
shutdown_sockets_on_interface_proc_callout,
ifp, NULL, NULL);
}
+
+__private_extern__ int
+inp_limit_companion_link(struct inpcbinfo *pcbinfo, u_int32_t limit)
+{
+ struct inpcb *inp;
+ struct socket *so = NULL;
+
+ lck_rw_lock_shared(pcbinfo->ipi_lock);
+ inp_gen_t gencnt = pcbinfo->ipi_gencnt;
+ for (inp = LIST_FIRST(pcbinfo->ipi_listhead);
+ inp != NULL; inp = LIST_NEXT(inp, inp_list)) {
+ if (inp->inp_gencnt <= gencnt &&
+ inp->inp_state != INPCB_STATE_DEAD &&
+ inp->inp_socket != NULL) {
+ so = inp->inp_socket;
+
+ if ((so->so_state & SS_DEFUNCT) || so->so_state & SS_ISDISCONNECTED ||
+ SOCK_PROTO(so) != IPPROTO_TCP || inp->inp_last_outifp == NULL ||
+ !IFNET_IS_COMPANION_LINK(inp->inp_last_outifp)) {
+ continue;
+ }
+ so->so_snd.sb_flags &= ~SB_LIMITED;
+ u_int32_t new_size = MAX(MIN(limit, so->so_snd.sb_lowat), so->so_snd.sb_cc);
+ sbreserve(&so->so_snd, new_size);
+ so->so_snd.sb_flags |= SB_LIMITED;
+ }
+ }
+ lck_rw_done(pcbinfo->ipi_lock);
+ return 0;
+}
+
+__private_extern__ int
+inp_recover_companion_link(struct inpcbinfo *pcbinfo)
+{
+ struct inpcb *inp;
+ inp_gen_t gencnt = pcbinfo->ipi_gencnt;
+ struct socket *so = NULL;
+
+ lck_rw_lock_shared(pcbinfo->ipi_lock);
+ for (inp = LIST_FIRST(pcbinfo->ipi_listhead);
+ inp != NULL; inp = LIST_NEXT(inp, inp_list)) {
+ if (inp->inp_gencnt <= gencnt &&
+ inp->inp_state != INPCB_STATE_DEAD &&
+ inp->inp_socket != NULL) {
+ so = inp->inp_socket;
+
+ if (SOCK_PROTO(so) != IPPROTO_TCP || inp->inp_last_outifp == NULL ||
+ !(so->so_snd.sb_flags & SB_LIMITED)) {
+ continue;
+ }
+
+ so->so_snd.sb_flags &= ~SB_LIMITED;
+ }
+ }
+ lck_rw_done(pcbinfo->ipi_lock);
+ return 0;
+}