xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / netinet / in_pcblist.c
index 73b55db69036e1f25976770e9c54a328c49ff81d..b87cf5d045fd9e08ab17d6f1832ebabb083f7ff2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2018 Apple Inc. All rights reserved.
+ * Copyright (c) 2010-2020 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
@@ -112,50 +112,54 @@ sotoxsocket_n(struct socket *so, struct xsocket_n *xso)
        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;
        }
 }
 
@@ -167,6 +171,10 @@ sbtoxsockstat_n(struct socket *so, struct xsockstat_n *xst)
        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;
@@ -430,29 +438,37 @@ inpcb_get_ports_used(uint32_t ifindex, int protocol, uint32_t flags,
        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;
                }
 
@@ -543,6 +559,15 @@ inpcb_get_ports_used(uint32_t ifindex, int protocol, uint32_t flags,
 
                        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:
@@ -562,26 +587,28 @@ inpcb_get_ports_used(uint32_t ifindex, int protocol, uint32_t flags,
                        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);
        }
@@ -689,34 +716,25 @@ inpcb_find_anypcb_byaddr(struct ifaddr *ifa, struct inpcbinfo *pcbinfo)
 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;
                }
@@ -773,3 +791,60 @@ shutdown_sockets_on_interface(struct ifnet *ifp)
            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;
+}