aboutsummaryrefslogtreecommitdiffstats
path: root/network_cmds/netstat.tproj
diff options
context:
space:
mode:
authorCameron Katri <me@cameronkatri.com>2021-05-09 14:20:58 -0400
committerCameron Katri <me@cameronkatri.com>2021-05-09 14:20:58 -0400
commit5fd83771641d15c418f747bd343ba6738d3875f7 (patch)
tree5abf0f78f680d9837dbd93d4d4c3933bb7509599 /network_cmds/netstat.tproj
downloadapple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.gz
apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.zst
apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.zip
Import macOS userland
adv_cmds-176 basic_cmds-55 bootstrap_cmds-116.100.1 developer_cmds-66 diskdev_cmds-667.40.1 doc_cmds-53.60.1 file_cmds-321.40.3 mail_cmds-35 misc_cmds-34 network_cmds-606.40.1 patch_cmds-17 remote_cmds-63 shell_cmds-216.60.1 system_cmds-880.60.2 text_cmds-106
Diffstat (limited to 'network_cmds/netstat.tproj')
-rw-r--r--network_cmds/netstat.tproj/DERIVED_FILES1
-rw-r--r--network_cmds/netstat.tproj/data.c28
-rw-r--r--network_cmds/netstat.tproj/if.c2259
-rw-r--r--network_cmds/netstat.tproj/inet.c1361
-rw-r--r--network_cmds/netstat.tproj/inet6.c1333
-rw-r--r--network_cmds/netstat.tproj/ipsec.c376
-rw-r--r--network_cmds/netstat.tproj/main.c638
-rw-r--r--network_cmds/netstat.tproj/mbuf.c476
-rw-r--r--network_cmds/netstat.tproj/mcast.c887
-rw-r--r--network_cmds/netstat.tproj/misc.c122
-rw-r--r--network_cmds/netstat.tproj/mptcp.c170
-rw-r--r--network_cmds/netstat.tproj/netstat.1445
-rw-r--r--network_cmds/netstat.tproj/netstat.h170
-rw-r--r--network_cmds/netstat.tproj/route.c795
-rw-r--r--network_cmds/netstat.tproj/systm.c503
-rw-r--r--network_cmds/netstat.tproj/tp_astring.c74
-rw-r--r--network_cmds/netstat.tproj/unix.c231
-rw-r--r--network_cmds/netstat.tproj/vsock.c187
18 files changed, 10056 insertions, 0 deletions
diff --git a/network_cmds/netstat.tproj/DERIVED_FILES b/network_cmds/netstat.tproj/DERIVED_FILES
new file mode 100644
index 0000000..a4fa6c9
--- /dev/null
+++ b/network_cmds/netstat.tproj/DERIVED_FILES
@@ -0,0 +1 @@
+unix/bsd/netiso/tp_astring.c
diff --git a/network_cmds/netstat.tproj/data.c b/network_cmds/netstat.tproj/data.c
new file mode 100644
index 0000000..9e0bbe2
--- /dev/null
+++ b/network_cmds/netstat.tproj/data.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/* NeXT */
+#ifndef EXTERN
+#define EXTERN
+#endif
+#include "netstat.h"
diff --git a/network_cmds/netstat.tproj/if.c b/network_cmds/netstat.tproj/if.c
new file mode 100644
index 0000000..2fe6182
--- /dev/null
+++ b/network_cmds/netstat.tproj/if.c
@@ -0,0 +1,2259 @@
+/*
+ * Copyright (c) 2008-2019 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/kern_control.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/if_mib.h>
+#include <net/if_llreach.h>
+#include <net/ethernet.h>
+#include <net/route.h>
+#include <net/ntstat.h>
+
+#include <net/pktsched/pktsched.h>
+#include <net/classq/if_classq.h>
+
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+
+#include <arpa/inet.h>
+
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <assert.h>
+
+#include "netstat.h"
+
+#define YES 1
+#define NO 0
+
+#define ROUNDUP(a, size) (((a) & ((size) - 1)) ? (1 + ((a)|(size - 1))) : (a))
+
+#define NEXT_SA(p) (struct sockaddr *) \
+ ((caddr_t)p + (p->sa_len ? ROUNDUP(p->sa_len, sizeof(uint32_t)) : \
+ sizeof(uint32_t)))
+
+static void sidewaysintpr ();
+static void catchalarm (int);
+static char *sec2str(time_t);
+static void llreach_sysctl(uint32_t);
+static char *nsec_to_str(unsigned long long);
+static char *sched2str(unsigned int);
+static char *pri2str(unsigned int i);
+
+#define AVGN_MAX 8
+
+struct queue_stats {
+ int avgn;
+ double avg_bytes;
+ double avg_packets;
+ u_int64_t prev_bytes;
+ u_int64_t prev_packets;
+ unsigned int handle;
+};
+
+static void update_avg(struct if_ifclassq_stats *, struct queue_stats *);
+static void print_fq_codel_stats(int slot, struct fq_codel_classstats *,
+ struct queue_stats *);
+
+struct queue_stats qstats[IFCQ_SC_MAX];
+
+#ifdef INET6
+char *netname6 (struct sockaddr_in6 *, struct sockaddr *);
+static char ntop_buf[INET6_ADDRSTRLEN]; /* for inet_ntop() */
+#endif
+
+/*
+ * Display a formatted value, or a '-' in the same space.
+ */
+static void
+show_stat(const char *fmt, int width, u_int64_t value, short showvalue)
+{
+ char newfmt[32];
+
+ /* Construct the format string */
+ if (showvalue) {
+ snprintf(newfmt, sizeof(newfmt), "%%%d%s", width, fmt);
+ printf(newfmt, value);
+ } else {
+ snprintf(newfmt, sizeof(newfmt), "%%%ds", width);
+ printf(newfmt, "-");
+ }
+}
+
+size_t
+get_rti_info(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
+{
+ int i;
+ size_t len = 0;
+
+ for (i = 0; i < RTAX_MAX; i++) {
+ if (addrs & (1 << i)) {
+ rti_info[i] = sa;
+ if (sa->sa_len < sizeof(struct sockaddr))
+ len += sizeof(struct sockaddr);
+ else
+ len += sa->sa_len;
+ sa = NEXT_SA(sa);
+ } else {
+ rti_info[i] = NULL;
+ }
+ }
+ return len;
+}
+
+static void
+multipr(int family, char *buf, char *lim)
+{
+ char *next;
+
+ for (next = buf; next < lim; ) {
+ struct ifma_msghdr2 *ifmam = (struct ifma_msghdr2 *)next;
+ struct sockaddr *rti_info[RTAX_MAX];
+ struct sockaddr *sa;
+ const char *fmt = 0;
+
+ next += ifmam->ifmam_msglen;
+ if (ifmam->ifmam_type == RTM_IFINFO2)
+ break;
+ else if (ifmam->ifmam_type != RTM_NEWMADDR2)
+ continue;
+ get_rti_info(ifmam->ifmam_addrs, (struct sockaddr*)(ifmam + 1), rti_info);
+ sa = rti_info[RTAX_IFA];
+
+ if (sa->sa_family != family)
+ continue;
+ switch (sa->sa_family) {
+ case AF_INET: {
+ struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+
+ fmt = routename(sin->sin_addr.s_addr);
+ break;
+ }
+ #ifdef INET6
+ case AF_INET6: {
+ struct sockaddr_in6 sin6;
+
+ memcpy(&sin6, sa, sizeof(struct sockaddr_in6));
+
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
+ IN6_IS_ADDR_MC_NODELOCAL(&sin6.sin6_addr) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) {
+ sin6.sin6_scope_id = ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
+ sin6.sin6_addr.s6_addr[2] = 0;
+ sin6.sin6_addr.s6_addr[3] = 0;
+ }
+
+ printf("%23s %-19.19s(refs: %d)\n", "",
+ inet_ntop(AF_INET6, &sin6.sin6_addr,
+ ntop_buf, sizeof(ntop_buf)),
+ ifmam->ifmam_refcount);
+ break;
+ }
+ #endif /* INET6 */
+ case AF_LINK: {
+ struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
+
+ switch (sdl->sdl_type) {
+ case IFT_ETHER:
+ case IFT_FDDI:
+ fmt = ether_ntoa((struct ether_addr *)
+ LLADDR(sdl));
+ break;
+ }
+ break;
+ }
+ }
+ if (fmt)
+ printf("%23s %s\n", "", fmt);
+ }
+}
+
+/*
+ * Print a description of the network interfaces.
+ */
+void
+intpr(void (*pfunc)(char *))
+{
+ u_int64_t opackets = 0;
+ u_int64_t ipackets = 0;
+ u_int64_t obytes = 0;
+ u_int64_t ibytes = 0;
+ u_int64_t oerrors = 0;
+ u_int64_t ierrors = 0;
+ u_int64_t collisions = 0;
+ u_int64_t fpackets = 0;
+ u_int64_t fbytes = 0;
+ uint32_t mtu = 0;
+ int timer = 0;
+ int drops = 0;
+ struct sockaddr *sa = NULL;
+ char name[32];
+ short network_layer;
+ short link_layer;
+ int mib[6];
+ char *buf = NULL, *lim, *next;
+ size_t len;
+ struct if_msghdr *ifm;
+ struct sockaddr *rti_info[RTAX_MAX];
+ unsigned int ifindex = 0;
+
+ if (interval) {
+ sidewaysintpr();
+ return;
+ }
+
+ if (interface != 0)
+ ifindex = if_nametoindex(interface);
+
+ mib[0] = CTL_NET; // networking subsystem
+ mib[1] = PF_ROUTE; // type of information
+ mib[2] = 0; // protocol (IPPROTO_xxx)
+ mib[3] = 0; // address family
+ mib[4] = NET_RT_IFLIST2; // operation
+ mib[5] = 0;
+ if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+ return;
+ if ((buf = malloc(len)) == NULL) {
+ printf("malloc failed\n");
+ exit(1);
+ }
+ if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
+ if (buf)
+ free(buf);
+ return;
+ }
+
+ if (!pfunc) {
+ if (lflag) {
+ printf("%-10.10s %-5.5s %-39.39s %-39.39s %8.8s %5.5s",
+ "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs");
+ } else {
+ printf("%-10.10s %-5.5s %-13.13s %-15.15s %8.8s %5.5s",
+ "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs");
+ }
+ if (prioflag >= 0)
+ printf(" %8.8s %8.8s", "Itcpkts", "Ipvpkts");
+ if (bflag) {
+ printf(" %10.10s","Ibytes");
+ if (prioflag >= 0)
+ printf(" %8.8s %8.8s", "Itcbytes", "Ipvbytes");
+ }
+ printf(" %8.8s %5.5s", "Opkts", "Oerrs");
+ if (prioflag >= 0)
+ printf(" %8.8s %8.8s", "Otcpkts", "Opvpkts");
+ if (bflag) {
+ printf(" %10.10s","Obytes");
+ if (prioflag >= 0)
+ printf(" %8.8s %8.8s", "Otcbytes", "Opvbytes");
+ }
+ printf(" %5s", "Coll");
+ if (tflag)
+ printf(" %s", "Time");
+ if (dflag)
+ printf(" %s", "Drop");
+ if (Fflag) {
+ printf(" %8.8s", "Fpkts");
+ if (bflag)
+ printf(" %10.10s", "Fbytes");
+ }
+ putchar('\n');
+ }
+ lim = buf + len;
+ for (next = buf; next < lim; ) {
+ char *cp;
+ int n, m;
+ struct ifmibdata_supplemental ifmsupp;
+ u_int64_t ift_itcp = 0; /* input tc packets */
+ u_int64_t ift_itcb = 0; /* input tc bytes */
+ u_int64_t ift_otcp = 0; /* output tc packets */
+ u_int64_t ift_otcb = 0; /* output tc bytes */
+ u_int64_t ift_ipvp = 0; /* input priv tc packets */
+ u_int64_t ift_ipvb = 0; /* input priv tc bytes */
+ u_int64_t ift_opvp = 0; /* output priv tc packets */
+ u_int64_t ift_opvb = 0; /* output priv tc bytes */
+
+ bzero(&ifmsupp, sizeof(struct ifmibdata_supplemental));
+
+ network_layer = 0;
+ link_layer = 0;
+ ifm = (struct if_msghdr *)next;
+ next += ifm->ifm_msglen;
+
+ if (ifm->ifm_type == RTM_IFINFO2) {
+ struct if_msghdr2 *if2m = (struct if_msghdr2 *)ifm;
+ struct sockaddr_dl *sdl =
+ (struct sockaddr_dl *)(if2m + 1);
+ int mibname[6];
+ size_t miblen = sizeof(struct ifmibdata_supplemental);
+
+ if (interface != 0 && if2m->ifm_index != ifindex)
+ continue;
+
+ /* The interface name is not a zero-ended string */
+ memcpy(name, sdl->sdl_data, MIN(sizeof(name) - 1, sdl->sdl_nlen));
+ name[MIN(sizeof(name) - 1, sdl->sdl_nlen)] = 0;
+
+ if (pfunc) {
+ (*pfunc)(name);
+ continue;
+ }
+
+ cp = index(name, '\0');
+ if ((if2m->ifm_flags & IFF_UP) == 0)
+ *cp++ = '*';
+ *cp = '\0';
+
+ /*
+ * Get the interface stats. These may get
+ * overriden below on a per-interface basis.
+ */
+ opackets = if2m->ifm_data.ifi_opackets;
+ ipackets = if2m->ifm_data.ifi_ipackets;
+ obytes = if2m->ifm_data.ifi_obytes;
+ ibytes = if2m->ifm_data.ifi_ibytes;
+ oerrors =if2m->ifm_data.ifi_oerrors;
+ ierrors = if2m->ifm_data.ifi_ierrors;
+ collisions = if2m->ifm_data.ifi_collisions;
+ timer = if2m->ifm_timer;
+ drops = if2m->ifm_snd_drops;
+ mtu = if2m->ifm_data.ifi_mtu;
+
+ /* Common OID prefix */
+ mibname[0] = CTL_NET;
+ mibname[1] = PF_LINK;
+ mibname[2] = NETLINK_GENERIC;
+ mibname[3] = IFMIB_IFDATA;
+ mibname[4] = if2m->ifm_index;
+ mibname[5] = IFDATA_SUPPLEMENTAL;
+ if (sysctl(mibname, 6, &ifmsupp, &miblen, NULL, 0) == -1)
+ err(1, "sysctl IFDATA_SUPPLEMENTAL");
+
+ fpackets = ifmsupp.ifmd_data_extended.ifi_fpackets;
+ fbytes = ifmsupp.ifmd_data_extended.ifi_fbytes;
+
+ if (prioflag >= 0) {
+ switch (prioflag) {
+ case SO_TC_BE:
+ ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ibepackets;
+ ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ibebytes;
+ ift_otcp = ifmsupp.ifmd_traffic_class.ifi_obepackets;
+ ift_otcb = ifmsupp.ifmd_traffic_class.ifi_obebytes;
+ break;
+ case SO_TC_BK:
+ ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ibkpackets;
+ ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ibkbytes;
+ ift_otcp = ifmsupp.ifmd_traffic_class.ifi_obkpackets;
+ ift_otcb = ifmsupp.ifmd_traffic_class.ifi_obkbytes;
+ break;
+ case SO_TC_VI:
+ ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ivipackets;
+ ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ivibytes;
+ ift_otcp = ifmsupp.ifmd_traffic_class.ifi_ovipackets;
+ ift_otcb = ifmsupp.ifmd_traffic_class.ifi_ovibytes;
+ break;
+ case SO_TC_VO:
+ ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ivopackets;
+ ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ivobytes;
+ ift_otcp = ifmsupp.ifmd_traffic_class.ifi_ovopackets;
+ ift_otcb = ifmsupp.ifmd_traffic_class.ifi_ovobytes;
+ break;
+ default:
+ ift_itcp = 0;
+ ift_itcb = 0;
+ ift_otcp = 0;
+ ift_otcb = 0;
+ ift_ipvp = 0;
+ ift_ipvb = 0;
+ ift_opvp = 0;
+ ift_opvb = 0;
+ break;
+ }
+ ift_ipvp = ifmsupp.ifmd_traffic_class.ifi_ipvpackets;
+ ift_ipvb = ifmsupp.ifmd_traffic_class.ifi_ipvbytes;
+ ift_opvp = ifmsupp.ifmd_traffic_class.ifi_opvpackets;
+ ift_opvb = ifmsupp.ifmd_traffic_class.ifi_opvbytes;
+ }
+
+ get_rti_info(if2m->ifm_addrs,
+ (struct sockaddr*)(if2m + 1), rti_info);
+ sa = rti_info[RTAX_IFP];
+ } else if (ifm->ifm_type == RTM_NEWADDR) {
+ struct ifa_msghdr *ifam = (struct ifa_msghdr *)ifm;
+
+ if (interface != 0 && ifam->ifam_index != ifindex)
+ continue;
+ get_rti_info(ifam->ifam_addrs,
+ (struct sockaddr*)(ifam + 1), rti_info);
+ sa = rti_info[RTAX_IFA];
+ } else {
+ continue;
+ }
+ if (lflag) {
+ printf("%-10.10s %-5u ", name, mtu);
+ } else {
+ printf("%-5.5s %-5u ", name, mtu);
+ }
+
+ if (sa == 0) {
+ printf(lflag ? "%-39.39s " : "%-13.13s ", "none");
+ printf(lflag ? "%-39.39s " : "%-15.15s ", "none");
+ } else {
+ switch (sa->sa_family) {
+ case AF_UNSPEC:
+ printf(lflag ? "%-39.39s " : "%-13.13s ", "none");
+ printf(lflag ? "%-39.39s " : "%-15.15s ", "none");
+ break;
+
+ case AF_INET: {
+ struct sockaddr_in *sin =
+ (struct sockaddr_in *)sa;
+ struct sockaddr_in mask;
+
+ mask.sin_addr.s_addr = 0;
+ memcpy(&mask, rti_info[RTAX_NETMASK],
+ ((struct sockaddr_in *)
+ rti_info[RTAX_NETMASK])->sin_len);
+
+ printf(lflag ? "%-39.39s " : "%-13.13s ",
+ netname(sin->sin_addr.s_addr &
+ mask.sin_addr.s_addr,
+ ntohl(mask.sin_addr.s_addr)));
+
+ printf(lflag ? "%-39.39s " : "%-15.15s ",
+ routename(sin->sin_addr.s_addr));
+
+ network_layer = 1;
+ break;
+ }
+#ifdef INET6
+ case AF_INET6: {
+ struct sockaddr_in6 *sin6 =
+ (struct sockaddr_in6 *)sa;
+ struct sockaddr *mask =
+ (struct sockaddr *)rti_info[RTAX_NETMASK];
+
+ printf(lflag ? "%-39.39s " : "%-11.11s ", netname6(sin6, mask));
+ printf(lflag ? "%-39.39s " : "%-17.17s ", (char *)inet_ntop(AF_INET6,
+ &sin6->sin6_addr, ntop_buf,
+ sizeof(ntop_buf)));
+
+ network_layer = 1;
+ break;
+ }
+#endif /*INET6*/
+ case AF_LINK: {
+ struct sockaddr_dl *sdl =
+ (struct sockaddr_dl *)sa;
+ char linknum[10];
+ cp = (char *)LLADDR(sdl);
+ n = sdl->sdl_alen;
+ snprintf(linknum, sizeof(linknum),
+ "<Link#%d>", sdl->sdl_index);
+ m = printf(lflag ? "%-39.39s " : "%-11.11s ", linknum);
+ goto hexprint;
+ }
+
+ default:
+ m = printf("(%d)", sa->sa_family);
+ for (cp = sa->sa_len + (char *)sa;
+ --cp > sa->sa_data && (*cp == 0);) {}
+ n = cp - sa->sa_data + 1;
+ cp = sa->sa_data;
+ hexprint:
+ while (--n >= 0)
+ m += printf("%02x%c", *cp++ & 0xff,
+ n > 0 ? ':' : ' ');
+ m = (lflag ? 80 : 30) - m;
+ while (m-- > 0)
+ putchar(' ');
+
+ link_layer = 1;
+ break;
+ }
+ }
+
+ show_stat("llu", 8, ipackets, link_layer|network_layer);
+ printf(" ");
+ show_stat("llu", 5, ierrors, link_layer);
+ printf(" ");
+ if (prioflag >= 0) {
+ show_stat("llu", 8, ift_itcp, link_layer|network_layer);
+ printf(" ");
+ show_stat("llu", 8, ift_ipvp, link_layer|network_layer);
+ printf(" ");
+ }
+ if (bflag) {
+ show_stat("llu", 10, ibytes, link_layer|network_layer);
+ printf(" ");
+ if (prioflag >= 0) {
+ show_stat("llu", 8, ift_itcb, link_layer|network_layer);
+ printf(" ");
+ show_stat("llu", 8, ift_ipvb, link_layer|network_layer);
+ printf(" ");
+ }
+ }
+ show_stat("llu", 8, opackets, link_layer|network_layer);
+ printf(" ");
+ show_stat("llu", 5, oerrors, link_layer);
+ printf(" ");
+ if (prioflag >= 0) {
+ show_stat("llu", 8, ift_otcp, link_layer|network_layer);
+ printf(" ");
+ show_stat("llu", 8, ift_opvp, link_layer|network_layer);
+ printf(" ");
+ }
+ if (bflag) {
+ show_stat("llu", 10, obytes, link_layer|network_layer);
+ printf(" ");
+ if (prioflag >= 0) {
+ show_stat("llu", 8, ift_otcb, link_layer|network_layer);
+ printf(" ");
+ show_stat("llu", 8, ift_opvb, link_layer|network_layer);
+ printf(" ");
+ }
+ }
+ show_stat("llu", 5, collisions, link_layer);
+ if (tflag) {
+ printf(" ");
+ show_stat("d", 3, timer, link_layer);
+ }
+ if (dflag) {
+ printf(" ");
+ show_stat("d", 3, drops, link_layer);
+ }
+ if (Fflag) {
+ printf(" ");
+ show_stat("llu", 8, fpackets, link_layer|network_layer);
+ if (bflag) {
+ printf(" ");
+ show_stat("llu", 10, fbytes,
+ link_layer|network_layer);
+ }
+ }
+ putchar('\n');
+
+ if (aflag)
+ multipr(sa->sa_family, next, lim);
+ }
+ free(buf);
+}
+
+struct iftot {
+ SLIST_ENTRY(iftot) chain;
+ char ift_name[16]; /* interface name */
+ u_int64_t ift_ip; /* input packets */
+ u_int64_t ift_ie; /* input errors */
+ u_int64_t ift_op; /* output packets */
+ u_int64_t ift_oe; /* output errors */
+ u_int64_t ift_co; /* collisions */
+ u_int64_t ift_dr; /* drops */
+ u_int64_t ift_ib; /* input bytes */
+ u_int64_t ift_ob; /* output bytes */
+ u_int64_t ift_itcp; /* input tc packets */
+ u_int64_t ift_itcb; /* input tc bytes */
+ u_int64_t ift_otcp; /* output tc packets */
+ u_int64_t ift_otcb; /* output tc bytes */
+ u_int64_t ift_ipvp; /* input priv tc packets */
+ u_int64_t ift_ipvb; /* input priv tc bytes */
+ u_int64_t ift_opvp; /* output priv tc packets */
+ u_int64_t ift_opvb; /* output priv tc bytes */
+ u_int64_t ift_fp; /* forwarded packets */
+ u_int64_t ift_fb; /* forwarded bytes */
+};
+
+u_char signalled; /* set if alarm goes off "early" */
+
+/*
+ * Print a running summary of interface statistics.
+ * Repeat display every interval seconds, showing statistics
+ * collected over that interval. Assumes that interval is non-zero.
+ * First line printed at top of screen is always cumulative.
+ * XXX - should be rewritten to use ifmib(4).
+ */
+static void
+sidewaysintpr()
+{
+ struct iftot *total, *sum, *interesting;
+ register int line;
+ int first;
+ int name[6];
+ size_t len;
+ unsigned int ifcount, i;
+ struct ifmibdata *ifmdall = 0;
+ int interesting_row;
+ sigset_t sigset, oldsigset;
+ struct itimerval timer_interval;
+
+ /* Common OID prefix */
+ name[0] = CTL_NET;
+ name[1] = PF_LINK;
+ name[2] = NETLINK_GENERIC;
+
+ len = sizeof(int);
+ name[3] = IFMIB_SYSTEM;
+ name[4] = IFMIB_IFCOUNT;
+ if (sysctl(name, 5, &ifcount, &len, 0, 0) == 1)
+ err(1, "sysctl IFMIB_IFCOUNT");
+
+ len = ifcount * sizeof(struct ifmibdata);
+ ifmdall = malloc(len);
+ if (ifmdall == 0)
+ err(1, "malloc failed");
+ name[3] = IFMIB_IFALLDATA;
+ name[4] = 0;
+ name[5] = IFDATA_GENERAL;
+ if (sysctl(name, 6, ifmdall, &len, (void *)0, 0) == -1)
+ err(1, "sysctl IFMIB_IFALLDATA");
+
+ interesting = NULL;
+ interesting_row = 0;
+ for (i = 0; i < ifcount; i++) {
+ struct ifmibdata *ifmd = ifmdall + i;
+
+ if (interface && strcmp(ifmd->ifmd_name, interface) == 0) {
+ if ((interesting = calloc(ifcount,
+ sizeof(struct iftot))) == NULL)
+ err(1, "malloc failed");
+ interesting_row = if_nametoindex(interface);
+ snprintf(interesting->ift_name, 16, "(%s)",
+ ifmd->ifmd_name);;
+ }
+ }
+ if ((total = calloc(1, sizeof(struct iftot))) == NULL)
+ err(1, "malloc failed");
+
+ if ((sum = calloc(1, sizeof(struct iftot))) == NULL)
+ err(1, "malloc failed");
+
+ /* create a timer that fires repeatedly every interval seconds */
+ timer_interval.it_value.tv_sec = interval;
+ timer_interval.it_value.tv_usec = 0;
+ timer_interval.it_interval.tv_sec = interval;
+ timer_interval.it_interval.tv_usec = 0;
+ (void)signal(SIGALRM, catchalarm);
+ signalled = NO;
+ (void)setitimer(ITIMER_REAL, &timer_interval, NULL);
+ first = 1;
+banner:
+ if (vflag > 0)
+ printf("%9s", " ");
+
+ if (prioflag >= 0)
+ printf("%39s %39s %36s", "input",
+ interesting ? interesting->ift_name : "(Total)", "output");
+ else
+ printf("%17s %14s %16s", "input",
+ interesting ? interesting->ift_name : "(Total)", "output");
+ putchar('\n');
+
+ if (vflag > 0)
+ printf("%9s", " ");
+
+ printf("%10s %5s %10s ", "packets", "errs", "bytes");
+ if (prioflag >= 0)
+ printf(" %10s %10s %10s %10s",
+ "tcpkts", "tcbytes", "pvpkts", "pvbytes");
+ printf("%10s %5s %10s %5s", "packets", "errs", "bytes", "colls");
+ if (dflag)
+ printf(" %5.5s", "drops");
+ if (prioflag >= 0)
+ printf(" %10s %10s %10s %10s",
+ "tcpkts", "tcbytes", "pvpkts", "pvbytes");
+ if (Fflag)
+ printf(" %10s %10s", "fpackets", "fbytes");
+ putchar('\n');
+ fflush(stdout);
+ line = 0;
+loop:
+ if (vflag && !first)
+ print_time();
+
+ if (interesting != NULL) {
+ struct ifmibdata ifmd;
+ struct ifmibdata_supplemental ifmsupp;
+
+ len = sizeof(struct ifmibdata);
+ name[3] = IFMIB_IFDATA;
+ name[4] = interesting_row;
+ name[5] = IFDATA_GENERAL;
+ if (sysctl(name, 6, &ifmd, &len, (void *)0, 0) == -1)
+ err(1, "sysctl IFDATA_GENERAL %d", interesting_row);
+
+ len = sizeof(struct ifmibdata_supplemental);
+ name[3] = IFMIB_IFDATA;
+ name[4] = interesting_row;
+ name[5] = IFDATA_SUPPLEMENTAL;
+ if (sysctl(name, 6, &ifmsupp, &len, (void *)0, 0) == -1)
+ err(1, "sysctl IFDATA_SUPPLEMENTAL %d",
+ interesting_row);
+
+ if (!first) {
+ printf("%10llu %5llu %10llu ",
+ ifmd.ifmd_data.ifi_ipackets - interesting->ift_ip,
+ ifmd.ifmd_data.ifi_ierrors - interesting->ift_ie,
+ ifmd.ifmd_data.ifi_ibytes - interesting->ift_ib);
+ switch (prioflag) {
+ case SO_TC_BE:
+ printf("%10llu %10llu ",
+ ifmsupp.ifmd_traffic_class.ifi_ibepackets -
+ interesting->ift_itcp,
+ ifmsupp.ifmd_traffic_class.ifi_ibebytes -
+ interesting->ift_itcb);
+ break;
+ case SO_TC_BK:
+ printf("%10llu %10llu ",
+ ifmsupp.ifmd_traffic_class.ifi_ibkpackets -
+ interesting->ift_itcp,
+ ifmsupp.ifmd_traffic_class.ifi_ibkbytes -
+ interesting->ift_itcb);
+ break;
+ case SO_TC_VI:
+ printf("%10llu %10llu ",
+ ifmsupp.ifmd_traffic_class.ifi_ivipackets -
+ interesting->ift_itcp,
+ ifmsupp.ifmd_traffic_class.ifi_ivibytes -
+ interesting->ift_itcb);
+ break;
+ case SO_TC_VO:
+ printf("%10llu %10llu ",
+ ifmsupp.ifmd_traffic_class.ifi_ivopackets -
+ interesting->ift_itcp,
+ ifmsupp.ifmd_traffic_class.ifi_ivobytes -
+ interesting->ift_itcb);
+ break;
+ default:
+ break;
+ }
+ if (prioflag >= 0) {
+ printf("%10llu %10llu ",
+ ifmsupp.ifmd_traffic_class.ifi_ipvpackets -
+ interesting->ift_ipvp,
+ ifmsupp.ifmd_traffic_class.ifi_ipvbytes -
+ interesting->ift_ipvb);
+ }
+ printf("%10llu %5llu %10llu %5llu",
+ ifmd.ifmd_data.ifi_opackets - interesting->ift_op,
+ ifmd.ifmd_data.ifi_oerrors - interesting->ift_oe,
+ ifmd.ifmd_data.ifi_obytes - interesting->ift_ob,
+ ifmd.ifmd_data.ifi_collisions - interesting->ift_co);
+ if (dflag)
+ printf(" %5llu",
+ ifmd.ifmd_snd_drops - interesting->ift_dr);
+ switch (prioflag) {
+ case SO_TC_BE:
+ printf(" %10llu %10llu",
+ ifmsupp.ifmd_traffic_class.ifi_obepackets -
+ interesting->ift_otcp,
+ ifmsupp.ifmd_traffic_class.ifi_obebytes -
+ interesting->ift_otcb);
+ break;
+ case SO_TC_BK:
+ printf(" %10llu %10llu",
+ ifmsupp.ifmd_traffic_class.ifi_obkpackets -
+ interesting->ift_otcp,
+ ifmsupp.ifmd_traffic_class.ifi_obkbytes -
+ interesting->ift_otcb);
+ break;
+ case SO_TC_VI:
+ printf(" %10llu %10llu",
+ ifmsupp.ifmd_traffic_class.ifi_ovipackets -
+ interesting->ift_otcp,
+ ifmsupp.ifmd_traffic_class.ifi_ovibytes -
+ interesting->ift_otcb);
+ break;
+ case SO_TC_VO:
+ printf(" %10llu %10llu",
+ ifmsupp.ifmd_traffic_class.ifi_ovopackets -
+ interesting->ift_otcp,
+ ifmsupp.ifmd_traffic_class.ifi_ovobytes -
+ interesting->ift_otcb);
+ break;
+ default:
+ break;
+ }
+ if (prioflag >= 0) {
+ printf("%10llu %10llu ",
+ ifmsupp.ifmd_traffic_class.ifi_opvpackets -
+ interesting->ift_opvp,
+ ifmsupp.ifmd_traffic_class.ifi_opvbytes -
+ interesting->ift_opvb);
+ }
+ if (Fflag) {
+ printf("%10llu %10llu",
+ ifmsupp.ifmd_data_extended.ifi_fpackets -
+ interesting->ift_fp,
+ ifmsupp.ifmd_data_extended.ifi_fbytes -
+ interesting->ift_fb);
+ }
+ }
+ interesting->ift_ip = ifmd.ifmd_data.ifi_ipackets;
+ interesting->ift_ie = ifmd.ifmd_data.ifi_ierrors;
+ interesting->ift_ib = ifmd.ifmd_data.ifi_ibytes;
+ interesting->ift_op = ifmd.ifmd_data.ifi_opackets;
+ interesting->ift_oe = ifmd.ifmd_data.ifi_oerrors;
+ interesting->ift_ob = ifmd.ifmd_data.ifi_obytes;
+ interesting->ift_co = ifmd.ifmd_data.ifi_collisions;
+ interesting->ift_dr = ifmd.ifmd_snd_drops;
+
+ /* private counters */
+ switch (prioflag) {
+ case SO_TC_BE:
+ interesting->ift_itcp =
+ ifmsupp.ifmd_traffic_class.ifi_ibepackets;
+ interesting->ift_itcb =
+ ifmsupp.ifmd_traffic_class.ifi_ibebytes;
+ interesting->ift_otcp =
+ ifmsupp.ifmd_traffic_class.ifi_obepackets;
+ interesting->ift_otcb =
+ ifmsupp.ifmd_traffic_class.ifi_obebytes;
+ break;
+ case SO_TC_BK:
+ interesting->ift_itcp =
+ ifmsupp.ifmd_traffic_class.ifi_ibkpackets;
+ interesting->ift_itcb =
+ ifmsupp.ifmd_traffic_class.ifi_ibkbytes;
+ interesting->ift_otcp =
+ ifmsupp.ifmd_traffic_class.ifi_obkpackets;
+ interesting->ift_otcb =
+ ifmsupp.ifmd_traffic_class.ifi_obkbytes;
+ break;
+ case SO_TC_VI:
+ interesting->ift_itcp =
+ ifmsupp.ifmd_traffic_class.ifi_ivipackets;
+ interesting->ift_itcb =
+ ifmsupp.ifmd_traffic_class.ifi_ivibytes;
+ interesting->ift_otcp =
+ ifmsupp.ifmd_traffic_class.ifi_ovipackets;
+ interesting->ift_otcb =
+ ifmsupp.ifmd_traffic_class.ifi_ovibytes;
+ break;
+ case SO_TC_VO:
+ interesting->ift_itcp =
+ ifmsupp.ifmd_traffic_class.ifi_ivopackets;
+ interesting->ift_itcb =
+ ifmsupp.ifmd_traffic_class.ifi_ivobytes;
+ interesting->ift_otcp =
+ ifmsupp.ifmd_traffic_class.ifi_ovopackets;
+ interesting->ift_otcb =
+ ifmsupp.ifmd_traffic_class.ifi_ovobytes;
+ break;
+ default:
+ break;
+ }
+ if (prioflag >= 0) {
+ interesting->ift_ipvp =
+ ifmsupp.ifmd_traffic_class.ifi_ipvpackets;
+ interesting->ift_ipvb =
+ ifmsupp.ifmd_traffic_class.ifi_ipvbytes;
+ interesting->ift_opvp =
+ ifmsupp.ifmd_traffic_class.ifi_opvpackets;
+ interesting->ift_opvb =
+ ifmsupp.ifmd_traffic_class.ifi_opvbytes;
+ }
+ interesting->ift_fp = ifmsupp.ifmd_data_extended.ifi_fpackets;
+ interesting->ift_fb = ifmsupp.ifmd_data_extended.ifi_fbytes;
+ } else {
+ unsigned int latest_ifcount;
+ struct ifmibdata_supplemental *ifmsuppall = NULL;
+
+ len = sizeof(int);
+ name[3] = IFMIB_SYSTEM;
+ name[4] = IFMIB_IFCOUNT;
+ if (sysctl(name, 5, &latest_ifcount, &len, 0, 0) == 1)
+ err(1, "sysctl IFMIB_IFCOUNT");
+ if (latest_ifcount > ifcount) {
+ ifcount = latest_ifcount;
+ len = ifcount * sizeof(struct ifmibdata);
+ free(ifmdall);
+ ifmdall = malloc(len);
+ if (ifmdall == 0)
+ err(1, "malloc ifmdall failed");
+ } else if (latest_ifcount > ifcount) {
+ ifcount = latest_ifcount;
+ len = ifcount * sizeof(struct ifmibdata);
+ }
+ len = ifcount * sizeof(struct ifmibdata);
+ name[3] = IFMIB_IFALLDATA;
+ name[4] = 0;
+ name[5] = IFDATA_GENERAL;
+ if (sysctl(name, 6, ifmdall, &len, (void *)0, 0) == -1)
+ err(1, "sysctl IFMIB_IFALLDATA");
+
+ len = ifcount * sizeof(struct ifmibdata_supplemental);
+ ifmsuppall = malloc(len);
+ if (ifmsuppall == NULL)
+ err(1, "malloc ifmsuppall failed");
+ name[3] = IFMIB_IFALLDATA;
+ name[4] = 0;
+ name[5] = IFDATA_SUPPLEMENTAL;
+ if (sysctl(name, 6, ifmsuppall, &len, (void *)0, 0) == -1)
+ err(1, "sysctl IFMIB_IFALLDATA SUPPLEMENTAL");
+
+ sum->ift_ip = 0;
+ sum->ift_ie = 0;
+ sum->ift_ib = 0;
+ sum->ift_op = 0;
+ sum->ift_oe = 0;
+ sum->ift_ob = 0;
+ sum->ift_co = 0;
+ sum->ift_dr = 0;
+ sum->ift_itcp = 0;
+ sum->ift_itcb = 0;
+ sum->ift_otcp = 0;
+ sum->ift_otcb = 0;
+ sum->ift_ipvp = 0;
+ sum->ift_ipvb = 0;
+ sum->ift_opvp = 0;
+ sum->ift_opvb = 0;
+ sum->ift_fp = 0;
+ sum->ift_fb = 0;
+ for (i = 0; i < ifcount; i++) {
+ struct ifmibdata *ifmd = ifmdall + i;
+ struct ifmibdata_supplemental *ifmsupp = ifmsuppall + i;
+
+ sum->ift_ip += ifmd->ifmd_data.ifi_ipackets;
+ sum->ift_ie += ifmd->ifmd_data.ifi_ierrors;
+ sum->ift_ib += ifmd->ifmd_data.ifi_ibytes;
+ sum->ift_op += ifmd->ifmd_data.ifi_opackets;
+ sum->ift_oe += ifmd->ifmd_data.ifi_oerrors;
+ sum->ift_ob += ifmd->ifmd_data.ifi_obytes;
+ sum->ift_co += ifmd->ifmd_data.ifi_collisions;
+ sum->ift_dr += ifmd->ifmd_snd_drops;
+ /* private counters */
+ if (prioflag >= 0) {
+ switch (prioflag) {
+ case SO_TC_BE:
+ sum->ift_itcp += ifmsupp->ifmd_traffic_class.ifi_ibepackets;
+ sum->ift_itcb += ifmsupp->ifmd_traffic_class.ifi_ibebytes;
+ sum->ift_otcp += ifmsupp->ifmd_traffic_class.ifi_obepackets;
+ sum->ift_otcb += ifmsupp->ifmd_traffic_class.ifi_obebytes;
+ break;
+ case SO_TC_BK:
+ sum->ift_itcp += ifmsupp->ifmd_traffic_class.ifi_ibkpackets;
+ sum->ift_itcb += ifmsupp->ifmd_traffic_class.ifi_ibkbytes;
+ sum->ift_otcp += ifmsupp->ifmd_traffic_class.ifi_obkpackets;
+ sum->ift_otcb += ifmsupp->ifmd_traffic_class.ifi_obkbytes;
+ break;
+ case SO_TC_VI:
+ sum->ift_itcp += ifmsupp->ifmd_traffic_class.ifi_ivipackets;
+ sum->ift_itcb += ifmsupp->ifmd_traffic_class.ifi_ivibytes;
+ sum->ift_otcp += ifmsupp->ifmd_traffic_class.ifi_ovipackets;
+ sum->ift_otcb += ifmsupp->ifmd_traffic_class.ifi_ovibytes;
+ break;
+ case SO_TC_VO:
+ sum->ift_itcp += ifmsupp->ifmd_traffic_class.ifi_ivopackets;
+ sum->ift_itcb += ifmsupp->ifmd_traffic_class.ifi_ivobytes;
+ sum->ift_otcp += ifmsupp->ifmd_traffic_class.ifi_ovopackets;
+ sum->ift_otcb += ifmsupp->ifmd_traffic_class.ifi_ovobytes;
+ break;
+ default:
+ break;
+ }
+ sum->ift_ipvp += ifmsupp->ifmd_traffic_class.ifi_ipvpackets;
+ sum->ift_ipvb += ifmsupp->ifmd_traffic_class.ifi_ipvbytes;
+ sum->ift_opvp += ifmsupp->ifmd_traffic_class.ifi_opvpackets;
+ sum->ift_opvb += ifmsupp->ifmd_traffic_class.ifi_opvbytes;
+ }
+ sum->ift_fp += ifmsupp->ifmd_data_extended.ifi_fpackets;
+ sum->ift_fb += ifmsupp->ifmd_data_extended.ifi_fbytes;
+ }
+ if (!first) {
+ printf("%10llu %5llu %10llu ",
+ sum->ift_ip - total->ift_ip,
+ sum->ift_ie - total->ift_ie,
+ sum->ift_ib - total->ift_ib);
+ if (prioflag >= 0)
+ printf(" %10llu %10llu %10llu %10llu",
+ sum->ift_itcp - total->ift_itcp,
+ sum->ift_itcb - total->ift_itcb,
+ sum->ift_ipvp - total->ift_ipvp,
+ sum->ift_ipvb - total->ift_ipvb);
+ printf("%10llu %5llu %10llu %5llu",
+ sum->ift_op - total->ift_op,
+ sum->ift_oe - total->ift_oe,
+ sum->ift_ob - total->ift_ob,
+ sum->ift_co - total->ift_co);
+ if (dflag)
+ printf(" %5llu", sum->ift_dr - total->ift_dr);
+ if (prioflag >= 0)
+ printf(" %10llu %10llu %10llu %10llu",
+ sum->ift_otcp - total->ift_otcp,
+ sum->ift_otcb - total->ift_otcb,
+ sum->ift_opvp - total->ift_opvp,
+ sum->ift_opvb - total->ift_opvb);
+ if (Fflag)
+ printf(" %10llu %10llu",
+ sum->ift_fp - total->ift_fp,
+ sum->ift_fb - total->ift_fb);
+ }
+ *total = *sum;
+
+ free(ifmsuppall);
+ }
+ if (!first)
+ putchar('\n');
+ fflush(stdout);
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGALRM);
+ (void)sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
+ if (!signalled) {
+ sigemptyset(&sigset);
+ sigsuspend(&sigset);
+ }
+ (void)sigprocmask(SIG_SETMASK, &oldsigset, NULL);
+
+ signalled = NO;
+ line++;
+ first = 0;
+ if (line == 21)
+ goto banner;
+ else
+ goto loop;
+ /*NOTREACHED*/
+}
+
+void
+intervalpr(void (*pr)(uint32_t, char *, int), uint32_t off, char *name , int af)
+{
+ struct itimerval timer_interval;
+ sigset_t sigset, oldsigset;
+
+ /* create a timer that fires repeatedly every interval seconds */
+ timer_interval.it_value.tv_sec = interval;
+ timer_interval.it_value.tv_usec = 0;
+ timer_interval.it_interval.tv_sec = interval;
+ timer_interval.it_interval.tv_usec = 0;
+ (void) signal(SIGALRM, catchalarm);
+ signalled = NO;
+ (void) setitimer(ITIMER_REAL, &timer_interval, NULL);
+
+ for (;;) {
+ pr(off, name, af);
+
+ fflush(stdout);
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGALRM);
+ (void) sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
+ if (!signalled) {
+ sigemptyset(&sigset);
+ sigsuspend(&sigset);
+ }
+ (void) sigprocmask(SIG_SETMASK, &oldsigset, NULL);
+ signalled = NO;
+ }
+}
+
+/*
+ * Called if an interval expires before sidewaysintpr has completed a loop.
+ * Sets a flag to not wait for the alarm.
+ */
+static void
+catchalarm(int signo )
+{
+ signalled = YES;
+}
+
+static char *
+sec2str(total)
+ time_t total;
+{
+ static char result[256];
+ int days, hours, mins, secs;
+ int first = 1;
+ char *p = result;
+
+ days = total / 3600 / 24;
+ hours = (total / 3600) % 24;
+ mins = (total / 60) % 60;
+ secs = total % 60;
+
+ if (days) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dd", days);
+ }
+ if (!first || hours) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dh", hours);
+ }
+ if (!first || mins) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dm", mins);
+ }
+ snprintf(p, sizeof(result) - (p - result), "%ds", secs);
+
+ return(result);
+}
+
+void
+intpr_ri(void (*pfunc)(char *))
+{
+ int mib[6];
+ char *buf = NULL, *lim, *next;
+ size_t len;
+ unsigned int ifindex = 0;
+ struct if_msghdr2 *if2m;
+
+ if (interface != 0) {
+ ifindex = if_nametoindex(interface);
+ if (ifindex == 0) {
+ printf("interface name is not valid: %s\n", interface);
+ exit(1);
+ }
+ }
+
+ mib[0] = CTL_NET; /* networking subsystem */
+ mib[1] = PF_ROUTE; /* type of information */
+ mib[2] = 0; /* protocol (IPPROTO_xxx) */
+ mib[3] = 0; /* address family */
+ mib[4] = NET_RT_IFLIST2; /* operation */
+ mib[5] = 0;
+ if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+ return;
+ if ((buf = malloc(len)) == NULL) {
+ printf("malloc failed\n");
+ exit(1);
+ }
+ if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
+ free(buf);
+ return;
+ }
+
+ printf("%-6s %-17s %8.8s %-9.9s %4s %4s",
+ "Proto", "Linklayer Address", "Netif", "Expire", "Refs",
+ "Prbs");
+ if (xflag)
+ printf(" %7s %7s %7s", "RSSI", "LQM", "NPM");
+ printf("\n");
+
+ lim = buf + len;
+ if2m = (struct if_msghdr2 *)buf;
+
+ for (next = buf; next < lim; ) {
+ if2m = (struct if_msghdr2 *)next;
+ next += if2m->ifm_msglen;
+
+ if (if2m->ifm_type != RTM_IFINFO2)
+ continue;
+ else if (interface != 0 && if2m->ifm_index != ifindex)
+ continue;
+
+ llreach_sysctl(if2m->ifm_index);
+ }
+ free(buf);
+}
+
+static void
+llreach_sysctl(uint32_t ifindex)
+{
+#define MAX_SYSCTL_TRY 5
+ int mib[6], i, ntry = 0;
+ size_t mibsize, len, needed, cnt;
+ struct if_llreach_info *lri;
+ struct timeval time;
+ char *buf;
+ char ifname[IF_NAMESIZE];
+
+ bzero(&mib, sizeof (mib));
+ mibsize = sizeof (mib) / sizeof (mib[0]);
+ if (sysctlnametomib("net.link.generic.system.llreach_info", mib,
+ &mibsize) == -1) {
+ perror("sysctlnametomib");
+ return;
+ }
+
+ needed = 0;
+ mib[5] = ifindex;
+
+ mibsize = sizeof (mib) / sizeof (mib[0]);
+ do {
+ if (sysctl(mib, mibsize, NULL, &needed, NULL, 0) == -1) {
+ perror("sysctl net.link.generic.system.llreach_info");
+ return;
+ }
+ if ((buf = malloc(needed)) == NULL) {
+ perror("malloc");
+ return;
+ }
+ if (sysctl(mib, mibsize, buf, &needed, NULL, 0) == -1) {
+ if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
+ perror("sysctl");
+ goto out_free;
+ }
+ free(buf);
+ buf = NULL;
+ }
+ } while (buf == NULL);
+
+ len = needed;
+ cnt = len / sizeof (*lri);
+ lri = (struct if_llreach_info *)buf;
+
+ gettimeofday(&time, 0);
+ if (if_indextoname(ifindex, ifname) == NULL)
+ snprintf(ifname, sizeof (ifname), "%s", "?");
+
+ for (i = 0; i < cnt; i++, lri++) {
+ printf("0x%-4x %-17s %8.8s ", lri->lri_proto,
+ ether_ntoa((struct ether_addr *)lri->lri_addr), ifname);
+
+ if (lri->lri_expire > time.tv_sec)
+ printf("%-9.9s", sec2str(lri->lri_expire - time.tv_sec));
+ else if (lri->lri_expire == 0)
+ printf("%-9.9s", "permanent");
+ else
+ printf("%-9.9s", "expired");
+
+ printf(" %4d", lri->lri_refcnt);
+ if (lri->lri_probes)
+ printf(" %4d", lri->lri_probes);
+
+ if (xflag) {
+ if (!lri->lri_probes)
+ printf(" %-4.4s", "none");
+
+ if (lri->lri_rssi != IFNET_RSSI_UNKNOWN)
+ printf(" %7d", lri->lri_rssi);
+ else
+ printf(" %-7.7s", "unknown");
+
+ switch (lri->lri_lqm)
+ {
+ case IFNET_LQM_THRESH_OFF:
+ printf(" %-7.7s", "off");
+ break;
+ case IFNET_LQM_THRESH_UNKNOWN:
+ printf(" %-7.7s", "unknown");
+ break;
+ case IFNET_LQM_THRESH_POOR:
+ printf(" %-7.7s", "poor");
+ break;
+ case IFNET_LQM_THRESH_GOOD:
+ printf(" %-7.7s", "good");
+ break;
+ default:
+ printf(" %7d", lri->lri_lqm);
+ break;
+ }
+
+ switch (lri->lri_npm)
+ {
+ case IFNET_NPM_THRESH_UNKNOWN:
+ printf(" %-7.7s", "unknown");
+ break;
+ case IFNET_NPM_THRESH_NEAR:
+ printf(" %-7.7s", "near");
+ break;
+ case IFNET_NPM_THRESH_GENERAL:
+ printf(" %-7.7s", "general");
+ break;
+ case IFNET_NPM_THRESH_FAR:
+ printf(" %-7.7s", "far");
+ break;
+ default:
+ printf(" %7d", lri->lri_npm);
+ break;
+ }
+ }
+
+ printf("\n");
+ len -= sizeof (*lri);
+ }
+
+ if (len > 0) {
+ fprintf(stderr, "warning: %u trailing bytes from %s\n",
+ (unsigned int)len, "net.link.generic.system.llreach_info");
+ }
+
+out_free:
+ free(buf);
+#undef MAX_SYSCTL_TRY
+}
+
+void
+aqstatpr(void)
+{
+ unsigned int ifindex;
+ struct itimerval timer_interval;
+ struct if_qstatsreq ifqr;
+ struct if_ifclassq_stats *ifcqs;
+ sigset_t sigset, oldsigset;
+ u_int32_t scheduler;
+ int s, n;
+
+ if (cq < -1 || cq >= IFCQ_SC_MAX) {
+ fprintf(stderr, "Invalid classq index (range is 0-%d)\n",
+ IFCQ_SC_MAX-1);
+ return;
+ }
+ ifindex = if_nametoindex(interface);
+ if (ifindex == 0) {
+ fprintf(stderr, "Invalid interface name\n");
+ return;
+ }
+
+ ifcqs = malloc(sizeof (*ifcqs));
+ if (ifcqs == NULL) {
+ fprintf(stderr, "Unable to allocate memory\n");
+ return;
+ }
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("Warning: socket(AF_INET)");
+ free(ifcqs);
+ return;
+ }
+
+ bzero(&ifqr, sizeof (ifqr));
+ strlcpy(ifqr.ifqr_name, interface, sizeof (ifqr.ifqr_name));
+ ifqr.ifqr_buf = ifcqs;
+ ifqr.ifqr_len = sizeof (*ifcqs);
+
+loop:
+ if (interval > 0) {
+ /* create a timer that fires repeatedly every interval seconds */
+ timer_interval.it_value.tv_sec = interval;
+ timer_interval.it_value.tv_usec = 0;
+ timer_interval.it_interval.tv_sec = interval;
+ timer_interval.it_interval.tv_usec = 0;
+ (void) signal(SIGALRM, catchalarm);
+ signalled = NO;
+ (void) setitimer(ITIMER_REAL, &timer_interval, NULL);
+ }
+
+ ifqr.ifqr_slot = 0;
+ if (ioctl(s, SIOCGIFQUEUESTATS, (char *)&ifqr) < 0) {
+ if (errno == ENXIO) {
+ printf("Queue statistics are not available on %s\n",
+ interface);
+ } else {
+ perror("Warning: ioctl(SIOCGIFQUEUESTATS)");
+ }
+ goto done;
+ }
+ scheduler = ifcqs->ifqs_scheduler;
+
+ printf("%s:\n"
+ " [ sched: %9s qlength: %3d/%3d ]\n",
+ interface, sched2str(ifcqs->ifqs_scheduler),
+ ifcqs->ifqs_len, ifcqs->ifqs_maxlen);
+ printf(" [ pkts: %10llu bytes: %10llu "
+ " dropped pkts: %6llu bytes: %6llu ]\n",
+ ifcqs->ifqs_xmitcnt.packets, ifcqs->ifqs_xmitcnt.bytes,
+ ifcqs->ifqs_dropcnt.packets, ifcqs->ifqs_dropcnt.bytes);
+
+ for (n = 0; n < IFCQ_SC_MAX && scheduler != PKTSCHEDT_NONE; n++) {
+ if (cq >= 0 && cq != n)
+ continue;
+
+ ifqr.ifqr_slot = n;
+ if (ioctl(s, SIOCGIFQUEUESTATS, (char *)&ifqr) < 0) {
+ perror("Warning: ioctl(SIOCGIFQUEUESTATS)");
+ goto done;
+ }
+
+ update_avg(ifcqs, &qstats[n]);
+
+ switch (scheduler) {
+ case PKTSCHEDT_FQ_CODEL:
+ print_fq_codel_stats(n,
+ &ifcqs->ifqs_fq_codel_stats,
+ &qstats[n]);
+ break;
+ case PKTSCHEDT_NONE:
+ default:
+ break;
+ }
+ }
+
+ fflush(stdout);
+
+ if (interval > 0) {
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGALRM);
+ (void) sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
+ if (!signalled) {
+ sigemptyset(&sigset);
+ sigsuspend(&sigset);
+ }
+ (void) sigprocmask(SIG_SETMASK, &oldsigset, NULL);
+
+ signalled = NO;
+ goto loop;
+ }
+
+done:
+ free(ifcqs);
+ close(s);
+}
+
+static void
+print_fq_codel_stats(int pri, struct fq_codel_classstats *fqst,
+ struct queue_stats *qs)
+{
+ int i = 0;
+
+ if (fqst->fcls_service_class == 0 && fqst->fcls_pri == 0)
+ return;
+ printf("=====================================================\n");
+ printf(" [ pri: %s (%d)\tsrv_cl: 0x%x\tquantum: %d\tdrr_max: %d ]\n",
+ pri2str(fqst->fcls_pri), fqst->fcls_pri,
+ fqst->fcls_service_class, fqst->fcls_quantum,
+ fqst->fcls_drr_max);
+ printf(" [ queued pkts: %llu\tbytes: %llu ]\n",
+ fqst->fcls_pkt_cnt, fqst->fcls_byte_cnt);
+ printf(" [ dequeued pkts: %llu\tbytes: %llu ]\n",
+ fqst->fcls_dequeue, fqst->fcls_dequeue_bytes);
+ printf(" [ budget: %lld\ttarget qdelay: %10s\t",
+ fqst->fcls_budget, nsec_to_str(fqst->fcls_target_qdelay));
+ printf("update interval:%10s ]\n",
+ nsec_to_str(fqst->fcls_update_interval));
+ printf(" [ flow control: %u\tfeedback: %u\tstalls: %u\tfailed: %u ]\n",
+ fqst->fcls_flow_control, fqst->fcls_flow_feedback,
+ fqst->fcls_dequeue_stall, fqst->fcls_flow_control_fail);
+ printf(" [ drop overflow: %llu\tearly: %llu\tmemfail: %u\tduprexmt:%u ]\n",
+ fqst->fcls_drop_overflow, fqst->fcls_drop_early,
+ fqst->fcls_drop_memfailure, fqst->fcls_dup_rexmts);
+ printf(" [ flows total: %u\tnew: %u\told: %u ]\n",
+ fqst->fcls_flows_cnt,
+ fqst->fcls_newflows_cnt, fqst->fcls_oldflows_cnt);
+ printf(" [ throttle on: %u\toff: %u\tdrop: %u ]\n",
+ fqst->fcls_throttle_on, fqst->fcls_throttle_off,
+ fqst->fcls_throttle_drops);
+ printf(" [ compressible pkts: %u compressed pkts: %u]\n",
+ fqst->fcls_pkts_compressible, fqst->fcls_pkts_compressed);
+
+ if (qflag < 2)
+ return;
+
+ if (fqst->fcls_flowstats_cnt > 0) {
+ printf("Flowhash\tBytes\tMin qdelay\tFlags\t\n");
+ for (i = 0; i < fqst->fcls_flowstats_cnt; i++) {
+ printf("%u\t%u\t%14s\t",
+ fqst->fcls_flowstats[i].fqst_flowhash,
+ fqst->fcls_flowstats[i].fqst_bytes,
+ nsec_to_str(fqst->fcls_flowstats[i].fqst_min_qdelay));
+ if (fqst->fcls_flowstats[i].fqst_flags &
+ FQ_FLOWSTATS_OLD_FLOW)
+ printf("O");
+ if (fqst->fcls_flowstats[i].fqst_flags &
+ FQ_FLOWSTATS_NEW_FLOW)
+ printf("N");
+ if (fqst->fcls_flowstats[i].fqst_flags &
+ FQ_FLOWSTATS_LARGE_FLOW)
+ printf("L");
+ if (fqst->fcls_flowstats[i].fqst_flags &
+ FQ_FLOWSTATS_DELAY_HIGH)
+ printf("D");
+ if (fqst->fcls_flowstats[i].fqst_flags &
+ FQ_FLOWSTATS_FLOWCTL_ON)
+ printf("F");
+ printf("\n");
+ }
+ }
+}
+
+static void
+update_avg(struct if_ifclassq_stats *ifcqs, struct queue_stats *qs)
+{
+ u_int64_t b, p;
+ int n;
+
+ n = qs->avgn;
+
+ switch (ifcqs->ifqs_scheduler) {
+ case PKTSCHEDT_FQ_CODEL:
+ b = ifcqs->ifqs_fq_codel_stats.fcls_dequeue_bytes;
+ p = ifcqs->ifqs_fq_codel_stats.fcls_dequeue;
+ break;
+ default:
+ b = 0;
+ p = 0;
+ break;
+ }
+
+ if (n == 0) {
+ qs->prev_bytes = b;
+ qs->prev_packets = p;
+ qs->avgn++;
+ return;
+ }
+
+ if (b >= qs->prev_bytes)
+ qs->avg_bytes = ((qs->avg_bytes * (n - 1)) +
+ (b - qs->prev_bytes)) / n;
+
+ if (p >= qs->prev_packets)
+ qs->avg_packets = ((qs->avg_packets * (n - 1)) +
+ (p - qs->prev_packets)) / n;
+
+ qs->prev_bytes = b;
+ qs->prev_packets = p;
+ if (n < AVGN_MAX)
+ qs->avgn++;
+}
+
+#define NSEC_PER_SEC 1000000000 /* nanoseconds per second */
+#define USEC_PER_SEC 1000000 /* microseconds per second */
+#define MSEC_PER_SEC 1000 /* milliseconds per second */
+
+static char *
+nsec_to_str(unsigned long long nsec)
+{
+ static char buf[32];
+ const char *u;
+ long double n = nsec, t;
+
+ if (nsec >= NSEC_PER_SEC) {
+ t = n / NSEC_PER_SEC;
+ u = "sec ";
+ } else if (n >= USEC_PER_SEC) {
+ t = n / USEC_PER_SEC;
+ u = "msec";
+ } else if (n >= MSEC_PER_SEC) {
+ t = n / MSEC_PER_SEC;
+ u = "usec";
+ } else {
+ t = n;
+ u = "nsec";
+ }
+
+ snprintf(buf, sizeof (buf), "%-4.2Lf %4s", t, u);
+ return (buf);
+}
+
+static char *
+sched2str(unsigned int s)
+{
+ char *c;
+
+ switch (s) {
+ case PKTSCHEDT_NONE:
+ c = "NONE";
+ break;
+ case PKTSCHEDT_FQ_CODEL:
+ c = "FQ_CODEL";
+ break;
+ default:
+ c = "UNKNOWN";
+ break;
+ }
+
+ return (c);
+}
+
+static char *
+pri2str(unsigned int i)
+{
+ char *c;
+ switch (i) {
+ case 9:
+ c = "BK_SYS";
+ break;
+ case 8:
+ c = "BK";
+ break;
+ case 7:
+ c = "BE";
+ break;
+ case 6:
+ c = "RD";
+ break;
+ case 5:
+ c = "OAM";
+ break;
+ case 4:
+ c = "AV";
+ break;
+ case 3:
+ c = "RV";
+ break;
+ case 2:
+ c = "VI";
+ break;
+ case 1:
+ c = "VO";
+ break;
+ case 0:
+ c = "CTL";
+ break;
+ default:
+ c = "?";
+ break;
+ }
+ return (c);
+}
+
+void
+rxpollstatpr(void)
+{
+ struct ifmibdata_supplemental ifmsupp;
+ size_t miblen = sizeof (ifmsupp);
+ struct itimerval timer_interval;
+ struct if_rxpoll_stats *sp;
+ struct if_netif_stats *np;
+ sigset_t sigset, oldsigset;
+ unsigned int ifindex;
+ int name[6];
+
+ ifindex = if_nametoindex(interface);
+ if (ifindex == 0) {
+ fprintf(stderr, "Invalid interface name\n");
+ return;
+ }
+
+ bzero(&ifmsupp, sizeof (struct ifmibdata_supplemental));
+
+loop:
+ if (interval > 0) {
+ /* create a timer that fires repeatedly every interval seconds */
+ timer_interval.it_value.tv_sec = interval;
+ timer_interval.it_value.tv_usec = 0;
+ timer_interval.it_interval.tv_sec = interval;
+ timer_interval.it_interval.tv_usec = 0;
+ (void) signal(SIGALRM, catchalarm);
+ signalled = NO;
+ (void) setitimer(ITIMER_REAL, &timer_interval, NULL);
+ }
+
+ /* Common OID prefix */
+ name[0] = CTL_NET;
+ name[1] = PF_LINK;
+ name[2] = NETLINK_GENERIC;
+ name[3] = IFMIB_IFDATA;
+ name[4] = ifindex;
+ name[5] = IFDATA_SUPPLEMENTAL;
+ if (sysctl(name, 6, &ifmsupp, &miblen, NULL, 0) == -1)
+ err(1, "sysctl IFDATA_SUPPLEMENTAL");
+
+ sp = &ifmsupp.ifmd_rxpoll_stats;
+
+ printf("%-4s [ poll on requests: %15u errors: %27u ]\n",
+ interface, sp->ifi_poll_on_req, sp->ifi_poll_on_err);
+ printf(" [ poll off requests: %15u errors: %27u ]\n",
+ sp->ifi_poll_off_req, sp->ifi_poll_off_err);
+ printf(" [ polled packets: %18llu per poll limit: %19u ]\n",
+ sp->ifi_poll_packets, sp->ifi_poll_packets_limit);
+ printf(" [ polled bytes: %20llu ]\n", sp->ifi_poll_bytes);
+ printf(" [ poll interval: %14llu nsec ]\n",
+ sp->ifi_poll_interval_time);
+ printf(" [ sampled packets avg/min/max: %12u / %12u / %12u ]\n",
+ sp->ifi_poll_packets_avg, sp->ifi_poll_packets_min,
+ sp->ifi_poll_packets_max);
+ printf(" [ sampled bytes avg/min/max: %12u / %12u / %12u ]\n",
+ sp->ifi_poll_bytes_avg, sp->ifi_poll_bytes_min,
+ sp->ifi_poll_bytes_max);
+ printf(" [ sampled wakeups avg: %12u ]\n",
+ sp->ifi_poll_wakeups_avg);
+ printf(" [ packets lowat/hiwat threshold: %10u / %10u ]\n",
+ sp->ifi_poll_packets_lowat, sp->ifi_poll_packets_hiwat);
+ printf(" [ bytes lowat/hiwat threshold: %10u / %10u ]\n",
+ sp->ifi_poll_bytes_lowat, sp->ifi_poll_bytes_hiwat);
+ printf(" [ wakeups lowat/hiwat threshold: %10u / %10u ]\n",
+ sp->ifi_poll_wakeups_lowat, sp->ifi_poll_wakeups_hiwat);
+
+ np = &ifmsupp.ifmd_netif_stats;
+ printf(" [ mit mode: %24U cfg idx: %26u ]\n",
+ np->ifn_rx_mit_mode, np->ifn_rx_mit_cfg_idx);
+ printf(" [ cfg packets lo/hi threshold: %12u / %12u ]\n",
+ np->ifn_rx_mit_cfg_packets_lowat, np->ifn_rx_mit_cfg_packets_hiwat);
+ printf(" [ cfg bytes lo/hi threshold: %12u / %12u ]\n",
+ np->ifn_rx_mit_cfg_bytes_lowat, np->ifn_rx_mit_cfg_bytes_hiwat);
+ printf(" [ cfg interval: %15u nsec ]\n",
+ np->ifn_rx_mit_cfg_interval);
+ printf(" [ mit interval: %15llu nsec ]\n",
+ np->ifn_rx_mit_interval);
+ printf(" [ mit packets avg/min/max: %12u / %12u / %12u ]\n",
+ np->ifn_rx_mit_packets_avg, np->ifn_rx_mit_packets_min,
+ np->ifn_rx_mit_packets_max);
+ printf(" [ mit bytes avg/min/max: %12u / %12u / %12u ]\n",
+ np->ifn_rx_mit_bytes_avg, np->ifn_rx_mit_bytes_min,
+ np->ifn_rx_mit_bytes_max);
+
+ fflush(stdout);
+
+ if (interval > 0) {
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGALRM);
+ (void) sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
+ if (!signalled) {
+ sigemptyset(&sigset);
+ sigsuspend(&sigset);
+ }
+ (void) sigprocmask(SIG_SETMASK, &oldsigset, NULL);
+
+ signalled = NO;
+ goto loop;
+ }
+}
+
+static int
+create_control_socket(const char *control_name)
+{
+ struct sockaddr_ctl sc;
+ struct ctl_info ctl;
+ int fd;
+
+ fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
+ if (fd == -1) {
+ perror("socket(PF_SYSTEM)");
+ return fd;
+ }
+
+ /* Get the control ID for statistics */
+ bzero(&ctl, sizeof(ctl));
+ strlcpy(ctl.ctl_name, control_name, sizeof(ctl.ctl_name));
+ if (ioctl(fd, CTLIOCGINFO, &ctl) == -1)
+ {
+ perror("ioctl(CTLIOCGINFO)");
+ close(fd);
+ return -1;
+ }
+
+ /* Connect to the statistics control */
+ bzero(&sc, sizeof(sc));
+ sc.sc_len = sizeof(sc);
+ sc.sc_family = AF_SYSTEM;
+ sc.ss_sysaddr = SYSPROTO_CONTROL;
+ sc.sc_id = ctl.ctl_id;
+ sc.sc_unit = 0;
+ if (connect(fd, (struct sockaddr*)&sc, sc.sc_len) != 0)
+ {
+ perror("connect(SYSPROTO_CONTROL)");
+ close(fd);
+ return -1;
+ }
+
+ /* Set socket to non-blocking operation */
+ if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) == -1) {
+ perror("fcnt(F_SETFL,O_NONBLOCK)");
+ close(fd);
+ return -1;
+ }
+ return fd;
+}
+
+static int
+add_nstat_src(int fd, const nstat_ifnet_add_param *ifparam,
+ nstat_src_ref_t *outsrc)
+{
+ nstat_msg_add_src_req *addreq;
+ nstat_msg_src_added *addedmsg;
+ nstat_ifnet_add_param *param;
+ char buffer[sizeof(*addreq) + sizeof(*param)];
+ ssize_t result;
+ const u_int32_t addreqsize =
+ offsetof(struct nstat_msg_add_src, param) + sizeof(*param);
+
+ /* Setup the add source request */
+ addreq = (nstat_msg_add_src_req *)buffer;
+ param = (nstat_ifnet_add_param*)addreq->param;
+ bzero(addreq, addreqsize);
+ addreq->hdr.context = (uintptr_t)&buffer;
+ addreq->hdr.type = NSTAT_MSG_TYPE_ADD_SRC;
+ addreq->provider = NSTAT_PROVIDER_IFNET;
+ bzero(param, sizeof(*param));
+ param->ifindex = ifparam->ifindex;
+ param->threshold = ifparam->threshold;
+
+ /* Send the add source request */
+ result = send(fd, addreq, addreqsize, 0);
+ if (result != addreqsize)
+ {
+ if (result == -1)
+ perror("send(NSTAT_ADD_SRC_REQ)");
+ else
+ fprintf(stderr, "%s: could only sent %ld out of %d\n",
+ __func__, result, addreqsize);
+ return -1;
+ }
+
+ /* Receive the response */
+ addedmsg = (nstat_msg_src_added *)buffer;
+ result = recv(fd, addedmsg, sizeof(buffer), 0);
+ if (result < sizeof(*addedmsg))
+ {
+ if (result == -1)
+ perror("recv(NSTAT_ADD_SRC_RSP)");
+ else
+ fprintf(stderr, "%s: recv too small, received %ld, "
+ "expected %lu\n", __func__, result,
+ sizeof(*addedmsg));
+ return -1;
+ }
+
+ if (addedmsg->hdr.type != NSTAT_MSG_TYPE_SRC_ADDED)
+ {
+ fprintf(stderr, "%s: received wrong message type, received %u "
+ "expected %u\n", __func__, addedmsg->hdr.type,
+ NSTAT_MSG_TYPE_SRC_ADDED);
+ return -1;
+ }
+
+ if (addedmsg->hdr.context != (uintptr_t)&buffer)
+ {
+ fprintf(stderr, "%s: received wrong context, received %llu "
+ "expected %lu\n", __func__, addedmsg->hdr.context,
+ (uintptr_t)&buffer);
+ return -1;
+ }
+ *outsrc = addedmsg->srcref;
+ return 0;
+}
+
+static int
+rem_nstat_src(int fd, nstat_src_ref_t sref)
+{
+ nstat_msg_rem_src_req *remreq;
+ nstat_msg_src_removed *remrsp;
+ char buffer[sizeof(*remreq)];
+ ssize_t result;
+
+ /* Setup the add source request */
+ remreq = (nstat_msg_rem_src_req *)buffer;
+ bzero(remreq, sizeof(*remreq));
+ remreq->hdr.type = NSTAT_MSG_TYPE_REM_SRC;
+ remreq->srcref = sref;
+
+ /* Send the remove source request */
+ result = send(fd, remreq, sizeof(*remreq), 0);
+ if (result != sizeof(*remreq)) {
+ if (result == -1)
+ perror("send(NSTAT_REM_SRC_REQ)");
+ else
+ fprintf(stderr, "%s: could only sent %ld out of %lu\n",
+ __func__, result, sizeof(*remreq));
+ return -1;
+ }
+
+ /* Receive the response */
+ remrsp = (nstat_msg_src_removed *)buffer;
+ result = recv(fd, remrsp, sizeof(buffer), 0);
+ if (result < sizeof(*remrsp)) {
+ if (result == -1)
+ perror("recv(NSTAT_REM_SRC_RSP)");
+ else
+ fprintf(stderr, "%s: recv too small, received %ld, "
+ "expected %lu\n", __func__, result,
+ sizeof(*remrsp));
+ return -1;
+ }
+
+ if (remrsp->hdr.type != NSTAT_MSG_TYPE_SRC_REMOVED) {
+ fprintf(stderr, "%s: received wrong message type, received %u "
+ "expected %u\n", __func__, remrsp->hdr.type,
+ NSTAT_MSG_TYPE_SRC_REMOVED);
+ return -1;
+ }
+
+ if (remrsp->srcref != sref) {
+ fprintf(stderr, "%s: received invalid srcref, received %llu "
+ "expected %llu\n", __func__, remrsp->srcref, sref);
+ }
+ return 0;
+}
+
+static int
+get_src_decsription(int fd, nstat_src_ref_t srcref,
+ struct nstat_ifnet_descriptor *ifdesc)
+{
+ nstat_msg_get_src_description *dreq;
+ nstat_msg_src_description *drsp;
+ char buffer[sizeof(*drsp) + sizeof(*ifdesc)];
+ ssize_t result;
+ const u_int32_t descsize =
+ offsetof(struct nstat_msg_src_description, data) +
+ sizeof(nstat_ifnet_descriptor);
+
+ dreq = (nstat_msg_get_src_description *)buffer;
+ bzero(dreq, sizeof(*dreq));
+ dreq->hdr.type = NSTAT_MSG_TYPE_GET_SRC_DESC;
+ dreq->srcref = srcref;
+ result = send(fd, dreq, sizeof(*dreq), 0);
+ if (result != sizeof(*dreq))
+ {
+ if (result == -1)
+ perror("send(NSTAT_GET_SRC_DESC_REQ)");
+ else
+ fprintf(stderr, "%s: sent %ld out of %lu\n",
+ __func__, result, sizeof(*dreq));
+ return -1;
+ }
+
+ /* Receive the source description response */
+ drsp = (nstat_msg_src_description *)buffer;
+ result = recv(fd, drsp, sizeof(buffer), 0);
+ if (result < descsize)
+ {
+ if (result == -1)
+ perror("recv(NSTAT_GET_SRC_DESC_RSP");
+ else
+ fprintf(stderr, "%s: recv too small, received %ld, "
+ "expected %u\n", __func__, result, descsize);
+ return -1;
+ }
+
+ if (drsp->hdr.type != NSTAT_MSG_TYPE_SRC_DESC)
+ {
+ fprintf(stderr, "%s: received wrong message type, received %u "
+ "expected %u\n", __func__, drsp->hdr.type,
+ NSTAT_MSG_TYPE_SRC_DESC);
+ return -1;
+ }
+
+ if (drsp->srcref != srcref)
+ {
+ fprintf(stderr, "%s: received message for wrong source, "
+ "received 0x%llx expected 0x%llx\n",
+ __func__, drsp->srcref, srcref);
+ return -1;
+ }
+
+ bcopy(drsp->data, ifdesc, sizeof(*ifdesc));
+ return 0;
+}
+
+static void
+print_wifi_status(nstat_ifnet_desc_wifi_status *status)
+{
+ int tmp;
+#define val(x, f) \
+ ((status->valid_bitmask & NSTAT_IFNET_DESC_WIFI_ ## f ## _VALID) ?\
+ status->x : -1)
+#define parg(n, un) #n, val(n, un)
+#define pretxtl(n, un) \
+ (((tmp = val(n, un)) == -1) ? "(not valid)" : \
+ ((tmp == NSTAT_IFNET_DESC_WIFI_UL_RETXT_LEVEL_NONE) ? "(none)" : \
+ ((tmp == NSTAT_IFNET_DESC_WIFI_UL_RETXT_LEVEL_LOW) ? "(low)" : \
+ ((tmp == NSTAT_IFNET_DESC_WIFI_UL_RETXT_LEVEL_MEDIUM) ? "(medium)" : \
+ ((tmp == NSTAT_IFNET_DESC_WIFI_UL_RETXT_LEVEL_HIGH) ? "(high)" : \
+ "(?)")))))
+
+ printf("\nwifi status:\n");
+ printf(
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t\t%d%s\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t\t%d\n",
+ parg(link_quality_metric, LINK_QUALITY_METRIC),
+ parg(ul_effective_bandwidth, UL_EFFECTIVE_BANDWIDTH),
+ parg(ul_max_bandwidth, UL_MAX_BANDWIDTH),
+ parg(ul_min_latency, UL_MIN_LATENCY),
+ parg(ul_effective_latency, UL_EFFECTIVE_LATENCY),
+ parg(ul_max_latency, UL_MAX_LATENCY),
+ parg(ul_retxt_level, UL_RETXT_LEVEL),
+ pretxtl(ul_retxt_level, UL_RETXT_LEVEL),
+ parg(ul_bytes_lost, UL_BYTES_LOST),
+ parg(ul_error_rate, UL_ERROR_RATE),
+ parg(dl_effective_bandwidth, DL_EFFECTIVE_BANDWIDTH),
+ parg(dl_max_bandwidth, DL_MAX_BANDWIDTH),
+ parg(dl_min_latency, DL_MIN_LATENCY),
+ parg(dl_effective_latency, DL_EFFECTIVE_LATENCY),
+ parg(dl_max_latency, DL_MAX_LATENCY),
+ parg(dl_error_rate, DL_ERROR_RATE),
+ parg(config_frequency, CONFIG_FREQUENCY),
+ parg(config_multicast_rate, CONFIG_MULTICAST_RATE),
+ parg(scan_count, CONFIG_SCAN_COUNT),
+ parg(scan_duration, CONFIG_SCAN_DURATION)
+ );
+#undef pretxtl
+#undef parg
+#undef val
+}
+
+static void
+print_cellular_status(nstat_ifnet_desc_cellular_status *status)
+{
+ int tmp, tmp_mss;
+#define val(x, f) \
+ ((status->valid_bitmask & NSTAT_IFNET_DESC_CELL_ ## f ## _VALID) ?\
+ status->x : -1)
+#define parg(n, un) #n, val(n, un)
+#define pretxtl(n, un) \
+ (((tmp = val(n, un)) == -1) ? "(not valid)" : \
+ ((tmp == NSTAT_IFNET_DESC_CELL_UL_RETXT_LEVEL_NONE) ? "(none)" : \
+ ((tmp == NSTAT_IFNET_DESC_CELL_UL_RETXT_LEVEL_LOW) ? "(low)" : \
+ ((tmp == NSTAT_IFNET_DESC_CELL_UL_RETXT_LEVEL_MEDIUM) ? "(medium)" : \
+ ((tmp == NSTAT_IFNET_DESC_CELL_UL_RETXT_LEVEL_HIGH) ? "(high)" : \
+ "(?)")))))
+#define pretxtm(n, un) \
+ (((tmp_mss = val(n,un)) == -1) ? "(not valid)" : \
+ ((tmp_mss == NSTAT_IFNET_DESC_MSS_RECOMMENDED_NONE) ? "(none)" : \
+ ((tmp_mss == NSTAT_IFNET_DESC_MSS_RECOMMENDED_MEDIUM) ? "(medium)" : \
+ ((tmp_mss == NSTAT_IFNET_DESC_MSS_RECOMMENDED_LOW) ? "(low)" : \
+ "(?)"))))
+
+ printf("\ncellular status:\n");
+ printf(
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t\t%d%s\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d %s\n",
+ parg(link_quality_metric, LINK_QUALITY_METRIC),
+ parg(ul_effective_bandwidth, UL_EFFECTIVE_BANDWIDTH),
+ parg(ul_max_bandwidth, UL_MAX_BANDWIDTH),
+ parg(ul_min_latency, UL_MIN_LATENCY),
+ parg(ul_effective_latency, UL_EFFECTIVE_LATENCY),
+ parg(ul_max_latency, UL_MAX_LATENCY),
+ parg(ul_retxt_level, UL_RETXT_LEVEL),
+ pretxtl(ul_retxt_level, UL_RETXT_LEVEL),
+ parg(ul_bytes_lost, UL_BYTES_LOST),
+ parg(ul_min_queue_size, UL_MIN_QUEUE_SIZE),
+ parg(ul_avg_queue_size, UL_AVG_QUEUE_SIZE),
+ parg(ul_max_queue_size, UL_MAX_QUEUE_SIZE),
+ parg(dl_effective_bandwidth, DL_EFFECTIVE_BANDWIDTH),
+ parg(dl_max_bandwidth, DL_MAX_BANDWIDTH),
+ parg(config_inactivity_time, CONFIG_INACTIVITY_TIME),
+ parg(config_backoff_time, CONFIG_BACKOFF_TIME),
+ parg(mss_recommended, MSS_RECOMMENDED),
+ pretxtm(mss_recommended, MSS_RECOMMENDED)
+ );
+#undef pretxtl
+#undef parg
+#undef val
+}
+
+static int
+get_interface_state(int fd, const char *ifname, struct ifreq *ifr)
+{
+ bzero(ifr, sizeof(*ifr));
+ snprintf(ifr->ifr_name, sizeof(ifr->ifr_name), "%s", ifname);
+
+ if (ioctl(fd, SIOCGIFINTERFACESTATE, ifr) == -1) {
+ perror("ioctl(CTLIOCGINFO)");
+ return -1;
+ }
+ return 0;
+}
+
+static void
+print_interface_state(struct ifreq *ifr)
+{
+ int lqm, rrc, avail;
+
+ printf("\ninterface state:\n");
+
+ if (ifr->ifr_interface_state.valid_bitmask &
+ IF_INTERFACE_STATE_LQM_STATE_VALID) {
+ printf("\tlqm: ");
+ lqm = ifr->ifr_interface_state.lqm_state;
+ if (lqm == IFNET_LQM_THRESH_GOOD)
+ printf("\"good\"");
+ else if (lqm == IFNET_LQM_THRESH_POOR)
+ printf("\"poor\"");
+ else if (lqm == IFNET_LQM_THRESH_BAD)
+ printf("\"bad\"");
+ else if (lqm == IFNET_LQM_THRESH_UNKNOWN)
+ printf("\"unknown\"");
+ else if (lqm == IFNET_LQM_THRESH_OFF)
+ printf("\"off\"");
+ else
+ printf("invalid(%d)", lqm);
+ }
+
+ if (ifr->ifr_interface_state.valid_bitmask &
+ IF_INTERFACE_STATE_RRC_STATE_VALID) {
+ printf("\trrc: ");
+ rrc = ifr->ifr_interface_state.rrc_state;
+ if (rrc == IF_INTERFACE_STATE_RRC_STATE_CONNECTED)
+ printf("\"connected\"");
+ else if (rrc == IF_INTERFACE_STATE_RRC_STATE_IDLE)
+ printf("\"idle\"");
+ else
+ printf("\"invalid(%d)\"", rrc);
+ }
+
+ if (ifr->ifr_interface_state.valid_bitmask &
+ IF_INTERFACE_STATE_INTERFACE_AVAILABILITY_VALID) {
+ printf("\tavailability: ");
+ avail = ifr->ifr_interface_state.interface_availability;
+ if (avail == IF_INTERFACE_STATE_INTERFACE_AVAILABLE)
+ printf("\"true\"");
+ else if (rrc == IF_INTERFACE_STATE_INTERFACE_UNAVAILABLE)
+ printf("\"false\"");
+ else
+ printf("\"invalid(%d)\"", avail);
+ }
+}
+
+void
+print_link_status(const char *ifname)
+{
+ unsigned int ifindex;
+ struct itimerval timer_interval;
+ sigset_t sigset, oldsigset;
+ struct nstat_ifnet_descriptor ifdesc;
+ nstat_ifnet_add_param ifparam;
+ nstat_src_ref_t sref = 0;
+ struct ifreq ifr;
+ int ctl_fd;
+
+ ifindex = if_nametoindex(ifname);
+ if (ifindex == 0) {
+ fprintf(stderr, "Invalid interface name\n");
+ return;
+ }
+
+ if ((ctl_fd = create_control_socket(NET_STAT_CONTROL_NAME)) < 0)
+ return;
+
+ ifparam.ifindex = ifindex;
+ ifparam.threshold = UINT64_MAX;
+ if (add_nstat_src(ctl_fd, &ifparam, &sref))
+ goto done;
+loop:
+ if (interval > 0) {
+ /* create a timer that fires repeatedly every interval
+ * seconds */
+ timer_interval.it_value.tv_sec = interval;
+ timer_interval.it_value.tv_usec = 0;
+ timer_interval.it_interval.tv_sec = interval;
+ timer_interval.it_interval.tv_usec = 0;
+ (void) signal(SIGALRM, catchalarm);
+ signalled = NO;
+ (void) setitimer(ITIMER_REAL, &timer_interval, NULL);
+ }
+
+ /* get interface state */
+ if (get_interface_state(ctl_fd, ifname, &ifr))
+ goto done;
+
+ /* get ntstat interface description */
+ if (get_src_decsription(ctl_fd, sref, &ifdesc))
+ goto done;
+
+ /* print time */
+ printf("\n%s: ", ifname);
+ print_time();
+
+ /* print interface state */
+ print_interface_state(&ifr);
+
+ /* print ntsat interface link status */
+ if (ifdesc.link_status.link_status_type ==
+ NSTAT_IFNET_DESC_LINK_STATUS_TYPE_CELLULAR)
+ print_cellular_status(&ifdesc.link_status.u.cellular);
+ else if (ifdesc.link_status.link_status_type ==
+ NSTAT_IFNET_DESC_LINK_STATUS_TYPE_WIFI)
+ print_wifi_status(&ifdesc.link_status.u.wifi);
+
+ fflush(stdout);
+
+ if (interval > 0) {
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGALRM);
+ (void) sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
+ if (!signalled) {
+ sigemptyset(&sigset);
+ sigsuspend(&sigset);
+ }
+ (void) sigprocmask(SIG_SETMASK, &oldsigset, NULL);
+
+ signalled = NO;
+ goto loop;
+ }
+done:
+ if (sref)
+ rem_nstat_src(ctl_fd, sref);
+ close(ctl_fd);
+}
diff --git a/network_cmds/netstat.tproj/inet.c b/network_cmds/netstat.tproj/inet.c
new file mode 100644
index 0000000..68e4ddb
--- /dev/null
+++ b/network_cmds/netstat.tproj/inet.c
@@ -0,0 +1,1361 @@
+/*
+ * Copyright (c) 2008-2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ ** @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1983, 1988, 1993, 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+
+#include <net/route.h>
+#include <net/if_arp.h>
+#include <net/net_perf.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#ifdef INET6
+#include <netinet/ip6.h>
+#endif /* INET6 */
+#include <netinet/in_pcb.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp_var.h>
+#include <netinet/igmp_var.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+#include <netinet/tcp_seq.h>
+#define TCPSTATES
+#include <netinet/tcp_fsm.h>
+#include <netinet/tcp_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#include <arpa/inet.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include "netstat.h"
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+#define ROUNDUP64(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint64_t) - 1))) : sizeof(uint64_t))
+#define ADVANCE64(x, n) (((char *)x) += ROUNDUP64(n))
+
+char *inetname (struct in_addr *);
+void inetprint (struct in_addr *, int, char *, int);
+#ifdef INET6
+extern void inet6print (struct in6_addr *, int, char *, int);
+static int udp_done, tcp_done;
+extern int mptcp_done;
+#endif /* INET6 */
+
+#ifdef SRVCACHE
+typedef struct __table_private table_t;
+
+extern table_t *_nc_table_new(uint32_t n);
+extern void _nc_table_free(table_t *tin);
+
+extern void _nc_table_insert(table_t *t, const char *key, void *datum);
+extern void *_nc_table_find(table_t *t, const char *key);
+extern void _nc_table_delete(table_t *t, const char *key);
+
+static table_t *_serv_cache = NULL;
+
+/*
+ * Read and cache all known services
+ */
+static void
+_serv_cache_open()
+{
+ struct servent *s;
+ char *key, *name, *test;
+
+ if (_serv_cache != NULL) return;
+
+ _serv_cache = _nc_table_new(8192);
+ setservent(0);
+
+ while (NULL != (s = getservent()))
+ {
+ if (s->s_name == NULL) continue;
+ key = NULL;
+ asprintf(&key, "%hu/%s", (unsigned short)ntohs(s->s_port), s->s_proto);
+ name = strdup(s->s_name);
+ test = _nc_table_find(_serv_cache, key);
+ if (test == NULL) _nc_table_insert(_serv_cache, key, name);
+ free(key);
+ }
+
+ endservent();
+}
+
+void
+_serv_cache_close()
+{
+ _nc_table_free(_serv_cache);
+ _serv_cache = NULL;
+}
+
+struct servent *
+_serv_cache_getservbyport(int port, char *proto)
+{
+ static struct servent s;
+ char *key;
+ unsigned short p;
+
+ _serv_cache_open();
+
+ memset(&s, 0, sizeof(struct servent));
+ asprintf(&key, "%u/%s", port, (proto == NULL) ? "udp" : proto);
+
+ s.s_name = _nc_table_find(_serv_cache, key);
+ free(key);
+ if (s.s_name == NULL) return NULL;
+
+ p = port;
+ s.s_port = htons(p);
+ s.s_proto = proto;
+ return &s;
+}
+
+#endif /* SRVCACHE */
+
+/*
+ * Print a summary of connections related to an Internet
+ * protocol. For TCP, also give state of connection.
+ * Listening processes (aflag) are suppressed unless the
+ * -a (all) flag is specified.
+ */
+
+struct xgen_n {
+ u_int32_t xgn_len; /* length of this structure */
+ u_int32_t xgn_kind; /* number of PCBs at this time */
+};
+
+#define ALL_XGN_KIND_INP (XSO_SOCKET | XSO_RCVBUF | XSO_SNDBUF | XSO_STATS | XSO_INPCB)
+#define ALL_XGN_KIND_TCP (ALL_XGN_KIND_INP | XSO_TCPCB)
+
+void
+protopr(uint32_t proto, /* for sysctl version we pass proto # */
+ char *name, int af)
+{
+ int istcp;
+ static int first = 1;
+ char *buf, *next;
+ const char *mibvar;
+ struct xinpgen *xig, *oxig;
+ struct xgen_n *xgn;
+ size_t len;
+ struct xtcpcb_n *tp = NULL;
+ struct xinpcb_n *inp = NULL;
+ struct xsocket_n *so = NULL;
+ struct xsockbuf_n *so_rcv = NULL;
+ struct xsockbuf_n *so_snd = NULL;
+ struct xsockstat_n *so_stat = NULL;
+ int which = 0;
+
+ istcp = 0;
+ switch (proto) {
+ case IPPROTO_TCP:
+#ifdef INET6
+ if (tcp_done != 0)
+ return;
+ else
+ tcp_done = 1;
+#endif
+ istcp = 1;
+ mibvar = "net.inet.tcp.pcblist_n";
+ break;
+ case IPPROTO_UDP:
+#ifdef INET6
+ if (udp_done != 0)
+ return;
+ else
+ udp_done = 1;
+#endif
+ mibvar = "net.inet.udp.pcblist_n";
+ break;
+ case IPPROTO_DIVERT:
+ mibvar = "net.inet.divert.pcblist_n";
+ break;
+ default:
+ mibvar = "net.inet.raw.pcblist_n";
+ break;
+ }
+ len = 0;
+ if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
+ if (errno != ENOENT)
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+ if ((buf = malloc(len)) == 0) {
+ warn("malloc %lu bytes", (u_long)len);
+ return;
+ }
+ if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ free(buf);
+ return;
+ }
+
+ /*
+ * Bail-out to avoid logic error in the loop below when
+ * there is in fact no more control block to process
+ */
+ if (len <= sizeof(struct xinpgen)) {
+ free(buf);
+ return;
+ }
+
+ oxig = xig = (struct xinpgen *)buf;
+ for (next = buf + ROUNDUP64(xig->xig_len); next < buf + len; next += ROUNDUP64(xgn->xgn_len)) {
+
+ xgn = (struct xgen_n*)next;
+ if (xgn->xgn_len <= sizeof(struct xinpgen))
+ break;
+
+ if ((which & xgn->xgn_kind) == 0) {
+ which |= xgn->xgn_kind;
+ switch (xgn->xgn_kind) {
+ case XSO_SOCKET:
+ so = (struct xsocket_n *)xgn;
+ break;
+ case XSO_RCVBUF:
+ so_rcv = (struct xsockbuf_n *)xgn;
+ break;
+ case XSO_SNDBUF:
+ so_snd = (struct xsockbuf_n *)xgn;
+ break;
+ case XSO_STATS:
+ so_stat = (struct xsockstat_n *)xgn;
+ break;
+ case XSO_INPCB:
+ inp = (struct xinpcb_n *)xgn;
+ break;
+ case XSO_TCPCB:
+ tp = (struct xtcpcb_n *)xgn;
+ break;
+ default:
+ printf("unexpected kind %d\n", xgn->xgn_kind);
+ break;
+ }
+ } else {
+ if (vflag)
+ printf("got %d twice\n", xgn->xgn_kind);
+ }
+
+ if ((istcp && which != ALL_XGN_KIND_TCP) || (!istcp && which != ALL_XGN_KIND_INP))
+ continue;
+ which = 0;
+
+ /* Ignore sockets for protocols other than the desired one. */
+ if (so->xso_protocol != (int)proto)
+ continue;
+
+ /* Ignore PCBs which were freed during copyout. */
+ if (inp->inp_gencnt > oxig->xig_gen)
+ continue;
+
+ if ((af == AF_INET && (inp->inp_vflag & INP_IPV4) == 0)
+#ifdef INET6
+ || (af == AF_INET6 && (inp->inp_vflag & INP_IPV6) == 0)
+#endif /* INET6 */
+ || (af == AF_UNSPEC && ((inp->inp_vflag & INP_IPV4) == 0
+#ifdef INET6
+ && (inp->inp_vflag &
+ INP_IPV6) == 0
+#endif /* INET6 */
+ ))
+ )
+ continue;
+
+ /*
+ * Local address is not an indication of listening socket or
+ * server sockey but just rather the socket has been bound.
+ * That why many UDP sockets were not displayed in the original code.
+ */
+ if (!aflag && istcp && tp->t_state <= TCPS_LISTEN)
+ continue;
+
+ if (Lflag && !so->so_qlimit)
+ continue;
+
+ if (first) {
+ if (!Lflag) {
+ printf("Active Internet connections");
+ if (aflag)
+ printf(" (including servers)");
+ } else
+ printf(
+ "Current listen queue sizes (qlen/incqlen/maxqlen)");
+ putchar('\n');
+ if (Aflag) {
+ printf("%-16.16s ", "Socket");
+ printf("%-9.9s", "Flowhash");
+ }
+ if (Lflag)
+ printf("%-14.14s %-22.22s\n",
+ "Listen", "Local Address");
+ else {
+ printf((Aflag && !Wflag) ?
+ "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %-11.11s" :
+ "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %-11.11s",
+ "Proto", "Recv-Q", "Send-Q",
+ "Local Address", "Foreign Address",
+ "(state)");
+ if (bflag > 0)
+ printf(" %10.10s %10.10s", "rxbytes", "txbytes");
+ if (prioflag >= 0)
+ printf(" %7.7s[%1d] %7.7s[%1d]", "rxbytes", prioflag, "txbytes", prioflag);
+ if (vflag > 0)
+ printf(" %6.6s %6.6s %6.6s %6.6s %6s %10s",
+ "rhiwat", "shiwat", "pid", "epid", "state", "options");
+ printf("\n");
+ }
+ first = 0;
+ }
+ if (Aflag) {
+ if (istcp)
+ printf("%16lx ", (u_long)inp->inp_ppcb);
+ else
+ printf("%16lx ", (u_long)so->so_pcb);
+ printf("%8x ", inp->inp_flowhash);
+ }
+ if (Lflag) {
+ char buf[15];
+
+ snprintf(buf, 15, "%d/%d/%d", so->so_qlen,
+ so->so_incqlen, so->so_qlimit);
+ printf("%-14.14s ", buf);
+ }
+ else {
+ const char *vchar;
+
+#ifdef INET6
+ if ((inp->inp_vflag & INP_IPV6) != 0)
+ vchar = ((inp->inp_vflag & INP_IPV4) != 0)
+ ? "46" : "6 ";
+ else
+#endif
+ vchar = ((inp->inp_vflag & INP_IPV4) != 0)
+ ? "4 " : " ";
+
+ printf("%-3.3s%-2.2s %6u %6u ", name, vchar,
+ so_rcv->sb_cc,
+ so_snd->sb_cc);
+ }
+ if (nflag) {
+ if (inp->inp_vflag & INP_IPV4) {
+ inetprint(&inp->inp_laddr, (int)inp->inp_lport,
+ name, 1);
+ if (!Lflag)
+ inetprint(&inp->inp_faddr,
+ (int)inp->inp_fport, name, 1);
+ }
+#ifdef INET6
+ else if (inp->inp_vflag & INP_IPV6) {
+ inet6print(&inp->in6p_laddr,
+ (int)inp->inp_lport, name, 1);
+ if (!Lflag)
+ inet6print(&inp->in6p_faddr,
+ (int)inp->inp_fport, name, 1);
+ } /* else nothing printed now */
+#endif /* INET6 */
+ } else if (inp->inp_flags & INP_ANONPORT) {
+ if (inp->inp_vflag & INP_IPV4) {
+ inetprint(&inp->inp_laddr, (int)inp->inp_lport,
+ name, 1);
+ if (!Lflag)
+ inetprint(&inp->inp_faddr,
+ (int)inp->inp_fport, name, 0);
+ }
+#ifdef INET6
+ else if (inp->inp_vflag & INP_IPV6) {
+ inet6print(&inp->in6p_laddr,
+ (int)inp->inp_lport, name, 1);
+ if (!Lflag)
+ inet6print(&inp->in6p_faddr,
+ (int)inp->inp_fport, name, 0);
+ } /* else nothing printed now */
+#endif /* INET6 */
+ } else {
+ if (inp->inp_vflag & INP_IPV4) {
+ inetprint(&inp->inp_laddr, (int)inp->inp_lport,
+ name, 0);
+ if (!Lflag)
+ inetprint(&inp->inp_faddr,
+ (int)inp->inp_fport, name,
+ inp->inp_lport !=
+ inp->inp_fport);
+ }
+#ifdef INET6
+ else if (inp->inp_vflag & INP_IPV6) {
+ inet6print(&inp->in6p_laddr,
+ (int)inp->inp_lport, name, 0);
+ if (!Lflag)
+ inet6print(&inp->in6p_faddr,
+ (int)inp->inp_fport, name,
+ inp->inp_lport !=
+ inp->inp_fport);
+ } /* else nothing printed now */
+#endif /* INET6 */
+ }
+ if (istcp && !Lflag) {
+ if (tp->t_state < 0 || tp->t_state >= TCP_NSTATES)
+ printf("%-11d", tp->t_state);
+ else {
+ printf("%-11s", tcpstates[tp->t_state]);
+ }
+ }
+ if (!istcp)
+ printf("%-11s", " ");
+ if (bflag > 0) {
+ int i;
+ u_int64_t rxbytes = 0;
+ u_int64_t txbytes = 0;
+
+ for (i = 0; i < SO_TC_STATS_MAX; i++) {
+ rxbytes += so_stat->xst_tc_stats[i].rxbytes;
+ txbytes += so_stat->xst_tc_stats[i].txbytes;
+ }
+
+ printf(" %10llu %10llu", rxbytes, txbytes);
+ }
+ if (prioflag >= 0) {
+ printf(" %10llu %10llu",
+ prioflag < SO_TC_STATS_MAX ? so_stat->xst_tc_stats[prioflag].rxbytes : 0,
+ prioflag < SO_TC_STATS_MAX ? so_stat->xst_tc_stats[prioflag].txbytes : 0);
+ }
+ if (vflag > 0) {
+ printf(" %6u %6u %6u %6u 0x%04x 0x%08x",
+ so_rcv->sb_hiwat,
+ so_snd->sb_hiwat,
+ so->so_last_pid,
+ so->so_e_pid,
+ so->so_state,
+ so->so_options);
+ }
+ putchar('\n');
+ }
+ if (xig != oxig && xig->xig_gen != oxig->xig_gen) {
+ if (oxig->xig_count > xig->xig_count) {
+ printf("Some %s sockets may have been deleted.\n",
+ name);
+ } else if (oxig->xig_count < xig->xig_count) {
+ printf("Some %s sockets may have been created.\n",
+ name);
+ } else {
+ printf("Some %s sockets may have been created or deleted",
+ name);
+ }
+ }
+ free(buf);
+}
+
+/*
+ * Dump TCP statistics structure.
+ */
+void
+tcp_stats(uint32_t off , char *name, int af)
+{
+ static struct tcpstat ptcpstat;
+ struct tcpstat tcpstat;
+ size_t len = sizeof tcpstat;
+ static uint32_t r_swcsum, pr_swcsum;
+ static uint32_t t_swcsum, pt_swcsum;
+
+ if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, 0, 0) < 0) {
+ warn("sysctl: net.inet.tcp.stats");
+ return;
+ }
+
+#ifdef INET6
+ if (tcp_done != 0 && interval == 0)
+ return;
+ else
+ tcp_done = 1;
+#endif
+
+ if (interval && vflag > 0)
+ print_time();
+ printf ("%s:\n", name);
+
+#define TCPDIFF(f) (tcpstat.f - ptcpstat.f)
+#define p(f, m) if (TCPDIFF(f) || sflag <= 1) \
+ printf(m, TCPDIFF(f), plural(TCPDIFF(f)))
+#define p1a(f, m) if (TCPDIFF(f) || sflag <= 1) \
+ printf(m, TCPDIFF(f))
+#define p2(f1, f2, m) if (TCPDIFF(f1) || TCPDIFF(f2) || sflag <= 1) \
+ printf(m, TCPDIFF(f1), plural(TCPDIFF(f1)), TCPDIFF(f2), plural(TCPDIFF(f2)))
+#define p2a(f1, f2, m) if (TCPDIFF(f1) || TCPDIFF(f2) || sflag <= 1) \
+ printf(m, TCPDIFF(f1), plural(TCPDIFF(f1)), TCPDIFF(f2))
+#define p3(f, m) if (TCPDIFF(f) || sflag <= 1) \
+ printf(m, TCPDIFF(f), plurales(TCPDIFF(f)))
+
+ p(tcps_sndtotal, "\t%u packet%s sent\n");
+ p2(tcps_sndpack,tcps_sndbyte,
+ "\t\t%u data packet%s (%u byte%s)\n");
+ p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
+ "\t\t%u data packet%s (%u byte%s) retransmitted\n");
+ p(tcps_mturesent, "\t\t%u resend%s initiated by MTU discovery\n");
+ p2a(tcps_sndacks, tcps_delack,
+ "\t\t%u ack-only packet%s (%u delayed)\n");
+ p(tcps_sndurg, "\t\t%u URG only packet%s\n");
+ p(tcps_sndprobe, "\t\t%u window probe packet%s\n");
+ p(tcps_sndwinup, "\t\t%u window update packet%s\n");
+ p(tcps_sndctrl, "\t\t%u control packet%s\n");
+ p(tcps_fcholdpacket, "\t\t%u data packet%s sent after flow control\n");
+ p(tcps_synchallenge, "\t\t%u challenge ACK%s sent due to unexpected SYN\n");
+ p(tcps_rstchallenge, "\t\t%u challenge ACK%s sent due to unexpected RST\n");
+ t_swcsum = tcpstat.tcps_snd_swcsum + tcpstat.tcps_snd6_swcsum;
+ if ((t_swcsum - pt_swcsum) || sflag <= 1)
+ printf("\t\t%u checksummed in software\n", (t_swcsum - pt_swcsum));
+ p2(tcps_snd_swcsum, tcps_snd_swcsum_bytes,
+ "\t\t\t%u segment%s (%u byte%s) over IPv4\n");
+#if INET6
+ p2(tcps_snd6_swcsum, tcps_snd6_swcsum_bytes,
+ "\t\t\t%u segment%s (%u byte%s) over IPv6\n");
+#endif /* INET6 */
+ p(tcps_rcvtotal, "\t%u packet%s received\n");
+ p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%u ack%s (for %u byte%s)\n");
+ p(tcps_rcvdupack, "\t\t%u duplicate ack%s\n");
+ p(tcps_rcvacktoomuch, "\t\t%u ack%s for unsent data\n");
+ p2(tcps_rcvpack, tcps_rcvbyte,
+ "\t\t%u packet%s (%u byte%s) received in-sequence\n");
+ p2(tcps_rcvduppack, tcps_rcvdupbyte,
+ "\t\t%u completely duplicate packet%s (%u byte%s)\n");
+ p(tcps_pawsdrop, "\t\t%u old duplicate packet%s\n");
+ p(tcps_rcvmemdrop, "\t\t%u received packet%s dropped due to low memory\n");
+ p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
+ "\t\t%u packet%s with some dup. data (%u byte%s duped)\n");
+ p2(tcps_rcvoopack, tcps_rcvoobyte,
+ "\t\t%u out-of-order packet%s (%u byte%s)\n");
+ p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
+ "\t\t%u packet%s (%u byte%s) of data after window\n");
+ p(tcps_rcvwinprobe, "\t\t%u window probe%s\n");
+ p(tcps_rcvwinupd, "\t\t%u window update packet%s\n");
+ p(tcps_recovered_pkts, "\t\t%u packet%s recovered after loss\n");
+ p(tcps_rcvafterclose, "\t\t%u packet%s received after close\n");
+ p(tcps_badrst, "\t\t%u bad reset%s\n");
+ p(tcps_rcvbadsum, "\t\t%u discarded for bad checksum%s\n");
+ r_swcsum = tcpstat.tcps_rcv_swcsum + tcpstat.tcps_rcv6_swcsum;
+ if ((r_swcsum - pr_swcsum) || sflag <= 1)
+ printf("\t\t%u checksummed in software\n",
+ (r_swcsum - pr_swcsum));
+ p2(tcps_rcv_swcsum, tcps_rcv_swcsum_bytes,
+ "\t\t\t%u segment%s (%u byte%s) over IPv4\n");
+#if INET6
+ p2(tcps_rcv6_swcsum, tcps_rcv6_swcsum_bytes,
+ "\t\t\t%u segment%s (%u byte%s) over IPv6\n");
+#endif /* INET6 */
+ p(tcps_rcvbadoff, "\t\t%u discarded for bad header offset field%s\n");
+ p1a(tcps_rcvshort, "\t\t%u discarded because packet too short\n");
+ p(tcps_connattempt, "\t%u connection request%s\n");
+ p(tcps_accepts, "\t%u connection accept%s\n");
+ p(tcps_badsyn, "\t%u bad connection attempt%s\n");
+ p(tcps_listendrop, "\t%u listen queue overflow%s\n");
+ p(tcps_connects, "\t%u connection%s established (including accepts)\n");
+ p2(tcps_closed, tcps_drops,
+ "\t%u connection%s closed (including %u drop%s)\n");
+ p(tcps_cachedrtt, "\t\t%u connection%s updated cached RTT on close\n");
+ p(tcps_cachedrttvar,
+ "\t\t%u connection%s updated cached RTT variance on close\n");
+ p(tcps_cachedssthresh,
+ "\t\t%u connection%s updated cached ssthresh on close\n");
+ p(tcps_usedrtt, "\t\t%u connection%s initialized RTT from route cache\n");
+ p(tcps_usedrttvar,
+ "\t\t%u connection%s initialized RTT variance from route cache\n");
+ p(tcps_usedssthresh,
+ "\t\t%u connection%s initialized ssthresh from route cache\n");
+ p(tcps_conndrops, "\t%u embryonic connection%s dropped\n");
+ p2(tcps_rttupdated, tcps_segstimed,
+ "\t%u segment%s updated rtt (of %u attempt%s)\n");
+ p(tcps_rexmttimeo, "\t%u retransmit timeout%s\n");
+ p(tcps_timeoutdrop, "\t\t%u connection%s dropped by rexmit timeout\n");
+ p(tcps_rxtfindrop, "\t\t%u connection%s dropped after retransmitting FIN\n");
+ p(tcps_sndrexmitbad, "\t\t%u unnecessary packet retransmissions%s\n");
+ p(tcps_persisttimeo, "\t%u persist timeout%s\n");
+ p(tcps_persistdrop, "\t\t%u connection%s dropped by persist timeout\n");
+ p(tcps_keeptimeo, "\t%u keepalive timeout%s\n");
+ p(tcps_keepprobe, "\t\t%u keepalive probe%s sent\n");
+ p(tcps_keepdrops, "\t\t%u connection%s dropped by keepalive\n");
+ p(tcps_ka_offload_drops, "\t\t%u connection%s dropped by keepalive offload\n");
+ p(tcps_predack, "\t%u correct ACK header prediction%s\n");
+ p(tcps_preddat, "\t%u correct data packet header prediction%s\n");
+#ifdef TCP_MAX_SACK
+ /* TCP_MAX_SACK indicates the header has the SACK structures */
+ p(tcps_sack_recovery_episode, "\t%u SACK recovery episode%s\n");
+ p(tcps_sack_rexmits,
+ "\t%u segment rexmit%s in SACK recovery episodes\n");
+ p(tcps_sack_rexmit_bytes,
+ "\t%u byte rexmit%s in SACK recovery episodes\n");
+ p(tcps_sack_rcv_blocks,
+ "\t%u SACK option%s (SACK blocks) received\n");
+ p(tcps_sack_send_blocks, "\t%u SACK option%s (SACK blocks) sent\n");
+ p1a(tcps_sack_sboverflow, "\t%u SACK scoreboard overflow\n");
+#endif /* TCP_MAX_SACK */
+ p(tcps_limited_txt, "\t%u limited transmit%s done\n");
+ p(tcps_early_rexmt, "\t%u early retransmit%s done\n");
+ p(tcps_sack_ackadv, "\t%u time%s cumulative ack advanced along with SACK\n");
+ p(tcps_pto, "\t%u probe timeout%s\n");
+ p(tcps_rto_after_pto, "\t\t%u time%s retransmit timeout triggered after probe\n");
+ p(tcps_probe_if, "\t\t%u time%s probe packets were sent for an interface\n");
+ p(tcps_probe_if_conflict, "\t\t%u time%s couldn't send probe packets for an interface\n");
+ p(tcps_tlp_recovery, "\t\t%u time%s fast recovery after tail loss\n");
+ p(tcps_tlp_recoverlastpkt, "\t\t%u time%s recovered last packet \n");
+ p(tcps_pto_in_recovery, "\t\t%u SACK based rescue retransmit%s\n");
+ p(tcps_ecn_client_setup, "\t%u client connection%s attempted to negotiate ECN\n");
+ p(tcps_ecn_client_success, "\t\t%u client connection%s successfully negotiated ECN\n");
+ p(tcps_ecn_not_supported, "\t\t%u time%s graceful fallback to Non-ECN connection\n");
+ p(tcps_ecn_lost_syn, "\t\t%u time%s lost ECN negotiating SYN, followed by retransmission\n");
+ p(tcps_ecn_server_setup, "\t\t%u server connection%s attempted to negotiate ECN\n");
+ p(tcps_ecn_server_success, "\t\t%u server connection%s successfully negotiated ECN\n");
+ p(tcps_ecn_lost_synack, "\t\t%u time%s lost ECN negotiating SYN-ACK, followed by retransmission\n");
+ p(tcps_ecn_recv_ce, "\t\t%u time%s received congestion experienced (CE) notification\n");
+ p(tcps_ecn_recv_ece, "\t\t%u time%s CWR was sent in response to ECE\n");
+ p(tcps_ecn_sent_ece, "\t\t%u time%s sent ECE notification\n");
+ p(tcps_ecn_conn_recv_ce, "\t\t%u connection%s received CE atleast once\n");
+ p(tcps_ecn_conn_recv_ece, "\t\t%u connection%s received ECE atleast once\n");
+ p(tcps_ecn_conn_plnoce, "\t\t%u connection%s using ECN have seen packet loss but no CE\n");
+ p(tcps_ecn_conn_pl_ce, "\t\t%u connection%s using ECN have seen packet loss and CE\n");
+ p(tcps_ecn_conn_nopl_ce, "\t\t%u connection%s using ECN received CE but no packet loss\n");
+ p(tcps_ecn_fallback_synloss, "\t\t%u connection%s fell back to non-ECN due to SYN-loss\n");
+ p(tcps_ecn_fallback_reorder, "\t\t%u connection%s fell back to non-ECN due to reordering\n");
+ p(tcps_ecn_fallback_ce, "\t\t%u connection%s fell back to non-ECN due to excessive CE-markings\n");
+ p(tcps_ecn_fallback_droprst, "\t\t%u connection%s fell back caused by connection drop due to RST\n");
+ p(tcps_ecn_fallback_droprxmt, "\t\t%u connection%s fell back due to drop after multiple retransmits \n");
+ p(tcps_ecn_fallback_synrst, "\t\t%u connection%s fell back due to RST after SYN\n");
+
+ p(tcps_detect_reordering, "\t%u time%s packet reordering was detected on a connection\n");
+ p(tcps_reordered_pkts, "\t\t%u time%s transmitted packets were reordered\n");
+ p(tcps_delay_recovery, "\t\t%u time%s fast recovery was delayed to handle reordering\n");
+ p(tcps_avoid_rxmt, "\t\t%u time%s retransmission was avoided by delaying recovery\n");
+ p(tcps_unnecessary_rxmt, "\t\t%u retransmission%s not needed \n");
+ p(tcps_tailloss_rto, "\t%u retransmission%s due to tail loss\n");
+ p(tcps_dsack_sent, "\t%u time%s DSACK option was sent\n");
+ p(tcps_dsack_recvd, "\t\t%u time%s DSACK option was received\n");
+ p(tcps_dsack_disable, "\t\t%u time%s DSACK was disabled on a connection\n");
+ p(tcps_dsack_badrexmt, "\t\t%u time%s recovered from bad retransmission using DSACK\n");
+ p(tcps_dsack_ackloss,"\t\t%u time%s ignored DSACK due to ack loss\n");
+ p(tcps_dsack_recvd_old,"\t\t%u time%s ignored old DSACK options\n");
+ p(tcps_pmtudbh_reverted, "\t%u time%s PMTU Blackhole detection, size reverted\n");
+ p(tcps_drop_after_sleep, "\t%u connection%s were dropped after long sleep\n");
+ p(tcps_nostretchack, "\t%u connection%s had stretch ack algorithm disabled\n");
+
+ p(tcps_tfo_cookie_sent,"\t%u time%s a TFO-cookie has been announced\n");
+ p(tcps_tfo_syn_data_rcv,"\t%u SYN%s with data and a valid TFO-cookie have been received\n");
+ p(tcps_tfo_cookie_req_rcv,"\t%u SYN%s with TFO-cookie-request received\n");
+ p(tcps_tfo_cookie_invalid,"\t%u time%s an invalid TFO-cookie has been received\n");
+ p(tcps_tfo_cookie_req,"\t%u time%s we requested a TFO-cookie\n");
+ p(tcps_tfo_cookie_rcv,"\t\t%u time%s the peer announced a TFO-cookie\n");
+ p(tcps_tfo_syn_data_sent,"\t%u time%s we combined SYN with data and a TFO-cookie\n");
+ p(tcps_tfo_syn_data_acked,"\t\t%u time%s our SYN with data has been acknowledged\n");
+ p(tcps_tfo_syn_loss,"\t%u time%s a connection-attempt with TFO fell back to regular TCP\n");
+ p(tcps_tfo_blackhole,"\t%u time%s a TFO-connection blackhole'd\n");
+ p(tcps_tfo_cookie_wrong,"\t%u time%s a TFO-cookie we sent was wrong\n");
+ p(tcps_tfo_no_cookie_rcv,"\t%u time%s did not received a TFO-cookie we asked for\n");
+ p(tcps_tfo_heuristics_disable,"\t%u time%s TFO got disabled due to heuristicsn\n");
+ p(tcps_tfo_sndblackhole,"\t%u time%s TFO got blackholed in the sending direction\n");
+
+ p(tcps_mss_to_default,"\t%u time%s maximum segment size was changed to default\n");
+ p(tcps_mss_to_medium,"\t%u time%s maximum segment size was changed to medium\n");
+ p(tcps_mss_to_low,"\t%u time%s maximum segment size was changed to low\n");
+
+ p(tcps_timer_drift_le_1_ms,"\t%u timer drift%s less or equal to 1 ms\n");
+ p(tcps_timer_drift_le_10_ms,"\t%u timer drift%s less or equal to 10 ms\n");
+ p(tcps_timer_drift_le_20_ms,"\t%u timer drift%s less or equal to 20 ms\n");
+ p(tcps_timer_drift_le_50_ms,"\t%u timer drift%s less or equal to 50 ms\n");
+ p(tcps_timer_drift_le_100_ms,"\t%u timer drift%s less or equal to 100 ms\n");
+ p(tcps_timer_drift_le_200_ms,"\t%u timer drift%s less or equal to 200 ms\n");
+ p(tcps_timer_drift_le_500_ms,"\t%u timer drift%s less or equal to 500 ms\n");
+ p(tcps_timer_drift_le_1000_ms,"\t%u timer drift%s less or equal to 1000 ms\n");
+ p(tcps_timer_drift_gt_1000_ms,"\t%u timer drift%s greater than to 1000 ms\n");
+
+ if (interval > 0) {
+ bcopy(&tcpstat, &ptcpstat, len);
+ pr_swcsum = r_swcsum;
+ pt_swcsum = t_swcsum;
+ }
+
+#undef TCPDIFF
+#undef p
+#undef p1a
+#undef p2
+#undef p2a
+#undef p3
+}
+
+/*
+ * Dump MPTCP statistics
+ */
+void
+mptcp_stats(uint32_t off , char *name, int af)
+{
+ static struct tcpstat ptcpstat;
+ struct tcpstat tcpstat;
+ size_t len = sizeof tcpstat;
+
+ if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, 0, 0) < 0) {
+ warn("sysctl: net.inet.tcp.stats");
+ return;
+ }
+
+#ifdef INET6
+ if (mptcp_done != 0 && interval == 0)
+ return;
+ else
+ mptcp_done = 1;
+#endif
+
+ if (interval && vflag > 0)
+ print_time();
+ printf ("%s:\n", name);
+
+#define MPTCPDIFF(f) (tcpstat.f - ptcpstat.f)
+#define p(f, m) if (MPTCPDIFF(f) || sflag <= 1) \
+ printf(m, MPTCPDIFF(f), plural(MPTCPDIFF(f)))
+#define p1a(f, m) if (MPTCPDIFF(f) || sflag <= 1) \
+ printf(m, MPTCPDIFF(f))
+#define p2(f1, f2, m) if (MPTCPDIFF(f1) || MPTCPDIFF(f2) || sflag <= 1) \
+ printf(m, MPTCPDIFF(f1), plural(MPTCPDIFF(f1)), \
+ MPTCPDIFF(f2), plural(MPTCPDIFF(f2)))
+#define p2a(f1, f2, m) if (MPTCPDIFF(f1) || MPTCPDIFF(f2) || sflag <= 1) \
+ printf(m, MPTCPDIFF(f1), plural(MPTCPDIFF(f1)), MPTCPDIFF(f2))
+#define p3(f, m) if (MPTCPDIFF(f) || sflag <= 1) \
+ printf(m, MPTCPDIFF(f), plurales(MPTCPDIFF(f)))
+
+ p(tcps_mp_sndpacks, "\t%u data packet%s sent\n");
+ p(tcps_mp_sndbytes, "\t%u data byte%s sent\n");
+ p(tcps_mp_rcvtotal, "\t%u data packet%s received\n");
+ p(tcps_mp_rcvbytes, "\t%u data byte%s received\n");
+ p(tcps_invalid_mpcap, "\t%u packet%s with an invalid MPCAP option\n");
+ p(tcps_invalid_joins, "\t%u packet%s with an invalid MPJOIN option\n");
+ p(tcps_mpcap_fallback, "\t%u time%s primary subflow fell back to "
+ "TCP\n");
+ p(tcps_join_fallback, "\t%u time%s secondary subflow fell back to "
+ "TCP\n");
+ p(tcps_estab_fallback, "\t%u DSS option drop%s\n");
+ p(tcps_invalid_opt, "\t%u other invalid MPTCP option%s\n");
+ p(tcps_mp_reducedwin, "\t%u time%s the MPTCP subflow window was reduced\n");
+ p(tcps_mp_badcsum, "\t%u bad DSS checksum%s\n");
+ p(tcps_mp_oodata, "\t%u time%s received out of order data \n");
+ p3(tcps_mp_switches, "\t%u subflow switch%s\n");
+ p3(tcps_mp_sel_symtomsd, "\t%u subflow switch%s due to advisory\n");
+ p3(tcps_mp_sel_rtt, "\t%u subflow switch%s due to rtt\n");
+ p3(tcps_mp_sel_rto, "\t%u subflow switch%s due to rto\n");
+ p3(tcps_mp_sel_peer, "\t%u subflow switch%s due to peer\n");
+ p3(tcps_mp_num_probes, "\t%u number of subflow probe%s\n");
+
+ if (interval > 0) {
+ bcopy(&tcpstat, &ptcpstat, len);
+ }
+
+#undef MPTCPDIFF
+#undef p
+#undef p1a
+#undef p2
+#undef p2a
+#undef p3
+}
+
+/*
+ * Dump UDP statistics structure.
+ */
+void
+udp_stats(uint32_t off , char *name, int af )
+{
+ static struct udpstat pudpstat;
+ struct udpstat udpstat;
+ size_t len = sizeof udpstat;
+ uint32_t delivered;
+ static uint32_t r_swcsum, pr_swcsum;
+ static uint32_t t_swcsum, pt_swcsum;
+
+ if (sysctlbyname("net.inet.udp.stats", &udpstat, &len, 0, 0) < 0) {
+ warn("sysctl: net.inet.udp.stats");
+ return;
+ }
+
+#ifdef INET6
+ if (udp_done != 0 && interval == 0)
+ return;
+ else
+ udp_done = 1;
+#endif
+
+ if (interval && vflag > 0)
+ print_time();
+ printf("%s:\n", name);
+
+#define UDPDIFF(f) (udpstat.f - pudpstat.f)
+#define p(f, m) if (UDPDIFF(f) || sflag <= 1) \
+ printf(m, UDPDIFF(f), plural(UDPDIFF(f)))
+#define p1a(f, m) if (UDPDIFF(f) || sflag <= 1) \
+ printf(m, UDPDIFF(f))
+#define p2(f1, f2, m) if (UDPDIFF(f1) || UDPDIFF(f2) || sflag <= 1) \
+ printf(m, UDPDIFF(f1), plural(UDPDIFF(f1)), UDPDIFF(f2), plural(UDPDIFF(f2)))
+ p(udps_ipackets, "\t%u datagram%s received\n");
+ p1a(udps_hdrops, "\t\t%u with incomplete header\n");
+ p1a(udps_badlen, "\t\t%u with bad data length field\n");
+ p1a(udps_badsum, "\t\t%u with bad checksum\n");
+ p1a(udps_nosum, "\t\t%u with no checksum\n");
+ r_swcsum = udpstat.udps_rcv_swcsum + udpstat.udps_rcv6_swcsum;
+ if ((r_swcsum - pr_swcsum) || sflag <= 1)
+ printf("\t\t%u checksummed in software\n", (r_swcsum - pr_swcsum));
+ p2(udps_rcv_swcsum, udps_rcv_swcsum_bytes,
+ "\t\t\t%u datagram%s (%u byte%s) over IPv4\n");
+#if INET6
+ p2(udps_rcv6_swcsum, udps_rcv6_swcsum_bytes,
+ "\t\t\t%u datagram%s (%u byte%s) over IPv6\n");
+#endif /* INET6 */
+ p1a(udps_noport, "\t\t%u dropped due to no socket\n");
+ p(udps_noportbcast,
+ "\t\t%u broadcast/multicast datagram%s undelivered\n");
+ /* the next statistic is cumulative in udps_noportbcast */
+ p(udps_filtermcast,
+ "\t\t%u time%s multicast source filter matched\n");
+ p1a(udps_fullsock, "\t\t%u dropped due to full socket buffers\n");
+ p1a(udpps_pcbhashmiss, "\t\t%u not for hashed pcb\n");
+ delivered = UDPDIFF(udps_ipackets) -
+ UDPDIFF(udps_hdrops) -
+ UDPDIFF(udps_badlen) -
+ UDPDIFF(udps_badsum) -
+ UDPDIFF(udps_noport) -
+ UDPDIFF(udps_noportbcast) -
+ UDPDIFF(udps_fullsock);
+ if (delivered || sflag <= 1)
+ printf("\t\t%u delivered\n", delivered);
+ p(udps_opackets, "\t%u datagram%s output\n");
+ t_swcsum = udpstat.udps_snd_swcsum + udpstat.udps_snd6_swcsum;
+ if ((t_swcsum - pt_swcsum) || sflag <= 1)
+ printf("\t\t%u checksummed in software\n", (t_swcsum - pt_swcsum));
+ p2(udps_snd_swcsum, udps_snd_swcsum_bytes,
+ "\t\t\t%u datagram%s (%u byte%s) over IPv4\n");
+#if INET6
+ p2(udps_snd6_swcsum, udps_snd6_swcsum_bytes,
+ "\t\t\t%u datagram%s (%u byte%s) over IPv6\n");
+#endif /* INET6 */
+
+ if (interval > 0) {
+ bcopy(&udpstat, &pudpstat, len);
+ pr_swcsum = r_swcsum;
+ pt_swcsum = t_swcsum;
+ }
+
+#undef UDPDIFF
+#undef p
+#undef p1a
+#undef p2
+}
+
+/*
+ * Dump IP statistics structure.
+ */
+void
+ip_stats(uint32_t off , char *name, int af )
+{
+ static struct ipstat pipstat;
+ struct ipstat ipstat;
+ size_t ipstat_len = sizeof ipstat;
+
+ static net_perf_t pout_net_perf, pin_net_perf;
+ net_perf_t out_net_perf, in_net_perf;
+ size_t out_net_perf_len = sizeof (out_net_perf);
+ size_t in_net_perf_len = sizeof (in_net_perf);
+
+ if (sysctlbyname("net.inet.ip.stats", &ipstat, &ipstat_len, 0, 0) < 0) {
+ warn("sysctl: net.inet.ip.stats");
+ return;
+ }
+
+ if (sysctlbyname("net.inet.ip.output_perf_data", &out_net_perf, &out_net_perf_len, 0, 0) < 0) {
+ warn("sysctl: net.inet.ip.output_perf_data");
+ bzero(&out_net_perf, out_net_perf_len);
+ }
+
+ if (sysctlbyname("net.inet.ip.input_perf_data", &in_net_perf, &in_net_perf_len, 0, 0) < 0) {
+ warn("sysctl: net.inet.ip.input_perf_data");
+ bzero(&in_net_perf, in_net_perf_len);
+ }
+
+ if (interval && vflag > 0)
+ print_time();
+ printf("%s:\n", name);
+
+#define IPDIFF(f) (ipstat.f - pipstat.f)
+#define p(f, m) if (IPDIFF(f) || sflag <= 1) \
+ printf(m, IPDIFF(f), plural(IPDIFF(f)))
+#define p1a(f, m) if (IPDIFF(f) || sflag <= 1) \
+ printf(m, IPDIFF(f))
+#define p2(f1, f2, m) if (IPDIFF(f1) || IPDIFF(f2) || sflag <= 1) \
+ printf(m, IPDIFF(f1), plural(IPDIFF(f1)), IPDIFF(f2), plural(IPDIFF(f2)))
+
+ p(ips_total, "\t%u total packet%s received\n");
+ p(ips_badsum, "\t\t%u bad header checksum%s\n");
+ p2(ips_rcv_swcsum, ips_rcv_swcsum_bytes,
+ "\t\t%u header%s (%u byte%s) checksummed in software\n");
+ p1a(ips_toosmall, "\t\t%u with size smaller than minimum\n");
+ p1a(ips_tooshort, "\t\t%u with data size < data length\n");
+ p1a(ips_adj, "\t\t%u with data size > data length\n");
+ p(ips_adj_hwcsum_clr,
+ "\t\t\t%u packet%s forced to software checksum\n");
+ p1a(ips_toolong, "\t\t%u with ip length > max ip packet size\n");
+ p1a(ips_badhlen, "\t\t%u with header length < data size\n");
+ p1a(ips_badlen, "\t\t%u with data length < header length\n");
+ p1a(ips_badoptions, "\t\t%u with bad options\n");
+ p1a(ips_badvers, "\t\t%u with incorrect version number\n");
+ p(ips_fragments, "\t\t%u fragment%s received\n");
+ p1a(ips_fragdropped, "\t\t\t%u dropped (dup or out of space)\n");
+ p1a(ips_fragtimeout, "\t\t\t%u dropped after timeout\n");
+ p1a(ips_reassembled, "\t\t\t%u reassembled ok\n");
+ p(ips_delivered, "\t\t%u packet%s for this host\n");
+ p(ips_noproto, "\t\t%u packet%s for unknown/unsupported protocol\n");
+ p(ips_forward, "\t\t%u packet%s forwarded");
+ p(ips_fastforward, " (%u packet%s fast forwarded)");
+ if (IPDIFF(ips_forward) || sflag <= 1)
+ putchar('\n');
+ p(ips_cantforward, "\t\t%u packet%s not forwardable\n");
+ p(ips_notmember,
+ "\t\t%u packet%s received for unknown multicast group\n");
+ p(ips_redirectsent, "\t\t%u redirect%s sent\n");
+ p(ips_rxc_collisions, "\t\t%u input packet%s not chained due to collision\n");
+ p(ips_rxc_chained, "\t\t%u input packet%s processed in a chain\n");
+ p(ips_rxc_notchain, "\t\t%u input packet%s unable to chain\n");
+ p(ips_rxc_chainsz_gt2,
+ "\t\t%u input packet chain%s processed with length greater than 2\n");
+ p(ips_rxc_chainsz_gt4,
+ "\t\t%u input packet chain%s processed with length greater than 4\n");
+ p(ips_rxc_notlist,
+ "\t\t%u input packet%s did not go through list processing path\n");
+
+ p(ips_rcv_if_weak_match,
+ "\t\t%u input packet%s that passed the weak ES interface address match\n");
+ p(ips_rcv_if_no_match,
+ "\t\t%u input packet%s with no interface address match\n");
+
+#define INPERFDIFF(f) (in_net_perf.f - pin_net_perf.f)
+ if (INPERFDIFF(np_total_pkts) > 0 && in_net_perf.np_total_usecs > 0) {
+ printf("\tInput Performance Stats:\n");
+ printf("\t\t%llu total packets measured\n", INPERFDIFF(np_total_pkts));
+ printf("\t\t%llu total usec elapsed\n", INPERFDIFF(np_total_usecs));
+ printf("\t\t%f usec per packet\n",
+ (double)in_net_perf.np_total_usecs/(double)in_net_perf.np_total_pkts);
+ printf("\t\tHistogram:\n");
+ printf("\t\t\t x <= %u: %llu\n", in_net_perf.np_hist_bars[0],
+ INPERFDIFF(np_hist1));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ in_net_perf.np_hist_bars[0], in_net_perf.np_hist_bars[1],
+ INPERFDIFF(np_hist2));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ in_net_perf.np_hist_bars[1], in_net_perf.np_hist_bars[2],
+ INPERFDIFF(np_hist3));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ in_net_perf.np_hist_bars[2], in_net_perf.np_hist_bars[3],
+ INPERFDIFF(np_hist4));
+ printf("\t\t\t %u < x: %llu\n",
+ in_net_perf.np_hist_bars[3], INPERFDIFF(np_hist5));
+ }
+#undef INPERFDIFF
+
+ p(ips_localout, "\t%u packet%s sent from this host\n");
+ p(ips_rawout, "\t\t%u packet%s sent with fabricated ip header\n");
+ p(ips_odropped,
+ "\t\t%u output packet%s dropped due to no bufs, etc.\n");
+ p(ips_noroute, "\t\t%u output packet%s discarded due to no route\n");
+ p(ips_fragmented, "\t\t%u output datagram%s fragmented\n");
+ p(ips_ofragments, "\t\t%u fragment%s created\n");
+ p(ips_cantfrag, "\t\t%u datagram%s that can't be fragmented\n");
+ p(ips_nogif, "\t\t%u tunneling packet%s that can't find gif\n");
+ p(ips_badaddr, "\t\t%u datagram%s with bad address in header\n");
+ p(ips_pktdropcntrl,
+ "\t\t%u packet%s dropped due to no bufs for control data\n");
+ p(ips_necp_policy_drop, "\t\t%u packet%s dropped due to NECP policy\n");
+ p2(ips_snd_swcsum, ips_snd_swcsum_bytes,
+ "\t\t%u header%s (%u byte%s) checksummed in software\n");
+
+#define OUTPERFDIFF(f) (out_net_perf.f - pout_net_perf.f)
+ if (OUTPERFDIFF(np_total_pkts) > 0 && out_net_perf.np_total_usecs > 0) {
+ printf("\tOutput Performance Stats:\n");
+ printf("\t\t%llu total packets measured\n", OUTPERFDIFF(np_total_pkts));
+ printf("\t\t%llu total usec elapsed\n", OUTPERFDIFF(np_total_usecs));
+ printf("\t\t%f usec per packet\n",
+ (double)out_net_perf.np_total_usecs/(double)out_net_perf.np_total_pkts);
+ printf("\t\tHistogram:\n");
+ printf("\t\t\t x <= %u: %llu\n", out_net_perf.np_hist_bars[0],
+ OUTPERFDIFF(np_hist1));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ out_net_perf.np_hist_bars[0], out_net_perf.np_hist_bars[1],
+ OUTPERFDIFF(np_hist2));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ out_net_perf.np_hist_bars[1], out_net_perf.np_hist_bars[2],
+ OUTPERFDIFF(np_hist3));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ out_net_perf.np_hist_bars[2], out_net_perf.np_hist_bars[3],
+ OUTPERFDIFF(np_hist4));
+ printf("\t\t\t %u < x: %llu\n",
+ out_net_perf.np_hist_bars[3], OUTPERFDIFF(np_hist5));
+ }
+#undef OUTPERFDIFF
+
+ if (interval > 0) {
+ bcopy(&ipstat, &pipstat, ipstat_len);
+ bcopy(&in_net_perf, &pin_net_perf, in_net_perf_len);
+ bcopy(&out_net_perf, &pout_net_perf, out_net_perf_len);
+ }
+
+#undef IPDIFF
+#undef p
+#undef p1a
+#undef p2
+}
+
+/*
+ * Dump ARP statistics structure.
+ */
+void
+arp_stats(uint32_t off, char *name, int af)
+{
+ static struct arpstat parpstat;
+ struct arpstat arpstat;
+ size_t len = sizeof (arpstat);
+
+ if (sysctlbyname("net.link.ether.inet.stats", &arpstat,
+ &len, 0, 0) < 0) {
+ warn("sysctl: net.link.ether.inet.stats");
+ return;
+ }
+
+ if (interval && vflag > 0)
+ print_time();
+ printf("%s:\n", name);
+
+#define ARPDIFF(f) (arpstat.f - parpstat.f)
+#define p(f, m) if (ARPDIFF(f) || sflag <= 1) \
+ printf(m, ARPDIFF(f), plural(ARPDIFF(f)))
+#define p2(f, m) if (ARPDIFF(f) || sflag <= 1) \
+ printf(m, ARPDIFF(f), pluralies(ARPDIFF(f)))
+#define p3(f, m) if (ARPDIFF(f) || sflag <= 1) \
+ printf(m, ARPDIFF(f), plural(ARPDIFF(f)), pluralies(ARPDIFF(f)))
+
+ p(txrequests, "\t%u broadast ARP request%s sent\n");
+ p(txurequests, "\t%u unicast ARP request%s sent\n");
+ p2(txreplies, "\t%u ARP repl%s sent\n");
+ p(txannounces, "\t%u ARP announcement%s sent\n");
+ p(rxrequests, "\t%u ARP request%s received\n");
+ p2(rxreplies, "\t%u ARP repl%s received\n");
+ p(received, "\t%u total ARP packet%s received\n");
+ p(txconflicts, "\t%u ARP conflict probe%s sent\n");
+ p(invalidreqs, "\t%u invalid ARP resolve request%s\n");
+ p(reqnobufs, "\t%u total packet%s dropped due to lack of memory\n");
+ p3(held, "\t%u total packet%s held awaiting ARP repl%s\n");
+ p(dropped, "\t%u total packet%s dropped due to no ARP entry\n");
+ p(purged, "\t%u total packet%s dropped during ARP entry removal\n");
+ p2(timeouts, "\t%u ARP entr%s timed out\n");
+ p(dupips, "\t%u Duplicate IP%s seen\n");
+
+ if (interval > 0)
+ bcopy(&arpstat, &parpstat, len);
+
+#undef ARPDIFF
+#undef p
+#undef p2
+}
+
+static char *icmpnames[] = {
+ "echo reply",
+ "#1",
+ "#2",
+ "destination unreachable",
+ "source quench",
+ "routing redirect",
+ "#6",
+ "#7",
+ "echo",
+ "router advertisement",
+ "router solicitation",
+ "time exceeded",
+ "parameter problem",
+ "time stamp",
+ "time stamp reply",
+ "information request",
+ "information request reply",
+ "address mask request",
+ "address mask reply",
+};
+
+/*
+ * Dump ICMP statistics.
+ */
+void
+icmp_stats(uint32_t off , char *name, int af )
+{
+ static struct icmpstat picmpstat;
+ struct icmpstat icmpstat;
+ int i, first;
+ int mib[4]; /* CTL_NET + PF_INET + IPPROTO_ICMP + req */
+ size_t len;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_INET;
+ mib[2] = IPPROTO_ICMP;
+ mib[3] = ICMPCTL_STATS;
+
+ len = sizeof icmpstat;
+ memset(&icmpstat, 0, len);
+ if (sysctl(mib, 4, &icmpstat, &len, (void *)0, 0) < 0)
+ return; /* XXX should complain, but not traditional */
+
+ if (interval && vflag > 0)
+ print_time();
+ printf("%s:\n", name);
+
+#define ICMPDIFF(f) (icmpstat.f - picmpstat.f)
+#define p(f, m) if (ICMPDIFF(f) || sflag <= 1) \
+ printf(m, ICMPDIFF(f), plural(ICMPDIFF(f)))
+#define p1a(f, m) if (ICMPDIFF(f) || sflag <= 1) \
+ printf(m, ICMPDIFF(f))
+
+ p(icps_error, "\t%u call%s to icmp_error\n");
+ p(icps_oldicmp,
+ "\t%u error%s not generated 'cuz old message was icmp\n");
+ for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
+ if (ICMPDIFF(icps_outhist[i]) != 0) {
+ if (first) {
+ printf("\tOutput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %u\n", icmpnames[i],
+ ICMPDIFF(icps_outhist[i]));
+ }
+ p(icps_badcode, "\t%u message%s with bad code fields\n");
+ p(icps_tooshort, "\t%u message%s < minimum length\n");
+ p(icps_checksum, "\t%u bad checksum%s\n");
+ p(icps_badlen, "\t%u message%s with bad length\n");
+ p1a(icps_bmcastecho, "\t%u multicast echo requests ignored\n");
+ p1a(icps_bmcasttstamp, "\t%u multicast timestamp requests ignored\n");
+ for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
+ if (ICMPDIFF(icps_inhist[i]) != 0) {
+ if (first) {
+ printf("\tInput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %u\n", icmpnames[i],
+ ICMPDIFF(icps_inhist[i]));
+ }
+ p(icps_reflect, "\t%u message response%s generated\n");
+
+#undef ICMPDIFF
+#undef p
+#undef p1a
+ mib[3] = ICMPCTL_MASKREPL;
+ len = sizeof i;
+ if (sysctl(mib, 4, &i, &len, (void *)0, 0) < 0)
+ return;
+ printf("\tICMP address mask responses are %sabled\n",
+ i ? "en" : "dis");
+
+ if (interval > 0)
+ bcopy(&icmpstat, &picmpstat, sizeof (icmpstat));
+}
+
+/*
+ * Dump IGMP statistics structure.
+ */
+void
+igmp_stats(uint32_t off , char *name, int af )
+{
+ static struct igmpstat_v3 pigmpstat;
+ struct igmpstat_v3 igmpstat;
+ size_t len = sizeof igmpstat;
+
+ if (sysctlbyname("net.inet.igmp.v3stats", &igmpstat, &len, 0, 0) < 0) {
+ warn("sysctl: net.inet.igmp.v3stats");
+ return;
+ }
+
+ if (igmpstat.igps_version != IGPS_VERSION_3) {
+ warnx("%s: version mismatch (%d != %d)", __func__,
+ igmpstat.igps_version, IGPS_VERSION_3);
+ }
+ if (igmpstat.igps_len != IGPS_VERSION3_LEN) {
+ warnx("%s: size mismatch (%d != %d)", __func__,
+ igmpstat.igps_len, IGPS_VERSION3_LEN);
+ }
+
+ if (interval && vflag > 0)
+ print_time();
+ printf("%s:\n", name);
+
+#define IGMPDIFF(f) ((uintmax_t)(igmpstat.f - pigmpstat.f))
+#define p64(f, m) if (IGMPDIFF(f) || sflag <= 1) \
+ printf(m, IGMPDIFF(f), plural(IGMPDIFF(f)))
+#define py64(f, m) if (IGMPDIFF(f) || sflag <= 1) \
+ printf(m, IGMPDIFF(f), IGMPDIFF(f) != 1 ? "ies" : "y")
+
+ p64(igps_rcv_total, "\t%ju message%s received\n");
+ p64(igps_rcv_tooshort, "\t%ju message%s received with too few bytes\n");
+ p64(igps_rcv_badttl, "\t%ju message%s received with wrong TTL\n");
+ p64(igps_rcv_badsum, "\t%ju message%s received with bad checksum\n");
+ py64(igps_rcv_v1v2_queries, "\t%ju V1/V2 membership quer%s received\n");
+ py64(igps_rcv_v3_queries, "\t%ju V3 membership quer%s received\n");
+ py64(igps_rcv_badqueries,
+ "\t%ju membership quer%s received with invalid field(s)\n");
+ py64(igps_rcv_gen_queries, "\t%ju general quer%s received\n");
+ py64(igps_rcv_group_queries, "\t%ju group quer%s received\n");
+ py64(igps_rcv_gsr_queries, "\t%ju group-source quer%s received\n");
+ py64(igps_drop_gsr_queries, "\t%ju group-source quer%s dropped\n");
+ p64(igps_rcv_reports, "\t%ju membership report%s received\n");
+ p64(igps_rcv_badreports,
+ "\t%ju membership report%s received with invalid field(s)\n");
+ p64(igps_rcv_ourreports,
+"\t%ju membership report%s received for groups to which we belong\n");
+ p64(igps_rcv_nora, "\t%ju V3 report%s received without Router Alert\n");
+ p64(igps_snd_reports, "\t%ju membership report%s sent\n");
+
+ if (interval > 0)
+ bcopy(&igmpstat, &pigmpstat, len);
+
+#undef IGMPDIFF
+#undef p64
+#undef py64
+}
+
+/*
+ * Pretty print an Internet address (net address + port).
+ */
+void
+inetprint(struct in_addr *in, int port, char *proto, int numeric_port)
+{
+ struct servent *sp = 0;
+ char line[80], *cp;
+ int width;
+
+ if (Wflag)
+ snprintf(line, sizeof(line), "%s.", inetname(in));
+ else
+ snprintf(line, sizeof(line), "%.*s.", (Aflag && !numeric_port) ? 12 : 16, inetname(in));
+ cp = index(line, '\0');
+ if (!numeric_port && port)
+#ifdef _SERVICE_CACHE_
+ sp = _serv_cache_getservbyport(port, proto);
+#else
+ sp = getservbyport((int)port, proto);
+#endif
+ if (sp || port == 0)
+ snprintf(cp, sizeof(line) - (cp - line), "%.15s ", sp ? sp->s_name : "*");
+ else
+ snprintf(cp, sizeof(line) - (cp - line), "%d ", ntohs((u_short)port));
+ width = (Aflag && !Wflag) ? 18 : 22;
+ if (Wflag)
+ printf("%-*s ", width, line);
+ else
+ printf("%-*.*s ", width, width, line);
+}
+
+/*
+ * Construct an Internet address representation.
+ * If the nflag has been supplied, give
+ * numeric value, otherwise try for symbolic name.
+ */
+char *
+inetname(struct in_addr *inp)
+{
+ register char *cp;
+ static char line[MAXHOSTNAMELEN];
+ struct hostent *hp;
+ struct netent *np;
+
+ cp = 0;
+ if (!nflag && inp->s_addr != INADDR_ANY) {
+ int net = inet_netof(*inp);
+ int lna = inet_lnaof(*inp);
+
+ if (lna == INADDR_ANY) {
+ np = getnetbyaddr(net, AF_INET);
+ if (np)
+ cp = np->n_name;
+ }
+ if (cp == 0) {
+ hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
+ if (hp) {
+ cp = hp->h_name;
+ //### trimdomain(cp, strlen(cp));
+ }
+ }
+ }
+ if (inp->s_addr == INADDR_ANY)
+ strlcpy(line, "*", sizeof(line));
+ else if (cp) {
+ strlcpy(line, cp, sizeof(line));
+ } else {
+ inp->s_addr = ntohl(inp->s_addr);
+#define C(x) ((u_int)((x) & 0xff))
+ snprintf(line, sizeof(line), "%u.%u.%u.%u", C(inp->s_addr >> 24),
+ C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
+ }
+ return (line);
+}
diff --git a/network_cmds/netstat.tproj/inet6.c b/network_cmds/netstat.tproj/inet6.c
new file mode 100644
index 0000000..4bc757c
--- /dev/null
+++ b/network_cmds/netstat.tproj/inet6.c
@@ -0,0 +1,1333 @@
+/*
+ * Copyright (c) 2008-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/* BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp */
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/netstat/inet6.c,v 1.3.2.9 2001/08/10 09:07:09 ru Exp $
+ */
+
+#ifdef INET6
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+
+#include <net/route.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/net_perf.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#include <netinet/in_systm.h>
+#include <netinet6/in6_pcb.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/ip6_var.h>
+#include <netinet6/raw_ip6.h>
+
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "netstat.h"
+
+#if defined(__APPLE__) && !defined(__unused)
+#define __unused
+#endif
+
+char *inet6name (struct in6_addr *);
+void inet6print (struct in6_addr *, int, char *, int);
+
+static char *ip6nh[] = {
+ "hop by hop",
+ "ICMP",
+ "IGMP",
+ "#3",
+ "IP",
+ "#5",
+ "TCP",
+ "#7",
+ "#8",
+ "#9",
+ "#10",
+ "#11",
+ "#12",
+ "#13",
+ "#14",
+ "#15",
+ "#16",
+ "UDP",
+ "#18",
+ "#19",
+ "#20",
+ "#21",
+ "IDP",
+ "#23",
+ "#24",
+ "#25",
+ "#26",
+ "#27",
+ "#28",
+ "TP",
+ "#30",
+ "#31",
+ "#32",
+ "#33",
+ "#34",
+ "#35",
+ "#36",
+ "#37",
+ "#38",
+ "#39",
+ "#40",
+ "IP6",
+ "#42",
+ "routing",
+ "fragment",
+ "#45",
+ "#46",
+ "#47",
+ "#48",
+ "#49",
+ "ESP",
+ "AH",
+ "#52",
+ "#53",
+ "#54",
+ "#55",
+ "#56",
+ "#57",
+ "ICMP6",
+ "no next header",
+ "destination option",
+ "#61",
+ "mobility",
+ "#63",
+ "#64",
+ "#65",
+ "#66",
+ "#67",
+ "#68",
+ "#69",
+ "#70",
+ "#71",
+ "#72",
+ "#73",
+ "#74",
+ "#75",
+ "#76",
+ "#77",
+ "#78",
+ "#79",
+ "ISOIP",
+ "#81",
+ "#82",
+ "#83",
+ "#84",
+ "#85",
+ "#86",
+ "#87",
+ "#88",
+ "OSPF",
+ "#80",
+ "#91",
+ "#92",
+ "#93",
+ "#94",
+ "#95",
+ "#96",
+ "Ethernet",
+ "#98",
+ "#99",
+ "#100",
+ "#101",
+ "#102",
+ "PIM",
+ "#104",
+ "#105",
+ "#106",
+ "#107",
+ "#108",
+ "#109",
+ "#110",
+ "#111",
+ "#112",
+ "#113",
+ "#114",
+ "#115",
+ "#116",
+ "#117",
+ "#118",
+ "#119",
+ "#120",
+ "#121",
+ "#122",
+ "#123",
+ "#124",
+ "#125",
+ "#126",
+ "#127",
+ "#128",
+ "#129",
+ "#130",
+ "#131",
+ "#132",
+ "#133",
+ "#134",
+ "#135",
+ "#136",
+ "#137",
+ "#138",
+ "#139",
+ "#140",
+ "#141",
+ "#142",
+ "#143",
+ "#144",
+ "#145",
+ "#146",
+ "#147",
+ "#148",
+ "#149",
+ "#150",
+ "#151",
+ "#152",
+ "#153",
+ "#154",
+ "#155",
+ "#156",
+ "#157",
+ "#158",
+ "#159",
+ "#160",
+ "#161",
+ "#162",
+ "#163",
+ "#164",
+ "#165",
+ "#166",
+ "#167",
+ "#168",
+ "#169",
+ "#170",
+ "#171",
+ "#172",
+ "#173",
+ "#174",
+ "#175",
+ "#176",
+ "#177",
+ "#178",
+ "#179",
+ "#180",
+ "#181",
+ "#182",
+ "#183",
+ "#184",
+ "#185",
+ "#186",
+ "#187",
+ "#188",
+ "#189",
+ "#180",
+ "#191",
+ "#192",
+ "#193",
+ "#194",
+ "#195",
+ "#196",
+ "#197",
+ "#198",
+ "#199",
+ "#200",
+ "#201",
+ "#202",
+ "#203",
+ "#204",
+ "#205",
+ "#206",
+ "#207",
+ "#208",
+ "#209",
+ "#210",
+ "#211",
+ "#212",
+ "#213",
+ "#214",
+ "#215",
+ "#216",
+ "#217",
+ "#218",
+ "#219",
+ "#220",
+ "#221",
+ "#222",
+ "#223",
+ "#224",
+ "#225",
+ "#226",
+ "#227",
+ "#228",
+ "#229",
+ "#230",
+ "#231",
+ "#232",
+ "#233",
+ "#234",
+ "#235",
+ "#236",
+ "#237",
+ "#238",
+ "#239",
+ "#240",
+ "#241",
+ "#242",
+ "#243",
+ "#244",
+ "#245",
+ "#246",
+ "#247",
+ "#248",
+ "#249",
+ "#250",
+ "#251",
+ "#252",
+ "#253",
+ "#254",
+ "#255",
+};
+
+
+static const char *srcrulenames[IP6S_SRCRULE_COUNT] = {
+ "default", // IP6S_SRCRULE_0
+ "prefer same address", // IP6S_SRCRULE_1
+ "prefer appropriate scope", // IP6S_SRCRULE_2
+ "avoid deprecated addresses", // IP6S_SRCRULE_3
+ "prefer home addresses", // IP6S_SRCRULE_4
+ "prefer outgoing interface", // IP6S_SRCRULE_5
+ "prefer matching label", // IP6S_SRCRULE_6
+ "prefer temporary addresses", // IP6S_SRCRULE_7
+ "prefer addresses on alive interfaces", // IP6S_SRCRULE_7x
+ "use longest matching prefix", // IP6S_SRCRULE_8
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+/*
+ * Dump IP6 statistics structure.
+ */
+void
+ip6_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct ip6stat pip6stat;
+ struct ip6stat ip6stat;
+ int first, i;
+ int mib[4];
+ size_t len;
+ static net_perf_t pout_net_perf, pin_net_perf;
+ net_perf_t out_net_perf, in_net_perf;
+ size_t out_net_perf_len = sizeof (out_net_perf);
+ size_t in_net_perf_len = sizeof (in_net_perf);
+
+ if (sysctlbyname("net.inet6.ip6.output_perf_data", &out_net_perf, &out_net_perf_len, 0, 0) < 0) {
+ perror("sysctl: net.inet6.ip6.output_perf_data");
+ return;
+ }
+
+ if (sysctlbyname("net.inet6.ip6.input_perf_data", &in_net_perf, &in_net_perf_len, 0, 0) < 0) {
+ perror("sysctl: net.inet6.ip6.input_perf_data");
+ return;
+ }
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_INET6;
+ mib[2] = IPPROTO_IPV6;
+ mib[3] = IPV6CTL_STATS;
+
+ len = sizeof ip6stat;
+ memset(&ip6stat, 0, len);
+ if (sysctl(mib, 4, &ip6stat, &len, (void *)0, 0) < 0)
+ return;
+ if (interval && vflag > 0)
+ print_time();
+ printf("%s:\n", name);
+
+#define IP6DIFF(f) (ip6stat.f - pip6stat.f)
+#define p(f, m) if (IP6DIFF(f) || sflag <= 1) \
+ printf(m, (unsigned long long)IP6DIFF(f), plural(IP6DIFF(f)))
+#define p1a(f, m) if (IP6DIFF(f) || sflag <= 1) \
+ printf(m, (unsigned long long)IP6DIFF(f))
+
+ p(ip6s_total, "\t%llu total packet%s received\n");
+ p1a(ip6s_toosmall, "\t\t%llu with size smaller than minimum\n");
+ p1a(ip6s_tooshort, "\t\t%llu with data size < data length\n");
+ p1a(ip6s_adj, "\t\t%llu with data size > data length\n");
+ p(ip6s_adj_hwcsum_clr,
+ "\t\t\t%llu packet%s forced to software checksum\n");
+ p1a(ip6s_badoptions, "\t\t%llu with bad options\n");
+ p1a(ip6s_badvers, "\t\t%llu with incorrect version number\n");
+ p(ip6s_fragments, "\t\t%llu fragment%s received\n");
+ p1a(ip6s_fragdropped,
+ "\t\t\t%llu dropped (dup or out of space)\n");
+ p1a(ip6s_fragtimeout, "\t\t\t%llu dropped after timeout\n");
+ p1a(ip6s_fragoverflow, "\t\t\t%llu exceeded limit\n");
+ p1a(ip6s_reassembled, "\t\t\t%llu reassembled ok\n");
+ p1a(ip6s_atmfrag_rcvd, "\t\t\t%llu atomic fragments received\n");
+ p(ip6s_delivered, "\t\t%llu packet%s for this host\n");
+ p(ip6s_forward, "\t\t%llu packet%s forwarded\n");
+ p(ip6s_cantforward, "\t\t%llu packet%s not forwardable\n");
+ p(ip6s_redirectsent, "\t\t%llu redirect%s sent\n");
+ p(ip6s_notmember, "\t\t%llu multicast packet%s which we don't join\n");
+ p(ip6s_exthdrtoolong,
+ "\t\t%llu packet%s whose headers are not continuous\n");
+ p(ip6s_nogif, "\t\t%llu tunneling packet%s that can't find gif\n");
+ p(ip6s_toomanyhdr,
+ "\t\t%llu packet%s discarded due to too may headers\n");
+ p1a(ip6s_forward_cachehit, "\t\t%llu forward cache hit\n");
+ p1a(ip6s_forward_cachemiss, "\t\t%llu forward cache miss\n");
+ p(ip6s_pktdropcntrl,
+ "\t\t%llu packet%s dropped due to no bufs for control data\n");
+ /* CLAT46 input stats */
+ p(ip6s_clat464_in_tooshort_drop,
+ "\t\t%llu input packet%s dropped due to too short length \n");
+ p(ip6s_clat464_in_nov6addr_drop,
+ "\t\t%llu input packet%s dropped due to missing CLAT46 IPv6 address\n");
+ p(ip6s_clat464_in_nov4addr_drop,
+ "\t\t%llu input packet%s dropped due to missing CLAT46 IPv4 address\n");
+ p(ip6s_clat464_in_v4synthfail_drop,
+ "\t\t%llu input packet%s dropped due to CLAT46 IPv4 address derivation failure\n");
+ p(ip6s_clat464_in_64transfail_drop,
+ "\t\t%llu input packet%s dropped due to CLAT46 IP header translation failure\n");
+ p(ip6s_clat464_in_64proto_transfail_drop,
+ "\t\t%llu input packet%s dropped due to CLAT46 protocol translation failure\n");
+ p(ip6s_clat464_in_64frag_transfail_drop,
+ "\t\t%llu input packet%s dropped due to CLAT46 fragment translation failure\n");
+ p(ip6s_clat464_in_invalpbuf_drop,
+ "\t\t%llu input packet%s dropped due to invalid pbuf\n");
+ p(ip6s_clat464_in_v4_drop,
+ "\t\t%llu input IPv4 packet%s dropped on CLAT46 enabled interface\n");
+ p(ip6s_clat464_in_drop,
+ "\t\t%llu input packet%s dropped due to CLAT46 failures\n");
+ p(ip6s_clat464_in_success,
+ "\t\t%llu input packet%s successfully translated from IPv6 to IPv4\n");
+
+#define INPERFDIFF(f) (in_net_perf.f - pin_net_perf.f)
+ if (INPERFDIFF(np_total_pkts) > 0 && in_net_perf.np_total_usecs > 0) {
+ printf("\tInput Performance Stats:\n");
+ printf("\t\t%llu total packets measured\n", INPERFDIFF(np_total_pkts));
+ printf("\t\t%llu total usec elapsed\n", INPERFDIFF(np_total_usecs));
+ printf("\t\t%f usec per packet\n",
+ (double)in_net_perf.np_total_usecs/(double)in_net_perf.np_total_pkts);
+ printf("\t\tPerformance Histogram:\n");
+ printf("\t\t\t x <= %u: %llu\n", in_net_perf.np_hist_bars[0],
+ INPERFDIFF(np_hist1));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ in_net_perf.np_hist_bars[0], in_net_perf.np_hist_bars[1],
+ INPERFDIFF(np_hist2));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ in_net_perf.np_hist_bars[1], in_net_perf.np_hist_bars[2],
+ INPERFDIFF(np_hist3));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ in_net_perf.np_hist_bars[2], in_net_perf.np_hist_bars[3],
+ INPERFDIFF(np_hist4));
+ printf("\t\t\t %u < x: %llu\n",
+ in_net_perf.np_hist_bars[3], INPERFDIFF(np_hist5));
+ }
+#undef INPERFDIFF
+
+ p(ip6s_localout, "\t%llu packet%s sent from this host\n");
+ p(ip6s_rawout, "\t\t%llu packet%s sent with fabricated ip header\n");
+ p(ip6s_odropped,
+ "\t\t%llu output packet%s dropped due to no bufs, etc.\n");
+ p(ip6s_noroute, "\t\t%llu output packet%s discarded due to no route\n");
+ p(ip6s_fragmented, "\t\t%llu output datagram%s fragmented\n");
+ p(ip6s_ofragments, "\t\t%llu fragment%s created\n");
+ p(ip6s_cantfrag, "\t\t%llu datagram%s that can't be fragmented\n");
+ p(ip6s_badscope, "\t\t%llu packet%s that violated scope rules\n");
+ p(ip6s_necp_policy_drop, "\t\t%llu packet%s dropped due to NECP policy\n");
+ /* CLAT46 output stats */
+ p(ip6s_clat464_out_nov6addr_drop,
+ "\t\t%llu output packet%s dropped due to missing CLAT46 IPv6 address\n");
+ p(ip6s_clat464_out_v6synthfail_drop,
+ "\t\t%llu output packet%s dropped due to CLAT46 IPv6 address synthesis failure\n");
+ p(ip6s_clat464_out_46transfail_drop,
+ "\t\t%llu output packet%s dropped due to CLAT46 IP header translation failure\n");
+ p(ip6s_clat464_out_46proto_transfail_drop,
+ "\t\t%llu output packet%s dropped due to CLAT46 protocol translation failure\n");
+ p(ip6s_clat464_out_46frag_transfail_drop,
+ "\t\t%llu output packet%s dropped due to CLAT46 fragment translation failure\n");
+ p(ip6s_clat464_out_invalpbuf_drop,
+ "\t\t%llu output packet%s dropped due to invalid pbuf\n");
+ p(ip6s_clat464_out_drop,
+ "\t\t%llu output packet%s dropped due to CLAT46 failures\n");
+ p(ip6s_clat464_out_success,
+ "\t\t%llu output packet%s successfully translated from IPv4 to IPv6\n");
+ p(ip6s_rcv_if_weak_match,
+ "\t\t%llu input packet%s that passed the weak ES interface address match\n");
+ p(ip6s_rcv_if_no_match,
+ "\t\t%llu input packet%s with no interface address match\n");
+
+#define OUTPERFDIFF(f) (out_net_perf.f - pout_net_perf.f)
+ if (OUTPERFDIFF(np_total_pkts) > 0 && out_net_perf.np_total_usecs > 0) {
+ printf("\tOutput Performance Stats:\n");
+ printf("\t\t%llu total packets measured\n", OUTPERFDIFF(np_total_pkts));
+ printf("\t\t%llu total usec elapsed\n", OUTPERFDIFF(np_total_usecs));
+ printf("\t\t%f usec per packet\n",
+ (double)out_net_perf.np_total_usecs/(double)out_net_perf.np_total_pkts);
+ printf("\t\tHistogram:\n");
+ printf("\t\t\t x <= %u: %llu\n", out_net_perf.np_hist_bars[0],
+ OUTPERFDIFF(np_hist1));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ out_net_perf.np_hist_bars[0], out_net_perf.np_hist_bars[1],
+ OUTPERFDIFF(np_hist2));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ out_net_perf.np_hist_bars[1], out_net_perf.np_hist_bars[2],
+ OUTPERFDIFF(np_hist3));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ out_net_perf.np_hist_bars[2], out_net_perf.np_hist_bars[3],
+ OUTPERFDIFF(np_hist4));
+ printf("\t\t\t %u < x: %llu\n",
+ out_net_perf.np_hist_bars[3], OUTPERFDIFF(np_hist5));
+ }
+#undef OUTPERFDIFF
+
+ for (first = 1, i = 0; i < 256; i++)
+ if (IP6DIFF(ip6s_nxthist[i]) != 0) {
+ if (first) {
+ printf("\tInput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %llu\n", ip6nh[i],
+ (unsigned long long)IP6DIFF(ip6s_nxthist[i]));
+ }
+ printf("\tMbuf statistics:\n");
+ printf("\t\t%llu one mbuf\n", (unsigned long long)IP6DIFF(ip6s_m1));
+ for (first = 1, i = 0; i < 32; i++) {
+ char ifbuf[IFNAMSIZ];
+ if (IP6DIFF(ip6s_m2m[i]) != 0) {
+ if (first) {
+ printf("\t\ttwo or more mbuf:\n");
+ first = 0;
+ }
+ printf("\t\t\t%s= %llu\n",
+ if_indextoname(i, ifbuf),
+ (unsigned long long)IP6DIFF(ip6s_m2m[i]));
+ }
+ }
+ printf("\t\t%llu one ext mbuf\n",
+ (unsigned long long)IP6DIFF(ip6s_mext1));
+ printf("\t\t%llu two or more ext mbuf\n",
+ (unsigned long long)IP6DIFF(ip6s_mext2m));
+
+ /* for debugging source address selection */
+#define PRINT_SCOPESTAT(s,i) do {\
+ switch(i) { /* XXX hardcoding in each case */\
+ case 1:\
+ p(s, "\t\t\t%llu node-local%s\n");\
+ break;\
+ case 2:\
+ p(s,"\t\t\t%llu link-local%s\n");\
+ break;\
+ case 5:\
+ p(s,"\t\t\t%llu site-local%s\n");\
+ break;\
+ case 14:\
+ p(s,"\t\t\t%llu global%s\n");\
+ break;\
+ default:\
+ printf("\t\t\t%llu addresses scope=%x\n",\
+ (unsigned long long)IP6DIFF(s), i);\
+ }\
+ } while (0);
+
+ p(ip6s_sources_none,
+ "\t\t%llu failure%s of source address selection\n");
+ for (first = 1, i = 0; i < SCOPE6_ID_MAX; i++) {
+ if (IP6DIFF(ip6s_sources_sameif[i]) || 1) {
+ if (first) {
+ printf("\t\tsource addresses on an outgoing I/F\n");
+ first = 0;
+ }
+ PRINT_SCOPESTAT(ip6s_sources_sameif[i], i);
+ }
+ }
+ for (first = 1, i = 0; i < SCOPE6_ID_MAX; i++) {
+ if (IP6DIFF(ip6s_sources_otherif[i]) || 1) {
+ if (first) {
+ printf("\t\tsource addresses on a non-outgoing I/F\n");
+ first = 0;
+ }
+ PRINT_SCOPESTAT(ip6s_sources_otherif[i], i);
+ }
+ }
+ for (first = 1, i = 0; i < SCOPE6_ID_MAX; i++) {
+ if (IP6DIFF(ip6s_sources_samescope[i]) || 1) {
+ if (first) {
+ printf("\t\tsource addresses of same scope\n");
+ first = 0;
+ }
+ PRINT_SCOPESTAT(ip6s_sources_samescope[i], i);
+ }
+ }
+ for (first = 1, i = 0; i < SCOPE6_ID_MAX; i++) {
+ if (IP6DIFF(ip6s_sources_otherscope[i]) || 1) {
+ if (first) {
+ printf("\t\tsource addresses of a different scope\n");
+ first = 0;
+ }
+ PRINT_SCOPESTAT(ip6s_sources_otherscope[i], i);
+ }
+ }
+ for (first = 1, i = 0; i < SCOPE6_ID_MAX; i++) {
+ if (IP6DIFF(ip6s_sources_deprecated[i]) || 1) {
+ if (first) {
+ printf("\t\tdeprecated source addresses\n");
+ first = 0;
+ }
+ PRINT_SCOPESTAT(ip6s_sources_deprecated[i], i);
+ }
+ }
+#define PRINT_SRCRULESTAT(s,i) do {\
+ if (srcrulenames[i] != NULL) \
+ printf("\t\t\t%llu rule%s %s\n", \
+ (unsigned long long)IP6DIFF(s), \
+ plural(IP6DIFF(s)), \
+ srcrulenames[i]); \
+} while (0);
+
+ for (first = 1, i = 0; i < IP6S_SRCRULE_COUNT; i++) {
+ if (IP6DIFF(ip6s_sources_rule[i]) || 1) {
+ if (first) {
+ printf("\t\tsource address selection\n");
+ first = 0;
+ }
+ PRINT_SRCRULESTAT(ip6s_sources_rule[i], i);
+ }
+ }
+
+ p(ip6s_dad_collide, "\t\t%llu duplicate address detection collision%s\n");
+
+ p(ip6s_dad_loopcount, "\t\t%llu duplicate address detection NS loop%s\n");
+
+ p(ip6s_sources_skip_expensive_secondary_if, "\t\t%llu time%s ignored source on secondary expensive I/F\n");
+
+ if (interval > 0) {
+ bcopy(&ip6stat, &pip6stat, len);
+ bcopy(&in_net_perf, &pin_net_perf, in_net_perf_len);
+ bcopy(&out_net_perf, &pout_net_perf, out_net_perf_len);
+ }
+#undef IP6DIFF
+#undef p
+#undef p1a
+}
+
+/*
+ * Dump IPv6 per-interface statistics based on RFC 2465.
+ */
+void
+ip6_ifstats(char *ifname)
+{
+ struct in6_ifreq ifr;
+ int s;
+#define p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
+ printf(m, (unsigned long long)ifr.ifr_ifru.ifru_stat.f, plural(ifr.ifr_ifru.ifru_stat.f))
+#define p_5(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
+ printf(m, (unsigned long long)ip6stat.f)
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror("Warning: socket(AF_INET6)");
+ return;
+ }
+
+ if (interval && vflag > 0)
+ print_time();
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ printf("ip6 on %s:\n", ifr.ifr_name);
+
+ if (ioctl(s, SIOCGIFSTAT_IN6, (char *)&ifr) < 0) {
+ perror("Warning: ioctl(SIOCGIFSTAT_IN6)");
+ goto end;
+ }
+
+ p(ifs6_in_receive, "\t%llu total input datagram%s\n");
+ p(ifs6_in_hdrerr, "\t%llu datagram%s with invalid header received\n");
+ p(ifs6_in_toobig, "\t%llu datagram%s exceeded MTU received\n");
+ p(ifs6_in_noroute, "\t%llu datagram%s with no route received\n");
+ p(ifs6_in_addrerr, "\t%llu datagram%s with invalid dst received\n");
+ p(ifs6_in_protounknown, "\t%llu datagram%s with unknown proto received\n");
+ p(ifs6_in_truncated, "\t%llu truncated datagram%s received\n");
+ p(ifs6_in_discard, "\t%llu input datagram%s discarded\n");
+ p(ifs6_in_deliver,
+ "\t%llu datagram%s delivered to an upper layer protocol\n");
+ p(ifs6_out_forward, "\t%llu datagram%s forwarded to this interface\n");
+ p(ifs6_out_request,
+ "\t%llu datagram%s sent from an upper layer protocol\n");
+ p(ifs6_out_discard, "\t%llu total discarded output datagram%s\n");
+ p(ifs6_out_fragok, "\t%llu output datagram%s fragmented\n");
+ p(ifs6_out_fragfail, "\t%llu output datagram%s failed on fragment\n");
+ p(ifs6_out_fragcreat, "\t%llu output datagram%s succeeded on fragment\n");
+ p(ifs6_reass_reqd, "\t%llu incoming datagram%s fragmented\n");
+ p(ifs6_reass_ok, "\t%llu datagram%s reassembled\n");
+ p(ifs6_atmfrag_rcvd, "\t%llu atomic fragments%s received\n");
+ p(ifs6_reass_fail, "\t%llu datagram%s failed on reassembling\n");
+ p(ifs6_in_mcast, "\t%llu multicast datagram%s received\n");
+ p(ifs6_out_mcast, "\t%llu multicast datagram%s sent\n");
+
+ p(ifs6_cantfoward_icmp6, "\t%llu ICMPv6 packet%s received for unreachable destination\n");
+ p(ifs6_addr_expiry_cnt, "\t%llu address expiry event%s reported\n");
+ p(ifs6_pfx_expiry_cnt, "\t%llu prefix expiry event%s reported\n");
+ p(ifs6_defrtr_expiry_cnt, "\t%llu default router expiry event%s reported\n");
+ end:
+ close(s);
+
+#undef p
+#undef p_5
+}
+
+static char *icmp6names[] = {
+ "#0",
+ "unreach",
+ "packet too big",
+ "time exceed",
+ "parameter problem",
+ "#5",
+ "#6",
+ "#7",
+ "#8",
+ "#9",
+ "#10",
+ "#11",
+ "#12",
+ "#13",
+ "#14",
+ "#15",
+ "#16",
+ "#17",
+ "#18",
+ "#19",
+ "#20",
+ "#21",
+ "#22",
+ "#23",
+ "#24",
+ "#25",
+ "#26",
+ "#27",
+ "#28",
+ "#29",
+ "#30",
+ "#31",
+ "#32",
+ "#33",
+ "#34",
+ "#35",
+ "#36",
+ "#37",
+ "#38",
+ "#39",
+ "#40",
+ "#41",
+ "#42",
+ "#43",
+ "#44",
+ "#45",
+ "#46",
+ "#47",
+ "#48",
+ "#49",
+ "#50",
+ "#51",
+ "#52",
+ "#53",
+ "#54",
+ "#55",
+ "#56",
+ "#57",
+ "#58",
+ "#59",
+ "#60",
+ "#61",
+ "#62",
+ "#63",
+ "#64",
+ "#65",
+ "#66",
+ "#67",
+ "#68",
+ "#69",
+ "#70",
+ "#71",
+ "#72",
+ "#73",
+ "#74",
+ "#75",
+ "#76",
+ "#77",
+ "#78",
+ "#79",
+ "#80",
+ "#81",
+ "#82",
+ "#83",
+ "#84",
+ "#85",
+ "#86",
+ "#87",
+ "#88",
+ "#89",
+ "#80",
+ "#91",
+ "#92",
+ "#93",
+ "#94",
+ "#95",
+ "#96",
+ "#97",
+ "#98",
+ "#99",
+ "#100",
+ "#101",
+ "#102",
+ "#103",
+ "#104",
+ "#105",
+ "#106",
+ "#107",
+ "#108",
+ "#109",
+ "#110",
+ "#111",
+ "#112",
+ "#113",
+ "#114",
+ "#115",
+ "#116",
+ "#117",
+ "#118",
+ "#119",
+ "#120",
+ "#121",
+ "#122",
+ "#123",
+ "#124",
+ "#125",
+ "#126",
+ "#127",
+ "echo",
+ "echo reply",
+ "multicast listener query",
+ "MLDv1 listener report",
+ "MLDv1 listener done",
+ "router solicitation",
+ "router advertisement",
+ "neighbor solicitation",
+ "neighbor advertisement",
+ "redirect",
+ "router renumbering",
+ "node information request",
+ "node information reply",
+ "inverse neighbor solicitation",
+ "inverse neighbor advertisement",
+ "MLDv2 listener report",
+ "#144",
+ "#145",
+ "#146",
+ "#147",
+ "#148",
+ "#149",
+ "#150",
+ "#151",
+ "#152",
+ "#153",
+ "#154",
+ "#155",
+ "#156",
+ "#157",
+ "#158",
+ "#159",
+ "#160",
+ "#161",
+ "#162",
+ "#163",
+ "#164",
+ "#165",
+ "#166",
+ "#167",
+ "#168",
+ "#169",
+ "#170",
+ "#171",
+ "#172",
+ "#173",
+ "#174",
+ "#175",
+ "#176",
+ "#177",
+ "#178",
+ "#179",
+ "#180",
+ "#181",
+ "#182",
+ "#183",
+ "#184",
+ "#185",
+ "#186",
+ "#187",
+ "#188",
+ "#189",
+ "#180",
+ "#191",
+ "#192",
+ "#193",
+ "#194",
+ "#195",
+ "#196",
+ "#197",
+ "#198",
+ "#199",
+ "#200",
+ "#201",
+ "#202",
+ "#203",
+ "#204",
+ "#205",
+ "#206",
+ "#207",
+ "#208",
+ "#209",
+ "#210",
+ "#211",
+ "#212",
+ "#213",
+ "#214",
+ "#215",
+ "#216",
+ "#217",
+ "#218",
+ "#219",
+ "#220",
+ "#221",
+ "#222",
+ "#223",
+ "#224",
+ "#225",
+ "#226",
+ "#227",
+ "#228",
+ "#229",
+ "#230",
+ "#231",
+ "#232",
+ "#233",
+ "#234",
+ "#235",
+ "#236",
+ "#237",
+ "#238",
+ "#239",
+ "#240",
+ "#241",
+ "#242",
+ "#243",
+ "#244",
+ "#245",
+ "#246",
+ "#247",
+ "#248",
+ "#249",
+ "#250",
+ "#251",
+ "#252",
+ "#253",
+ "#254",
+ "#255",
+};
+
+/*
+ * Dump ICMP6 statistics.
+ */
+void
+icmp6_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct icmp6stat picmp6stat;
+ struct icmp6stat icmp6stat;
+ register int i, first;
+ int mib[4];
+ size_t len;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_INET6;
+ mib[2] = IPPROTO_ICMPV6;
+ mib[3] = ICMPV6CTL_STATS;
+
+ len = sizeof icmp6stat;
+ memset(&icmp6stat, 0, len);
+ if (sysctl(mib, 4, &icmp6stat, &len, (void *)0, 0) < 0)
+ return;
+ if (interval && vflag > 0)
+ print_time();
+ printf("%s:\n", name);
+
+#define ICMP6DIFF(f) (icmp6stat.f - picmp6stat.f)
+#define p(f, m) if (ICMP6DIFF(f) || sflag <= 1) \
+ printf(m, (unsigned long long)ICMP6DIFF(f), plural(ICMP6DIFF(f)))
+#define p_5(f, m) printf(m, (unsigned long long)ICMP6DIFF(f))
+
+ p(icp6s_error, "\t%llu call%s to icmp_error\n");
+ p(icp6s_canterror,
+ "\t%llu error%s not generated because old message was icmp error or so\n");
+ p(icp6s_toofreq,
+ "\t%llu error%s not generated because rate limitation\n");
+#define NELEM (sizeof(icmp6stat.icp6s_outhist)/sizeof(icmp6stat.icp6s_outhist[0]))
+ for (first = 1, i = 0; i < NELEM; i++)
+ if (ICMP6DIFF(icp6s_outhist[i]) != 0) {
+ if (first) {
+ printf("\tOutput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %llu\n", icmp6names[i],
+ (unsigned long long)ICMP6DIFF(icp6s_outhist[i]));
+ }
+#undef NELEM
+ p(icp6s_badcode, "\t%llu message%s with bad code fields\n");
+ p(icp6s_tooshort, "\t%llu message%s < minimum length\n");
+ p(icp6s_checksum, "\t%llu bad checksum%s\n");
+ p(icp6s_badlen, "\t%llu message%s with bad length\n");
+#define NELEM (sizeof(icmp6stat.icp6s_inhist)/sizeof(icmp6stat.icp6s_inhist[0]))
+ for (first = 1, i = 0; i < NELEM; i++)
+ if (ICMP6DIFF(icp6s_inhist[i]) != 0) {
+ if (first) {
+ printf("\tInput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %llu\n", icmp6names[i],
+ (unsigned long long)ICMP6DIFF(icp6s_inhist[i]));
+ }
+#undef NELEM
+ printf("\tHistogram of error messages to be generated:\n");
+ p_5(icp6s_odst_unreach_noroute, "\t\t%llu no route\n");
+ p_5(icp6s_odst_unreach_admin, "\t\t%llu administratively prohibited\n");
+ p_5(icp6s_odst_unreach_beyondscope, "\t\t%llu beyond scope\n");
+ p_5(icp6s_odst_unreach_addr, "\t\t%llu address unreachable\n");
+ p_5(icp6s_odst_unreach_noport, "\t\t%llu port unreachable\n");
+ p_5(icp6s_opacket_too_big, "\t\t%llu packet too big\n");
+ p_5(icp6s_otime_exceed_transit, "\t\t%llu time exceed transit\n");
+ p_5(icp6s_otime_exceed_reassembly, "\t\t%llu time exceed reassembly\n");
+ p_5(icp6s_oparamprob_header, "\t\t%llu erroneous header field\n");
+ p_5(icp6s_oparamprob_nextheader, "\t\t%llu unrecognized next header\n");
+ p_5(icp6s_oparamprob_option, "\t\t%llu unrecognized option\n");
+ p_5(icp6s_oredirect, "\t\t%llu redirect\n");
+ p_5(icp6s_ounknown, "\t\t%llu unknown\n");
+
+ p(icp6s_reflect, "\t%llu message response%s generated\n");
+ p(icp6s_nd_toomanyopt, "\t%llu message%s with too many ND options\n");
+ p(icp6s_nd_badopt, "\t%qu message%s with bad ND options\n");
+ p(icp6s_badns, "\t%qu bad neighbor solicitation message%s\n");
+ p(icp6s_badna, "\t%qu bad neighbor advertisement message%s\n");
+ p(icp6s_badrs, "\t%qu bad router solicitation message%s\n");
+ p(icp6s_badra, "\t%qu bad router advertisement message%s\n");
+ p(icp6s_badredirect, "\t%qu bad redirect message%s\n");
+ p(icp6s_pmtuchg, "\t%llu path MTU change%s\n");
+ p(icp6s_rfc6980_drop, "\t%qu dropped fragmented NDP message%s\n");
+
+ if (interval > 0)
+ bcopy(&icmp6stat, &picmp6stat, len);
+
+#undef ICMP6DIFF
+#undef p
+#undef p_5
+}
+
+/*
+ * Dump ICMPv6 per-interface statistics based on RFC 2466.
+ */
+void
+icmp6_ifstats(char *ifname)
+{
+ struct in6_ifreq ifr;
+ int s;
+#define p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \
+ printf(m, (unsigned long long)ifr.ifr_ifru.ifru_icmp6stat.f, plural(ifr.ifr_ifru.ifru_icmp6stat.f))
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror("Warning: socket(AF_INET6)");
+ return;
+ }
+
+ if (interval && vflag > 0)
+ print_time();
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ printf("icmp6 on %s:\n", ifr.ifr_name);
+
+ if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) {
+ perror("Warning: ioctl(SIOCGIFSTAT_ICMP6)");
+ goto end;
+ }
+
+ p(ifs6_in_msg, "\t%llu total input message%s\n");
+ p(ifs6_in_error, "\t%llu total input error message%s\n");
+ p(ifs6_in_dstunreach, "\t%llu input destination unreachable error%s\n");
+ p(ifs6_in_adminprohib, "\t%llu input administratively prohibited error%s\n");
+ p(ifs6_in_timeexceed, "\t%llu input time exceeded error%s\n");
+ p(ifs6_in_paramprob, "\t%llu input parameter problem error%s\n");
+ p(ifs6_in_pkttoobig, "\t%llu input packet too big error%s\n");
+ p(ifs6_in_echo, "\t%llu input echo request%s\n");
+ p(ifs6_in_echoreply, "\t%llu input echo reply%s\n");
+ p(ifs6_in_routersolicit, "\t%llu input router solicitation%s\n");
+ p(ifs6_in_routeradvert, "\t%llu input router advertisement%s\n");
+ p(ifs6_in_neighborsolicit, "\t%llu input neighbor solicitation%s\n");
+ p(ifs6_in_neighboradvert, "\t%llu input neighbor advertisement%s\n");
+ p(ifs6_in_redirect, "\t%llu input redirect%s\n");
+ p(ifs6_in_mldquery, "\t%llu input MLD query%s\n");
+ p(ifs6_in_mldreport, "\t%llu input MLD report%s\n");
+ p(ifs6_in_mlddone, "\t%llu input MLD done%s\n");
+
+ p(ifs6_out_msg, "\t%llu total output message%s\n");
+ p(ifs6_out_error, "\t%llu total output error message%s\n");
+ p(ifs6_out_dstunreach, "\t%llu output destination unreachable error%s\n");
+ p(ifs6_out_adminprohib, "\t%llu output administratively prohibited error%s\n");
+ p(ifs6_out_timeexceed, "\t%llu output time exceeded error%s\n");
+ p(ifs6_out_paramprob, "\t%llu output parameter problem error%s\n");
+ p(ifs6_out_pkttoobig, "\t%llu output packet too big error%s\n");
+ p(ifs6_out_echo, "\t%llu output echo request%s\n");
+ p(ifs6_out_echoreply, "\t%llu output echo reply%s\n");
+ p(ifs6_out_routersolicit, "\t%llu output router solicitation%s\n");
+ p(ifs6_out_routeradvert, "\t%llu output router advertisement%s\n");
+ p(ifs6_out_neighborsolicit, "\t%llu output neighbor solicitation%s\n");
+ p(ifs6_out_neighboradvert, "\t%llu output neighbor advertisement%s\n");
+ p(ifs6_out_redirect, "\t%llu output redirect%s\n");
+ p(ifs6_out_mldquery, "\t%llu output MLD query%s\n");
+ p(ifs6_out_mldreport, "\t%llu output MLD report%s\n");
+ p(ifs6_out_mlddone, "\t%llu output MLD done%s\n");
+
+ end:
+ close(s);
+#undef p
+}
+
+/*
+ * Dump raw ip6 statistics structure.
+ */
+void
+rip6_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct rip6stat prip6stat;
+ struct rip6stat rip6stat;
+ u_quad_t delivered;
+ int mib[4];
+ size_t l;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_INET6;
+ mib[2] = IPPROTO_IPV6;
+ mib[3] = IPV6CTL_RIP6STATS;
+ l = sizeof(rip6stat);
+ if (sysctl(mib, 4, &rip6stat, &l, NULL, 0) < 0) {
+ perror("Warning: sysctl(net.inet6.ip6.rip6stats)");
+ return;
+ }
+
+ if (interval && vflag > 0)
+ print_time();
+ printf("%s:\n", name);
+
+#define RIP6DIFF(f) (rip6stat.f - prip6stat.f)
+#define p(f, m) if (RIP6DIFF(f) || sflag <= 1) \
+ printf(m, (unsigned long long)RIP6DIFF(f), plural(RIP6DIFF(f)))
+ p(rip6s_ipackets, "\t%llu message%s received\n");
+ p(rip6s_isum, "\t%llu checksum calculation%s on inbound\n");
+ p(rip6s_badsum, "\t%llu message%s with bad checksum\n");
+ p(rip6s_nosock, "\t%llu message%s dropped due to no socket\n");
+ p(rip6s_nosockmcast,
+ "\t%llu multicast message%s dropped due to no socket\n");
+ p(rip6s_fullsock,
+ "\t%llu message%s dropped due to full socket buffers\n");
+ delivered = RIP6DIFF(rip6s_ipackets) -
+ RIP6DIFF(rip6s_badsum) -
+ RIP6DIFF(rip6s_nosock) -
+ RIP6DIFF(rip6s_nosockmcast) -
+ RIP6DIFF(rip6s_fullsock);
+ if (delivered || sflag <= 1)
+ printf("\t%llu delivered\n", (unsigned long long)delivered);
+ p(rip6s_opackets, "\t%llu datagram%s output\n");
+
+ if (interval > 0)
+ bcopy(&rip6stat, &prip6stat, l);
+
+#undef RIP6DIFF
+#undef p
+}
+
+/*
+ * Pretty print an Internet address (net address + port).
+ * If the nflag was specified, use numbers instead of names.
+ */
+#ifdef SRVCACHE
+extern struct servent * _serv_cache_getservbyport(int port, char *proto);
+
+#define GETSERVBYPORT6(port, proto, ret)\
+{\
+ if (strcmp((proto), "tcp6") == 0)\
+ (ret) = _serv_cache_getservbyport((int)(port), "tcp");\
+ else if (strcmp((proto), "udp6") == 0)\
+ (ret) = _serv_cache_getservbyport((int)(port), "udp");\
+ else\
+ (ret) = _serv_cache_getservbyport((int)(port), (proto));\
+};
+#else
+#define GETSERVBYPORT6(port, proto, ret)\
+{\
+ if (strcmp((proto), "tcp6") == 0)\
+ (ret) = getservbyport((int)(port), "tcp");\
+ else if (strcmp((proto), "udp6") == 0)\
+ (ret) = getservbyport((int)(port), "udp");\
+ else\
+ (ret) = getservbyport((int)(port), (proto));\
+};
+#endif
+void
+inet6print(struct in6_addr *in6, int port, char *proto, int numeric)
+{
+ struct servent *sp = 0;
+ char line[80], *cp;
+ int width;
+
+ snprintf(line, sizeof(line), "%.*s.", lflag ? 39 :
+ (Aflag && !numeric) ? 12 : 16, inet6name(in6));
+ cp = index(line, '\0');
+ if (!numeric && port)
+ GETSERVBYPORT6(port, proto, sp);
+ if (sp || port == 0)
+ snprintf(cp, sizeof(line) - (cp - line), "%.15s", sp ? sp->s_name : "*");
+ else
+ snprintf(cp, sizeof(line) - (cp - line), "%d", ntohs((u_short)port));
+ width = lflag ? 45 : Aflag ? 18 : 22;
+ printf("%-*.*s ", width, width, line);
+}
+
+/*
+ * Construct an Internet address representation.
+ * If the nflag has been supplied, give
+ * numeric value, otherwise try for symbolic name.
+ */
+
+char *
+inet6name(struct in6_addr *in6p)
+{
+ register char *cp;
+ static char line[50];
+ struct hostent *hp;
+ static char domain[MAXHOSTNAMELEN];
+ static int first = 1;
+ char hbuf[NI_MAXHOST];
+ struct sockaddr_in6 sin6;
+ const int niflag = NI_NUMERICHOST;
+
+ if (first && !nflag) {
+ first = 0;
+ if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
+ (cp = index(domain, '.')))
+ (void) memmove(domain, cp + 1, strlen(cp + 1) + 1);
+ else
+ domain[0] = 0;
+ }
+ cp = 0;
+ if (!nflag && !IN6_IS_ADDR_UNSPECIFIED(in6p)) {
+ hp = gethostbyaddr((char *)in6p, sizeof(*in6p), AF_INET6);
+ if (hp) {
+ if ((cp = index(hp->h_name, '.')) &&
+ !strcmp(cp + 1, domain))
+ *cp = 0;
+ cp = hp->h_name;
+ }
+ }
+ if (IN6_IS_ADDR_UNSPECIFIED(in6p))
+ strlcpy(line, "*", sizeof(line));
+ else if (cp)
+ strlcpy(line, cp, sizeof(line));
+ else {
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_len = sizeof(sin6);
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr = *in6p;
+
+ if (IN6_IS_ADDR_LINKLOCAL(in6p) ||
+ IN6_IS_ADDR_MC_NODELOCAL(in6p) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(in6p)) {
+ sin6.sin6_scope_id =
+ ntohs(*(u_int16_t *)&in6p->s6_addr[2]);
+ sin6.sin6_addr.s6_addr[2] = 0;
+ sin6.sin6_addr.s6_addr[3] = 0;
+ }
+
+ if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
+ hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
+ strlcpy(hbuf, "?", sizeof(hbuf));
+ strlcpy(line, hbuf, sizeof(line));
+ }
+ return (line);
+}
+#endif /*INET6*/
diff --git a/network_cmds/netstat.tproj/ipsec.c b/network_cmds/netstat.tproj/ipsec.c
new file mode 100644
index 0000000..0eab162
--- /dev/null
+++ b/network_cmds/netstat.tproj/ipsec.c
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2008-2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/* $FreeBSD: src/usr.bin/netstat/ipsec.c,v 1.1.2.3 2001/08/10 09:07:09 ru Exp $ */
+/* $NetBSD: inet.c,v 1.35.2.1 1999/04/29 14:57:08 perry Exp $ */
+/* $KAME: ipsec.c,v 1.25 2001/03/12 09:04:39 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <netinet/in.h>
+
+#ifdef IPSEC
+#include <netinet6/ipsec.h>
+#include <netkey/keysock.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "netstat.h"
+
+#if defined(__APPLE__) && !defined(__unused)
+#define __unused
+#endif
+/*
+ * portability issues:
+ * - bsdi[34] uses PLURAL(), not plural().
+ * - freebsd2 can't print "unsigned long long" properly.
+ */
+/*
+ * XXX see PORTABILITY for the twist
+ */
+#define LLU "%llu"
+#define CAST unsigned long long
+
+#ifdef IPSEC
+struct val2str {
+ int val;
+ const char *str;
+};
+
+static struct val2str ipsec_ahnames[] = {
+ { SADB_AALG_NONE, "none", },
+ { SADB_AALG_MD5HMAC, "hmac-md5", },
+ { SADB_AALG_SHA1HMAC, "hmac-sha1", },
+ { SADB_X_AALG_MD5, "md5", },
+ { SADB_X_AALG_SHA, "sha", },
+ { SADB_X_AALG_NULL, "null", },
+#ifdef SADB_X_AALG_SHA2_256
+ { SADB_X_AALG_SHA2_256, "hmac-sha2-256", },
+#endif
+#ifdef SADB_X_AALG_SHA2_384
+ { SADB_X_AALG_SHA2_384, "hmac-sha2-384", },
+#endif
+#ifdef SADB_X_AALG_SHA2_512
+ { SADB_X_AALG_SHA2_512, "hmac-sha2-512", },
+#endif
+ { -1, NULL },
+};
+
+static struct val2str ipsec_espnames[] = {
+ { SADB_EALG_NONE, "none", },
+ { SADB_EALG_DESCBC, "des-cbc", },
+ { SADB_EALG_3DESCBC, "3des-cbc", },
+ { SADB_EALG_NULL, "null", },
+#ifdef SADB_X_EALG_RC5CBC
+ { SADB_X_EALG_RC5CBC, "rc5-cbc", },
+#endif
+ { SADB_X_EALG_CAST128CBC, "cast128-cbc", },
+ { SADB_X_EALG_BLOWFISHCBC, "blowfish-cbc", },
+#ifdef SADB_X_EALG_RIJNDAELCBC
+ { SADB_X_EALG_RIJNDAELCBC, "rijndael-cbc", },
+#endif
+ { -1, NULL },
+};
+
+static struct val2str ipsec_compnames[] = {
+ { SADB_X_CALG_NONE, "none", },
+ { SADB_X_CALG_OUI, "oui", },
+ { SADB_X_CALG_DEFLATE, "deflate", },
+ { SADB_X_CALG_LZS, "lzs", },
+ { -1, NULL },
+};
+
+static const char *pfkey_msgtypenames[] = {
+ "reserved", "getspi", "update", "add", "delete",
+ "get", "acquire", "register", "expire", "flush",
+ "dump", "x_promisc", "x_pchange", "x_spdupdate", "x_spdadd",
+ "x_spddelete", "x_spdget", "x_spdacquire", "x_spddump", "x_spdflush",
+ "x_spdsetidx", "x_spdexpire", "x_spddelete2"
+};
+
+static struct ipsecstat pipsecstat;
+static struct ipsecstat ipsecstat;
+
+static void print_ipsecstats (void);
+static const char *pfkey_msgtype_names (int);
+static void ipsec_hist (const u_quad_t *, const u_quad_t *, size_t,
+ const struct val2str *, const char *);
+
+/*
+ * Dump IPSEC statistics structure.
+ */
+static void
+ipsec_hist(const u_quad_t *hist,
+ const u_quad_t *phist,
+ size_t histmax,
+ const struct val2str *name,
+ const char *title)
+{
+ int first;
+ size_t proto;
+ const struct val2str *p;
+
+ first = 1;
+ for (proto = 0; proto < histmax; proto++) {
+ if ((hist[proto] - phist[proto]) <= 0)
+ continue;
+ if (first) {
+ printf("\t%s histogram:\n", title);
+ first = 0;
+ }
+ for (p = name; p && p->str; p++) {
+ if (p->val == (int)proto)
+ break;
+ }
+ if (p && p->str) {
+ printf("\t\t%s: " LLU "\n", p->str,
+ (CAST)hist[proto] - (CAST)phist[proto]);
+ } else {
+ printf("\t\t#%ld: " LLU "\n", (long)proto,
+ (CAST)hist[proto] - (CAST)phist[proto]);
+ }
+ }
+}
+
+static void
+print_ipsecstats(void)
+{
+#define IPSECDIFF(f) (ipsecstat.f - pipsecstat.f)
+#define p(f, m) if (IPSECDIFF(f) || sflag <= 1) \
+ printf(m, (CAST)IPSECDIFF(f), plural(IPSECDIFF(f)))
+#define hist(f, n, t) \
+ ipsec_hist(ipsecstat.f, pipsecstat.f, \
+ sizeof(ipsecstat.f)/sizeof(ipsecstat.f[0]), (n), (t));
+
+ if (interval && vflag > 0)
+ print_time();
+
+ p(in_success, "\t" LLU " inbound packet%s processed successfully\n");
+ p(in_polvio, "\t" LLU " inbound packet%s violated process security "
+ "policy\n");
+ p(in_nosa, "\t" LLU " inbound packet%s with no SA available\n");
+ p(in_inval, "\t" LLU " invalid inbound packet%s\n");
+ p(in_nomem, "\t" LLU " inbound packet%s failed due to insufficient memory\n");
+ p(in_badspi, "\t" LLU " inbound packet%s failed getting SPI\n");
+ p(in_ahreplay, "\t" LLU " inbound packet%s failed on AH replay check\n");
+ p(in_espreplay, "\t" LLU " inbound packet%s failed on ESP replay check\n");
+ p(in_ahauthsucc, "\t" LLU " inbound packet%s considered authentic\n");
+ p(in_ahauthfail, "\t" LLU " inbound packet%s failed on authentication\n");
+ hist(in_ahhist, ipsec_ahnames, "AH input");
+ hist(in_esphist, ipsec_espnames, "ESP input");
+ hist(in_comphist, ipsec_compnames, "IPComp input");
+
+ p(out_success, "\t" LLU " outbound packet%s processed successfully\n");
+ p(out_polvio, "\t" LLU " outbound packet%s violated process security "
+ "policy\n");
+ p(out_nosa, "\t" LLU " outbound packet%s with no SA available\n");
+ p(out_inval, "\t" LLU " invalid outbound packet%s\n");
+ p(out_nomem, "\t" LLU " outbound packet%s failed due to insufficient memory\n");
+ p(out_noroute, "\t" LLU " outbound packet%s with no route\n");
+ hist(out_ahhist, ipsec_ahnames, "AH output");
+ hist(out_esphist, ipsec_espnames, "ESP output");
+ hist(out_comphist, ipsec_compnames, "IPComp output");
+#undef IPSECDIFF
+#undef p
+#undef hist
+}
+
+void
+ipsec_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ size_t len;
+
+ len = sizeof(struct ipsecstat);
+ if (strcmp(name, "ipsec") == 0) {
+ if (sysctlbyname("net.inet.ipsec.stats", &ipsecstat, &len, 0, 0) == -1)
+ return;
+ } else if (strcmp(name, "ipsec6") == 0) {
+ if (sysctlbyname("net.inet6.ipsec6.stats", &ipsecstat, &len, 0, 0) == -1)
+ return;
+ } else
+ return;
+ printf ("%s:\n", name);
+
+ print_ipsecstats();
+
+ if (interval > 0)
+ bcopy(&ipsecstat, &pipsecstat, len);
+}
+
+static const char *
+pfkey_msgtype_names(int x)
+{
+ const int max =
+ sizeof(pfkey_msgtypenames)/sizeof(pfkey_msgtypenames[0]);
+ static char buf[10];
+
+ if (x < max && pfkey_msgtypenames[x])
+ return pfkey_msgtypenames[x];
+ snprintf(buf, sizeof(buf), "#%d", x);
+ return buf;
+}
+
+void
+pfkey_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct pfkeystat ppfkeystat;
+ struct pfkeystat pfkeystat;
+ unsigned first, type;
+ size_t len;
+
+ len = sizeof(struct pfkeystat);
+ if (sysctlbyname("net.key.pfkeystat", &pfkeystat, &len, 0, 0) == -1)
+ return;
+ if (interval && vflag > 0)
+ print_time();
+ printf ("%s:\n", name);
+
+#define PFKEYDIFF(f) (pfkeystat.f - ppfkeystat.f)
+#define p(f, m) if (PFKEYDIFF(f) || sflag <= 1) \
+ printf(m, (CAST)PFKEYDIFF(f), plural(PFKEYDIFF(f)))
+
+ /* kernel -> userland */
+ p(out_total, "\t" LLU " request%s sent to userland\n");
+ p(out_bytes, "\t" LLU " byte%s sent to userland\n");
+ for (first = 1, type = 0;
+ type < sizeof(pfkeystat.out_msgtype)/sizeof(pfkeystat.out_msgtype[0]);
+ type++) {
+ if (PFKEYDIFF(out_msgtype[type]) <= 0)
+ continue;
+ if (first) {
+ printf("\thistogram by message type:\n");
+ first = 0;
+ }
+ printf("\t\t%s: " LLU "\n", pfkey_msgtype_names(type),
+ (CAST)PFKEYDIFF(out_msgtype[type]));
+ }
+ p(out_invlen, "\t" LLU " message%s with invalid length field\n");
+ p(out_invver, "\t" LLU " message%s with invalid version field\n");
+ p(out_invmsgtype, "\t" LLU " message%s with invalid message type field\n");
+ p(out_tooshort, "\t" LLU " message%s too short\n");
+ p(out_nomem, "\t" LLU " message%s with memory allocation failure\n");
+ p(out_dupext, "\t" LLU " message%s with duplicate extension\n");
+ p(out_invexttype, "\t" LLU " message%s with invalid extension type\n");
+ p(out_invsatype, "\t" LLU " message%s with invalid sa type\n");
+ p(out_invaddr, "\t" LLU " message%s with invalid address extension\n");
+
+ /* userland -> kernel */
+ p(in_total, "\t" LLU " request%s sent from userland\n");
+ p(in_bytes, "\t" LLU " byte%s sent from userland\n");
+ for (first = 1, type = 0;
+ type < sizeof(pfkeystat.in_msgtype)/sizeof(pfkeystat.in_msgtype[0]);
+ type++) {
+ if (PFKEYDIFF(in_msgtype[type]) <= 0)
+ continue;
+ if (first) {
+ printf("\thistogram by message type:\n");
+ first = 0;
+ }
+ printf("\t\t%s: " LLU "\n", pfkey_msgtype_names(type),
+ (CAST)PFKEYDIFF(in_msgtype[type]));
+ }
+ p(in_msgtarget[KEY_SENDUP_ONE],
+ "\t" LLU " message%s toward single socket\n");
+ p(in_msgtarget[KEY_SENDUP_ALL],
+ "\t" LLU " message%s toward all sockets\n");
+ p(in_msgtarget[KEY_SENDUP_REGISTERED],
+ "\t" LLU " message%s toward registered sockets\n");
+ p(in_nomem, "\t" LLU " message%s with memory allocation failure\n");
+
+ if (interval > 0)
+ bcopy(&pfkeystat, &ppfkeystat, len);
+#undef PFKEYDIFF
+#undef p
+}
+#endif /*IPSEC*/
diff --git a/network_cmds/netstat.tproj/main.c b/network_cmds/netstat.tproj/main.c
new file mode 100644
index 0000000..1b8381e
--- /dev/null
+++ b/network_cmds/netstat.tproj/main.c
@@ -0,0 +1,638 @@
+/*
+ * Copyright (c) 2008-2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char const copyright[] =
+"@(#) Copyright (c) 1983, 1988, 1993\n\
+ Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/sys_domain.h>
+
+#include <netinet/in.h>
+#include <net/pfkeyv2.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <nlist.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "netstat.h"
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ * $Id: main.c,v 1.8 2004/10/14 22:24:09 lindak Exp $
+ *
+ */
+
+struct protox {
+ void (*pr_cblocks)(uint32_t, char *, int);
+ /* control blocks printing routine */
+ void (*pr_stats)(uint32_t, char *, int);
+ /* statistics printing routine */
+ void (*pr_istats)(char *); /* per/if statistics printing routine */
+ char *pr_name; /* well-known name */
+ int pr_protocol;
+} protox[] = {
+ { protopr, tcp_stats, NULL, "tcp", IPPROTO_TCP },
+ { protopr, udp_stats, NULL, "udp", IPPROTO_UDP },
+ { protopr, NULL, NULL, "divert", IPPROTO_DIVERT },
+ { protopr, ip_stats, NULL, "ip", IPPROTO_RAW },
+ { protopr, icmp_stats, NULL, "icmp", IPPROTO_ICMP },
+ { protopr, igmp_stats, NULL, "igmp", IPPROTO_IGMP },
+#ifdef IPSEC
+ { NULL, ipsec_stats, NULL, "ipsec", IPPROTO_ESP},
+#endif
+ { NULL, arp_stats, NULL, "arp", 0 },
+ { mptcppr, mptcp_stats, NULL, "mptcp", IPPROTO_TCP },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+
+#ifdef INET6
+struct protox ip6protox[] = {
+ { protopr, tcp_stats, NULL, "tcp", IPPROTO_TCP },
+ { protopr, udp_stats, NULL, "udp", IPPROTO_UDP },
+ { protopr, ip6_stats, ip6_ifstats, "ip6", IPPROTO_RAW },
+ { protopr, icmp6_stats, icmp6_ifstats, "icmp6",IPPROTO_ICMPV6 },
+#ifdef IPSEC
+ { NULL, ipsec_stats, NULL, "ipsec6", IPPROTO_ESP },
+#endif
+ { NULL, rip6_stats, NULL, "rip6", IPPROTO_RAW },
+ { mptcppr, mptcp_stats, NULL, "mptcp", IPPROTO_TCP },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+#endif /*INET6*/
+
+#ifdef IPSEC
+struct protox pfkeyprotox[] = {
+ { NULL, pfkey_stats, NULL, "pfkey", PF_KEY_V2 },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+#endif
+
+
+struct protox systmprotox[] = {
+ { systmpr, NULL, NULL, "reg", 0 },
+ { systmpr, kevt_stats, NULL, "kevt", SYSPROTO_EVENT },
+ { systmpr, kctl_stats, NULL, "kctl", SYSPROTO_CONTROL },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+
+struct protox nstatprotox[] = {
+ { NULL, print_nstat_stats, NULL, "nstat", 0 },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+
+struct protox ipcprotox[] = {
+ { NULL, print_extbkidle_stats, NULL, "xbkidle", 0 },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+
+struct protox kernprotox[] = {
+ { NULL, print_net_api_stats, NULL, "net_api", 0 },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+
+#ifdef AF_VSOCK
+struct protox vsockprotox[] = {
+ { vsockpr, NULL, NULL, "vsock", 0 },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+#endif
+
+struct protox *protoprotox[] = {
+ protox,
+#ifdef INET6
+ ip6protox,
+#endif
+#ifdef IPSEC
+ pfkeyprotox,
+#endif
+ systmprotox,
+ nstatprotox,
+ ipcprotox,
+ kernprotox,
+#ifdef AF_VSOCK
+ vsockprotox,
+#endif
+ NULL
+};
+
+static void printproto (struct protox *, char *);
+static void usage (void);
+static struct protox *name2protox (char *);
+static struct protox *knownname (char *);
+#ifdef SRVCACHE
+extern void _serv_cache_close();
+#endif
+
+int Aflag; /* show addresses of protocol control block */
+int aflag; /* show all sockets (including servers) */
+int bflag; /* show i/f total bytes in/out */
+int cflag; /* show specific classq */
+int dflag; /* show i/f dropped packets */
+int Fflag; /* show i/f forwarded packets */
+#if defined(__APPLE__)
+int gflag; /* show group (multicast) routing or stats */
+#endif
+int iflag; /* show interfaces */
+int lflag; /* show routing table with more information */
+int Lflag; /* show size of listen queues */
+int mflag; /* show memory stats */
+int nflag; /* show addresses numerically */
+static int pflag; /* show given protocol */
+int prioflag = -1; /* show packet priority statistics */
+int Rflag; /* show reachability information */
+int rflag; /* show routing tables (or routing stats) */
+int sflag; /* show protocol statistics */
+int Sflag; /* show additional i/f link status */
+int tflag; /* show i/f watchdog timers */
+int vflag; /* more verbose */
+int Wflag; /* wide display */
+int qflag; /* classq stats display */
+int Qflag; /* opportunistic polling stats display */
+int xflag; /* show extended link-layer reachability information */
+int zflag; /* show only entries with non zero rtt metrics */
+
+int cq = -1; /* send classq index (-1 for all) */
+int interval; /* repeat interval for i/f stats */
+
+char *interface; /* desired i/f for stats, or NULL for all i/fs */
+int unit; /* unit number for above */
+
+int af; /* address family */
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct protox *tp = NULL; /* for printing cblocks & stats */
+ int ch;
+
+ af = AF_UNSPEC;
+
+ while ((ch = getopt(argc, argv, "Aabc:dFf:gI:ikLlmnP:p:qQrRsStuvWw:xz")) != -1)
+ switch(ch) {
+ case 'A':
+ Aflag = 1;
+ break;
+ case 'a':
+ aflag = 1;
+ break;
+ case 'b':
+ bflag = 1;
+ break;
+ case 'c':
+ cflag = 1;
+ cq = atoi(optarg);
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'F':
+ Fflag = 1;
+ break;
+ case 'f':
+ if (strcmp(optarg, "ipx") == 0)
+ af = AF_IPX;
+ else if (strcmp(optarg, "inet") == 0)
+ af = AF_INET;
+#ifdef INET6
+ else if (strcmp(optarg, "inet6") == 0)
+ af = AF_INET6;
+#endif /*INET6*/
+#ifdef INET6
+ else if (strcmp(optarg, "pfkey") == 0)
+ af = PF_KEY;
+#endif /*INET6*/
+ else if (strcmp(optarg, "unix") == 0)
+ af = AF_UNIX;
+ else if (strcmp(optarg, "systm") == 0)
+ af = AF_SYSTEM;
+ else {
+ errx(1, "%s: unknown address family", optarg);
+ }
+ break;
+#if defined(__APPLE__)
+ case 'g':
+ gflag = 1;
+ break;
+#endif
+ case 'I': {
+ char *cp;
+
+ iflag = 1;
+ for (cp = interface = optarg; isalpha(*cp); cp++)
+ continue;
+ unit = atoi(cp);
+ break;
+ }
+ case 'i':
+ iflag = 1;
+ break;
+ case 'l':
+ lflag += 1;
+ break;
+ case 'L':
+ Lflag = 1;
+ break;
+ case 'm':
+ mflag++;
+ break;
+ case 'n':
+ nflag = 1;
+ break;
+ case 'P':
+ prioflag = atoi(optarg);
+ break;
+ case 'p':
+ if ((tp = name2protox(optarg)) == NULL) {
+ errx(1,
+ "%s: unknown or uninstrumented protocol",
+ optarg);
+ }
+ pflag = 1;
+ break;
+ case 'q':
+ qflag++;
+ break;
+ case 'Q':
+ Qflag++;
+ break;
+ case 'R':
+ Rflag = 1;
+ break;
+ case 'r':
+ rflag = 1;
+ break;
+ case 's':
+ ++sflag;
+ break;
+ case 'S':
+ Sflag = 1;
+ break;
+ case 't':
+ tflag = 1;
+ break;
+ case 'u':
+ af = AF_UNIX;
+ break;
+ case 'v':
+ vflag++;
+ break;
+ case 'W':
+ Wflag = 1;
+ break;
+ case 'w':
+ interval = atoi(optarg);
+ iflag = 1;
+ break;
+ case 'x':
+ xflag = 1;
+ Rflag = 1;
+ break;
+ case 'z':
+ zflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argv += optind;
+ argc -= optind;
+
+#define BACKWARD_COMPATIBILITY
+#ifdef BACKWARD_COMPATIBILITY
+ if (*argv) {
+ if (isdigit(**argv)) {
+ interval = atoi(*argv);
+ if (interval <= 0)
+ usage();
+ ++argv;
+ iflag = 1;
+ }
+ }
+#endif
+
+ if (mflag) {
+ mbpr();
+ exit(0);
+ }
+ if (iflag && !sflag && !Sflag && !gflag && !qflag && !Qflag) {
+ if (Rflag)
+ intpr_ri(NULL);
+ else
+ intpr(NULL);
+ exit(0);
+ }
+ if (rflag) {
+ if (sflag)
+ rt_stats();
+ else
+ routepr();
+ exit(0);
+ }
+ if (qflag || Qflag) {
+ if (interface == NULL) {
+ fprintf(stderr, "%s statistics option "
+ "requires interface name\n", qflag ? "Queue" :
+ "Polling");
+ } else if (qflag) {
+ aqstatpr();
+ } else {
+ rxpollstatpr();
+ }
+ exit(0);
+ }
+ if (Sflag) {
+ if (interface == NULL) {
+ fprintf(stderr, "additional link status option"
+ " requires interface name\n");
+ } else {
+ print_link_status(interface);
+ }
+ exit(0);
+ }
+
+#if defined(__APPLE__)
+ if (gflag) {
+ ifmalist_dump();
+ exit(0);
+ }
+#endif
+
+ if (tp) {
+ printproto(tp, tp->pr_name);
+ exit(0);
+ }
+ if (af == AF_INET || af == AF_UNSPEC)
+ for (tp = protox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#ifdef INET6
+ if (af == AF_INET6 || af == AF_UNSPEC)
+ for (tp = ip6protox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#endif /*INET6*/
+#ifdef IPSEC
+ if (af == PF_KEY || af == AF_UNSPEC)
+ for (tp = pfkeyprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#endif /*IPSEC*/
+ if ((af == AF_UNIX || af == AF_UNSPEC) && !Lflag && !sflag)
+ unixpr();
+
+ if ((af == AF_SYSTEM || af == AF_UNSPEC) && !Lflag)
+ for (tp = systmprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#if TARGET_OS_IPHONE
+ if (af == AF_UNSPEC && !Lflag)
+ for (tp = nstatprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#endif /* TARGET_OS_IPHONE */
+
+ if (af == AF_UNSPEC && !Lflag)
+ for (tp = ipcprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+
+ if (af == AF_UNSPEC && !Lflag)
+ for (tp = kernprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+
+#ifdef AF_VSOCK
+ if (af == AF_VSOCK || af == AF_UNSPEC)
+ for (tp = vsockprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#endif /*AF_VSOCK*/
+
+#ifdef SRVCACHE
+ _serv_cache_close();
+#endif
+ exit(0);
+}
+
+/*
+ * Print out protocol statistics or control blocks (per sflag).
+ * If the interface was not specifically requested, and the symbol
+ * is not in the namelist, ignore this one.
+ */
+static void
+printproto(tp, name)
+ register struct protox *tp;
+ char *name;
+{
+ void (*pr)(uint32_t, char *, int);
+ uint32_t off;
+
+ if (sflag) {
+ if (iflag && !pflag) {
+ if (tp->pr_istats)
+ intpr(tp->pr_istats);
+ else if (vflag)
+ printf("%s: no per-interface stats routine\n",
+ tp->pr_name);
+ return;
+ }
+ else {
+ pr = tp->pr_stats;
+ if (!pr) {
+ if (pflag && vflag)
+ printf("%s: no stats routine\n",
+ tp->pr_name);
+ return;
+ }
+ off = tp->pr_protocol;
+ }
+ } else {
+ pr = tp->pr_cblocks;
+ if (!pr) {
+ if (pflag && vflag)
+ printf("%s: no PCB routine\n", tp->pr_name);
+ return;
+ }
+ off = tp->pr_protocol;
+ }
+ if (pr != NULL) {
+ if (sflag && iflag && pflag)
+ intervalpr(pr, off, name, af);
+ else
+ (*pr)(off, name, af);
+ } else {
+ printf("### no stats for %s\n", name);
+ }
+}
+
+char *
+plural(int n)
+{
+ return (n > 1 ? "s" : "");
+}
+
+char *
+plurales(int n)
+{
+ return (n > 1 ? "es" : "");
+}
+
+char *
+pluralies(int n)
+{
+ return (n > 1 ? "ies" : "y");
+}
+
+/*
+ * Find the protox for the given "well-known" name.
+ */
+static struct protox *
+knownname(char *name)
+{
+ struct protox **tpp, *tp;
+
+ for (tpp = protoprotox; *tpp; tpp++)
+ for (tp = *tpp; tp->pr_name; tp++)
+ if (strcmp(tp->pr_name, name) == 0)
+ return (tp);
+ return (NULL);
+}
+
+/*
+ * Find the protox corresponding to name.
+ */
+static struct protox *
+name2protox(char *name)
+{
+ struct protox *tp;
+ char **alias; /* alias from p->aliases */
+ struct protoent *p;
+
+ /*
+ * Try to find the name in the list of "well-known" names. If that
+ * fails, check if name is an alias for an Internet protocol.
+ */
+ if ((tp = knownname(name)) != NULL)
+ return (tp);
+
+ setprotoent(1); /* make protocol lookup cheaper */
+ while ((p = getprotoent()) != NULL) {
+ /* assert: name not same as p->name */
+ for (alias = p->p_aliases; *alias; alias++)
+ if (strcmp(name, *alias) == 0) {
+ endprotoent();
+ return (knownname(p->p_name));
+ }
+ }
+ endprotoent();
+ return (NULL);
+}
+
+#define NETSTAT_USAGE "\
+Usage: netstat [-AaLlnW] [-f address_family | -p protocol]\n\
+ netstat [-gilns] [-f address_family]\n\
+ netstat -i | -I interface [-w wait] [-abdgRtS]\n\
+ netstat -s [-s] [-f address_family | -p protocol] [-w wait]\n\
+ netstat -i | -I interface -s [-f address_family | -p protocol]\n\
+ netstat -m [-m]\n\
+ netstat -r [-Aaln] [-f address_family]\n\
+ netstat -rs [-s]\n\
+"
+
+static void
+usage(void)
+{
+ (void) fprintf(stderr, "%s\n", NETSTAT_USAGE);
+ exit(1);
+}
+
+int
+print_time(void)
+{
+ time_t now;
+ struct tm tm;
+ int num_written = 0;
+
+ (void) time(&now);
+ (void) localtime_r(&now, &tm);
+
+ num_written += printf("%02d:%02d:%02d ", tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+ return (num_written);
+}
+
diff --git a/network_cmds/netstat.tproj/mbuf.c b/network_cmds/netstat.tproj/mbuf.c
new file mode 100644
index 0000000..38645e9
--- /dev/null
+++ b/network_cmds/netstat.tproj/mbuf.c
@@ -0,0 +1,476 @@
+/*
+ * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/mbuf.h>
+#include <sys/sysctl.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "netstat.h"
+
+#define YES 1
+typedef int bool;
+
+struct mbstat mbstat;
+
+static struct mbtypes {
+ int mt_type;
+ char *mt_name;
+} mbtypes[] = {
+ { MT_DATA, "data" },
+ { MT_OOBDATA, "oob data" },
+ { MT_CONTROL, "ancillary data" },
+ { MT_HEADER, "packet headers" },
+ { MT_SOCKET, "socket structures" }, /* XXX */
+ { MT_PCB, "protocol control blocks" }, /* XXX */
+ { MT_RTABLE, "routing table entries" }, /* XXX */
+ { MT_HTABLE, "IMP host table entries" }, /* XXX */
+ { MT_ATABLE, "address resolution tables" },
+ { MT_FTABLE, "fragment reassembly queue headers" }, /* XXX */
+ { MT_SONAME, "socket names and addresses" },
+ { MT_SOOPTS, "socket options" },
+ { MT_RIGHTS, "access rights" },
+ { MT_IFADDR, "interface addresses" }, /* XXX */
+ { MT_TAG, "packet tags" }, /* XXX */
+ { 0, 0 }
+};
+
+int nmbtypes = sizeof(mbstat.m_mtypes) / sizeof(short);
+bool seen[256]; /* "have we seen this type yet?" */
+
+mb_stat_t *mb_stat;
+unsigned int njcl, njclbytes;
+mleak_stat_t *mleak_stat;
+struct mleak_table table;
+
+#define KERN_IPC_MB_STAT "kern.ipc.mb_stat"
+#define KERN_IPC_NJCL "kern.ipc.njcl"
+#define KERN_IPC_NJCL_BYTES "kern.ipc.njclbytes"
+#define KERN_IPC_MLEAK_TABLE "kern.ipc.mleak_table"
+#define KERN_IPC_MLEAK_TOP_TRACE "kern.ipc.mleak_top_trace"
+
+#define MB_STAT_HDR1 "\
+class buf active ctotal total cache cached uncached memory\n\
+name size bufs bufs bufs state bufs bufs usage\n\
+---------- ----- -------- -------- -------- ----- -------- -------- ---------\n\
+"
+
+#define MB_STAT_HDR2 "\n\
+class waiter notify purge wretry nwretry failure\n\
+name count count count count count count\n\
+---------- -------- -------- -------- -------- -------- --------\n\
+"
+
+#define MB_LEAK_HDR "\n\
+ calltrace [1] calltrace [2] calltrace [3] calltrace [4] calltrace [5] \n\
+ ------------------ ------------------ ------------------ ------------------ ------------------ \n\
+"
+
+#define MB_LEAK_SPACING " "
+static const char *mbpr_state(int);
+static const char *mbpr_mem(u_int32_t);
+static int mbpr_getdata(void);
+
+/*
+ * Print mbuf statistics.
+ */
+void
+mbpr(void)
+{
+ unsigned long totmem = 0, totfree = 0, totmbufs, totused, totreturned = 0;
+ double totpct;
+ u_int32_t m_msize, m_mbufs = 0, m_clfree = 0, m_bigclfree = 0;
+ u_int32_t m_mbufclfree = 0, m_mbufbigclfree = 0;
+ u_int32_t m_16kclusters = 0, m_16kclfree = 0, m_mbuf16kclfree = 0;
+ int i;
+ struct mbtypes *mp;
+ mb_class_stat_t *cp;
+
+ if (mbpr_getdata() != 0)
+ return;
+
+ m_msize = mbstat.m_msize;
+ cp = &mb_stat->mbs_class[0];
+ for (i = 0; i < mb_stat->mbs_cnt; i++, cp++) {
+ if (cp->mbcl_size == m_msize) {
+ m_mbufs = cp->mbcl_active;
+ } else if (cp->mbcl_size == mbstat.m_mclbytes) {
+ m_clfree = cp->mbcl_total - cp->mbcl_active;
+ } else if (cp->mbcl_size == mbstat.m_bigmclbytes) {
+ m_bigclfree = cp->mbcl_total - cp->mbcl_active;
+ } else if (njcl > 0 && cp->mbcl_size == njclbytes) {
+ m_16kclfree = cp->mbcl_total - cp->mbcl_active;
+ m_16kclusters = cp->mbcl_total;
+ } else if (cp->mbcl_size == (m_msize + mbstat.m_mclbytes)) {
+ m_mbufclfree = cp->mbcl_total - cp->mbcl_active;
+ } else if (cp->mbcl_size == (m_msize + mbstat.m_bigmclbytes)) {
+ m_mbufbigclfree = cp->mbcl_total - cp->mbcl_active;
+ } else if (njcl > 0 && cp->mbcl_size == (m_msize + njclbytes)) {
+ m_mbuf16kclfree = cp->mbcl_total - cp->mbcl_active;
+ }
+ }
+
+ /* adjust free counts to include composite caches */
+ m_clfree += m_mbufclfree;
+ m_bigclfree += m_mbufbigclfree;
+ m_16kclfree += m_mbuf16kclfree;
+
+ cp = &mb_stat->mbs_class[0];
+ for (i = 0; i < mb_stat->mbs_cnt; i++, cp++) {
+ u_int32_t mem;
+
+ mem = cp->mbcl_ctotal * cp->mbcl_size;
+ totmem += mem;
+ totreturned += cp->mbcl_release_cnt;
+ totfree += (cp->mbcl_mc_cached + cp->mbcl_infree) *
+ cp->mbcl_size;
+ if (mflag > 1) {
+ if (i == 0)
+ printf(MB_STAT_HDR1);
+
+ if (njcl == 0 &&
+ cp->mbcl_size > (m_msize + mbstat.m_bigmclbytes))
+ continue;
+
+ printf("%-10s %5u %8u %8u %8u %5s %8u %8u %9s\n",
+ cp->mbcl_cname, cp->mbcl_size, cp->mbcl_active,
+ cp->mbcl_ctotal, cp->mbcl_total,
+ mbpr_state(cp->mbcl_mc_state), cp->mbcl_mc_cached,
+ cp->mbcl_infree, mbpr_mem(mem));
+ }
+ }
+
+ cp = &mb_stat->mbs_class[0];
+ for (i = 0; i < mb_stat->mbs_cnt; i++, cp++) {
+ if (mflag > 2) {
+ if (i == 0)
+ printf(MB_STAT_HDR2);
+
+ if (njcl == 0 &&
+ cp->mbcl_size > (m_msize + mbstat.m_bigmclbytes))
+ continue;
+
+ printf("%-10s %8u %8llu %8llu %8u %8u %8llu\n",
+ cp->mbcl_cname, cp->mbcl_mc_waiter_cnt,
+ cp->mbcl_notified, cp->mbcl_purge_cnt,
+ cp->mbcl_mc_wretry_cnt, cp->mbcl_mc_nwretry_cnt,
+ cp->mbcl_fail_cnt);
+ }
+ }
+
+ if (mflag > 1)
+ printf("\n");
+
+ totmbufs = 0;
+ for (mp = mbtypes; mp->mt_name; mp++)
+ totmbufs += mbstat.m_mtypes[mp->mt_type];
+ /*
+ * These stats are not updated atomically in the kernel;
+ * adjust the total as neeeded.
+ */
+ if (totmbufs > m_mbufs)
+ totmbufs = m_mbufs;
+ printf("%lu/%u mbufs in use:\n", totmbufs, m_mbufs);
+ for (mp = mbtypes; mp->mt_name; mp++)
+ if (mbstat.m_mtypes[mp->mt_type]) {
+ seen[mp->mt_type] = YES;
+ printf("\t%u mbufs allocated to %s\n",
+ mbstat.m_mtypes[mp->mt_type], mp->mt_name);
+ }
+ seen[MT_FREE] = YES;
+ for (i = 0; i < nmbtypes; i++)
+ if (!seen[i] && mbstat.m_mtypes[i]) {
+ printf("\t%u mbufs allocated to <mbuf type %d>\n",
+ mbstat.m_mtypes[i], i);
+ }
+ if ((m_mbufs - totmbufs) > 0)
+ printf("\t%lu mbufs allocated to caches\n",
+ m_mbufs - totmbufs);
+ printf("%u/%u mbuf 2KB clusters in use\n",
+ (unsigned int)(mbstat.m_clusters - m_clfree),
+ (unsigned int)mbstat.m_clusters);
+ printf("%u/%u mbuf 4KB clusters in use\n",
+ (unsigned int)(mbstat.m_bigclusters - m_bigclfree),
+ (unsigned int)mbstat.m_bigclusters);
+ if (njcl > 0) {
+ printf("%u/%u mbuf %uKB clusters in use\n",
+ m_16kclusters - m_16kclfree, m_16kclusters,
+ njclbytes/1024);
+ }
+ totused = totmem - totfree;
+ if (totmem == 0)
+ totpct = 0;
+ else if (totused < (ULONG_MAX/100))
+ totpct = (totused * 100)/(double)totmem;
+ else {
+ u_long totmem1 = totmem/100;
+ u_long totused1 = totused/100;
+ totpct = (totused1 * 100)/(double)totmem1;
+ }
+ printf("%lu KB allocated to network (%.1f%% in use)\n",
+ totmem / 1024, totpct);
+ printf("%lu KB returned to the system\n", totreturned / 1024);
+
+ printf("%u requests for memory denied\n", (unsigned int)mbstat.m_drops);
+ printf("%u requests for memory delayed\n", (unsigned int)mbstat.m_wait);
+ printf("%u calls to drain routines\n", (unsigned int)mbstat.m_drain);
+
+ free(mb_stat);
+ mb_stat = NULL;
+
+ if (mleak_stat != NULL) {
+ mleak_trace_stat_t *mltr;
+
+ printf("\nmbuf leak detection table:\n");
+ printf("\ttotal captured: %u (one per %u)\n"
+ "\ttotal allocs outstanding: %llu\n"
+ "\tnew hash recorded: %llu allocs, %llu traces\n"
+ "\thash collisions: %llu allocs, %llu traces\n"
+ "\toverwrites: %llu allocs, %llu traces\n"
+ "\tlock conflicts: %llu\n\n",
+ table.mleak_capture / table.mleak_sample_factor,
+ table.mleak_sample_factor,
+ table.outstanding_allocs,
+ table.alloc_recorded, table.trace_recorded,
+ table.alloc_collisions, table.trace_collisions,
+ table.alloc_overwrites, table.trace_overwrites,
+ table.total_conflicts);
+
+ printf("top %d outstanding traces:\n", mleak_stat->ml_cnt);
+ for (i = 0; i < mleak_stat->ml_cnt; i++) {
+ mltr = &mleak_stat->ml_trace[i];
+ printf("[%d] %llu outstanding alloc(s), "
+ "%llu hit(s), %llu collision(s)\n", (i + 1),
+ mltr->mltr_allocs, mltr->mltr_hitcount,
+ mltr->mltr_collisions);
+ }
+
+ printf(MB_LEAK_HDR);
+ for (i = 0; i < MLEAK_STACK_DEPTH; i++) {
+ int j;
+
+ printf("%2d: ", (i + 1));
+ for (j = 0; j < mleak_stat->ml_cnt; j++) {
+ mltr = &mleak_stat->ml_trace[j];
+ if (i < mltr->mltr_depth) {
+ if (mleak_stat->ml_isaddr64) {
+ printf("0x%0llx ",
+ mltr->mltr_addr[i]);
+ } else {
+ printf("0x%08x ",
+ (u_int32_t)mltr->mltr_addr[i]);
+ }
+ } else {
+ printf(MB_LEAK_SPACING);
+ }
+ }
+ printf("\n");
+ }
+ free(mleak_stat);
+ mleak_stat = NULL;
+ }
+}
+
+static const char *
+mbpr_state(int state)
+{
+ char *msg = "?";
+
+ switch (state) {
+ case MCS_DISABLED:
+ msg = "dis";
+ break;
+
+ case MCS_ONLINE:
+ msg = "on";
+ break;
+
+ case MCS_PURGING:
+ msg = "purge";
+ break;
+
+ case MCS_OFFLINE:
+ msg = "off";
+ break;
+ }
+ return (msg);
+}
+
+static const char *
+mbpr_mem(u_int32_t bytes)
+{
+ static char buf[33];
+ double mem = bytes;
+
+ if (mem < 1024) {
+ (void) snprintf(buf, sizeof (buf), "%d", (int)mem);
+ } else if ((mem /= 1024) < 1024) {
+ (void) snprintf(buf, sizeof (buf), "%.1f KB", mem);
+ } else {
+ mem /= 1024;
+ (void) snprintf(buf, sizeof (buf), "%.1f MB", mem);
+ }
+ return (buf);
+}
+
+static int
+mbpr_getdata(void)
+{
+ size_t len;
+ int error = -1;
+
+ if (nmbtypes != 256) {
+ (void) fprintf(stderr,
+ "netstat: unexpected change to mbstat; check source\n");
+ goto done;
+ }
+
+ len = sizeof(mbstat);
+ if (sysctlbyname("kern.ipc.mbstat", &mbstat, &len, 0, 0) == -1)
+ goto done;
+
+ if (sysctlbyname(KERN_IPC_MB_STAT, NULL, &len, 0, 0) == -1) {
+ (void) fprintf(stderr,
+ "Error retrieving length for %s\n", KERN_IPC_MB_STAT);
+ goto done;
+ }
+
+ mb_stat = calloc(1, len);
+ if (mb_stat == NULL) {
+ (void) fprintf(stderr,
+ "Error allocating %lu bytes for sysctl data\n", len);
+ goto done;
+ }
+
+ if (sysctlbyname(KERN_IPC_MB_STAT, mb_stat, &len, 0, 0) == -1) {
+ (void) fprintf(stderr,
+ "Error %d getting %s\n", errno, KERN_IPC_MB_STAT);
+ goto done;
+ }
+
+ if (mb_stat->mbs_cnt == 0) {
+ (void) fprintf(stderr,
+ "Invalid mbuf class count (%d)\n", mb_stat->mbs_cnt);
+ goto done;
+ }
+
+ /* mbuf leak detection! */
+ if (mflag > 3) {
+ errno = 0;
+ len = sizeof (table);
+ if (sysctlbyname(KERN_IPC_MLEAK_TABLE, &table, &len, 0, 0) ==
+ -1 && errno != ENXIO) {
+ (void) fprintf(stderr, "error %d getting %s\n", errno,
+ KERN_IPC_MLEAK_TABLE);
+ goto done;
+ } else if (errno == ENXIO) {
+ (void) fprintf(stderr, "mbuf leak detection is not "
+ "enabled in the kernel.\n");
+ goto skip;
+ }
+
+ if (sysctlbyname(KERN_IPC_MLEAK_TOP_TRACE, NULL, &len,
+ 0, 0) == -1) {
+ (void) fprintf(stderr, "Error retrieving length for "
+ "%s: %d\n", KERN_IPC_MB_STAT, errno);
+ goto done;
+ }
+
+ mleak_stat = calloc(1, len);
+ if (mleak_stat == NULL) {
+ (void) fprintf(stderr, "Error allocating %lu bytes "
+ "for sysctl data\n", len);
+ goto done;
+ }
+
+ if (sysctlbyname(KERN_IPC_MLEAK_TOP_TRACE, mleak_stat, &len,
+ 0, 0) == -1) {
+ (void) fprintf(stderr, "error %d getting %s\n", errno,
+ KERN_IPC_MLEAK_TOP_TRACE);
+ goto done;
+ }
+ }
+
+skip:
+ len = sizeof (njcl);
+ (void) sysctlbyname(KERN_IPC_NJCL, &njcl, &len, 0, 0);
+ len = sizeof (njclbytes);
+ (void) sysctlbyname(KERN_IPC_NJCL_BYTES, &njclbytes, &len, 0, 0);
+
+ error = 0;
+
+done:
+ if (error != 0 && mb_stat != NULL) {
+ free(mb_stat);
+ mb_stat = NULL;
+ }
+
+ if (error != 0 && mleak_stat != NULL) {
+ free(mleak_stat);
+ mleak_stat = NULL;
+ }
+
+ return (error);
+}
diff --git a/network_cmds/netstat.tproj/mcast.c b/network_cmds/netstat.tproj/mcast.c
new file mode 100644
index 0000000..3637f4d
--- /dev/null
+++ b/network_cmds/netstat.tproj/mcast.c
@@ -0,0 +1,887 @@
+/*
+ * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 2007 Bruce M. Simpson <bms@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+
+/*
+ * Print the running system's current multicast group memberships.
+ * As this relies on getifmaddrs(), it may not be used with a core file.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_mib.h>
+#include <net/if_types.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/igmp_var.h>
+#include <netinet6/mld6_var.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <ifaddrs.h>
+#include <sysexits.h>
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <ifaddrs.h>
+
+
+#include "netstat.h"
+
+union sockunion {
+ struct sockaddr_storage ss;
+ struct sockaddr sa;
+ struct sockaddr_dl sdl;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+};
+typedef union sockunion sockunion_t;
+
+/*
+ * This may have been defined in <net/if.h>. Note that if <net/if.h> is
+ * to be included it must be included before this header file.
+ */
+#ifndef ifa_broadaddr
+#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
+#endif
+
+//struct ifmaddrs {
+// struct ifmaddrs *ifma_next;
+// struct sockaddr *ifma_name;
+// struct sockaddr *ifma_addr;
+// struct sockaddr *ifma_lladdr;
+//};
+
+void ifmalist_dump_af(const struct ifmaddrs * const ifmap, int const af);
+static int ifmalist_dump_mcstat(struct ifmaddrs *);
+static void in_ifinfo(struct igmp_ifinfo *);
+static const char *inm_mode(u_int);
+static void inm_print_sources_sysctl(uint32_t, struct in_addr);
+#ifdef INET6
+static void in6_ifinfo(struct mld_ifinfo *);
+static void in6m_print_sources_sysctl(uint32_t, struct in6_addr *);
+static const char *inet6_n2a(struct in6_addr *);
+#endif
+static void printb(const char *, unsigned int, const char *);
+static const char *sdl_addr_to_hex(const struct sockaddr_dl *, char *, int);
+
+extern char *routename6(struct sockaddr_in6 *);
+
+#define sa_equal(a1, a2) \
+ (bcmp((a1), (a2), ((a1))->sa_len) == 0)
+
+#define sa_dl_equal(a1, a2) \
+ ((((struct sockaddr_dl *)(a1))->sdl_len == \
+ ((struct sockaddr_dl *)(a2))->sdl_len) && \
+ (bcmp(LLADDR((struct sockaddr_dl *)(a1)), \
+ LLADDR((struct sockaddr_dl *)(a2)), \
+ ((struct sockaddr_dl *)(a1))->sdl_alen) == 0))
+
+#define SALIGN (sizeof(uint32_t) - 1)
+#define SA_RLEN(sa) (sa ? ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : \
+ (SALIGN + 1)) : 0)
+#define MAX_SYSCTL_TRY 5
+#define RTA_MASKS (RTA_GATEWAY | RTA_IFP | RTA_IFA)
+
+void
+ifmalist_dump_af(const struct ifmaddrs * const ifmap, int const af)
+{
+ const struct ifmaddrs *ifma;
+ sockunion_t *psa;
+ char myifname[IFNAMSIZ];
+ char *pcolon;
+ char *pafname, *pifname, *plladdr = NULL, *pgroup = NULL;
+
+ switch (af) {
+ case AF_INET:
+ pafname = "IPv4";
+ break;
+#ifdef INET6
+ case AF_INET6:
+ pafname = "IPv6";
+ break;
+#endif
+ case AF_LINK:
+ pafname = "Link-layer";
+ break;
+ default:
+ return; /* XXX */
+ }
+
+ fprintf(stdout, "%s Multicast Group Memberships\n", pafname);
+ fprintf(stdout, "%-20s\t%-16s\t%s\n", "Group", "Link-layer Address",
+ "Netif");
+
+ for (ifma = ifmap; ifma; ifma = ifma->ifma_next) {
+
+ if (ifma->ifma_name == NULL || ifma->ifma_addr == NULL)
+ continue;
+
+ /* Group address */
+ psa = (sockunion_t *)ifma->ifma_addr;
+ if (psa->sa.sa_family != af)
+ continue;
+
+ switch (psa->sa.sa_family) {
+ case AF_INET:
+ pgroup = inet_ntoa(psa->sin.sin_addr);
+ break;
+#ifdef INET6
+ case AF_INET6:
+ pgroup = routename6(&(psa->sin6));
+ break;
+#endif
+ case AF_LINK:
+ if ((psa->sdl.sdl_alen == ETHER_ADDR_LEN) ||
+ (psa->sdl.sdl_type == IFT_ETHER)) {
+ pgroup =
+ether_ntoa((struct ether_addr *)&psa->sdl.sdl_data);
+#ifdef notyet
+ } else {
+ pgroup = addr2ascii(AF_LINK,
+ &psa->sdl,
+ sizeof(struct sockaddr_dl),
+ addrbuf);
+#endif
+ }
+ break;
+ default:
+ continue; /* XXX */
+ }
+
+ /* Link-layer mapping, if any */
+ psa = (sockunion_t *)ifma->ifma_lladdr;
+ if (psa != NULL) {
+ if (psa->sa.sa_family == AF_LINK) {
+ if ((psa->sdl.sdl_alen == ETHER_ADDR_LEN) ||
+ (psa->sdl.sdl_type == IFT_ETHER)) {
+ /* IEEE 802 */
+ plladdr =
+ether_ntoa((struct ether_addr *)&psa->sdl.sdl_data);
+#ifdef notyet
+ } else {
+ /* something more exotic */
+ plladdr = addr2ascii(AF_LINK,
+ &psa->sdl,
+ sizeof(struct sockaddr_dl),
+ addrbuf);
+#endif
+ }
+ } else {
+ int i;
+
+ /* not a link-layer address */
+ plladdr = "<invalid>";
+
+ for (i = 0; psa->sa.sa_len > 2 && i < psa->sa.sa_len - 2; i++)
+ printf("0x%x ", psa->sa.sa_data[i]);
+ printf("\n");
+ }
+ } else {
+ plladdr = "<none>";
+ }
+
+ /* Interface upon which the membership exists */
+ psa = (sockunion_t *)ifma->ifma_name;
+ if (psa != NULL && psa->sa.sa_family == AF_LINK) {
+ strlcpy(myifname, link_ntoa(&psa->sdl), sizeof(myifname));
+ pcolon = strchr(myifname, ':');
+ if (pcolon)
+ *pcolon = '\0';
+ pifname = myifname;
+ } else {
+ pifname = "";
+ }
+
+ fprintf(stdout, "%-20s\t%-16s\t%s\n", pgroup, plladdr, pifname);
+ }
+}
+
+void
+ifmalist_dump(void)
+{
+ struct ifmaddrs *ifmap;
+
+ if (getifmaddrs(&ifmap))
+ err(EX_OSERR, "getifmaddrs");
+
+ ifmalist_dump_af(ifmap, AF_LINK);
+ fputs("\n", stdout);
+ ifmalist_dump_af(ifmap, AF_INET);
+#ifdef INET6
+ fputs("\n", stdout);
+ ifmalist_dump_af(ifmap, AF_INET6);
+#endif
+ if (sflag) {
+ fputs("\n", stdout);
+ ifmalist_dump_mcstat(ifmap);
+ }
+
+ freeifmaddrs(ifmap);
+}
+
+static int
+ifmalist_dump_mcstat(struct ifmaddrs *ifmap)
+{
+ char thisifname[IFNAMSIZ];
+ char addrbuf[NI_MAXHOST];
+ struct ifaddrs *ifap, *ifa;
+ struct ifmaddrs *ifma;
+ sockunion_t lastifasa;
+ sockunion_t *psa, *pgsa, *pllsa, *pifasa;
+ char *pcolon;
+ char *pafname;
+ uint32_t lastifindex, thisifindex;
+ int error;
+ uint32_t ifindex = 0;
+
+ if (interface != NULL)
+ ifindex = if_nametoindex(interface);
+
+ error = 0;
+ ifap = NULL;
+ lastifindex = 0;
+ thisifindex = 0;
+ lastifasa.ss.ss_family = AF_UNSPEC;
+
+ if (getifaddrs(&ifap) != 0) {
+ warn("getifmaddrs");
+ return (-1);
+ }
+
+ for (ifma = ifmap; ifma; ifma = ifma->ifma_next) {
+ error = 0;
+ if (ifma->ifma_name == NULL || ifma->ifma_addr == NULL)
+ continue;
+
+ psa = (sockunion_t *)ifma->ifma_name;
+ if (psa->sa.sa_family != AF_LINK) {
+ fprintf(stderr,
+ "WARNING: Kernel returned invalid data.\n");
+ error = -1;
+ break;
+ }
+
+ /* Filter on interface name. */
+ thisifindex = psa->sdl.sdl_index;
+ if (ifindex != 0 && thisifindex != ifindex)
+ continue;
+
+ /* Filter on address family. */
+ pgsa = (sockunion_t *)ifma->ifma_addr;
+ if (af != 0 && pgsa->sa.sa_family != af)
+ continue;
+
+ strlcpy(thisifname, link_ntoa(&psa->sdl), sizeof(thisifname));
+ pcolon = strchr(thisifname, ':');
+ if (pcolon)
+ *pcolon = '\0';
+
+ /* Only print the banner for the first ifmaddrs entry. */
+ if (lastifindex == 0 || lastifindex != thisifindex) {
+ lastifindex = thisifindex;
+ fprintf(stdout, "%s:\n", thisifname);
+ }
+
+ /*
+ * Currently, multicast joins only take place on the
+ * primary IPv4 address, and only on the link-local IPv6
+ * address, as per IGMPv2/3 and MLDv1/2 semantics.
+ * Therefore, we only look up the primary address on
+ * the first pass.
+ */
+ pifasa = NULL;
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if ((strcmp(ifa->ifa_name, thisifname) != 0) ||
+ (ifa->ifa_addr == NULL) ||
+ (ifa->ifa_addr->sa_family != pgsa->sa.sa_family))
+ continue;
+ /*
+ * For AF_INET6 only the link-local address should
+ * be returned. If built without IPv6 support,
+ * skip this address entirely.
+ */
+ pifasa = (sockunion_t *)ifa->ifa_addr;
+ if (pifasa->sa.sa_family == AF_INET6
+#ifdef INET6
+ && !IN6_IS_ADDR_LINKLOCAL(&pifasa->sin6.sin6_addr)
+#endif
+ ) {
+ pifasa = NULL;
+ continue;
+ }
+ break;
+ }
+ if (pifasa == NULL)
+ continue; /* primary address not found */
+
+ if (!vflag && pifasa->sa.sa_family == AF_LINK)
+ continue;
+
+ /* Parse and print primary address, if not already printed. */
+ if (lastifasa.ss.ss_family == AF_UNSPEC ||
+ ((lastifasa.ss.ss_family == AF_LINK &&
+ !sa_dl_equal(&lastifasa.sa, &pifasa->sa)) ||
+ !sa_equal(&lastifasa.sa, &pifasa->sa))) {
+
+ switch (pifasa->sa.sa_family) {
+ case AF_INET:
+ pafname = "inet";
+ break;
+ case AF_INET6:
+ pafname = "inet6";
+ break;
+ case AF_LINK:
+ pafname = "link";
+ break;
+ default:
+ pafname = "unknown";
+ break;
+ }
+
+ switch (pifasa->sa.sa_family) {
+ case AF_INET6:
+#ifdef INET6
+ {
+ const char *p =
+ inet6_n2a(&pifasa->sin6.sin6_addr);
+ strlcpy(addrbuf, p, sizeof(addrbuf));
+ break;
+ }
+#else
+ /* FALLTHROUGH */
+#endif
+ case AF_INET:
+ error = getnameinfo(&pifasa->sa,
+ pifasa->sa.sa_len,
+ addrbuf, sizeof(addrbuf), NULL, 0,
+ NI_NUMERICHOST);
+ if (error)
+ printf("getnameinfo: %s\n",
+ gai_strerror(error));
+ break;
+ case AF_LINK: {
+ (void) sdl_addr_to_hex(&pifasa->sdl, addrbuf,
+ sizeof (addrbuf));
+ break;
+ }
+ default:
+ addrbuf[0] = '\0';
+ break;
+ }
+
+ fprintf(stdout, "\t%s %s\n", pafname, addrbuf);
+ /*
+ * Print per-link IGMP information, if available.
+ */
+ if (pifasa->sa.sa_family == AF_INET) {
+ struct igmp_ifinfo igi;
+ size_t mibsize, len;
+ int mib[5];
+
+ mibsize = sizeof(mib) / sizeof(mib[0]);
+ if (sysctlnametomib("net.inet.igmp.ifinfo",
+ mib, &mibsize) == -1) {
+ perror("sysctlnametomib");
+ goto next_ifnet;
+ }
+ mib[mibsize] = thisifindex;
+ len = sizeof(struct igmp_ifinfo);
+ if (sysctl(mib, mibsize + 1, &igi, &len, NULL,
+ 0) == -1) {
+ perror("sysctl net.inet.igmp.ifinfo");
+ goto next_ifnet;
+ }
+ in_ifinfo(&igi);
+ }
+#ifdef INET6
+ /*
+ * Print per-link MLD information, if available.
+ */
+ if (pifasa->sa.sa_family == AF_INET6) {
+ struct mld_ifinfo mli;
+ size_t mibsize, len;
+ int mib[5];
+
+ mibsize = sizeof(mib) / sizeof(mib[0]);
+ if (sysctlnametomib("net.inet6.mld.ifinfo",
+ mib, &mibsize) == -1) {
+ perror("sysctlnametomib");
+ goto next_ifnet;
+ }
+ mib[mibsize] = thisifindex;
+ len = sizeof(struct mld_ifinfo);
+ if (sysctl(mib, mibsize + 1, &mli, &len, NULL,
+ 0) == -1) {
+ perror("sysctl net.inet6.mld.ifinfo");
+ goto next_ifnet;
+ }
+ in6_ifinfo(&mli);
+ }
+#endif /* INET6 */
+#if defined(INET6)
+next_ifnet:
+#endif
+ lastifasa = *pifasa;
+ }
+
+ /* Print this group address. */
+#ifdef INET6
+ if (pgsa->sa.sa_family == AF_INET6) {
+ const char *p = inet6_n2a(&pgsa->sin6.sin6_addr);
+ strlcpy(addrbuf, p, sizeof(addrbuf));
+ } else
+#endif
+ if (pgsa->sa.sa_family == AF_INET) {
+ error = getnameinfo(&pgsa->sa, pgsa->sa.sa_len,
+ addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST);
+ if (error)
+ printf("getnameinfo: %s\n",
+ gai_strerror(error));
+ } else {
+ (void) sdl_addr_to_hex(&pgsa->sdl, addrbuf,
+ sizeof (addrbuf));
+ }
+
+ fprintf(stdout, "\t\tgroup %s", addrbuf);
+ if (pgsa->sa.sa_family == AF_INET) {
+ inm_print_sources_sysctl(thisifindex,
+ pgsa->sin.sin_addr);
+ }
+#ifdef INET6
+ if (pgsa->sa.sa_family == AF_INET6) {
+ in6m_print_sources_sysctl(thisifindex,
+ &pgsa->sin6.sin6_addr);
+ }
+#endif
+ fprintf(stdout, "\n");
+
+ /* Link-layer mapping, if present. */
+ pllsa = (sockunion_t *)ifma->ifma_lladdr;
+ if (pllsa != NULL) {
+ (void) sdl_addr_to_hex(&pllsa->sdl, addrbuf,
+ sizeof (addrbuf));
+ fprintf(stdout, "\t\t\tmcast-macaddr %s\n", addrbuf);
+ }
+ }
+
+ if (ifap != NULL)
+ freeifaddrs(ifap);
+
+ return (error);
+}
+
+static void
+in_ifinfo(struct igmp_ifinfo *igi)
+{
+
+ printf("\t");
+ switch (igi->igi_version) {
+ case IGMP_VERSION_1:
+ case IGMP_VERSION_2:
+ case IGMP_VERSION_3:
+ printf("igmpv%d", igi->igi_version);
+ break;
+ default:
+ printf("igmpv?(%d)", igi->igi_version);
+ break;
+ }
+ printb(" flags", igi->igi_flags, "\020\1SILENT\2LOOPBACK");
+ if (igi->igi_version == IGMP_VERSION_3) {
+ printf(" rv %u qi %u qri %u uri %u",
+ igi->igi_rv, igi->igi_qi, igi->igi_qri, igi->igi_uri);
+ }
+ if (vflag >= 2) {
+ printf(" v1timer %u v2timer %u v3timer %u",
+ igi->igi_v1_timer, igi->igi_v2_timer, igi->igi_v3_timer);
+ }
+ printf("\n");
+}
+
+static const char *inm_modes[] = {
+ "undefined",
+ "include",
+ "exclude",
+};
+
+static const char *
+inm_mode(u_int mode)
+{
+
+ if (mode >= MCAST_UNDEFINED && mode <= MCAST_EXCLUDE)
+ return (inm_modes[mode]);
+ return (NULL);
+}
+
+/*
+ * Retrieve per-group source filter mode and lists via sysctl.
+ */
+static void
+inm_print_sources_sysctl(uint32_t ifindex, struct in_addr gina)
+{
+#define MAX_SYSCTL_TRY 5
+ int mib[7];
+ int ntry = 0;
+ size_t mibsize;
+ size_t len;
+ size_t needed;
+ size_t cnt;
+ int i;
+ char *buf;
+ struct in_addr *pina;
+ uint32_t *p;
+ uint32_t fmode;
+ const char *modestr;
+
+ mibsize = sizeof(mib) / sizeof(mib[0]);
+ if (sysctlnametomib("net.inet.ip.mcast.filters", mib, &mibsize) == -1) {
+ perror("sysctlnametomib");
+ return;
+ }
+
+ needed = 0;
+ mib[5] = ifindex;
+ mib[6] = gina.s_addr; /* 32 bits wide */
+ mibsize = sizeof(mib) / sizeof(mib[0]);
+ do {
+ if (sysctl(mib, mibsize, NULL, &needed, NULL, 0) == -1) {
+ perror("sysctl net.inet.ip.mcast.filters");
+ return;
+ }
+ if ((buf = malloc(needed)) == NULL) {
+ perror("malloc");
+ return;
+ }
+ if (sysctl(mib, mibsize, buf, &needed, NULL, 0) == -1) {
+ if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
+ perror("sysctl");
+ goto out_free;
+ }
+ free(buf);
+ buf = NULL;
+ }
+ } while (buf == NULL);
+
+ len = needed;
+ if (len < sizeof(uint32_t)) {
+ perror("sysctl");
+ goto out_free;
+ }
+
+ p = (uint32_t *)buf;
+ fmode = *p++;
+ len -= sizeof(uint32_t);
+
+ modestr = inm_mode(fmode);
+ if (modestr)
+ printf(" mode %s", modestr);
+ else
+ printf(" mode (%u)", fmode);
+
+ if (vflag == 0)
+ goto out_free;
+
+ cnt = len / sizeof(struct in_addr);
+ pina = (struct in_addr *)p;
+
+ for (i = 0; i < cnt; i++) {
+ if (i == 0)
+ printf(" srcs ");
+ fprintf(stdout, "%s%s", (i == 0 ? "" : ","),
+ inet_ntoa(*pina++));
+ len -= sizeof(struct in_addr);
+ }
+ if (len > 0) {
+ fprintf(stderr, "warning: %u trailing bytes from %s\n",
+ (unsigned int)len, "net.inet.ip.mcast.filters");
+ }
+
+out_free:
+ free(buf);
+#undef MAX_SYSCTL_TRY
+}
+
+#ifdef INET6
+
+static void
+in6_ifinfo(struct mld_ifinfo *mli)
+{
+
+ printf("\t");
+ switch (mli->mli_version) {
+ case MLD_VERSION_1:
+ case MLD_VERSION_2:
+ printf("mldv%d", mli->mli_version);
+ break;
+ default:
+ printf("mldv?(%d)", mli->mli_version);
+ break;
+ }
+ printb(" flags", mli->mli_flags, "\020\1SILENT");
+ if (mli->mli_version == MLD_VERSION_2) {
+ printf(" rv %u qi %u qri %u uri %u",
+ mli->mli_rv, mli->mli_qi, mli->mli_qri, mli->mli_uri);
+ }
+ if (vflag >= 2) {
+ printf(" v1timer %u v2timer %u", mli->mli_v1_timer,
+ mli->mli_v2_timer);
+ }
+ printf("\n");
+}
+
+/*
+ * Retrieve MLD per-group source filter mode and lists via sysctl.
+ *
+ * Note: The 128-bit IPv6 group addres needs to be segmented into
+ * 32-bit pieces for marshaling to sysctl. So the MIB name ends
+ * up looking like this:
+ * a.b.c.d.e.ifindex.g[0].g[1].g[2].g[3]
+ * Assumes that pgroup originated from the kernel, so its components
+ * are already in network-byte order.
+ */
+static void
+in6m_print_sources_sysctl(uint32_t ifindex, struct in6_addr *pgroup)
+{
+#define MAX_SYSCTL_TRY 5
+ char addrbuf[INET6_ADDRSTRLEN];
+ int mib[10];
+ int ntry = 0;
+ int *pi;
+ size_t mibsize;
+ size_t len;
+ size_t needed;
+ size_t cnt;
+ int i;
+ char *buf;
+ struct in6_addr *pina;
+ uint32_t *p;
+ uint32_t fmode;
+ const char *modestr;
+
+ mibsize = sizeof(mib) / sizeof(mib[0]);
+ if (sysctlnametomib("net.inet6.ip6.mcast.filters", mib,
+ &mibsize) == -1) {
+ perror("sysctlnametomib");
+ return;
+ }
+
+ needed = 0;
+ mib[5] = ifindex;
+ pi = (int *)pgroup;
+ for (i = 0; i < 4; i++)
+ mib[6 + i] = *pi++;
+
+ mibsize = sizeof(mib) / sizeof(mib[0]);
+ do {
+ if (sysctl(mib, mibsize, NULL, &needed, NULL, 0) == -1) {
+ perror("sysctl net.inet6.ip6.mcast.filters");
+ return;
+ }
+ if ((buf = malloc(needed)) == NULL) {
+ perror("malloc");
+ return;
+ }
+ if (sysctl(mib, mibsize, buf, &needed, NULL, 0) == -1) {
+ if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
+ perror("sysctl");
+ goto out_free;
+ }
+ free(buf);
+ buf = NULL;
+ }
+ } while (buf == NULL);
+
+ len = needed;
+ if (len < sizeof(uint32_t)) {
+ perror("sysctl");
+ goto out_free;
+ }
+
+ p = (uint32_t *)buf;
+ fmode = *p++;
+ len -= sizeof(uint32_t);
+
+ modestr = inm_mode(fmode);
+ if (modestr)
+ printf(" mode %s", modestr);
+ else
+ printf(" mode (%u)", fmode);
+
+ if (vflag == 0)
+ goto out_free;
+
+ cnt = len / sizeof(struct in6_addr);
+ pina = (struct in6_addr *)p;
+
+ for (i = 0; i < cnt; i++) {
+ if (i == 0)
+ printf(" srcs ");
+ inet_ntop(AF_INET6, (const char *)pina++, addrbuf,
+ INET6_ADDRSTRLEN);
+ fprintf(stdout, "%s%s", (i == 0 ? "" : ","), addrbuf);
+ len -= sizeof(struct in6_addr);
+ }
+ if (len > 0) {
+ fprintf(stderr, "warning: %u trailing bytes from %s\n",
+ (unsigned int)len, "net.inet6.ip6.mcast.filters");
+ }
+
+out_free:
+ free(buf);
+#undef MAX_SYSCTL_TRY
+}
+
+static const char *
+inet6_n2a(struct in6_addr *p)
+{
+ static char buf[NI_MAXHOST];
+ struct sockaddr_in6 sin6;
+ u_int32_t scopeid;
+ const int niflags = NI_NUMERICHOST;
+
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sin6.sin6_addr = *p;
+ if (IN6_IS_ADDR_LINKLOCAL(p) || IN6_IS_ADDR_MC_LINKLOCAL(p) ||
+ IN6_IS_ADDR_MC_NODELOCAL(p)) {
+ scopeid = ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
+ if (scopeid) {
+ sin6.sin6_scope_id = scopeid;
+ sin6.sin6_addr.s6_addr[2] = 0;
+ sin6.sin6_addr.s6_addr[3] = 0;
+ }
+ }
+ if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
+ buf, sizeof(buf), NULL, 0, niflags) == 0) {
+ return (buf);
+ } else {
+ return ("(invalid)");
+ }
+}
+#endif /* INET6 */
+
+/*
+ * Print a value a la the %b format of the kernel's printf
+ */
+void
+printb(const char *s, unsigned int v, const char *bits)
+{
+ int i, any = 0;
+ char c;
+
+ if (bits && *bits == 8)
+ printf("%s=%o", s, v);
+ else
+ printf("%s=%x", s, v);
+ bits++;
+ if (bits) {
+ putchar('<');
+ while ((i = *bits++) != '\0') {
+ if (v & (1 << (i-1))) {
+ if (any)
+ putchar(',');
+ any = 1;
+ for (; (c = *bits) > 32; bits++)
+ putchar(c);
+ } else
+ for (; *bits > 32; bits++)
+ ;
+ }
+ putchar('>');
+ }
+}
+
+/*
+ * convert hardware address to hex string for logging errors.
+ */
+static const char *
+sdl_addr_to_hex(const struct sockaddr_dl *sdl, char *orig_buf, int buflen)
+{
+ char *buf = orig_buf;
+ int i;
+ const u_char *lladdr;
+ int maxbytes = buflen / 3;
+
+ lladdr = (u_char *)(size_t)sdl->sdl_data + sdl->sdl_nlen;
+
+ if (maxbytes > sdl->sdl_alen) {
+ maxbytes = sdl->sdl_alen;
+ }
+ *buf = '\0';
+ for (i = 0; i < maxbytes; i++) {
+ snprintf(buf, 3, "%02x", lladdr[i]);
+ buf += 2;
+ *buf = (i == maxbytes - 1) ? '\0' : ':';
+ buf++;
+ }
+ return (orig_buf);
+}
+
diff --git a/network_cmds/netstat.tproj/misc.c b/network_cmds/netstat.tproj/misc.c
new file mode 100644
index 0000000..ac2a2ca
--- /dev/null
+++ b/network_cmds/netstat.tproj/misc.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2017 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+#include <sys/sysctl.h>
+
+#include <net/net_api_stats.h>
+#include <err.h>
+#include <stdio.h>
+
+#include "netstat.h"
+
+void
+print_net_api_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct net_api_stats pnet_api_stats;
+ struct net_api_stats net_api_stats;
+ size_t len = sizeof(struct net_api_stats);
+ const char *mibvar = "net.api_stats";
+
+ if (sysctlbyname(mibvar, &net_api_stats, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+
+#define STATDIFF(f) (net_api_stats.f - pnet_api_stats.f)
+#define p(f, m) if (STATDIFF(f) || sflag <= 1) \
+ printf(m, STATDIFF(f), plural(STATDIFF(f)))
+#define p1a(f, m) if (STATDIFF(f) || sflag <= 1) \
+ printf(m, STATDIFF(f))
+
+ if (interval && vflag > 0)
+ print_time();
+ printf ("%s:\n", name);
+
+ p(nas_iflt_attach_count, "\t%lld interface filter%s currently attached\n");
+ p(nas_iflt_attach_total, "\t%lld interface filter%s attached since boot\n");
+ p(nas_iflt_attach_os_total, "\t%lld interface filter%s attached since boot by OS\n");
+
+ p(nas_ipf_add_count, "\t%lld IP filter%s currently attached\n");
+ p(nas_ipf_add_total, "\t%lld IP filter%s attached since boot\n");
+ p(nas_ipf_add_os_total, "\t%lld IP filter%s attached since boot by OS\n");
+
+ p(nas_sfltr_register_count, "\t%lld socket filter%s currently attached\n");
+ p(nas_sfltr_register_total, "\t%lld socket filter%s attached since boot\n");
+ p(nas_sfltr_register_os_total, "\t%lld socket filter%s attached since boot by OS\n");
+
+ p(nas_socket_alloc_total, "\t%lld socket%s allocated since boot\n");
+ p(nas_socket_in_kernel_total, "\t%lld socket%s allocated in-kernel since boot\n");
+ p(nas_socket_in_kernel_os_total, "\t%lld socket%s allocated in-kernel by OS\n");
+ p(nas_socket_necp_clientuuid_total, "\t%lld socket%s with NECP client UUID since boot\n");
+
+ p(nas_socket_domain_local_total, "\t%lld local domain socket%s allocated since boot\n");
+ p(nas_socket_domain_route_total, "\t%lld route domain socket%s allocated since boot\n");
+ p(nas_socket_domain_inet_total, "\t%lld inet domain socket%s allocated since boot\n");
+ p(nas_socket_domain_inet6_total, "\t%lld inet6 domain socket%s allocated since boot\n");
+ p(nas_socket_domain_system_total, "\t%lld system domain socket%s allocated since boot\n");
+ p(nas_socket_domain_multipath_total, "\t%lld multipath domain socket%s allocated since boot\n");
+ p(nas_socket_domain_key_total, "\t%lld key domain socket%s allocated since boot\n");
+ p(nas_socket_domain_ndrv_total, "\t%lld ndrv domain socket%s allocated since boot\n");
+ p(nas_socket_domain_other_total, "\t%lld other domains socket%s allocated since boot\n");
+
+ p(nas_socket_inet_stream_total, "\t%lld IPv4 stream socket%s created since boot\n");
+ p(nas_socket_inet_dgram_total, "\t%lld IPv4 datagram socket%s created since boot\n");
+ p(nas_socket_inet_dgram_connected, "\t%lld IPv4 datagram socket%s connected\n");
+ p(nas_socket_inet_dgram_dns, "\t%lld IPv4 DNS socket%s\n");
+ p(nas_socket_inet_dgram_no_data, "\t%lld IPv4 datagram socket%s without data\n");
+
+ p(nas_socket_inet6_stream_total, "\t%lld IPv6 stream socket%s created since boot\n");
+ p(nas_socket_inet6_dgram_total, "\t%lld IPv6 datagram socket%s created since boot\n");
+ p(nas_socket_inet6_dgram_connected, "\t%lld IPv6 datagram socket%s connected\n");
+ p(nas_socket_inet6_dgram_dns, "\t%lld IPv6 DNS socket%s\n");
+ p(nas_socket_inet6_dgram_no_data, "\t%lld IPv6 datagram socket%s without data\n");
+
+ p(nas_socket_mcast_join_total, "\t%lld socket multicast join%s since boot\n");
+ p(nas_socket_mcast_join_os_total, "\t%lld socket multicast join%s since boot by OS\n");
+
+ p(nas_nx_flow_inet_stream_total, "\t%lld IPv4 stream nexus flow%s added since boot\n");
+ p(nas_nx_flow_inet_dgram_total, "\t%lld IPv4 datagram nexus flow%s added since boot\n");
+
+ p(nas_nx_flow_inet6_stream_total, "\t%lld IPv6 stream nexus flow%s added since boot\n");
+ p(nas_nx_flow_inet6_dgram_total, "\t%lld IPv6 datagram nexus flow%s added since boot\n");
+
+ p(nas_ifnet_alloc_count, "\t%lld interface%s currently allocated\n");
+ p(nas_ifnet_alloc_total, "\t%lld interface%s allocated since boot\n");
+ p(nas_ifnet_alloc_os_count, "\t%lld interface%s currently allocated by OS\n");
+ p(nas_ifnet_alloc_os_total, "\t%lld extended interface%s allocated since boot by OS\n");
+
+ p(nas_pf_addrule_total, "\t%lld PF addrule operation%s since boot\n");
+ p(nas_pf_addrule_os, "\t%lld PF addrule operation%s since boot by OS\n");
+
+ p(nas_vmnet_total, "\t%lld vmnet start%s since boot\n");
+
+#undef STATDIFF
+#undef p
+#undef p1a
+}
+
diff --git a/network_cmds/netstat.tproj/mptcp.c b/network_cmds/netstat.tproj/mptcp.c
new file mode 100644
index 0000000..70be928
--- /dev/null
+++ b/network_cmds/netstat.tproj/mptcp.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+#include <stdio.h>
+#include <err.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <inttypes.h>
+
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netinet/mptcp_var.h>
+
+#include <arpa/inet.h>
+
+#include "netstat.h"
+
+/* XXX we can't include tcp_fsm.h because inet.c already includes it. */
+static const char *tcpstates[] = {
+ "CLOSED", "LISTEN", "SYN_SENT", "SYN_RCVD",
+ "ESTABLISHED", "CLOSE_WAIT", "FIN_WAIT_1", "CLOSING",
+ "LAST_ACK", "FIN_WAIT_2", "TIME_WAIT"
+};
+
+static const char *mptcpstates[] = {
+ "CLOSED", "LISTEN", "ESTABLISHED", "CLOSE_WAIT", "FIN_WAIT_1",
+ "CLOSING", "LAST_ACK", "FIN_WAIT_2", "TIME_WAIT", "TERMINATE"
+};
+
+int mptcp_done = 0;
+extern void inetprint (struct in_addr *, int, char *, int);
+extern void inet6print (struct in6_addr *, int, char *, int);
+
+static void
+printmptcp(int id, conninfo_mptcp_t *mptcp)
+{
+ int i;
+ conninfo_tcp_t *tcpci;
+ struct sockaddr_storage *src, *dst;
+ mptcp_flow_t *flow;
+ int af;
+
+ printf("mptcp/%-2.2d %-8.8x/%-8.8x %50s \n"
+ " [tok(%#"PRIx32") snd(%#"PRIx64") rcv(%#"PRIx64") "
+ "aid(%d)]\n", id,
+ mptcp->mptcpci_mpte_flags, mptcp->mptcpci_flags,
+ mptcpstates[mptcp->mptcpci_state], mptcp->mptcpci_rtoken,
+ mptcp->mptcpci_sndnxt, mptcp->mptcpci_rcvnxt,
+ mptcp->mptcpci_mpte_addrid);
+
+ flow = (mptcp_flow_t*)((caddr_t)mptcp + mptcp->mptcpci_flow_offset);
+
+ for (i = 0; i < mptcp->mptcpci_nflows; i++) {
+ src = &flow->flow_src;
+ dst = &flow->flow_dst;
+ af = src->ss_family;
+ printf(" tcp%d/%-2.2d ", af == AF_INET ? 4 : 6,
+ flow->flow_cid);
+ printf("%-8.8x ", flow->flow_flags);
+#define SIN(x) ((struct sockaddr_in *)(x))
+#define SIN6(x) ((struct sockaddr_in6 *)(x))
+ switch (af) {
+ case AF_INET:
+ inetprint(&SIN(src)->sin_addr, SIN(src)->sin_port,
+ "tcp", nflag);
+ inetprint(&SIN(dst)->sin_addr, SIN(dst)->sin_port,
+ "tcp", nflag);
+ break;
+#ifdef INET6
+ case AF_INET6:
+ inet6print(&SIN6(src)->sin6_addr, SIN6(src)->sin6_port,
+ "tcp", nflag);
+ inet6print(&SIN6(dst)->sin6_addr, SIN6(dst)->sin6_port,
+ "tcp", nflag);
+ break;
+ }
+#endif
+#undef SIN
+#undef SIN6
+ tcpci = (conninfo_tcp_t*)((caddr_t)flow +
+ flow->flow_tcpci_offset);
+ printf("%s \n"
+ " [relseq(%-4.4d), err(%d)]\n",
+ tcpstates[tcpci->tcpci_tcp_info.tcpi_state],
+ flow->flow_relseq,
+ flow->flow_soerror);
+
+ flow = (mptcp_flow_t*)((caddr_t)flow + flow->flow_len);
+ }
+}
+
+void
+mptcppr(uint32_t off, char *name, int af)
+{
+#pragma unused(off, name, af)
+ const char *mibvar = "net.inet.mptcp.pcblist";
+ size_t len = 0;
+ conninfo_mptcp_t *mptcp;
+ char *buf, *bufp;
+ int id = 0;
+
+ if (Lflag || Aflag || mptcp_done)
+ return;
+ mptcp_done = 1;
+
+ if (sysctlbyname(mibvar, 0, &len, NULL, 0) < 0) {
+ if (errno != ENOENT)
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+ if ((buf = malloc(len)) == NULL) {
+ warn("malloc");
+ return;
+ }
+ if (sysctlbyname(mibvar, buf, &len, NULL, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ free(buf);
+ return;
+ }
+
+ printf("Active Multipath Internet connections\n");
+ printf("%-8.8s %-9.9s %-22.22s %-22.22s %-11.11s\n",
+ "Proto/ID", "Flags",
+ "Local Address", "Foreign Address",
+ "(state)");
+
+ bufp = buf;
+ while (bufp < buf + len) {
+ /* Sanity check */
+ if (buf + len - bufp < sizeof(conninfo_mptcp_t))
+ break;
+ mptcp = (conninfo_mptcp_t *)bufp;
+ printmptcp(id++, mptcp);
+ bufp += mptcp->mptcpci_len;
+ }
+ free(buf);
+}
diff --git a/network_cmds/netstat.tproj/netstat.1 b/network_cmds/netstat.tproj/netstat.1
new file mode 100644
index 0000000..61ab843
--- /dev/null
+++ b/network_cmds/netstat.tproj/netstat.1
@@ -0,0 +1,445 @@
+.\" Copyright (c) 2015 Apple Inc. All rights reserved.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+.\"
+.\" This file contains Original Code and/or Modifications of Original Code
+.\" as defined in and that are subject to the Apple Public Source License
+.\" Version 2.0 (the 'License'). You may not use this file except in
+.\" compliance with the License. The rights granted to you under the License
+.\" may not be used to create, or enable the creation or redistribution of,
+.\" unlawful or unlicensed copies of an Apple operating system, or to
+.\" circumvent, violate, or enable the circumvention or violation of, any
+.\" terms of an Apple operating system software license agreement.
+.\"
+.\" Please obtain a copy of the License at
+.\" http://www.opensource.apple.com/apsl/ and read it before using this file.
+.\"
+.\" The Original Code and all software distributed under the License are
+.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+.\" Please see the License for the specific language governing rights and
+.\" limitations under the License.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+.\"
+.\" Copyright (c) 1983, 1990, 1992, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)netstat.1 8.8 (Berkeley) 4/18/94
+.\" $FreeBSD: src/usr.bin/netstat/netstat.1,v 1.22.2.7 2001/08/10 09:07:09 ru Exp $
+.\"
+.Dd June 15, 2001
+.Dt NETSTAT 1
+.Os Darwin
+.Sh NAME
+.Nm netstat
+.Nd show network status
+.Sh SYNOPSIS
+.Nm
+.Op Fl AaLlnW
+.Op Fl f Ar address_family | Fl p Ar protocol
+.Nm
+.Op Fl gilns
+.Op Fl v
+.Op Fl f Ar address_family
+.Op Fl I Ar interface
+.Nm
+.Fl i | I Ar interface
+.Op Fl w Ar wait
+.Op Fl c Ar queue
+.Op Fl abdgqRtS
+.Nm
+.Fl s Op Fl s
+.Op Fl f Ar address_family | Fl p Ar protocol
+.Op Fl w Ar wait
+.Nm
+.Fl i | I Ar interface Fl s
+.Op Fl f Ar address_family | Fl p Ar protocol
+.Nm
+.Fl m
+.Op Fl m
+.Nm
+.Fl r
+.Op Fl Aaln
+.Op Fl f Ar address_family
+.Nm
+.Fl rs
+.Op Fl s
+.\"-----------------------------------------------------------------------------------------
+.Sh DESCRIPTION
+.\"-----------------------------------------------------------------------------------------
+The
+.Nm
+command symbolically displays the contents of various network-related data structures.
+There are a number of output formats, depending on the options for the information presented.
+The first form of the command displays a list of active sockets for each protocol.
+The second form presents the contents of one of the other network data structures according
+to the option selected. Using the third form, with a
+.Ar wait
+interval specified,
+.Nm
+will continuously display the information regarding packet traffic on the configured network
+interfaces. The fourth form displays statistics for the specified protocol or address family. If a
+.Ar wait
+interval is specified, the protocol information over the last interval seconds will be displayed.
+The fifth form displays per-interface statistics for the specified protocol or address family.
+The sixth form displays
+.Xr mbuf 9
+statistics. The seventh form displays routing table for the specified address family. The
+eighth form displays routing statistics.
+.Pp
+The options have the following meaning:
+.Bl -tag -width flag
+.It Fl A
+With the default display, show the address of any protocol control blocks associated with
+sockets and the flow hash; used for debugging.
+.It Fl a
+With the default display, show the state of all sockets; normally sockets used by server
+processes are not shown. With the routing table display (option
+.Fl r ,
+as described below), show protocol-cloned routes (routes generated by a
+.Dv RTF_PRCLONING
+parent route); normally these routes are not shown.
+.It Fl b
+With the interface display (option
+.Fl i ,
+as described below), show the number of bytes in and out.
+.It Fl c Ar queue
+With the queue statistics (option
+.Fl q ,
+as described below), show only those for the specified
+.Ar queue .
+.It Fl d
+With either interface display (option
+.Fl i
+or an interval, as described below), show the number of dropped packets.
+.It Fl f Ar address_family
+Limit statistics or address control block reports to those of the specified
+.Ar address family .
+The following address families are recognized:
+.Ar inet ,
+for
+.Dv AF_INET ,
+.Ar inet6 ,
+for
+.Dv AF_INET6
+and
+.Ar unix ,
+for
+.Dv AF_UNIX .
+.It Fl g
+Show information related to multicast (group address) membership. If the
+.Fl s
+option is also present, show extended interface group management statistics. If the
+.Fl v
+option is specified, show link-layer memberships; they are suppressed by default.
+Source lists for each group will also be printed. Specifiying
+.Fl v
+twice will print the control plane timers for each interface and the source list counters
+for each group. If the
+.Fl i
+is specified, only that interface will be shown. If the
+.Fl f
+is specified, only information for the address family will be displayed.
+.It Fl I Ar interface
+Show information about the specified interface; used with a
+.Ar wait
+interval as described below.
+If the
+.Fl s
+option is present, show per-interface protocol statistics on the
+.Ar interface
+for the specified
+.Ar address_family
+or
+.Ar protocol ,
+or for all protocol families.
+.It Fl i
+Show the state of interfaces which have been auto-configured (interfaces statically
+configured into a system, but not located at boot time are not shown). If the
+.Fl a
+options is also present, multicast addresses currently in use are shown for each
+Ethernet interface and for each IP interface address. Multicast addresses are shown
+on separate lines following the interface address with which they are associated.
+If the
+.Fl s
+option is present, show per-interface statistics on all interfaces for the specified
+.Ar address_family
+or
+.Ar protocol ,
+or for all protocol families.
+.It Fl L
+Show the size of the various listen queues. The first count shows the number of
+unaccepted connections. The second count shows the amount of unaccepted incomplete
+connections. The third count is the maximum number of queued connections.
+.It Fl l
+Print full IPv6 address.
+.It Fl m
+Show statistics recorded by the memory management routines (the network stack manages a private pool of memory buffers). More detailed information about the buffers, which includes their cache related statistics, can be obtained by using
+.Fl mm
+or
+.Fl m
+.Fl m
+option.
+.It Fl n
+Show network addresses as numbers (normally
+.Nm
+interprets addresses and attempts to display them symbolically). This option may be
+used with any of the display formats.
+.It Fl p Ar protocol
+Show statistics about
+.Ar protocol ,
+which is either a well-known name for a protocol or an alias for it. Some protocol
+names and aliases are listed in the file
+.Pa /etc/protocols .
+The special protocol name
+.Dq bdg
+is used to show bridging statistics. A null response typically means that there are
+no interesting numbers to report. The program will complain if
+.Ar protocol
+is unknown or if there is no statistics routine for it.
+.It Fl q
+Show network interface send queue statistics. By default all queues are displayed, unless
+specified with
+.Fl c .
+This option requires specifying an interface with
+.Fl I
+option. More detailed information about the queues, which includes their queueing algorithm related statistics, can be obtained by using
+.Fl qq
+or
+.Fl q
+.Fl q
+option.
+.It Fl r
+Show the routing tables. Use with
+.Fl a
+to show protocol-cloned routes. When
+.Fl s
+is also present, show routing statistics instead. When
+.Fl l
+is also present,
+.Nm
+assumes more columns are there and the maximum transmission unit.
+More detailed information about the route metrics are displayed with
+.Fl ll
+for TCP round trip times
+.Fl lll
+for all metrics.
+Use the
+.Fl z
+flags to display only entries with non-zero RTT values.
+.Pq Dq mtu
+are also displayed.
+.It Fl R
+Show reachability information. Use with
+.Fl i
+to show link-layer reachability information for a given interface.
+.It Fl s
+Show per-protocol statistics. If this option is repeated, counters with a value of
+zero are suppressed. For security reasons, root privileges are required to read TCP statistics and in the absence of such privileges all TCP counters will be reported as zero.
+.It Fl S
+Show interface link status and interface state information about the specified interface. This option requires specifying an interface with
+.Fl I
+option.
+.It Fl v
+Increase verbosity level.
+.It Fl W
+In certain displays, avoid truncating addresses even if this causes some fields to
+overflow.
+.It Fl w Ar wait
+Show network interface or protocol statistics at intervals of
+.Ar wait
+seconds.
+.It Fl x
+Show extended link-layer reachability information in addition to that shown by
+the
+.Fl R
+flag.
+.El
+.Pp
+.\"-------------------------------------------------------------------------------
+.Sh OUTPUT
+.\"-------------------------------------------------------------------------------
+The default display, for active sockets, shows the local and remote addresses,
+send and receive queue sizes (in bytes), protocol, and the internal state of
+the protocol. Address formats are of the form
+.Dq host.port
+or
+.Dq network.port
+if a socket's address specifies a network but no specific host address.
+If known, the host and network addresses are displayed symbolically
+according to the databases
+.Pa /etc/hosts
+and
+.Pa /etc/networks ,
+respectively. If a symbolic name for an address is unknown, or if the
+.Fl n
+option is specified, the address is printed numerically, according to the
+address family. For more information regarding the Internet
+.Dq dot format ,
+refer to
+.Xr inet 3 ) .
+Unspecified,
+or
+.Dq wildcard ,
+addresses and ports appear as
+.Dq * .
+.Pp
+Internet domain socket states:
+.Bl -column X LISTEN
+CLOSED: The socket is not in use.
+.Pp
+LISTEN: The socket is listening for incoming connections. Unconnected
+listening sockets like these are only displayed when using the -a option.
+.Pp
+SYN_SENT: The socket is actively trying to establish a connection to a
+remote peer.
+.Pp
+SYN_RCVD: The socket has passively received a connection request from a
+remote peer.
+.Pp
+ESTABLISHED: The socket has an established connection between a local
+application and a remote peer.
+.Pp
+CLOSE_WAIT: The socket connection has been closed by the remote peer,
+and the system is waiting for the local application to close its half of
+the connection.
+.Pp
+LAST_ACK: The socket connection has been closed by the remote peer, the
+local application has closed its half of the connection, and the system
+is waiting for the remote peer to acknowledge the close.
+.Pp
+FIN_WAIT_1: The socket connection has been closed by the local
+application, the remote peer has not yet acknowledged the close, and the
+system is waiting for it to close its half of the connection.
+.Pp
+FIN_WAIT_2: The socket connection has been closed by the local
+application, the remote peer has acknowledged the close, and the system
+is waiting for it to close its half of the connection.
+.Pp
+CLOSING: The socket connection has been closed by the local application
+and the remote peer simultaneously, and the remote peer has not yet
+acknowledged the close attempt of the local application.
+.Pp
+TIME_WAIT: The socket connection has been closed by the local
+application, the remote peer has closed its half of the connection, and
+the system is waiting to be sure that the remote peer received the last
+acknowledgement.
+.El
+.Pp
+The interface display provides a table of cumulative statistics regarding
+packets transferred, errors, and collisions. The network addresses of the
+interface and the maximum transmission unit
+.Pq Dq mtu
+are also displayed.
+.Pp
+The routing table display indicates the available routes and their status.
+Each route consists of a destination host or network and a gateway to use
+in forwarding packets. The flags field shows a collection of information
+about the route stored as binary choices. The individual flags are discussed
+in more detail in the
+.Xr route 8
+and
+.Xr route 4
+manual pages. The mapping between letters and flags is:
+.Bl -column XXXX RTF_BLACKHOLE
+1 RTF_PROTO1 Protocol specific routing flag #1
+2 RTF_PROTO2 Protocol specific routing flag #2
+3 RTF_PROTO3 Protocol specific routing flag #3
+B RTF_BLACKHOLE Just discard packets (during updates)
+b RTF_BROADCAST The route represents a broadcast address
+C RTF_CLONING Generate new routes on use
+c RTF_PRCLONING Protocol-specified generate new routes on use
+D RTF_DYNAMIC Created dynamically (by redirect)
+G RTF_GATEWAY Destination requires forwarding by intermediary
+H RTF_HOST Host entry (net otherwise)
+I RTF_IFSCOPE Route is associated with an interface scope
+i RTF_IFREF Route is holding a reference to the interface
+L RTF_LLINFO Valid protocol to link address translation
+M RTF_MODIFIED Modified dynamically (by redirect)
+m RTF_MULTICAST The route represents a multicast address
+R RTF_REJECT Host or net unreachable
+r RTF_ROUTER Host is a default router
+S RTF_STATIC Manually added
+U RTF_UP Route usable
+W RTF_WASCLONED Route was generated as a result of cloning
+X RTF_XRESOLVE External daemon translates proto to link address
+Y RTF_PROXY Proxying; cloned routes will not be scoped
+.El
+.Pp
+Direct routes are created for each interface attached to the local host;
+the gateway field for such entries shows the address of the outgoing
+interface. The refcnt field gives the current number of active uses of
+the route. Connection oriented protocols normally hold on to a single
+route for the duration of a connection while connectionless protocols
+obtain a route while sending to the same destination. The use field
+provides a count of the number of packets sent using that route. The
+interface entry indicates the network interface utilized for the route.
+A route which is marked with the RTF_IFSCOPE flag is instantiated for
+the corresponding interface. A cloning route which is marked with the
+RTF_PROXY flag will not generate new routes that are associated
+with its interface scope.
+.Pp
+When
+.Nm netstat
+is invoked with the
+.Fl w
+option and a
+.Ar wait
+interval argument, it displays a running count of statistics related to
+network interfaces or protocols. An obsolete version of this option used a numeric
+parameter with no option, and is currently supported for backward
+compatibility. By default, this display summarizes information for all
+interfaces. Information for a specific interface may be displayed with the
+.Fl I
+option.
+.Sh SEE ALSO
+.Xr nfsstat 1 ,
+.Xr ps 1 ,
+.Xr inet 4 ,
+.Xr unix 4 ,
+.Xr hosts 5 ,
+.Xr networks 5 ,
+.Xr protocols 5 ,
+.Xr route 8 ,
+.Xr services 5 ,
+.Xr iostat 8 ,
+.Sh HISTORY
+The
+.Nm netstat
+command appeared in
+.Bx 4.2 .
+.Pp
+IPv6 support was added by WIDE/KAME project.
+.Sh BUGS
+The notion of errors is ill-defined.
diff --git a/network_cmds/netstat.tproj/netstat.h b/network_cmds/netstat.tproj/netstat.h
new file mode 100644
index 0000000..68511da
--- /dev/null
+++ b/network_cmds/netstat.tproj/netstat.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2008-2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1992, 1993
+ * Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)netstat.h 8.2 (Berkeley) 1/4/94
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <stdint.h>
+
+#include <TargetConditionals.h>
+
+extern int Aflag; /* show addresses of protocol control block */
+extern int aflag; /* show all sockets (including servers) */
+extern int bflag; /* show i/f total bytes in/out */
+extern int cflag; /* show specific classq */
+extern int dflag; /* show i/f dropped packets */
+extern int Fflag; /* show i/f forwarded packets */
+extern int gflag; /* show group (multicast) routing or stats */
+extern int iflag; /* show interfaces */
+extern int lflag; /* show routing table with use and ref */
+extern int Lflag; /* show size of listen queues */
+extern int mflag; /* show memory stats */
+extern int nflag; /* show addresses numerically */
+extern int Rflag; /* show reachability information */
+extern int rflag; /* show routing tables (or routing stats) */
+extern int sflag; /* show protocol statistics */
+extern int prioflag; /* show packet priority statistics */
+extern int tflag; /* show i/f watchdog timers */
+extern int vflag; /* more verbose */
+extern int Wflag; /* wide display */
+extern int qflag; /* Display ifclassq stats */
+extern int Qflag; /* Display opportunistic polling stats */
+extern int xflag; /* show extended link-layer reachability information */
+extern int zflag; /* show only entries with non zero rtt metrics */
+
+extern int cq; /* send classq index (-1 for all) */
+extern int interval; /* repeat interval for i/f stats */
+
+extern char *interface; /* desired i/f for stats, or NULL for all i/fs */
+extern int unit; /* unit number for above */
+
+extern int af; /* address family */
+
+extern char *plural(int);
+extern char *plurales(int);
+extern char *pluralies(int);
+
+extern void protopr(uint32_t, char *, int);
+extern void mptcppr(uint32_t, char *, int);
+extern void tcp_stats(uint32_t, char *, int);
+extern void mptcp_stats(uint32_t, char *, int);
+extern void udp_stats(uint32_t, char *, int);
+extern void ip_stats(uint32_t, char *, int);
+extern void icmp_stats(uint32_t, char *, int);
+extern void igmp_stats(uint32_t, char *, int);
+extern void arp_stats(uint32_t, char *, int);
+#ifdef IPSEC
+extern void ipsec_stats(uint32_t, char *, int);
+#endif
+
+#ifdef INET6
+extern void ip6_stats(uint32_t, char *, int);
+extern void ip6_ifstats(char *);
+extern void icmp6_stats(uint32_t, char *, int);
+extern void icmp6_ifstats(char *);
+extern void rip6_stats(uint32_t, char *, int);
+
+/* forward references */
+struct sockaddr_in6;
+struct in6_addr;
+struct sockaddr;
+
+extern char *routename6(struct sockaddr_in6 *);
+extern char *netname6(struct sockaddr_in6 *, struct sockaddr *);
+#endif /*INET6*/
+
+#ifdef IPSEC
+extern void pfkey_stats(uint32_t, char *, int);
+#endif
+
+extern void systmpr(uint32_t, char *, int);
+extern void kctl_stats(uint32_t, char *, int);
+extern void kevt_stats(uint32_t, char *, int);
+
+extern void mbpr(void);
+
+extern void intpr(void (*)(char *));
+extern void intpr_ri(void (*)(char *));
+extern void intervalpr(void (*)(uint32_t, char *, int), uint32_t,
+ char *, int);
+
+extern void pr_rthdr(int);
+extern void pr_family(int);
+extern void rt_stats(void);
+extern void upHex(char *);
+extern char *routename(uint32_t);
+extern char *netname(uint32_t, uint32_t);
+extern void routepr(void);
+
+extern void unixpr(void);
+extern void aqstatpr(void);
+extern void rxpollstatpr(void);
+extern void vsockpr(uint32_t,char *,int);
+
+extern void ifmalist_dump(void);
+
+extern int print_time(void);
+extern void print_link_status(const char *);
+
+extern void print_extbkidle_stats(uint32_t, char *, int);
+extern void print_nstat_stats(uint32_t, char *, int);
+extern void print_net_api_stats(uint32_t, char *, int);
+
diff --git a/network_cmds/netstat.tproj/route.c b/network_cmds/netstat.tproj/route.c
new file mode 100644
index 0000000..943e3c8
--- /dev/null
+++ b/network_cmds/netstat.tproj/route.c
@@ -0,0 +1,795 @@
+/*
+ * Copyright (c) 2008-2017 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/route.h>
+#include <net/radix.h>
+
+#include <netinet/in.h>
+
+#include <sys/sysctl.h>
+
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <err.h>
+#include <time.h>
+#include "netstat.h"
+
+/* alignment constraint for routing socket */
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+/*
+ * Definitions for showing gateway flags.
+ */
+struct bits {
+ uint32_t b_mask;
+ char b_val;
+} bits[] = {
+ { RTF_UP, 'U' },
+ { RTF_GATEWAY, 'G' },
+ { RTF_HOST, 'H' },
+ { RTF_REJECT, 'R' },
+ { RTF_DYNAMIC, 'D' },
+ { RTF_MODIFIED, 'M' },
+ { RTF_MULTICAST,'m' },
+ { RTF_DONE, 'd' }, /* Completed -- for routing messages only */
+ { RTF_CLONING, 'C' },
+ { RTF_XRESOLVE, 'X' },
+ { RTF_LLINFO, 'L' },
+ { RTF_STATIC, 'S' },
+ { RTF_PROTO1, '1' },
+ { RTF_PROTO2, '2' },
+ { RTF_WASCLONED,'W' },
+ { RTF_PRCLONING,'c' },
+ { RTF_PROTO3, '3' },
+ { RTF_BLACKHOLE,'B' },
+ { RTF_BROADCAST,'b' },
+ { RTF_IFSCOPE, 'I' },
+ { RTF_IFREF, 'i' },
+ { RTF_PROXY, 'Y' },
+ { RTF_ROUTER, 'r' },
+ { 0 }
+};
+
+typedef union {
+ uint32_t dummy; /* Helps align structure. */
+ struct sockaddr u_sa;
+ u_short u_data[128];
+} sa_u;
+
+static void np_rtentry __P((struct rt_msghdr2 *));
+static void p_sockaddr __P((struct sockaddr *, struct sockaddr *, int, int));
+static void p_flags __P((int, char *));
+static uint32_t forgemask __P((uint32_t));
+static void domask __P((char *, uint32_t, uint32_t));
+
+/*
+ * Print address family header before a section of the routing table.
+ */
+void
+pr_family(int af)
+{
+ char *afname;
+
+ switch (af) {
+ case AF_INET:
+ afname = "Internet";
+ break;
+#ifdef INET6
+ case AF_INET6:
+ afname = "Internet6";
+ break;
+#endif /*INET6*/
+ case AF_IPX:
+ afname = "IPX";
+ break;
+ default:
+ afname = NULL;
+ break;
+ }
+ if (afname)
+ printf("\n%s:\n", afname);
+ else
+ printf("\nProtocol Family %d:\n", af);
+}
+
+/* column widths; each followed by one space */
+#ifndef INET6
+#define WID_DST(af) 18 /* width of destination column */
+#define WID_GW(af) 18 /* width of gateway column */
+#define WID_RT_IFA(af) 18 /* width of source column */
+#define WID_IF(af) 7 /* width of netif column */
+#else
+#define WID_DST(af) \
+ ((af) == AF_INET6 ? (lflag ? 39 : (nflag ? 39: 18)) : 18)
+#define WID_GW(af) \
+ ((af) == AF_INET6 ? (lflag ? 31 : (nflag ? 31 : 18)) : 18)
+#define WID_RT_IFA(af) \
+ ((af) == AF_INET6 ? (lflag ? 39 : (nflag ? 39 : 18)) : 18)
+#define WID_IF(af) ((af) == AF_INET6 ? 8 : 7)
+#endif /*INET6*/
+
+/*
+ * Print header for routing table columns.
+ */
+void
+pr_rthdr(int af)
+{
+ if (lflag) {
+ if (lflag > 2)
+ printf("%-*.*s %-*.*s %-*.*s %-10.10s %6.6s %8.8s %6.6s %*.*s %6s "
+ "%10s %10s %8s %8s %8s\n",
+ WID_DST(af), WID_DST(af), "Destination",
+ WID_GW(af), WID_GW(af), "Gateway",
+ WID_RT_IFA(af), WID_RT_IFA(af), "RT_IFA",
+ "Flags", "Refs", "Use", "Mtu",
+ WID_IF(af), WID_IF(af), "Netif", "Expire",
+ "rtt(ms)", "rttvar(ms)", "recvpipe", "sendpipe", "ssthresh");
+ else if (lflag > 1)
+ printf("%-*.*s %-*.*s %-*.*s %-10.10s %6.6s %8.8s %6.6s %*.*s %6s "
+ "%10s %10s\n",
+ WID_DST(af), WID_DST(af), "Destination",
+ WID_GW(af), WID_GW(af), "Gateway",
+ WID_RT_IFA(af), WID_RT_IFA(af), "RT_IFA",
+ "Flags", "Refs", "Use", "Mtu",
+ WID_IF(af), WID_IF(af), "Netif", "Expire",
+ "rtt(ms)", "rttvar(ms)");
+ else
+ printf("%-*.*s %-*.*s %-*.*s %-10.10s %6.6s %8.8s %6.6s %*.*s %6s\n",
+ WID_DST(af), WID_DST(af), "Destination",
+ WID_GW(af), WID_GW(af), "Gateway",
+ WID_RT_IFA(af), WID_RT_IFA(af), "RT_IFA",
+ "Flags", "Refs", "Use", "Mtu",
+ WID_IF(af), WID_IF(af), "Netif", "Expire");
+ } else {
+ printf("%-*.*s %-*.*s %-10.10s %*.*s %6s\n",
+ WID_DST(af), WID_DST(af), "Destination",
+ WID_GW(af), WID_GW(af), "Gateway",
+ "Flags", WID_IF(af), WID_IF(af), "Netif", "Expire");
+ }
+}
+
+/*
+ * Print routing tables.
+ */
+void
+routepr(void)
+{
+ size_t extra_space;
+ size_t needed;
+ int mib[6];
+ char *buf, *next, *lim;
+ struct rt_msghdr2 *rtm;
+ int try = 1;
+
+ printf("Routing tables\n");
+
+ again:
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = 0;
+ mib[4] = NET_RT_DUMP2;
+ mib[5] = 0;
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
+ err(1, "sysctl: net.route.0.0.dump estimate");
+ }
+ /* allocate extra space in case the table grows */
+ extra_space = needed / 2;
+ if (needed <= (SIZE_MAX - extra_space)) {
+ needed += extra_space;
+ }
+ if ((buf = malloc(needed)) == 0) {
+ err(2, "malloc(%lu)", (unsigned long)needed);
+ }
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
+#define MAX_TRIES 10
+ if (errno == ENOMEM && try < MAX_TRIES) {
+ /* the buffer we provided was too small, try again */
+ free(buf);
+ try++;
+ goto again;
+ }
+ err(1, "sysctl: net.route.0.0.dump");
+ }
+ lim = buf + needed;
+ for (next = buf; next < lim; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr2 *)next;
+ np_rtentry(rtm);
+ }
+}
+
+static void
+get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
+{
+ int i;
+
+ for (i = 0; i < RTAX_MAX; i++) {
+ if (addrs & (1 << i)) {
+ rti_info[i] = sa;
+ sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
+ } else {
+ rti_info[i] = NULL;
+ }
+}
+}
+
+static void
+np_rtentry(struct rt_msghdr2 *rtm)
+{
+ struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
+ struct sockaddr *rti_info[RTAX_MAX];
+ static int old_fam;
+ int fam = 0;
+ u_short lastindex = 0xffff;
+ static char ifname[IFNAMSIZ + 1];
+ sa_u addr, mask;
+
+ /*
+ * Don't print protocol-cloned routes unless -a.
+ */
+ if ((rtm->rtm_flags & RTF_WASCLONED) &&
+ (rtm->rtm_parentflags & RTF_PRCLONING) &&
+ !aflag) {
+ return;
+ }
+
+ if (lflag > 1 && zflag != 0 && rtm->rtm_rmx.rmx_rtt == 0 && rtm->rtm_rmx.rmx_rttvar == 0)
+ return;
+ fam = sa->sa_family;
+ if (af != AF_UNSPEC && af != fam)
+ return;
+ if (fam != old_fam) {
+ pr_family(fam);
+ pr_rthdr(fam);
+ old_fam = fam;
+ }
+ get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
+ bzero(&addr, sizeof(addr));
+ if ((rtm->rtm_addrs & RTA_DST))
+ bcopy(rti_info[RTAX_DST], &addr, rti_info[RTAX_DST]->sa_len);
+ bzero(&mask, sizeof(mask));
+ if ((rtm->rtm_addrs & RTA_NETMASK))
+ bcopy(rti_info[RTAX_NETMASK], &mask, rti_info[RTAX_NETMASK]->sa_len);
+ p_sockaddr(&addr.u_sa, &mask.u_sa, rtm->rtm_flags,
+ WID_DST(addr.u_sa.sa_family));
+
+ p_sockaddr(rti_info[RTAX_GATEWAY], NULL, RTF_HOST,
+ WID_GW(addr.u_sa.sa_family));
+
+ if (lflag && (rtm->rtm_addrs & RTA_IFA)) {
+ p_sockaddr(rti_info[RTAX_IFA], NULL, RTF_HOST,
+ WID_RT_IFA(addr.u_sa.sa_family));
+ }
+
+ p_flags(rtm->rtm_flags, "%-10.10s ");
+
+ if (lflag) {
+ printf("%6u %8u ", rtm->rtm_refcnt, (unsigned int)rtm->rtm_use);
+ if (rtm->rtm_rmx.rmx_mtu != 0)
+ printf("%6u ", rtm->rtm_rmx.rmx_mtu);
+ else
+ printf("%6s ", "");
+ }
+
+ if (rtm->rtm_index != lastindex) {
+ if_indextoname(rtm->rtm_index, ifname);
+ lastindex = rtm->rtm_index;
+ }
+ printf("%*.*s", WID_IF(addr.u_sa.sa_family),
+ WID_IF(addr.u_sa.sa_family), ifname);
+
+ if (rtm->rtm_rmx.rmx_expire) {
+ time_t expire_time;
+
+ if ((expire_time =
+ rtm->rtm_rmx.rmx_expire - time((time_t *)0)) > 0)
+ printf(" %6d", (int)expire_time);
+ else
+ printf(" %6s", "!");
+ } else {
+ printf(" %6s", "");
+ }
+ if (lflag > 1) {
+ if (rtm->rtm_rmx.rmx_rtt != 0)
+ printf(" %6u.%03u", rtm->rtm_rmx.rmx_rtt / 1000,
+ rtm->rtm_rmx.rmx_rtt % 1000);
+ else
+ printf(" %10s", "");
+ if (rtm->rtm_rmx.rmx_rttvar != 0)
+ printf(" %6u.%03u", rtm->rtm_rmx.rmx_rttvar / 1000,
+ rtm->rtm_rmx.rmx_rttvar % 1000);
+ else
+ printf(" %10s", "");
+ if (lflag > 2) {
+ if (rtm->rtm_rmx.rmx_recvpipe != 0)
+ printf(" %8u", rtm->rtm_rmx.rmx_recvpipe);
+ else
+ printf(" %8s", "");
+ if (rtm->rtm_rmx.rmx_sendpipe != 0)
+ printf(" %8u", rtm->rtm_rmx.rmx_sendpipe);
+ else
+ printf(" %8s", "");
+ if (rtm->rtm_rmx.rmx_ssthresh != 0)
+ printf(" %8u", rtm->rtm_rmx.rmx_ssthresh);
+ else
+ printf(" %8s", "");
+ }
+ }
+ putchar('\n');
+}
+
+static void
+p_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags, int width)
+{
+ char workbuf[128], *cplim;
+ char *cp = workbuf;
+
+ switch(sa->sa_family) {
+ case AF_INET: {
+ struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+
+ if ((sin->sin_addr.s_addr == INADDR_ANY) &&
+ mask &&
+ (ntohl(((struct sockaddr_in *)mask)->sin_addr.s_addr) == 0L || mask->sa_len == 0))
+ cp = "default" ;
+ else if (flags & RTF_HOST)
+ cp = routename(sin->sin_addr.s_addr);
+ else if (mask)
+ cp = netname(sin->sin_addr.s_addr,
+ ntohl(((struct sockaddr_in *)mask)->
+ sin_addr.s_addr));
+ else
+ cp = netname(sin->sin_addr.s_addr, 0L);
+ break;
+ }
+
+#ifdef INET6
+ case AF_INET6: {
+ struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
+ struct in6_addr *in6 = &sa6->sin6_addr;
+
+ /*
+ * XXX: This is a special workaround for KAME kernels.
+ * sin6_scope_id field of SA should be set in the future.
+ */
+ if (IN6_IS_ADDR_LINKLOCAL(in6) ||
+ IN6_IS_ADDR_MC_NODELOCAL(in6) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(in6)) {
+ /* XXX: override is ok? */
+ sa6->sin6_scope_id = (u_int32_t)ntohs(*(u_short *)&in6->s6_addr[2]);
+ *(u_short *)&in6->s6_addr[2] = 0;
+ }
+
+ if (flags & RTF_HOST)
+ cp = routename6(sa6);
+ else if (mask)
+ cp = netname6(sa6, mask);
+ else
+ cp = netname6(sa6, NULL);
+ break;
+ }
+#endif /*INET6*/
+
+ case AF_LINK: {
+ struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
+
+ if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 &&
+ sdl->sdl_slen == 0) {
+ (void) snprintf(workbuf, sizeof(workbuf), "link#%d", sdl->sdl_index);
+ } else {
+ switch (sdl->sdl_type) {
+
+ case IFT_ETHER: {
+ int i;
+ u_char *lla = (u_char *)sdl->sdl_data +
+ sdl->sdl_nlen;
+
+ cplim = "";
+ for (i = 0; i < sdl->sdl_alen; i++, lla++) {
+ cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), "%s%x", cplim, *lla);
+ cplim = ":";
+ }
+ cp = workbuf;
+ break;
+ }
+
+ default:
+ cp = link_ntoa(sdl);
+ break;
+ }
+ }
+ break;
+ }
+
+ default: {
+ u_char *s = (u_char *)sa->sa_data, *slim;
+
+ slim = sa->sa_len + (u_char *) sa;
+ cplim = cp + sizeof(workbuf) - 6;
+ cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), "(%d)", sa->sa_family);
+ while (s < slim && cp < cplim) {
+ cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), " %02x", *s++);
+ if (s < slim)
+ cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), "%02x", *s++);
+ }
+ cp = workbuf;
+ }
+ }
+ if (width < 0 ) {
+ printf("%s ", cp);
+ } else {
+ if (nflag)
+ printf("%-*s ", width, cp);
+ else
+ printf("%-*.*s ", width, width, cp);
+ }
+}
+
+static void
+p_flags(int f, char *format)
+{
+ char name[33], *flags;
+ struct bits *p = bits;
+
+ for (flags = name; p->b_mask; p++)
+ if (p->b_mask & f)
+ *flags++ = p->b_val;
+ *flags = '\0';
+ printf(format, name);
+}
+
+char *
+routename(uint32_t in)
+{
+ char *cp;
+ static char line[MAXHOSTNAMELEN];
+ struct hostent *hp;
+
+ cp = 0;
+ if (!nflag) {
+ hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
+ AF_INET);
+ if (hp) {
+ cp = hp->h_name;
+ //### trimdomain(cp, strlen(cp));
+ }
+ }
+ if (cp) {
+ strlcpy(line, cp, sizeof(line));
+ } else {
+#define C(x) ((x) & 0xff)
+ in = ntohl(in);
+ snprintf(line, sizeof(line), "%u.%u.%u.%u",
+ C(in >> 24), C(in >> 16), C(in >> 8), C(in));
+ }
+ return (line);
+}
+
+static uint32_t
+forgemask(uint32_t a)
+{
+ uint32_t m;
+
+ if (IN_CLASSA(a))
+ m = IN_CLASSA_NET;
+ else if (IN_CLASSB(a))
+ m = IN_CLASSB_NET;
+ else
+ m = IN_CLASSC_NET;
+ return (m);
+}
+
+static void
+domask(char *dst, uint32_t addr, uint32_t mask)
+{
+ int b, i;
+
+ if (!mask || (forgemask(addr) == mask)) {
+ *dst = '\0';
+ return;
+ }
+ i = 0;
+ for (b = 0; b < 32; b++)
+ if (mask & (1 << b)) {
+ int bb;
+
+ i = b;
+ for (bb = b+1; bb < 32; bb++)
+ if (!(mask & (1 << bb))) {
+ i = -1; /* noncontig */
+ break;
+ }
+ break;
+ }
+ if (i == -1)
+ snprintf(dst, sizeof(dst), "&0x%x", mask);
+ else
+ snprintf(dst, sizeof(dst), "/%d", 32-i);
+}
+
+/*
+ * Return the name of the network whose address is given.
+ * The address is assumed to be that of a net or subnet, not a host.
+ */
+char *
+netname(uint32_t in, uint32_t mask)
+{
+ char *cp = 0;
+ static char line[MAXHOSTNAMELEN];
+ struct netent *np = 0;
+ uint32_t net, omask, dmask;
+ uint32_t i;
+
+ i = ntohl(in);
+ dmask = forgemask(i);
+ omask = mask;
+ if (!nflag && i) {
+ net = i & dmask;
+ if (!(np = getnetbyaddr(i, AF_INET)) && net != i)
+ np = getnetbyaddr(net, AF_INET);
+ if (np) {
+ cp = np->n_name;
+ //### trimdomain(cp, strlen(cp));
+ }
+ }
+ if (cp)
+ strlcpy(line, cp, sizeof(line));
+ else {
+ switch (dmask) {
+ case IN_CLASSA_NET:
+ if ((i & IN_CLASSA_HOST) == 0) {
+ snprintf(line, sizeof(line), "%u", C(i >> 24));
+ break;
+ }
+ /* FALLTHROUGH */
+ case IN_CLASSB_NET:
+ if ((i & IN_CLASSB_HOST) == 0) {
+ snprintf(line, sizeof(line), "%u.%u",
+ C(i >> 24), C(i >> 16));
+ break;
+ }
+ /* FALLTHROUGH */
+ case IN_CLASSC_NET:
+ if ((i & IN_CLASSC_HOST) == 0) {
+ snprintf(line, sizeof(line), "%u.%u.%u",
+ C(i >> 24), C(i >> 16), C(i >> 8));
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ snprintf(line, sizeof(line), "%u.%u.%u.%u",
+ C(i >> 24), C(i >> 16), C(i >> 8), C(i));
+ break;
+ }
+ }
+ domask(line+strlen(line), i, omask);
+ return (line);
+}
+
+#ifdef INET6
+char *
+netname6(struct sockaddr_in6 *sa6, struct sockaddr *sam)
+{
+ static char line[MAXHOSTNAMELEN];
+ u_char *lim;
+ int masklen, illegal = 0, flag = NI_WITHSCOPEID;
+ struct in6_addr *mask = sam ? &((struct sockaddr_in6 *)sam)->sin6_addr : 0;
+
+ if (sam && sam->sa_len == 0) {
+ masklen = 0;
+ } else if (mask) {
+ u_char *p = (u_char *)mask;
+ for (masklen = 0, lim = p + 16; p < lim; p++) {
+ switch (*p) {
+ case 0xff:
+ masklen += 8;
+ break;
+ case 0xfe:
+ masklen += 7;
+ break;
+ case 0xfc:
+ masklen += 6;
+ break;
+ case 0xf8:
+ masklen += 5;
+ break;
+ case 0xf0:
+ masklen += 4;
+ break;
+ case 0xe0:
+ masklen += 3;
+ break;
+ case 0xc0:
+ masklen += 2;
+ break;
+ case 0x80:
+ masklen += 1;
+ break;
+ case 0x00:
+ break;
+ default:
+ illegal ++;
+ break;
+ }
+ }
+ if (illegal)
+ fprintf(stderr, "illegal prefixlen\n");
+ } else {
+ masklen = 128;
+ }
+ if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr))
+ return("default");
+
+ if (nflag)
+ flag |= NI_NUMERICHOST;
+ getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, sizeof(line),
+ NULL, 0, flag);
+
+ if (nflag)
+ snprintf(&line[strlen(line)], sizeof(line) - strlen(line), "/%d", masklen);
+
+ return line;
+}
+
+char *
+routename6(struct sockaddr_in6 *sa6)
+{
+ static char line[MAXHOSTNAMELEN];
+ int flag = NI_WITHSCOPEID;
+ /* use local variable for safety */
+ struct sockaddr_in6 sa6_local = {sizeof(sa6_local), AF_INET6, };
+
+ sa6_local.sin6_addr = sa6->sin6_addr;
+ sa6_local.sin6_scope_id = sa6->sin6_scope_id;
+
+ if (nflag)
+ flag |= NI_NUMERICHOST;
+
+ getnameinfo((struct sockaddr *)&sa6_local, sa6_local.sin6_len,
+ line, sizeof(line), NULL, 0, flag);
+
+ return line;
+}
+#endif /*INET6*/
+
+/*
+ * Print routing statistics
+ */
+void
+rt_stats(void)
+{
+ struct rtstat rtstat;
+ int rttrash;
+ int mib[6];
+ size_t len;
+
+ mib[0] = CTL_NET;
+ mib[1] = AF_ROUTE;
+ mib[2] = 0;
+ mib[3] = 0;
+ mib[4] = NET_RT_STAT;
+ mib[5] = 0;
+ len = sizeof(struct rtstat);
+ if (sysctl(mib, 6, &rtstat, &len, 0, 0) == -1)
+ return;
+
+ mib[0] = CTL_NET;
+ mib[1] = AF_ROUTE;
+ mib[2] = 0;
+ mib[3] = 0;
+ mib[4] = NET_RT_TRASH;
+ mib[5] = 0;
+ len = sizeof(rttrash);
+ if (sysctl(mib, 6, &rttrash, &len, 0, 0) == -1)
+ return;
+
+ printf("routing:\n");
+
+#define p(f, m) if (rtstat.f || sflag <= 1) \
+ printf(m, rtstat.f, plural(rtstat.f))
+
+ p(rts_badredirect, "\t%u bad routing redirect%s\n");
+ p(rts_dynamic, "\t%u dynamically created route%s\n");
+ p(rts_newgateway, "\t%u new gateway%s due to redirects\n");
+ p(rts_unreach, "\t%u destination%s found unreachable\n");
+ p(rts_wildcard, "\t%u use%s of a wildcard route\n");
+ p(rts_badrtgwroute, "\t%u lookup%s returned indirect "
+ "routes pointing to indirect gateway route\n");
+#undef p
+
+ if (rttrash || sflag <= 1)
+ printf("\t%u route%s not in table but not freed\n",
+ rttrash, plural(rttrash));
+}
+
+void
+upHex(char *p0)
+{
+ char *p = p0;
+
+ for (; *p; p++)
+ switch (*p) {
+
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ *p += ('A' - 'a');
+ break;
+ }
+}
diff --git a/network_cmds/netstat.tproj/systm.c b/network_cmds/netstat.tproj/systm.c
new file mode 100644
index 0000000..3e076ca
--- /dev/null
+++ b/network_cmds/netstat.tproj/systm.c
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) 2014-2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+#include <sys/sys_domain.h>
+#include <sys/kern_control.h>
+#include <sys/kern_event.h>
+#include <net/ntstat.h>
+
+#include <errno.h>
+#include <err.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include "netstat.h"
+
+#define ROUNDUP64(a) \
+((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint64_t) - 1))) : sizeof(uint64_t))
+#define ADVANCE64(x, n) (((char *)x) += ROUNDUP64(n))
+
+struct xgen_n {
+ u_int32_t xgn_len; /* length of this structure */
+ u_int32_t xgn_kind; /* number of PCBs at this time */
+};
+
+#define ALL_XGN_KIND_KCREG (XSO_KCREG)
+#define ALL_XGN_KIND_EVT (XSO_SOCKET | XSO_RCVBUF | XSO_SNDBUF | XSO_STATS | XSO_EVT)
+#define ALL_XGN_KIND_KCB (XSO_SOCKET | XSO_RCVBUF | XSO_SNDBUF | XSO_STATS | XSO_KCB)
+
+void
+systmpr(uint32_t proto,
+ char *name, int af)
+{
+ const char *mibvar;
+ size_t len;
+ char *buf, *next;
+ struct xsystmgen *xig, *oxig;
+ struct xgen_n *xgn;
+ int which = 0;
+ struct xsocket_n *so = NULL;
+ struct xsockbuf_n *so_rcv = NULL;
+ struct xsockbuf_n *so_snd = NULL;
+ struct xsockstat_n *so_stat = NULL;
+ struct xkctl_reg *kctl = NULL;
+ struct xkctlpcb *kcb = NULL;
+ struct xkevtpcb *kevb = NULL;
+ int first = 1;
+
+ switch (proto) {
+ case SYSPROTO_EVENT:
+ mibvar = "net.systm.kevt.pcblist";
+ break;
+ case SYSPROTO_CONTROL:
+ mibvar = "net.systm.kctl.pcblist";
+ break;
+ case 0:
+ mibvar = "net.systm.kctl.reg_list";
+ break;
+ default:
+ mibvar = NULL;
+ break;
+ }
+ if (mibvar == NULL)
+ return;
+ len = 0;
+ if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
+ if (errno != ENOENT)
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+ if ((buf = malloc(len)) == 0) {
+ warn("malloc %lu bytes", (u_long)len);
+ return;
+ }
+ if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ free(buf);
+ return;
+ }
+ /*
+ * Bail-out to avoid logic error in the loop below when
+ * there is in fact no more control block to process
+ */
+ if (len <= sizeof(struct xsystmgen)) {
+ free(buf);
+ return;
+ }
+ oxig = xig = (struct xsystmgen *)buf;
+ for (next = buf + ROUNDUP64(xig->xg_len); next < buf + len;
+ next += ROUNDUP64(xgn->xgn_len)) {
+ xgn = (struct xgen_n*)next;
+ if (xgn->xgn_len <= sizeof(struct xsystmgen))
+ break;
+
+ if ((which & xgn->xgn_kind) == 0) {
+ which |= xgn->xgn_kind;
+ switch (xgn->xgn_kind) {
+ case XSO_SOCKET:
+ so = (struct xsocket_n *)xgn;
+ break;
+ case XSO_RCVBUF:
+ so_rcv = (struct xsockbuf_n *)xgn;
+ break;
+ case XSO_SNDBUF:
+ so_snd = (struct xsockbuf_n *)xgn;
+ break;
+ case XSO_STATS:
+ so_stat = (struct xsockstat_n *)xgn;
+ break;
+ case XSO_KCREG:
+ kctl = (struct xkctl_reg *)xgn;
+ break;
+ case XSO_KCB:
+ kcb = (struct xkctlpcb *)xgn;
+ break;
+ case XSO_EVT:
+ kevb = (struct xkevtpcb *)xgn;
+ break;
+ default:
+ printf("unexpected kind %d\n", xgn->xgn_kind);
+ break;
+ }
+ } else {
+ if (vflag)
+ printf("got %d twice\n", xgn->xgn_kind);
+ }
+
+ if (which == ALL_XGN_KIND_KCREG) {
+ which = 0;
+
+ if (first) {
+ printf("Registered kernel control modules\n");
+ if (Aflag)
+ printf("%-16.16s ", "kctlref");
+ printf("%-8.8s ", "id");
+ if (Aflag)
+ printf("%-8.8s ", "unit");
+ printf("%-8.8s ", "flags");
+ printf("%-8.8s ", "pcbcount");
+ printf("%-8.8s ", "rcvbuf");
+ printf("%-8.8s ", "sndbuf");
+ printf("%s ", "name");
+ printf("\n");
+ first = 0;
+ }
+ if (Aflag)
+ printf("%16llx ", kctl->xkr_kctlref);
+ printf("%8x ", kctl->xkr_id);
+ if (Aflag)
+ printf("%8d ", kctl->xkr_reg_unit);
+ printf("%8x ", kctl->xkr_flags);
+ printf("%8d ", kctl->xkr_pcbcount);
+ printf("%8d ", kctl->xkr_recvbufsize);
+ printf("%8d ", kctl->xkr_sendbufsize);
+ printf("%s ", kctl->xkr_name);
+ printf("\n");
+ } else if (which == ALL_XGN_KIND_KCB) {
+ which = 0;
+
+ if (first) {
+ printf("Active kernel control sockets\n");
+ if (Aflag)
+ printf("%16.16s ", "pcb");
+ printf("%-5.5s %-6.6s %-6.6s ",
+ "Proto", "Recv-Q", "Send-Q");
+ if (bflag > 0)
+ printf("%10.10s %10.10s ",
+ "rxbytes", "txbytes");
+ if (vflag > 0)
+ printf("%6.6s %6.6s %6.6s %6.6s ",
+ "rhiwat", "shiwat", "pid", "epid");
+ printf("%6.6s ", "unit");
+ printf("%6.6s ", "id");
+ printf("%s", "name");
+ printf("\n");
+ first = 0;
+ }
+ if (Aflag)
+ printf("%16llx ", kcb->xkp_kctpcb);
+ printf("%-5.5s %6u %6u ", name,
+ so_rcv->sb_cc,
+ so_snd->sb_cc);
+ if (bflag > 0) {
+ int i;
+ u_int64_t rxbytes = 0;
+ u_int64_t txbytes = 0;
+
+ for (i = 0; i < SO_TC_STATS_MAX; i++) {
+ rxbytes += so_stat->xst_tc_stats[i].rxbytes;
+ txbytes += so_stat->xst_tc_stats[i].txbytes;
+ }
+ printf("%10llu %10llu ", rxbytes, txbytes);
+ }
+ if (vflag > 0) {
+ printf("%6u %6u %6u %6u ",
+ so_rcv->sb_hiwat,
+ so_snd->sb_hiwat,
+ so->so_last_pid,
+ so->so_e_pid);
+ }
+ printf("%6d ", kcb->xkp_unit);
+ printf("%6d ", kcb->xkp_kctlid);
+ printf("%s", kcb->xkp_kctlname);
+ printf("\n");
+
+ } else if (which == ALL_XGN_KIND_EVT) {
+ which = 0;
+ if (first) {
+ printf("Active kernel event sockets\n");
+ if (Aflag)
+ printf("%16.16s ", "pcb");
+ printf("%-5.5s %-6.6s %-6.6s ",
+ "Proto", "Recv-Q", "Send-Q");
+ printf("%6.6s ", "vendor");
+ printf("%6.6s ", "class");
+ printf("%6.6s", "subclass");
+ if (bflag > 0)
+ printf("%10.10s %10.10s ",
+ "rxbytes", "txbytes");
+ if (vflag > 0)
+ printf("%6.6s %6.6s %6.6s %6.6s",
+ "rhiwat", "shiwat", "pid", "epid");
+ printf("\n");
+ first = 0;
+ }
+ if (Aflag)
+ printf("%16llx ", kevb->kep_evtpcb);
+ printf("%-5.5s %6u %6u ", name,
+ so_rcv->sb_cc,
+ so_snd->sb_cc);
+ printf("%6d ", kevb->kep_vendor_code_filter);
+ printf("%6d ", kevb->kep_class_filter);
+ printf("%6d", kevb->kep_subclass_filter);
+ if (bflag > 0) {
+ int i;
+ u_int64_t rxbytes = 0;
+ u_int64_t txbytes = 0;
+
+ for (i = 0; i < SO_TC_STATS_MAX; i++) {
+ rxbytes += so_stat->xst_tc_stats[i].rxbytes;
+ txbytes += so_stat->xst_tc_stats[i].txbytes;
+ }
+ printf("%10llu %10llu ", rxbytes, txbytes);
+ }
+ if (vflag > 0) {
+ printf("%6u %6u %6u %6u",
+ so_rcv->sb_hiwat,
+ so_snd->sb_hiwat,
+ so->so_last_pid,
+ so->so_e_pid);
+ }
+ printf("\n");
+ }
+
+ }
+ if (xig != oxig && xig->xg_gen != oxig->xg_gen) {
+ if (oxig->xg_count > xig->xg_count) {
+ printf("Some %s sockets may have been deleted.\n",
+ name);
+ } else if (oxig->xg_count < xig->xg_count) {
+ printf("Some %s sockets may have been created.\n",
+ name);
+ } else {
+ printf("Some %s sockets may have been created or deleted",
+ name);
+ }
+ }
+ free(buf);
+}
+
+void
+kctl_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct kctlstat pkctlstat;
+ struct kctlstat kctlstat;
+ size_t len = sizeof(struct kctlstat);
+ const char *mibvar = "net.systm.kctl.stats";
+
+ if (sysctlbyname(mibvar, &kctlstat, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+ if (interval && vflag > 0)
+ print_time();
+ printf ("%s:\n", name);
+
+#define STATDIFF(f) (kctlstat.f - pkctlstat.f)
+#define p(f, m) if (STATDIFF(f) || sflag <= 1) \
+ printf(m, STATDIFF(f), plural(STATDIFF(f)))
+#define p1a(f, m) if (STATDIFF(f) || sflag <= 1) \
+ printf(m, STATDIFF(f))
+
+ p(kcs_reg_total, "\t%llu total kernel control module%s registered\n");
+ p(kcs_reg_count, "\t%llu current kernel control module%s registered\n");
+ p(kcs_pcbcount, "\t%llu current kernel control socket%s\n");
+ p1a(kcs_gencnt, "\t%llu kernel control generation count\n");
+ p(kcs_connections, "\t%llu connection attempt%s\n");
+ p(kcs_conn_fail, "\t%llu connection failure%s\n");
+ p(kcs_send_fail, "\t%llu send failure%s\n");
+ p(kcs_send_list_fail, "\t%llu send list failure%s\n");
+ p(kcs_enqueue_fail, "\t%llu enqueue failure%s\n");
+ p(kcs_enqueue_fullsock, "\t%llu packet%s dropped due to full socket buffers\n");
+ p(kcs_bad_kctlref, "\t%llu failure%s with bad kern_ctl_ref\n");
+ p(kcs_tbl_size_too_big, "\t%llu register failure%s because of too many kern_ctl_ref\n");
+ p(kcs_enqdata_mb_alloc_fail, "\t%llu enqueuedata failure%s because could not allocate a packet\n");
+ p(kcs_enqdata_sbappend_fail, "\t%llu enqueuedata failure%s due to full socket buffers\n");
+
+#undef STATDIFF
+#undef p
+#undef p1a
+
+ if (interval > 0)
+ bcopy(&kctlstat, &pkctlstat, len);
+}
+
+void
+kevt_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct kevtstat pkevtstat;
+ struct kevtstat kevtstat;
+ size_t len = sizeof(struct kevtstat);
+ const char *mibvar = "net.systm.kevt.stats";
+
+ if (sysctlbyname(mibvar, &kevtstat, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+ if (interval && vflag > 0)
+ print_time();
+ printf ("%s:\n", name);
+
+#define STATDIFF(f) (kevtstat.f - pkevtstat.f)
+#define p(f, m) if (STATDIFF(f) || sflag <= 1) \
+ printf(m, STATDIFF(f), plural(STATDIFF(f)))
+#define p1a(f, m) if (STATDIFF(f) || sflag <= 1) \
+ printf(m, STATDIFF(f))
+
+ p(kes_pcbcount, "\t%llu current kernel control socket%s\n");
+ p1a(kes_gencnt, "\t%llu kernel control generation count\n");
+ p(kes_badvendor, "\t%llu bad vendor failure%s\n");
+ p(kes_toobig, "\t%llu message too big failure%s\n");
+ p(kes_nomem, "\t%llu out of memory failure%s\n");
+ p(kes_fullsock, "\t%llu message%s dropped due to full socket buffers\n");
+ p(kes_posted, "\t%llu message%s posted\n");
+
+#undef STATDIFF
+#undef p
+#undef p1a
+
+ if (interval > 0)
+ bcopy(&kevtstat, &pkevtstat, len);
+}
+
+void
+print_extbkidle_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct soextbkidlestat psoextbkidlestat;
+ struct soextbkidlestat soextbkidlestat;
+ size_t len = sizeof(struct soextbkidlestat);
+ const char *mibvar = "kern.ipc.extbkidlestat";
+
+ if (sysctlbyname(mibvar, &soextbkidlestat, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+
+#define STATDIFF(f) (soextbkidlestat.f - psoextbkidlestat.f)
+#define p(f, m) if (STATDIFF(f) || sflag <= 1) \
+ printf(m, STATDIFF(f), plural(STATDIFF(f)))
+#define p1a(f, m) if (STATDIFF(f) || sflag <= 1) \
+ printf(m, STATDIFF(f))
+
+ if (interval && vflag > 0)
+ print_time();
+ printf ("%s:\n", name);
+
+ p1a(so_xbkidle_maxperproc, "\t%u max per process\n");
+ p1a(so_xbkidle_time, "\t%u maximum time (seconds)\n");
+ p1a(so_xbkidle_rcvhiwat, "\t%u high water mark\n");
+ p(so_xbkidle_notsupp, "\t%u socket option not supported failure%s\n");
+ p(so_xbkidle_toomany, "\t%u too many sockets failure%s\n");
+ p(so_xbkidle_wantok, "\t%u total socket%s requested OK\n");
+ p(so_xbkidle_active, "\t%u extended bk idle socket%s\n");
+ p(so_xbkidle_nocell, "\t%u no cellular failure%s\n");
+ p(so_xbkidle_notime, "\t%u no time failures%s\n");
+ p(so_xbkidle_forced, "\t%u forced defunct socket%s\n");
+ p(so_xbkidle_resumed, "\t%u resumed socket%s\n");
+ p(so_xbkidle_expired, "\t%u timeout expired failure%s\n");
+ p1a(so_xbkidle_expired, "\t%u timer rescheduled\n");
+ p(so_xbkidle_nodlgtd, "\t%u no delegated failure%s\n");
+
+#undef STATDIFF
+#undef p
+#undef p1a
+}
+
+void
+print_nstat_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct nstat_stats pnstat_stats;
+ struct nstat_stats nstat_stats;
+ size_t len = sizeof(struct nstat_stats);
+ const char *mibvar = "net.stats.stats";
+
+ if (sysctlbyname(mibvar, &nstat_stats, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+
+#define STATDIFF(f) (nstat_stats.f - pnstat_stats.f)
+#define p(f, m) if (STATDIFF(f) || sflag <= 1) \
+printf(m, STATDIFF(f), plural(STATDIFF(f)))
+#define p1a(f, m) if (STATDIFF(f) || sflag <= 1) \
+printf(m, STATDIFF(f))
+
+ if (interval && vflag > 0)
+ print_time();
+ printf ("%s:\n", name);
+
+ p(nstat_successmsgfailures, "\t%u enqueue success message failure%s\n");
+ p(nstat_sendcountfailures, "\t%u enqueue source counts message failure%s\n");
+ p(nstat_sysinfofailures, "\t%u enqueue sysinfo message failure%s\n");
+ p(nstat_srcupatefailures, "\t%u enqueue source udpate message failure%s\n");
+ p(nstat_descriptionfailures, "\t%u enqueue description message failure%s\n");
+ p(nstat_msgremovedfailures, "\t%u enqueue remove message failure%s\n");
+ p(nstat_srcaddedfailures, "\t%u enqueue source added message failure%s\n");
+ p(nstat_msgerrorfailures, "\t%u enqueue error message failure%s\n");
+ p(nstat_copy_descriptor_failures, "\t%u copy descriptor failure%s\n");
+ p(nstat_provider_counts_failures, "\t%u provider counts failure%s\n");
+ p(nstat_control_send_description_failures, "\t%u control send description failure%s\n");
+ p(nstat_control_send_goodbye_failures, "\t%u control send goodbye failure%s\n");
+ p(nstat_flush_accumulated_msgs_failures, "\t%u flush accumulated messages failure%s\n");
+ p(nstat_accumulate_msg_failures, "\t%u accumulated message failure%s\n");
+ p(nstat_control_cleanup_source_failures, "\t%u control cleanup source failure%s\n");
+ p(nstat_handle_msg_failures, "\t%u handle message failure%s\n");
+
+#undef STATDIFF
+#undef p
+#undef p1a
+}
diff --git a/network_cmds/netstat.tproj/tp_astring.c b/network_cmds/netstat.tproj/tp_astring.c
new file mode 100644
index 0000000..af08ceb
--- /dev/null
+++ b/network_cmds/netstat.tproj/tp_astring.c
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)tp_astring.c 8.1 (Berkeley) 6/10/93
+ */
+
+char *tp_sstring[] = {
+"ST_ERROR(0x0)",
+"TP_CLOSED(0x1)",
+"TP_CRSENT(0x2)",
+"TP_AKWAIT(0x3)",
+"TP_OPEN(0x4)",
+"TP_CLOSING(0x5)",
+"TP_REFWAIT(0x6)",
+"TP_LISTENING(0x7)",
+"TP_CONFIRMING(0x8)",
+};
+
+char *tp_estring[] = {
+"TM_inact(0x0)",
+"TM_retrans(0x1)",
+"TM_sendack(0x2)",
+"TM_notused(0x3)",
+"TM_reference(0x4)",
+"TM_data_retrans(0x5)",
+"ER_TPDU(0x6)",
+"CR_TPDU(0x7)",
+"DR_TPDU(0x8)",
+"DC_TPDU(0x9)",
+"CC_TPDU(0xa)",
+"AK_TPDU(0xb)",
+"DT_TPDU(0xc)",
+"XPD_TPDU(0xd)",
+"XAK_TPDU(0xe)",
+"T_CONN_req(0xf)",
+"T_DISC_req(0x10)",
+"T_LISTEN_req(0x11)",
+"T_DATA_req(0x12)",
+"T_XPD_req(0x13)",
+"T_USR_rcvd(0x14)",
+"T_USR_Xrcvd(0x15)",
+"T_DETACH(0x16)",
+"T_NETRESET(0x17)",
+"T_ACPT_req(0x18)",
+};
diff --git a/network_cmds/netstat.tproj/unix.c b/network_cmds/netstat.tproj/unix.c
new file mode 100644
index 0000000..eece65a
--- /dev/null
+++ b/network_cmds/netstat.tproj/unix.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Display protocol blocks in the unix domain.
+ */
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/mbuf.h>
+#include <sys/sysctl.h>
+#include <sys/un.h>
+#include <sys/unpcb.h>
+
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <err.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "netstat.h"
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+static void unixdomainpr __P((struct xunpcb64 *, struct xsocket64 *));
+#else
+static void unixdomainpr __P((struct xunpcb *, struct xsocket *));
+#endif
+
+static const char *const socktype[] =
+ { "#0", "stream", "dgram", "raw" };
+
+void
+unixpr()
+{
+ char *buf;
+ int type;
+ size_t len;
+ struct xunpgen *xug, *oxug;
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ struct xsocket64 *so;
+ struct xunpcb64 *xunp;
+ char mibvar[sizeof "net.local.seqpacket.pcblist64"];
+#else
+ struct xsocket *so;
+ struct xunpcb *xunp;
+ char mibvar[sizeof "net.local.seqpacket.pcblist"];
+#endif
+
+ for (type = SOCK_STREAM; type <= SOCK_RAW; type++) {
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ snprintf(mibvar, sizeof(mibvar), "net.local.%s.pcblist64", socktype[type]);
+#else
+ snprintf(mibvar, sizeof(mibvar), "net.local.%s.pcblist", socktype[type]);
+#endif
+ len = 0;
+ if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
+ if (errno != ENOENT)
+ warn("sysctl: %s", mibvar);
+ continue;
+ }
+ if ((buf = malloc(len)) == 0) {
+ warn("malloc %lu bytes", (u_long)len);
+ return;
+ }
+ if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ free(buf);
+ return;
+ }
+
+ oxug = xug = (struct xunpgen *)buf;
+ for (xug = (struct xunpgen *)((char *)xug + xug->xug_len);
+ xug->xug_len > sizeof(struct xunpgen);
+ xug = (struct xunpgen *)((char *)xug + xug->xug_len)) {
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ xunp = (struct xunpcb64 *)xug;
+#else
+ xunp = (struct xunpcb *)xug;
+#endif
+ so = &xunp->xu_socket;
+
+ /* Ignore PCBs which were freed during copyout. */
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ if (xunp->xunp_gencnt > oxug->xug_gen)
+#else
+ if (xunp->xu_unp.unp_gencnt > oxug->xug_gen)
+#endif
+ continue;
+ unixdomainpr(xunp, so);
+ }
+ if (xug != oxug && xug->xug_gen != oxug->xug_gen) {
+ if (oxug->xug_count > xug->xug_count) {
+ printf("Some %s sockets may have been deleted.\n",
+ socktype[type]);
+ } else if (oxug->xug_count < xug->xug_count) {
+ printf("Some %s sockets may have been created.\n",
+ socktype[type]);
+ } else {
+ printf("Some %s sockets may have been created or deleted\n",
+ socktype[type]);
+ }
+ }
+ free(buf);
+ }
+}
+
+static void
+unixdomainpr(xunp, so)
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ struct xunpcb64 *xunp;
+ struct xsocket64 *so;
+#else
+ struct xunpcb *xunp;
+ struct xsocket *so;
+#endif
+{
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ struct unpcb *unp;
+#endif
+ struct sockaddr_un *sa;
+ static int first = 1;
+
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ sa = &xunp->xu_addr;
+#else
+ unp = &xunp->xu_unp;
+ if (unp->unp_addr)
+ sa = &xunp->xu_addr;
+ else
+ sa = (struct sockaddr_un *)0;
+#endif
+
+ if (first) {
+ printf("Active LOCAL (UNIX) domain sockets\n");
+ printf(
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+"%-16.16s %-6.6s %-6.6s %-6.6s %16.16s %16.16s %16.16s %16.16s Addr\n",
+#else
+"%-8.8s %-6.6s %-6.6s %-6.6s %8.8s %8.8s %8.8s %8.8s Addr\n",
+#endif
+ "Address", "Type", "Recv-Q", "Send-Q",
+ "Inode", "Conn", "Refs", "Nextref");
+ first = 0;
+ }
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ printf("%16lx %-6.6s %6u %6u %16lx %16lx %16lx %16lx",
+ (long)xunp->xu_unpp, socktype[so->so_type], so->so_rcv.sb_cc,
+ so->so_snd.sb_cc,
+ (long)xunp->xunp_vnode, (long)xunp->xunp_conn,
+ (long)xunp->xunp_refs, (long)xunp->xunp_reflink.le_next);
+#else
+ printf("%8lx %-6.6s %6u %6u %8lx %8lx %8lx %8lx",
+ (long)so->so_pcb, socktype[so->so_type], so->so_rcv.sb_cc,
+ so->so_snd.sb_cc,
+ (long)unp->unp_vnode, (long)unp->unp_conn,
+ (long)unp->unp_refs.lh_first, (long)unp->unp_reflink.le_next);
+#endif
+
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ if (sa->sun_len)
+#else
+ if (sa)
+#endif
+ printf(" %.*s",
+ (int)(sa->sun_len - offsetof(struct sockaddr_un, sun_path)),
+ sa->sun_path);
+ putchar('\n');
+}
diff --git a/network_cmds/netstat.tproj/vsock.c b/network_cmds/netstat.tproj/vsock.c
new file mode 100644
index 0000000..b52dc5e
--- /dev/null
+++ b/network_cmds/netstat.tproj/vsock.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Display protocol blocks in the vsock domain.
+ */
+#include <sys/proc_info.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+#include <sys/vsock.h>
+
+#include <errno.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "netstat.h"
+
+#ifdef AF_VSOCK
+
+static void vsockdomainpr __P((struct xvsockpcb *));
+
+void
+vsockpr(uint32_t proto,
+char *name, int af)
+{
+ char *buf, *next;
+ size_t len;
+ struct xvsockpgen *xvg, *oxvg;
+ struct xvsockpcb *xpcb;
+
+ const char* mibvar = "net.vsock.pcblist";
+ len = 0;
+ if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
+ if (errno != ENOENT)
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+ if ((buf = malloc(len)) == 0) {
+ warn("malloc %lu bytes", (u_long)len);
+ return;
+ }
+ if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ free(buf);
+ return;
+ }
+
+ /*
+ * Bail-out to avoid logic error in the loop below when
+ * there is in fact no more control block to process
+ */
+ if (len <= 2 * sizeof(struct xvsockpgen)) {
+ free(buf);
+ return;
+ }
+
+ oxvg = (struct xvsockpgen *)buf;
+
+ // Save room for the last xvsockpgen.
+ len -= oxvg->xvg_len;
+
+ for (next = buf + oxvg->xvg_len; next < buf + len; next += xpcb->xv_len) {
+ xpcb = (struct xvsockpcb *)next;
+
+ /* Ignore PCBs which were freed during copyout. */
+ if (xpcb->xvp_gencnt > oxvg->xvg_gen)
+ continue;
+ vsockdomainpr(xpcb);
+ }
+ xvg = (struct xvsockpgen *)next;
+ if (xvg != oxvg && xvg->xvg_gen != oxvg->xvg_gen) {
+ if (oxvg->xvg_count > xvg->xvg_count) {
+ printf("Some vsock sockets may have been deleted.\n");
+ } else if (oxvg->xvg_count < xvg->xvg_count) {
+ printf("Some vsock sockets may have been created.\n");
+ } else {
+ printf("Some vsock sockets may have been created or deleted.\n");
+ }
+ }
+ free(buf);
+}
+
+static void
+vsock_print_addr(buf, cid, port)
+ char *buf;
+ uint32_t cid;
+ uint32_t port;
+{
+ if (cid == VMADDR_CID_ANY && port == VMADDR_PORT_ANY) {
+ (void) sprintf(buf, "*:*");
+ } else if (cid == VMADDR_CID_ANY) {
+ (void) sprintf(buf, "*:%u", port);
+ } else if (port == VMADDR_PORT_ANY) {
+ (void) sprintf(buf, "%u:*", cid);
+ } else {
+ (void) sprintf(buf, "%u:%u", cid, port);
+ }
+}
+
+static void
+vsockdomainpr(xpcb)
+ struct xvsockpcb *xpcb;
+{
+ static int first = 1;
+
+ if (first) {
+ printf("Active VSock sockets\n");
+ printf("%-5.5s %-6.6s %-6.6s %-6.6s %-18.18s %-18.18s %-11.11s",
+ "Proto", "Type",
+ "Recv-Q", "Send-Q",
+ "Local Address", "Foreign Address",
+ "State");
+ if (vflag > 0)
+ printf(" %10.10s %10.10s %10.10s %10.10s %6.6s %6.6s %6.6s %6s %10s",
+ "rxcnt", "txcnt", "peer_rxcnt", "peer_rxhiwat",
+ "rxhiwat", "txhiwat", "pid", "state", "options");
+ printf("\n");
+ first = 0;
+ }
+
+ struct xsocket *so = &xpcb->xv_socket;
+
+ char srcAddr[50];
+ char dstAddr[50];
+
+ vsock_print_addr(srcAddr, xpcb->xvp_local_cid, xpcb->xvp_local_port);
+ vsock_print_addr(dstAddr, xpcb->xvp_remote_cid, xpcb->xvp_remote_port);
+
+ // Determine the vsock socket state.
+ char *state;
+ if (so->so_state & SOI_S_ISCONNECTING) {
+ state = "CONNECTING";
+ } else if (so->so_state & SOI_S_ISCONNECTED) {
+ state = "ESTABLISHED";
+ } else if (so->so_state & SOI_S_ISDISCONNECTING) {
+ state = "CLOSING";
+ } else if (so->so_options & SO_ACCEPTCONN) {
+ state = "LISTEN";
+ } else {
+ state = "CLOSED";
+ }
+
+ printf("%-5.5s %-6.6s %6u %6u %-18s %-18s %-11s",
+ "vsock", "stream",
+ so->so_rcv.sb_cc, so->so_snd.sb_cc,
+ srcAddr, dstAddr,
+ state);
+ if (vflag > 0)
+ printf(" %10u %10u %10u %10u %6u %6u %6u 0x%04x 0x%08x",
+ xpcb->xvp_rxcnt,
+ xpcb->xvp_txcnt,
+ xpcb->xvp_peer_rxcnt,
+ xpcb->xvp_peer_rxhiwat,
+ so->so_rcv.sb_hiwat,
+ so->so_snd.sb_hiwat,
+ xpcb->xvp_last_pid,
+ so->so_state,
+ so->so_options);
+ printf("\n");
+}
+
+#endif /* AF_VSOCK */