summaryrefslogtreecommitdiff
path: root/usr.bin/netstat
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
commitd6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch)
treeece253b876159b39c620e62b6c9b1174642e070e /usr.bin/netstat
initial import of NetBSD tree
Diffstat (limited to 'usr.bin/netstat')
-rw-r--r--usr.bin/netstat/Makefile13
-rw-r--r--usr.bin/netstat/if.c395
-rw-r--r--usr.bin/netstat/inet.c502
-rw-r--r--usr.bin/netstat/iso.c845
-rw-r--r--usr.bin/netstat/main.c517
-rw-r--r--usr.bin/netstat/mbuf.c121
-rw-r--r--usr.bin/netstat/mroute.c260
-rw-r--r--usr.bin/netstat/netstat.1296
-rw-r--r--usr.bin/netstat/netstat.h111
-rw-r--r--usr.bin/netstat/ns.c357
-rw-r--r--usr.bin/netstat/route.c676
-rw-r--r--usr.bin/netstat/unix.c140
12 files changed, 4233 insertions, 0 deletions
diff --git a/usr.bin/netstat/Makefile b/usr.bin/netstat/Makefile
new file mode 100644
index 00000000000..b5fc9c34add
--- /dev/null
+++ b/usr.bin/netstat/Makefile
@@ -0,0 +1,13 @@
+# $NetBSD: Makefile,v 1.11 1995/10/03 21:42:34 thorpej Exp $
+# from: @(#)Makefile 8.1 (Berkeley) 6/12/93
+
+PROG= netstat
+SRCS= if.c inet.c iso.c main.c mbuf.c mroute.c ns.c route.c \
+ tp_astring.c unix.c
+.PATH: ${.CURDIR}/../../sys/netiso
+BINGRP= kmem
+BINMODE=2555
+LDADD= -lkvm
+DPADD= ${LIBKVM}
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/netstat/if.c b/usr.bin/netstat/if.c
new file mode 100644
index 00000000000..bb270fe734c
--- /dev/null
+++ b/usr.bin/netstat/if.c
@@ -0,0 +1,395 @@
+/* $NetBSD: if.c,v 1.13 1995/10/03 21:42:36 thorpej 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.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "from: @(#)if.c 8.2 (Berkeley) 2/21/94";
+#else
+static char *rcsid = "$NetBSD: if.c,v 1.13 1995/10/03 21:42:36 thorpej Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#include <netiso/iso.h>
+#include <netiso/iso_var.h>
+#include <arpa/inet.h>
+
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "netstat.h"
+
+#define YES 1
+#define NO 0
+
+static void sidewaysintpr __P((u_int, u_long));
+static void catchalarm __P((int));
+
+/*
+ * Print a description of the network interfaces.
+ */
+void
+intpr(interval, ifnetaddr)
+ int interval;
+ u_long ifnetaddr;
+{
+ struct ifnet ifnet;
+ union {
+ struct ifaddr ifa;
+ struct in_ifaddr in;
+ struct ns_ifaddr ns;
+ struct iso_ifaddr iso;
+ } ifaddr;
+ u_long ifaddraddr;
+ struct sockaddr *sa;
+ char name[16];
+
+ if (ifnetaddr == 0) {
+ printf("ifnet: symbol not defined\n");
+ return;
+ }
+ if (interval) {
+ sidewaysintpr((unsigned)interval, ifnetaddr);
+ return;
+ }
+ if (kread(ifnetaddr, (char *)&ifnetaddr, sizeof ifnetaddr))
+ return;
+ printf("%-5.5s %-5.5s %-11.11s %-15.15s %10.10s %5.5s %8.8s %5.5s",
+ "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs",
+ "Opkts", "Oerrs");
+ printf(" %5s", "Coll");
+ if (tflag)
+ printf(" %s", "Time");
+ if (dflag)
+ printf(" %s", "Drop");
+ putchar('\n');
+ ifaddraddr = 0;
+ while (ifnetaddr || ifaddraddr) {
+ struct sockaddr_in *sin;
+ register char *cp;
+ int n, m;
+
+ if (ifaddraddr == 0) {
+ if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet) ||
+ kread((u_long)ifnet.if_name, name, 16))
+ return;
+ name[15] = '\0';
+ ifnetaddr = (u_long)ifnet.if_list.tqe_next;
+ if (interface != 0 && (strcmp(name, interface) != 0 ||
+ unit != ifnet.if_unit))
+ continue;
+ cp = index(name, '\0');
+ cp += sprintf(cp, "%d", ifnet.if_unit);
+ if ((ifnet.if_flags & IFF_UP) == 0)
+ *cp++ = '*';
+ *cp = '\0';
+ ifaddraddr = (u_long)ifnet.if_addrlist.tqh_first;
+ }
+ printf("%-5.5s %-5d ", name, ifnet.if_mtu);
+ if (ifaddraddr == 0) {
+ printf("%-11.11s ", "none");
+ printf("%-15.15s ", "none");
+ } else {
+ if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) {
+ ifaddraddr = 0;
+ continue;
+ }
+#define CP(x) ((char *)(x))
+ cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) +
+ CP(&ifaddr); sa = (struct sockaddr *)cp;
+ switch (sa->sa_family) {
+ case AF_UNSPEC:
+ printf("%-11.11s ", "none");
+ printf("%-17.17s ", "none");
+ break;
+ case AF_INET:
+ sin = (struct sockaddr_in *)sa;
+#ifdef notdef
+ /* can't use inet_makeaddr because kernel
+ * keeps nets unshifted.
+ */
+ in = inet_makeaddr(ifaddr.in.ia_subnet,
+ INADDR_ANY);
+ printf("%-11.11s ", netname(in.s_addr,
+ ifaddr.in.ia_subnetmask));
+#else
+ printf("%-11.11s ",
+ netname(ifaddr.in.ia_subnet,
+ ifaddr.in.ia_subnetmask));
+#endif
+ printf("%-17.17s ",
+ routename(sin->sin_addr.s_addr));
+
+ if (aflag) {
+ u_long multiaddr;
+ struct in_multi inm;
+
+ multiaddr = (u_long)ifaddr.in.ia_multiaddrs.lh_first;
+ while (multiaddr != 0) {
+ kread(multiaddr, (char *)&inm,
+ sizeof inm);
+ printf("\n%23s %-15.15s ", "",
+ routename(inm.inm_addr.s_addr));
+ multiaddr = (u_long)inm.inm_list.le_next;
+ }
+ }
+ break;
+ case AF_NS:
+ {
+ struct sockaddr_ns *sns =
+ (struct sockaddr_ns *)sa;
+ u_long net;
+ char netnum[8];
+
+ *(union ns_net *) &net = sns->sns_addr.x_net;
+ sprintf(netnum, "%lxH", ntohl(net));
+ upHex(netnum);
+ printf("ns:%-8s ", netnum);
+ printf("%-17s ",
+ ns_phost((struct sockaddr *)sns));
+ }
+ break;
+ case AF_LINK:
+ {
+ struct sockaddr_dl *sdl =
+ (struct sockaddr_dl *)sa;
+ cp = (char *)LLADDR(sdl);
+ n = sdl->sdl_alen;
+ }
+ m = printf("%-11.11s ", "<Link>");
+ 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("%x%c", *cp++ & 0xff,
+ n > 0 ? '.' : ' ');
+ m = 30 - m;
+ while (m-- > 0)
+ putchar(' ');
+ break;
+ }
+ ifaddraddr = (u_long)ifaddr.ifa.ifa_list.tqe_next;
+ }
+ printf("%8d %5d %8d %5d %5d",
+ ifnet.if_ipackets, ifnet.if_ierrors,
+ ifnet.if_opackets, ifnet.if_oerrors,
+ ifnet.if_collisions);
+ if (tflag)
+ printf(" %3d", ifnet.if_timer);
+ if (dflag)
+ printf(" %3d", ifnet.if_snd.ifq_drops);
+ putchar('\n');
+ }
+}
+
+#define MAXIF 10
+struct iftot {
+ char ift_name[16]; /* interface name */
+ int ift_ip; /* input packets */
+ int ift_ie; /* input errors */
+ int ift_op; /* output packets */
+ int ift_oe; /* output errors */
+ int ift_co; /* collisions */
+ int ift_dr; /* drops */
+} iftot[MAXIF];
+
+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.
+ */
+static void
+sidewaysintpr(interval, off)
+ unsigned interval;
+ u_long off;
+{
+ struct ifnet ifnet;
+ u_long firstifnet;
+ register struct iftot *ip, *total;
+ register int line;
+ struct iftot *lastif, *sum, *interesting;
+ int oldmask;
+
+ if (kread(off, (char *)&firstifnet, sizeof (u_long)))
+ return;
+ lastif = iftot;
+ sum = iftot + MAXIF - 1;
+ total = sum - 1;
+ interesting = iftot;
+ for (off = firstifnet, ip = iftot; off;) {
+ char *cp;
+
+ if (kread(off, (char *)&ifnet, sizeof ifnet))
+ break;
+ ip->ift_name[0] = '(';
+ if (kread((u_long)ifnet.if_name, ip->ift_name + 1, 15))
+ break;
+ if (interface && strcmp(ip->ift_name + 1, interface) == 0 &&
+ unit == ifnet.if_unit)
+ interesting = ip;
+ ip->ift_name[15] = '\0';
+ cp = index(ip->ift_name, '\0');
+ sprintf(cp, "%d)", ifnet.if_unit);
+ ip++;
+ if (ip >= iftot + MAXIF - 2)
+ break;
+ off = (u_long)ifnet.if_list.tqe_next;
+ }
+ lastif = ip;
+
+ (void)signal(SIGALRM, catchalarm);
+ signalled = NO;
+ (void)alarm(interval);
+banner:
+ printf(" input %-6.6s output ", interesting->ift_name);
+ if (lastif - iftot > 0) {
+ if (dflag)
+ printf(" ");
+ printf(" input (Total) output");
+ }
+ for (ip = iftot; ip < iftot + MAXIF; ip++) {
+ ip->ift_ip = 0;
+ ip->ift_ie = 0;
+ ip->ift_op = 0;
+ ip->ift_oe = 0;
+ ip->ift_co = 0;
+ ip->ift_dr = 0;
+ }
+ putchar('\n');
+ printf("%8.8s %5.5s %8.8s %5.5s %5.5s ",
+ "packets", "errs", "packets", "errs", "colls");
+ if (dflag)
+ printf("%5.5s ", "drops");
+ if (lastif - iftot > 0)
+ printf(" %8.8s %5.5s %8.8s %5.5s %5.5s",
+ "packets", "errs", "packets", "errs", "colls");
+ if (dflag)
+ printf(" %5.5s", "drops");
+ putchar('\n');
+ fflush(stdout);
+ line = 0;
+loop:
+ sum->ift_ip = 0;
+ sum->ift_ie = 0;
+ sum->ift_op = 0;
+ sum->ift_oe = 0;
+ sum->ift_co = 0;
+ sum->ift_dr = 0;
+ for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) {
+ if (kread(off, (char *)&ifnet, sizeof ifnet)) {
+ off = 0;
+ continue;
+ }
+ if (ip == interesting) {
+ printf("%8d %5d %8d %5d %5d",
+ ifnet.if_ipackets - ip->ift_ip,
+ ifnet.if_ierrors - ip->ift_ie,
+ ifnet.if_opackets - ip->ift_op,
+ ifnet.if_oerrors - ip->ift_oe,
+ ifnet.if_collisions - ip->ift_co);
+ if (dflag)
+ printf(" %5d",
+ ifnet.if_snd.ifq_drops - ip->ift_dr);
+ }
+ ip->ift_ip = ifnet.if_ipackets;
+ ip->ift_ie = ifnet.if_ierrors;
+ ip->ift_op = ifnet.if_opackets;
+ ip->ift_oe = ifnet.if_oerrors;
+ ip->ift_co = ifnet.if_collisions;
+ ip->ift_dr = ifnet.if_snd.ifq_drops;
+ sum->ift_ip += ip->ift_ip;
+ sum->ift_ie += ip->ift_ie;
+ sum->ift_op += ip->ift_op;
+ sum->ift_oe += ip->ift_oe;
+ sum->ift_co += ip->ift_co;
+ sum->ift_dr += ip->ift_dr;
+ off = (u_long)ifnet.if_list.tqe_next;
+ }
+ if (lastif - iftot > 0) {
+ printf(" %8d %5d %8d %5d %5d",
+ sum->ift_ip - total->ift_ip,
+ sum->ift_ie - total->ift_ie,
+ sum->ift_op - total->ift_op,
+ sum->ift_oe - total->ift_oe,
+ sum->ift_co - total->ift_co);
+ if (dflag)
+ printf(" %5d", sum->ift_dr - total->ift_dr);
+ }
+ *total = *sum;
+ putchar('\n');
+ fflush(stdout);
+ line++;
+ oldmask = sigblock(sigmask(SIGALRM));
+ if (! signalled) {
+ sigpause(0);
+ }
+ sigsetmask(oldmask);
+ signalled = NO;
+ (void)alarm(interval);
+ if (line == 21)
+ goto banner;
+ goto loop;
+ /*NOTREACHED*/
+}
+
+/*
+ * Called if an interval expires before sidewaysintpr has completed a loop.
+ * Sets a flag to not wait for the alarm.
+ */
+static void
+catchalarm(signo)
+ int signo;
+{
+ signalled = YES;
+}
diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c
new file mode 100644
index 00000000000..e5ac793a228
--- /dev/null
+++ b/usr.bin/netstat/inet.c
@@ -0,0 +1,502 @@
+/* $NetBSD: inet.c,v 1.14 1995/10/03 21:42:37 thorpej 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.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "from: @(#)inet.c 8.4 (Berkeley) 4/20/94";
+#else
+static char *rcsid = "$NetBSD: inet.c,v 1.14 1995/10/03 21:42:37 thorpej Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#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_timer.h>
+#include <netinet/tcp_var.h>
+#include <netinet/tcp_debug.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "netstat.h"
+
+struct inpcb inpcb;
+struct tcpcb tcpcb;
+struct socket sockb;
+
+char *inetname __P((struct in_addr *));
+void inetprint __P((struct in_addr *, int, char *));
+
+/*
+ * 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.
+ */
+void
+protopr(off, name)
+ u_long off;
+ char *name;
+{
+ struct inpcbtable table;
+ register struct inpcb *head, *next, *prev;
+ struct inpcb inpcb;
+ int istcp;
+ static int first = 1;
+
+ if (off == 0)
+ return;
+ istcp = strcmp(name, "tcp") == 0;
+ kread(off, (char *)&table, sizeof table);
+ prev = head =
+ (struct inpcb *)&((struct inpcbtable *)off)->inpt_queue.cqh_first;
+ next = table.inpt_queue.cqh_first;
+
+ while (next != head) {
+ kread((u_long)next, (char *)&inpcb, sizeof inpcb);
+ if (inpcb.inp_queue.cqe_prev != prev) {
+ printf("???\n");
+ break;
+ }
+ prev = next;
+ next = inpcb.inp_queue.cqe_next;
+
+ if (!aflag &&
+ inet_lnaof(inpcb.inp_laddr) == INADDR_ANY)
+ continue;
+ kread((u_long)inpcb.inp_socket, (char *)&sockb, sizeof (sockb));
+ if (istcp) {
+ kread((u_long)inpcb.inp_ppcb,
+ (char *)&tcpcb, sizeof (tcpcb));
+ }
+ if (first) {
+ printf("Active Internet connections");
+ if (aflag)
+ printf(" (including servers)");
+ putchar('\n');
+ if (Aflag)
+ printf("%-8.8s ", "PCB");
+ printf(Aflag ?
+ "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %s\n" :
+ "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %s\n",
+ "Proto", "Recv-Q", "Send-Q",
+ "Local Address", "Foreign Address", "(state)");
+ first = 0;
+ }
+ if (Aflag)
+ if (istcp)
+ printf("%8x ", inpcb.inp_ppcb);
+ else
+ printf("%8x ", prev);
+ printf("%-5.5s %6d %6d ", name, sockb.so_rcv.sb_cc,
+ sockb.so_snd.sb_cc);
+ inetprint(&inpcb.inp_laddr, (int)inpcb.inp_lport, name);
+ inetprint(&inpcb.inp_faddr, (int)inpcb.inp_fport, name);
+ if (istcp) {
+ if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES)
+ printf(" %d", tcpcb.t_state);
+ else
+ printf(" %s", tcpstates[tcpcb.t_state]);
+ }
+ putchar('\n');
+ }
+}
+
+/*
+ * Dump TCP statistics structure.
+ */
+void
+tcp_stats(off, name)
+ u_long off;
+ char *name;
+{
+ struct tcpstat tcpstat;
+
+ if (off == 0)
+ return;
+ printf ("%s:\n", name);
+ kread(off, (char *)&tcpstat, sizeof (tcpstat));
+
+#define p(f, m) if (tcpstat.f || sflag <= 1) \
+ printf(m, tcpstat.f, plural(tcpstat.f))
+#define p2(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
+ printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2, plural(tcpstat.f2))
+#define p3(f, m) if (tcpstat.f || sflag <= 1) \
+ printf(m, tcpstat.f, plurales(tcpstat.f))
+
+ p(tcps_sndtotal, "\t%d packet%s sent\n");
+ p2(tcps_sndpack,tcps_sndbyte,
+ "\t\t%d data packet%s (%d byte%s)\n");
+ p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
+ "\t\t%d data packet%s (%d byte%s) retransmitted\n");
+ p2(tcps_sndacks, tcps_delack,
+ "\t\t%d ack-only packet%s (%d delayed)\n");
+ p(tcps_sndurg, "\t\t%d URG only packet%s\n");
+ p(tcps_sndprobe, "\t\t%d window probe packet%s\n");
+ p(tcps_sndwinup, "\t\t%d window update packet%s\n");
+ p(tcps_sndctrl, "\t\t%d control packet%s\n");
+ p(tcps_rcvtotal, "\t%d packet%s received\n");
+ p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%d ack%s (for %d byte%s)\n");
+ p(tcps_rcvdupack, "\t\t%d duplicate ack%s\n");
+ p(tcps_rcvacktoomuch, "\t\t%d ack%s for unsent data\n");
+ p2(tcps_rcvpack, tcps_rcvbyte,
+ "\t\t%d packet%s (%d byte%s) received in-sequence\n");
+ p2(tcps_rcvduppack, tcps_rcvdupbyte,
+ "\t\t%d completely duplicate packet%s (%d byte%s)\n");
+ p(tcps_pawsdrop, "\t\t%d old duplicate packet%s\n");
+ p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
+ "\t\t%d packet%s with some dup. data (%d byte%s duped)\n");
+ p2(tcps_rcvoopack, tcps_rcvoobyte,
+ "\t\t%d out-of-order packet%s (%d byte%s)\n");
+ p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
+ "\t\t%d packet%s (%d byte%s) of data after window\n");
+ p(tcps_rcvwinprobe, "\t\t%d window probe%s\n");
+ p(tcps_rcvwinupd, "\t\t%d window update packet%s\n");
+ p(tcps_rcvafterclose, "\t\t%d packet%s received after close\n");
+ p(tcps_rcvbadsum, "\t\t%d discarded for bad checksum%s\n");
+ p(tcps_rcvbadoff, "\t\t%d discarded for bad header offset field%s\n");
+ p(tcps_rcvshort, "\t\t%d discarded because packet too short\n");
+ p(tcps_connattempt, "\t%d connection request%s\n");
+ p(tcps_accepts, "\t%d connection accept%s\n");
+ p(tcps_connects, "\t%d connection%s established (including accepts)\n");
+ p2(tcps_closed, tcps_drops,
+ "\t%d connection%s closed (including %d drop%s)\n");
+ p(tcps_conndrops, "\t%d embryonic connection%s dropped\n");
+ p2(tcps_rttupdated, tcps_segstimed,
+ "\t%d segment%s updated rtt (of %d attempt%s)\n");
+ p(tcps_rexmttimeo, "\t%d retransmit timeout%s\n");
+ p(tcps_timeoutdrop, "\t\t%d connection%s dropped by rexmit timeout\n");
+ p(tcps_persisttimeo, "\t%d persist timeout%s\n");
+ p(tcps_keeptimeo, "\t%d keepalive timeout%s\n");
+ p(tcps_keepprobe, "\t\t%d keepalive probe%s sent\n");
+ p(tcps_keepdrops, "\t\t%d connection%s dropped by keepalive\n");
+ p(tcps_predack, "\t%d correct ACK header prediction%s\n");
+ p(tcps_preddat, "\t%d correct data packet header prediction%s\n");
+ p3(tcps_pcbcachemiss, "\t%d PCB cache miss%s\n");
+#undef p
+#undef p2
+#undef p3
+}
+
+/*
+ * Dump UDP statistics structure.
+ */
+void
+udp_stats(off, name)
+ u_long off;
+ char *name;
+{
+ struct udpstat udpstat;
+ u_long delivered;
+
+ if (off == 0)
+ return;
+ kread(off, (char *)&udpstat, sizeof (udpstat));
+ printf("%s:\n", name);
+#define p(f, m) if (udpstat.f || sflag <= 1) \
+ printf(m, udpstat.f, plural(udpstat.f))
+ p(udps_ipackets, "\t%u datagram%s received\n");
+ p(udps_hdrops, "\t%u with incomplete header\n");
+ p(udps_badlen, "\t%u with bad data length field\n");
+ p(udps_badsum, "\t%u with bad checksum\n");
+ p(udps_noport, "\t%u dropped due to no socket\n");
+ p(udps_noportbcast, "\t%u broadcast/multicast datagram%s dropped due to no socket\n");
+ p(udps_fullsock, "\t%u dropped due to full socket buffers\n");
+ delivered = udpstat.udps_ipackets -
+ udpstat.udps_hdrops -
+ udpstat.udps_badlen -
+ udpstat.udps_badsum -
+ udpstat.udps_noport -
+ udpstat.udps_noportbcast -
+ udpstat.udps_fullsock;
+ if (delivered || sflag <= 1)
+ printf("\t%u delivered\n", delivered);
+ p(udps_opackets, "\t%u datagram%s output\n");
+#undef p
+}
+
+/*
+ * Dump IP statistics structure.
+ */
+void
+ip_stats(off, name)
+ u_long off;
+ char *name;
+{
+ struct ipstat ipstat;
+
+ if (off == 0)
+ return;
+ kread(off, (char *)&ipstat, sizeof (ipstat));
+ printf("%s:\n", name);
+
+#define p(f, m) if (ipstat.f || sflag <= 1) \
+ printf(m, ipstat.f, plural(ipstat.f))
+
+ p(ips_total, "\t%u total packet%s received\n");
+ p(ips_badsum, "\t%u bad header checksum%s\n");
+ p(ips_toosmall, "\t%u with size smaller than minimum\n");
+ p(ips_tooshort, "\t%u with data size < data length\n");
+ p(ips_badhlen, "\t%u with header length < data size\n");
+ p(ips_badlen, "\t%u with data length < header length\n");
+ p(ips_badoptions, "\t%u with bad options\n");
+ p(ips_badvers, "\t%u with incorrect version number\n");
+ p(ips_fragments, "\t%u fragment%s received\n");
+ p(ips_fragdropped, "\t%u fragment%s dropped (dup or out of space)\n");
+ p(ips_badfrags, "\t%u malformed fragment%s dropped\n");
+ p(ips_fragtimeout, "\t%u fragment%s dropped after timeout\n");
+ p(ips_reassembled, "\t%u packet%s reassembled ok\n");
+ p(ips_delivered, "\t%u packet%s for this host\n");
+ p(ips_noproto, "\t%u packet%s for unknown/unsupported protocol\n");
+ p(ips_forward, "\t%u packet%s forwarded\n");
+ p(ips_cantforward, "\t%u packet%s not forwardable\n");
+ p(ips_redirectsent, "\t%u redirect%s sent\n");
+ p(ips_localout, "\t%u packet%s sent from this host\n");
+ p(ips_rawout, "\t%u packet%s sent with fabricated ip header\n");
+ p(ips_odropped, "\t%u output packet%s dropped due to no bufs, etc.\n");
+ p(ips_noroute, "\t%u output packet%s discarded due to no route\n");
+ p(ips_fragmented, "\t%u output datagram%s fragmented\n");
+ p(ips_ofragments, "\t%u fragment%s created\n");
+ p(ips_cantfrag, "\t%u datagram%s that can't be fragmented\n");
+#undef p
+}
+
+static char *icmpnames[] = {
+ "echo reply",
+ "#1",
+ "#2",
+ "destination unreachable",
+ "source quench",
+ "routing redirect",
+ "#6",
+ "#7",
+ "echo",
+ "#9",
+ "#10",
+ "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(off, name)
+ u_long off;
+ char *name;
+{
+ struct icmpstat icmpstat;
+ register int i, first;
+
+ if (off == 0)
+ return;
+ kread(off, (char *)&icmpstat, sizeof (icmpstat));
+ printf("%s:\n", name);
+
+#define p(f, m) if (icmpstat.f || sflag <= 1) \
+ printf(m, icmpstat.f, plural(icmpstat.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 (icmpstat.icps_outhist[i] != 0) {
+ if (first) {
+ printf("\tOutput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %u\n", icmpnames[i],
+ icmpstat.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");
+ for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
+ if (icmpstat.icps_inhist[i] != 0) {
+ if (first) {
+ printf("\tInput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %u\n", icmpnames[i],
+ icmpstat.icps_inhist[i]);
+ }
+ p(icps_reflect, "\t%u message response%s generated\n");
+#undef p
+}
+
+/*
+ * Dump IGMP statistics structure.
+ */
+void
+igmp_stats(off, name)
+ u_long off;
+ char *name;
+{
+ struct igmpstat igmpstat;
+
+ if (off == 0)
+ return;
+ kread(off, (char *)&igmpstat, sizeof (igmpstat));
+ printf("%s:\n", name);
+
+#define p(f, m) if (igmpstat.f || sflag <= 1) \
+ printf(m, igmpstat.f, plural(igmpstat.f))
+#define py(f, m) if (igmpstat.f || sflag <= 1) \
+ printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
+ p(igps_rcv_total, "\t%u message%s received\n");
+ p(igps_rcv_tooshort, "\t%u message%s received with too few bytes\n");
+ p(igps_rcv_badsum, "\t%u message%s received with bad checksum\n");
+ py(igps_rcv_queries, "\t%u membership quer%s received\n");
+ py(igps_rcv_badqueries, "\t%u membership quer%s received with invalid field(s)\n");
+ p(igps_rcv_reports, "\t%u membership report%s received\n");
+ p(igps_rcv_badreports, "\t%u membership report%s received with invalid field(s)\n");
+ p(igps_rcv_ourreports, "\t%u membership report%s received for groups to which we belong\n");
+ p(igps_snd_reports, "\t%u membership report%s sent\n");
+#undef p
+#undef py
+}
+
+/*
+ * Pretty print an Internet address (net address + port).
+ * If the nflag was specified, use numbers instead of names.
+ */
+void
+inetprint(in, port, proto)
+ register struct in_addr *in;
+ int port;
+ char *proto;
+{
+ struct servent *sp = 0;
+ char line[80], *cp;
+ int width;
+
+ sprintf(line, "%.*s.", (Aflag && !nflag) ? 12 : 16, inetname(in));
+ cp = index(line, '\0');
+ if (!nflag && port)
+ sp = getservbyport((int)port, proto);
+ if (sp || port == 0)
+ sprintf(cp, "%.8s", sp ? sp->s_name : "*");
+ else
+ sprintf(cp, "%d", ntohs((u_short)port));
+ width = 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 *
+inetname(inp)
+ struct in_addr *inp;
+{
+ register char *cp;
+ static char line[50];
+ struct hostent *hp;
+ struct netent *np;
+ static char domain[MAXHOSTNAMELEN + 1];
+ static int first = 1;
+
+ if (first && !nflag) {
+ first = 0;
+ if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
+ (cp = index(domain, '.')))
+ (void) strcpy(domain, cp + 1);
+ else
+ domain[0] = 0;
+ }
+ 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) {
+ if ((cp = index(hp->h_name, '.')) &&
+ !strcmp(cp + 1, domain))
+ *cp = 0;
+ cp = hp->h_name;
+ }
+ }
+ }
+ if (inp->s_addr == INADDR_ANY)
+ strcpy(line, "*");
+ else if (cp)
+ strcpy(line, cp);
+ else {
+ inp->s_addr = ntohl(inp->s_addr);
+#define C(x) ((x) & 0xff)
+ sprintf(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/usr.bin/netstat/iso.c b/usr.bin/netstat/iso.c
new file mode 100644
index 00000000000..32fdce09fb3
--- /dev/null
+++ b/usr.bin/netstat/iso.c
@@ -0,0 +1,845 @@
+/* $NetBSD: iso.c,v 1.12 1995/10/03 21:42:38 thorpej 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.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "from: @(#)iso.c 8.1 (Berkeley) 6/6/93";
+#else
+static char *rcsid = "$NetBSD: iso.c,v 1.12 1995/10/03 21:42:38 thorpej Exp $";
+#endif
+#endif /* not lint */
+
+/*******************************************************************************
+ Copyright IBM Corporation 1987
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of IBM not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+*******************************************************************************/
+
+/*
+ * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/mbuf.h>
+#include <sys/time.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <errno.h>
+#include <net/if.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netiso/iso.h>
+#include <netiso/iso_errno.h>
+#include <netiso/clnp.h>
+#include <netiso/esis.h>
+#include <netiso/clnp_stat.h>
+#include <netiso/argo_debug.h>
+#undef satosiso
+#include <netiso/tp_param.h>
+#include <netiso/tp_states.h>
+#include <netiso/tp_pcb.h>
+#include <netiso/tp_stat.h>
+#include <netiso/iso_pcb.h>
+#include <netiso/cltp_var.h>
+#include <netiso/cons.h>
+#ifdef IncStat
+#undef IncStat
+#endif
+#include <netiso/cons_pcb.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "netstat.h"
+
+static void tprintstat __P((struct tp_stat *, int));
+static void isonetprint __P((struct sockaddr_iso *, int));
+static void hexprint __P((int, char *, char *));
+extern void inetprint __P((struct in_addr *, int, char *));
+
+/*
+ * Dump esis stats
+ */
+void
+esis_stats(off, name)
+ u_long off;
+ char *name;
+{
+ struct esis_stat esis_stat;
+
+ if (off == 0 ||
+ kread(off, (char *)&esis_stat, sizeof (struct esis_stat)))
+ return;
+ printf("%s:\n", name);
+ printf("\t%d esh sent, %d esh received\n", esis_stat.es_eshsent,
+ esis_stat.es_eshrcvd);
+ printf("\t%d ish sent, %d ish received\n", esis_stat.es_ishsent,
+ esis_stat.es_ishrcvd);
+ printf("\t%d rd sent, %d rd received\n", esis_stat.es_rdsent,
+ esis_stat.es_rdrcvd);
+ printf("\t%d pdus not sent due to insufficient memory\n",
+ esis_stat.es_nomem);
+ printf("\t%d pdus received with bad checksum\n", esis_stat.es_badcsum);
+ printf("\t%d pdus received with bad version number\n",
+ esis_stat.es_badvers);
+ printf("\t%d pdus received with bad type field\n", esis_stat.es_badtype);
+ printf("\t%d short pdus received\n", esis_stat.es_toosmall);
+}
+
+/*
+ * Dump clnp statistics structure.
+ */
+void
+clnp_stats(off, name)
+ u_long off;
+ char *name;
+{
+ struct clnp_stat clnp_stat;
+
+ if (off == 0 ||
+ kread(off, (char *)&clnp_stat, sizeof (clnp_stat)))
+ return;
+
+ printf("%s:\n\t%d total packets sent\n", name, clnp_stat.cns_sent);
+ printf("\t%d total fragments sent\n", clnp_stat.cns_fragments);
+ printf("\t%d total packets received\n", clnp_stat.cns_total);
+ printf("\t%d with fixed part of header too small\n",
+ clnp_stat.cns_toosmall);
+ printf("\t%d with header length not reasonable\n", clnp_stat.cns_badhlen);
+ printf("\t%d incorrect checksum%s\n",
+ clnp_stat.cns_badcsum, plural(clnp_stat.cns_badcsum));
+ printf("\t%d with unreasonable address lengths\n", clnp_stat.cns_badaddr);
+ printf("\t%d with forgotten segmentation information\n",
+ clnp_stat.cns_noseg);
+ printf("\t%d with an incorrect protocol identifier\n", clnp_stat.cns_noproto);
+ printf("\t%d with an incorrect version\n", clnp_stat.cns_badvers);
+ printf("\t%d dropped because the ttl has expired\n",
+ clnp_stat.cns_ttlexpired);
+ printf("\t%d clnp cache misses\n", clnp_stat.cns_cachemiss);
+ printf("\t%d clnp congestion experience bits set\n",
+ clnp_stat.cns_congest_set);
+ printf("\t%d clnp congestion experience bits received\n",
+ clnp_stat.cns_congest_rcvd);
+}
+/*
+ * Dump CLTP statistics structure.
+ */
+void
+cltp_stats(off, name)
+ u_long off;
+ char *name;
+{
+ struct cltpstat cltpstat;
+
+ if (off == 0 ||
+ kread(off, (char *)&cltpstat, sizeof (cltpstat)))
+ return;
+ printf("%s:\n\t%u incomplete header%s\n", name,
+ cltpstat.cltps_hdrops, plural(cltpstat.cltps_hdrops));
+ printf("\t%u bad data length field%s\n",
+ cltpstat.cltps_badlen, plural(cltpstat.cltps_badlen));
+ printf("\t%u bad checksum%s\n",
+ cltpstat.cltps_badsum, plural(cltpstat.cltps_badsum));
+}
+
+struct tp_pcb tpcb;
+struct isopcb isopcb;
+struct socket sockb;
+union {
+ struct sockaddr_iso siso;
+ char data[128];
+} laddr, faddr;
+#define kget(o, p) \
+ (kread((u_long)(o), (char *)&p, sizeof (p)))
+
+static int first = 1;
+
+/*
+ * Print a summary of connections related to an Internet
+ * protocol. For TP, also give state of connection.
+ * Listening processes (aflag) are suppressed unless the
+ * -a (all) flag is specified.
+ */
+void
+iso_protopr(off, name)
+ u_long off;
+ char *name;
+{
+ struct isopcb cb;
+ register struct isopcb *prev, *next;
+
+ if (off == 0) {
+ printf("%s control block: symbol not in namelist\n", name);
+ return;
+ }
+ if (strcmp(name, "tp") == 0) {
+ tp_protopr(off, name);
+ return;
+ }
+ if (kread(off, (char *)&cb, sizeof(cb)))
+ return;
+ isopcb = cb;
+ prev = (struct isopcb *)off;
+ if (isopcb.isop_next == (struct isopcb *)off)
+ return;
+ while (isopcb.isop_next != (struct isopcb *)off) {
+ next = isopcb.isop_next;
+ kget(next, isopcb);
+ if (isopcb.isop_prev != prev) {
+ printf("prev 0x%x next 0x%x isop_prev 0x%x isop_next 0x%x???\n",
+ prev, next, isopcb.isop_prev, isopcb.isop_next);
+ break;
+ }
+ kget(isopcb.isop_socket, sockb);
+ iso_protopr1((u_long)next, 0);
+ putchar('\n');
+ prev = next;
+ }
+}
+
+void
+iso_protopr1(kern_addr, istp)
+ u_long kern_addr;
+ int istp;
+{
+ if (first) {
+ printf("Active ISO net connections");
+ if (aflag)
+ printf(" (including servers)");
+ putchar('\n');
+ if (Aflag)
+ printf("%-8.8s ", "PCB");
+ printf(Aflag ?
+ "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %s\n" :
+ "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %s\n",
+ "Proto", "Recv-Q", "Send-Q",
+ "Local Address", "Foreign Address", "(state)");
+ first = 0;
+ }
+ if (Aflag)
+ printf("%8x ",
+ (sockb.so_pcb ? (void *)sockb.so_pcb : (void *)kern_addr));
+ printf("%-5.5s %6d %6d ", "tp", sockb.so_rcv.sb_cc, sockb.so_snd.sb_cc);
+ if (istp && tpcb.tp_lsuffixlen) {
+ hexprint(tpcb.tp_lsuffixlen, tpcb.tp_lsuffix, "()");
+ printf("\t");
+ } else if (isopcb.isop_laddr == 0)
+ printf("*.*\t");
+ else {
+ if ((char *)isopcb.isop_laddr == ((char *)kern_addr) +
+ _offsetof(struct isopcb, isop_sladdr))
+ laddr.siso = isopcb.isop_sladdr;
+ else
+ kget(isopcb.isop_laddr, laddr);
+ isonetprint((struct sockaddr_iso *)&laddr, 1);
+ }
+ if (istp && tpcb.tp_fsuffixlen) {
+ hexprint(tpcb.tp_fsuffixlen, tpcb.tp_fsuffix, "()");
+ printf("\t");
+ } else if (isopcb.isop_faddr == 0)
+ printf("*.*\t");
+ else {
+ if ((char *)isopcb.isop_faddr == ((char *)kern_addr) +
+ _offsetof(struct isopcb, isop_sfaddr))
+ faddr.siso = isopcb.isop_sfaddr;
+ else
+ kget(isopcb.isop_faddr, faddr);
+ isonetprint((struct sockaddr_iso *)&faddr, 0);
+ }
+}
+
+void
+tp_protopr(off, name)
+ u_long off;
+ char *name;
+{
+ extern char *tp_sstring[];
+ struct tp_ref *tpr, *tpr_base;
+ struct tp_refinfo tpkerninfo;
+ int size;
+
+ kget(off, tpkerninfo);
+ size = tpkerninfo.tpr_size * sizeof (*tpr);
+ tpr_base = (struct tp_ref *)malloc(size);
+ if (tpr_base == 0)
+ return;
+ kread((u_long)(tpkerninfo.tpr_base), (char *)tpr_base, size);
+ for (tpr = tpr_base; tpr < tpr_base + tpkerninfo.tpr_size; tpr++) {
+ if (tpr->tpr_pcb == 0)
+ continue;
+ kget(tpr->tpr_pcb, tpcb);
+ if (tpcb.tp_state == ST_ERROR)
+ printf("undefined tpcb state: 0x%x\n", tpr->tpr_pcb);
+ if (!aflag &&
+ (tpcb.tp_state == TP_LISTENING ||
+ tpcb.tp_state == TP_CLOSED ||
+ tpcb.tp_state == TP_REFWAIT)) {
+ continue;
+ }
+ kget(tpcb.tp_sock, sockb);
+ if (tpcb.tp_npcb) switch(tpcb.tp_netservice) {
+ case IN_CLNS:
+ tp_inproto((u_long)tpkerninfo.tpr_base);
+ break;
+ default:
+ kget(tpcb.tp_npcb, isopcb);
+ iso_protopr1((u_long)tpcb.tp_npcb, 1);
+ break;
+ }
+ if (tpcb.tp_state >= tp_NSTATES)
+ printf(" %d", tpcb.tp_state);
+ else
+ printf(" %-12.12s", tp_sstring[tpcb.tp_state]);
+ putchar('\n');
+ }
+}
+
+void
+tp_inproto(pcb)
+ u_long pcb;
+{
+ struct inpcb inpcb;
+ kget(tpcb.tp_npcb, inpcb);
+ if (!aflag && inet_lnaof(inpcb.inp_laddr) == INADDR_ANY)
+ return;
+ if (Aflag)
+ printf("%8x ", pcb);
+ printf("%-5.5s %6d %6d ", "tpip",
+ sockb.so_rcv.sb_cc, sockb.so_snd.sb_cc);
+ inetprint(&inpcb.inp_laddr, inpcb.inp_lport, "tp");
+ inetprint(&inpcb.inp_faddr, inpcb.inp_fport, "tp");
+}
+
+/*
+ * Pretty print an iso address (net address + port).
+ * If the nflag was specified, use numbers instead of names.
+ */
+
+#ifdef notdef
+char *
+isonetname(iso)
+ register struct iso_addr *iso;
+{
+ struct sockaddr_iso sa;
+ struct iso_hostent *ihe = 0;
+ struct iso_hostent *iso_gethostentrybyaddr();
+ struct iso_hostent *iso_getserventrybytsel();
+ struct iso_hostent Ihe;
+ static char line[80];
+
+ bzero(line, sizeof(line));
+ if( iso->isoa_afi ) {
+ sa.siso_family = AF_ISO;
+ sa.siso_addr = *iso;
+ sa.siso_tsuffix = 0;
+
+ if (!nflag )
+ ihe = iso_gethostentrybyaddr( &sa, 0, 0 );
+ if( ihe ) {
+ Ihe = *ihe;
+ ihe = &Ihe;
+ sprintf(line, "%s", ihe->isoh_hname);
+ } else {
+ sprintf(line, "%s", iso_ntoa(iso));
+ }
+ } else {
+ sprintf(line, "*");
+ }
+ return line;
+}
+
+static void
+isonetprint(iso, sufx, sufxlen, islocal)
+ register struct iso_addr *iso;
+ char *sufx;
+ u_short sufxlen;
+ int islocal;
+{
+ struct iso_hostent *iso_getserventrybytsel(), *ihe;
+ struct iso_hostent Ihe;
+ char *line, *cp;
+ int Alen = Aflag?18:22;
+
+ line = isonetname(iso);
+ cp = index(line, '\0');
+ ihe = (struct iso_hostent *)0;
+
+ if( islocal )
+ islocal = 20;
+ else
+ islocal = 22 + Alen;
+
+ if(Aflag)
+ islocal += 10 ;
+
+ if(!nflag) {
+ if( (cp -line)>10 ) {
+ cp = line+10;
+ bzero(cp, sizeof(line)-10);
+ }
+ }
+
+ *cp++ = '.';
+ if(sufxlen) {
+ if( !Aflag && !nflag && (ihe=iso_getserventrybytsel(sufx, sufxlen))) {
+ Ihe = *ihe;
+ ihe = &Ihe;
+ }
+ if( ihe && (strlen(ihe->isoh_aname)>0) ) {
+ sprintf(cp, "%s", ihe->isoh_aname);
+ } else {
+ iso_sprinttsel(cp, sufx, sufxlen);
+ }
+ } else
+ sprintf(cp, "*");
+ /*
+ fprintf(stdout, Aflag?" %-18.18s":" %-22.22s", line);
+ */
+
+ if( strlen(line) > Alen ) {
+ fprintf(stdout, " %s", line);
+ fprintf(stdout, "\n %*.s", islocal+Alen," ");
+ } else {
+ fprintf(stdout, " %-*.*s", Alen, Alen,line);
+ }
+}
+#endif
+
+#ifdef notdef
+static void
+x25_protopr(off, name)
+ u_long off;
+ char *name;
+{
+ static char *xpcb_states[] = {
+ "CLOSED",
+ "LISTENING",
+ "CLOSING",
+ "CONNECTING",
+ "ACKWAIT",
+ "OPEN",
+ };
+ register struct isopcb *prev, *next;
+ struct x25_pcb xpcb;
+
+ if (off == 0) {
+ printf("%s control block: symbol not in namelist\n", name);
+ return;
+ }
+ kread(off, &xpcb, sizeof (struct x25_pcb));
+ prev = (struct isopcb *)off;
+ if (xpcb.x_next == (struct isopcb *)off)
+ return;
+ while (xpcb.x_next != (struct isopcb *)off) {
+ next = isopcb.isop_next;
+ kread((u_long)next, &xpcb, sizeof (struct x25_pcb));
+ if (xpcb.x_prev != prev) {
+ printf("???\n");
+ break;
+ }
+ kread((u_long)xpcb.x_socket, &sockb, sizeof (sockb));
+
+ if (!aflag &&
+ xpcb.x_state == LISTENING ||
+ xpcb.x_state == TP_CLOSED ) {
+ prev = next;
+ continue;
+ }
+ if (first) {
+ printf("Active X25 net connections");
+ if (aflag)
+ printf(" (including servers)");
+ putchar('\n');
+ if (Aflag)
+ printf("%-8.8s ", "PCB");
+ printf(Aflag ?
+ "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %s\n" :
+ "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %s\n",
+ "Proto", "Recv-Q", "Send-Q",
+ "Local Address", "Foreign Address", "(state)");
+ first = 0;
+ }
+ printf("%-5.5s %6d %6d ", name, sockb.so_rcv.sb_cc,
+ sockb.so_snd.sb_cc);
+ isonetprint(&xpcb.x_laddr.siso_addr, &xpcb.x_lport,
+ sizeof(xpcb.x_lport), 1);
+ isonetprint(&xpcb.x_faddr.siso_addr, &xpcb.x_fport,
+ sizeof(xpcb.x_lport), 0);
+ if (xpcb.x_state < 0 || xpcb.x_state >= x25_NSTATES)
+ printf(" 0x0x0x0x0x0x0x0x0x%x", xpcb.x_state);
+ else
+ printf(" %-12.12s", xpcb_states[xpcb.x_state]);
+ putchar('\n');
+ prev = next;
+ }
+}
+#endif
+
+struct tp_stat tp_stat;
+
+void
+tp_stats(off, name)
+ caddr_t off, name;
+{
+ if (off == 0) {
+ printf("TP not configured\n\n");
+ return;
+ }
+ printf("%s:\n", name);
+ kget(off, tp_stat);
+ tprintstat(&tp_stat, 8);
+}
+
+#define OUT stdout
+
+static void
+tprintstat(s, indent)
+ register struct tp_stat *s;
+ int indent;
+{
+ fprintf(OUT,
+ "%*sReceiving:\n",indent," ");
+ fprintf(OUT,
+ "\t%*s%d variable parameter%s ignored\n", indent," ",
+ s->ts_param_ignored ,plural(s->ts_param_ignored));
+ fprintf(OUT,
+ "\t%*s%d invalid parameter code%s\n", indent, " ",
+ s->ts_inv_pcode ,plural(s->ts_inv_pcode));
+ fprintf(OUT,
+ "\t%*s%d invalid parameter value%s\n", indent, " ",
+ s->ts_inv_pval ,plural(s->ts_inv_pval));
+ fprintf(OUT,
+ "\t%*s%d invalid dutype%s\n", indent, " ",
+ s->ts_inv_dutype ,plural(s->ts_inv_dutype));
+ fprintf(OUT,
+ "\t%*s%d negotiation failure%s\n", indent, " ",
+ s->ts_negotfailed ,plural(s->ts_negotfailed));
+ fprintf(OUT,
+ "\t%*s%d invalid destination reference%s\n", indent, " ",
+ s->ts_inv_dref ,plural(s->ts_inv_dref));
+ fprintf(OUT,
+ "\t%*s%d invalid suffix parameter%s\n", indent, " ",
+ s->ts_inv_sufx ,plural(s->ts_inv_sufx));
+ fprintf(OUT,
+ "\t%*s%d invalid length\n",indent, " ", s->ts_inv_length);
+ fprintf(OUT,
+ "\t%*s%d invalid checksum%s\n", indent, " ",
+ s->ts_bad_csum ,plural(s->ts_bad_csum));
+ fprintf(OUT,
+ "\t%*s%d DT%s out of order\n", indent, " ",
+ s->ts_dt_ooo ,plural(s->ts_dt_ooo));
+ fprintf(OUT,
+ "\t%*s%d DT%s not in window\n", indent, " ",
+ s->ts_dt_niw ,plural(s->ts_dt_niw));
+ fprintf(OUT,
+ "\t%*s%d duplicate DT%s\n", indent, " ",
+ s->ts_dt_dup ,plural(s->ts_dt_dup));
+ fprintf(OUT,
+ "\t%*s%d XPD%s not in window\n", indent, " ",
+ s->ts_xpd_niw ,plural(s->ts_xpd_niw));
+ fprintf(OUT,
+ "\t%*s%d XPD%s w/o credit to stash\n", indent, " ",
+ s->ts_xpd_dup ,plural(s->ts_xpd_dup));
+ fprintf(OUT,
+ "\t%*s%d time%s local credit reneged\n", indent, " ",
+ s->ts_lcdt_reduced ,plural(s->ts_lcdt_reduced));
+ fprintf(OUT,
+ "\t%*s%d concatenated TPDU%s\n", indent, " ",
+ s->ts_concat_rcvd ,plural(s->ts_concat_rcvd));
+ fprintf(OUT,
+ "%*sSending:\n", indent, " ");
+ fprintf(OUT,
+ "\t%*s%d XPD mark%s discarded\n", indent, " ",
+ s->ts_xpdmark_del ,plural(s->ts_xpdmark_del));
+ fprintf(OUT,
+ "\t%*sXPD stopped data flow %d time%s\n", indent, " ",
+ s->ts_xpd_intheway ,plural(s->ts_xpd_intheway));
+ fprintf(OUT,
+ "\t%*s%d time%s foreign window closed\n", indent, " ",
+ s->ts_zfcdt ,plural(s->ts_zfcdt));
+ fprintf(OUT,
+ "%*sMiscellaneous:\n", indent, " ");
+ fprintf(OUT,
+ "\t%*s%d small mbuf%s\n", indent, " ",
+ s->ts_mb_small ,plural(s->ts_mb_small));
+ fprintf(OUT,
+ "\t%*s%d cluster%s\n", indent, " ",
+ s->ts_mb_cluster, plural(s->ts_mb_cluster));
+ fprintf(OUT,
+ "\t%*s%d source quench \n",indent, " ",
+ s->ts_quench);
+ fprintf(OUT,
+ "\t%*s%d dec bit%s\n", indent, " ",
+ s->ts_rcvdecbit, plural(s->ts_rcvdecbit));
+ fprintf(OUT,
+ "\t%*sM:L ( M mbuf chains of length L)\n", indent, " ");
+ {
+ register int j;
+
+ fprintf(OUT, "\t%*s%d: over 16\n", indent, " ",
+ s->ts_mb_len_distr[0]);
+ for( j=1; j<=8; j++) {
+ fprintf(OUT,
+ "\t%*s%d: %d\t\t%d: %d\n", indent, " ",
+ s->ts_mb_len_distr[j],j,
+ s->ts_mb_len_distr[j<<1],j<<1
+ );
+ }
+ }
+ fprintf(OUT,
+ "\t%*s%d EOT rcvd\n", indent, " ", s->ts_eot_input);
+ fprintf(OUT,
+ "\t%*s%d EOT sent\n", indent, " ", s->ts_EOT_sent);
+ fprintf(OUT,
+ "\t%*s%d EOT indication%s\n", indent, " ",
+ s->ts_eot_user ,plural(s->ts_eot_user));
+
+ fprintf(OUT,
+ "%*sConnections:\n", indent, " ");
+ fprintf(OUT,
+ "\t%*s%d connection%s used extended format\n", indent, " ",
+ s->ts_xtd_fmt ,plural(s->ts_xtd_fmt));
+ fprintf(OUT,
+ "\t%*s%d connection%s allowed transport expedited data\n", indent, " ",
+ s->ts_use_txpd ,plural(s->ts_use_txpd));
+ fprintf(OUT,
+ "\t%*s%d connection%s turned off checksumming\n", indent, " ",
+ s->ts_csum_off ,plural(s->ts_csum_off));
+ fprintf(OUT,
+ "\t%*s%d connection%s dropped due to retrans limit\n", indent, " ",
+ s->ts_conn_gaveup ,plural(s->ts_conn_gaveup));
+ fprintf(OUT,
+ "\t%*s%d tp 4 connection%s\n", indent, " ",
+ s->ts_tp4_conn ,plural(s->ts_tp4_conn));
+ fprintf(OUT,
+ "\t%*s%d tp 0 connection%s\n", indent, " ",
+ s->ts_tp0_conn ,plural(s->ts_tp0_conn));
+ {
+ register int j;
+ static char *name[]= {
+ "~LOCAL, PDN",
+ "~LOCAL,~PDN",
+ " LOCAL,~PDN",
+ " LOCAL, PDN"
+ };
+
+ fprintf(OUT,
+ "\n%*sRound trip times, listed in ticks:\n", indent, " ");
+ fprintf(OUT,
+ "\t%*s%11.11s %12.12s | %12.12s | %s\n", indent, " ",
+ "Category",
+ "Smoothed avg", "Deviation", "Deviation/Avg");
+ for (j = 0; j <= 3; j++) {
+ fprintf(OUT,
+ "\t%*s%11.11s: %-11d | %-11d | %-11d | %-11d\n", indent, " ",
+ name[j],
+ s->ts_rtt[j],
+ s->ts_rtt[j],
+ s->ts_rtv[j],
+ s->ts_rtv[j]);
+ }
+ }
+ fprintf(OUT,
+"\n%*sTpdus RECVD [%d valid, %3.6f %% of total (%d); %d dropped]\n",indent," ",
+ s->ts_tpdu_rcvd ,
+ ((s->ts_pkt_rcvd > 0) ?
+ ((100 * (float)s->ts_tpdu_rcvd)/(float)s->ts_pkt_rcvd)
+ : 0),
+ s->ts_pkt_rcvd,
+ s->ts_recv_drop );
+
+ fprintf(OUT,
+ "\t%*sDT %6d AK %6d DR %4d CR %4d \n", indent, " ",
+ s->ts_DT_rcvd, s->ts_AK_rcvd, s->ts_DR_rcvd, s->ts_CR_rcvd);
+ fprintf(OUT,
+ "\t%*sXPD %6d XAK %6d DC %4d CC %4d ER %4d\n", indent, " ",
+ s->ts_XPD_rcvd, s->ts_XAK_rcvd, s->ts_DC_rcvd, s->ts_CC_rcvd,
+ s->ts_ER_rcvd);
+ fprintf(OUT,
+ "\n%*sTpdus SENT [%d total, %d dropped]\n", indent, " ",
+ s->ts_tpdu_sent, s->ts_send_drop);
+
+ fprintf(OUT,
+ "\t%*sDT %6d AK %6d DR %4d CR %4d \n", indent, " ",
+ s->ts_DT_sent, s->ts_AK_sent, s->ts_DR_sent, s->ts_CR_sent);
+ fprintf(OUT,
+ "\t%*sXPD %6d XAK %6d DC %4d CC %4d ER %4d\n", indent, " ",
+ s->ts_XPD_sent, s->ts_XAK_sent, s->ts_DC_sent, s->ts_CC_sent,
+ s->ts_ER_sent);
+
+ fprintf(OUT,
+ "\n%*sRetransmissions:\n", indent, " ");
+#define PERCENT(X,Y) (((Y)>0)?((100 *(float)(X)) / (float) (Y)):0)
+
+ fprintf(OUT,
+ "\t%*sCR %6d CC %6d DR %6d \n", indent, " ",
+ s->ts_retrans_cr, s->ts_retrans_cc, s->ts_retrans_dr);
+ fprintf(OUT,
+ "\t%*sDT %6d (%5.2f%%)\n", indent, " ",
+ s->ts_retrans_dt,
+ PERCENT(s->ts_retrans_dt, s->ts_DT_sent));
+ fprintf(OUT,
+ "\t%*sXPD %6d (%5.2f%%)\n", indent, " ",
+ s->ts_retrans_xpd,
+ PERCENT(s->ts_retrans_xpd, s->ts_XPD_sent));
+
+
+ fprintf(OUT,
+ "\n%*sE Timers: [%6d ticks]\n", indent, " ", s->ts_Eticks);
+ fprintf(OUT,
+ "%*s%6d timer%s set \t%6d timer%s expired \t%6d timer%s cancelled\n",indent, " ",
+ s->ts_Eset ,plural(s->ts_Eset),
+ s->ts_Eexpired ,plural(s->ts_Eexpired),
+ s->ts_Ecan_act ,plural(s->ts_Ecan_act));
+
+ fprintf(OUT,
+ "\n%*sC Timers: [%6d ticks]\n", indent, " ",s->ts_Cticks);
+ fprintf(OUT,
+ "%*s%6d timer%s set \t%6d timer%s expired \t%6d timer%s cancelled\n",
+ indent, " ",
+ s->ts_Cset ,plural(s->ts_Cset),
+ s->ts_Cexpired ,plural(s->ts_Cexpired),
+ s->ts_Ccan_act ,plural(s->ts_Ccan_act));
+ fprintf(OUT,
+ "%*s%6d inactive timer%s cancelled\n", indent, " ",
+ s->ts_Ccan_inact ,plural(s->ts_Ccan_inact));
+
+ fprintf(OUT,
+ "\n%*sPathological debugging activity:\n", indent, " ");
+ fprintf(OUT,
+ "\t%*s%6d CC%s sent to zero dref\n", indent, " ",
+ s->ts_zdebug ,plural(s->ts_zdebug));
+ /* SAME LINE AS ABOVE */
+ fprintf(OUT,
+ "\t%*s%6d random DT%s dropped\n", indent, " ",
+ s->ts_ydebug ,plural(s->ts_ydebug));
+ fprintf(OUT,
+ "\t%*s%6d illegally large XPD TPDU%s\n", indent, " ",
+ s->ts_vdebug ,plural(s->ts_vdebug));
+ fprintf(OUT,
+ "\t%*s%6d faked reneging of cdt\n", indent, " ",
+ s->ts_ldebug );
+
+ fprintf(OUT,
+ "\n%*sACK reasons:\n", indent, " ");
+ fprintf(OUT, "\t%*s%6d not acked immediately\n", indent, " ",
+ s->ts_ackreason[_ACK_DONT_] );
+ fprintf(OUT, "\t%*s%6d strategy==each\n", indent, " ",
+ s->ts_ackreason[_ACK_STRAT_EACH_] );
+ fprintf(OUT, "\t%*s%6d strategy==fullwindow\n", indent, " ",
+ s->ts_ackreason[_ACK_STRAT_FULLWIN_] );
+ fprintf(OUT, "\t%*s%6d duplicate DT\n", indent, " ",
+ s->ts_ackreason[_ACK_DUP_] );
+ fprintf(OUT, "\t%*s%6d EOTSDU\n", indent, " ",
+ s->ts_ackreason[_ACK_EOT_] );
+ fprintf(OUT, "\t%*s%6d reordered DT\n", indent, " ",
+ s->ts_ackreason[_ACK_REORDER_] );
+ fprintf(OUT, "\t%*s%6d user rcvd\n", indent, " ",
+ s->ts_ackreason[_ACK_USRRCV_] );
+ fprintf(OUT, "\t%*s%6d fcc reqd\n", indent, " ",
+ s->ts_ackreason[_ACK_FCC_] );
+}
+#ifndef SSEL
+#define SSEL(s) ((s)->siso_tlen + TSEL(s))
+#define PSEL(s) ((s)->siso_slen + SSEL(s))
+#endif
+
+static void
+isonetprint(siso, islocal)
+ register struct sockaddr_iso *siso;
+ int islocal;
+{
+ hexprint(siso->siso_nlen, siso->siso_addr.isoa_genaddr, "{}");
+ if (siso->siso_tlen || siso->siso_slen || siso->siso_plen)
+ hexprint(siso->siso_tlen, TSEL(siso), "()");
+ if (siso->siso_slen || siso->siso_plen)
+ hexprint(siso->siso_slen, SSEL(siso), "[]");
+ if (siso->siso_plen)
+ hexprint(siso->siso_plen, PSEL(siso), "<>");
+ putchar(' ');
+}
+
+static char hexlist[] = "0123456789abcdef", obuf[128];
+
+static void
+hexprint(n, buf, delim)
+ int n;
+ char *buf, *delim;
+{
+ register u_char *in = (u_char *)buf, *top = in + n;
+ register char *out = obuf;
+ register int i;
+
+ if (n == 0)
+ return;
+ while (in < top) {
+ i = *in++;
+ *out++ = '.';
+ if (i > 0xf) {
+ out[1] = hexlist[i & 0xf];
+ i >>= 4;
+ out[0] = hexlist[i];
+ out += 2;
+ } else
+ *out++ = hexlist[i];
+ }
+ *obuf = *delim; *out++ = delim[1]; *out = 0;
+ printf("%s", obuf);
+}
diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c
new file mode 100644
index 00000000000..bb66217ca51
--- /dev/null
+++ b/usr.bin/netstat/main.c
@@ -0,0 +1,517 @@
+/* $NetBSD: main.c,v 1.8 1995/10/03 21:42:40 thorpej Exp $ */
+
+/*
+ * 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 copyright[] =
+"@(#) Copyright (c) 1983, 1988, 1993\n\
+ Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "from: @(#)main.c 8.4 (Berkeley) 3/1/94";
+#else
+static char *rcsid = "$NetBSD: main.c,v 1.8 1995/10/03 21:42:40 thorpej Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <kvm.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"
+
+struct nlist nl[] = {
+#define N_MBSTAT 0
+ { "_mbstat" },
+#define N_IPSTAT 1
+ { "_ipstat" },
+#define N_TCBTABLE 2
+ { "_tcbtable" },
+#define N_TCPSTAT 3
+ { "_tcpstat" },
+#define N_UDBTABLE 4
+ { "_udbtable" },
+#define N_UDPSTAT 5
+ { "_udpstat" },
+#define N_IFNET 6
+ { "_ifnet" },
+#define N_IMP 7
+ { "_imp_softc" },
+#define N_ICMPSTAT 8
+ { "_icmpstat" },
+#define N_RTSTAT 9
+ { "_rtstat" },
+#define N_UNIXSW 10
+ { "_unixsw" },
+#define N_IDP 11
+ { "_nspcb"},
+#define N_IDPSTAT 12
+ { "_idpstat"},
+#define N_SPPSTAT 13
+ { "_spp_istat"},
+#define N_NSERR 14
+ { "_ns_errstat"},
+#define N_CLNPSTAT 15
+ { "_clnp_stat"},
+#define IN_NOTUSED 16
+ { "_tp_inpcb" },
+#define ISO_TP 17
+ { "_tp_refinfo" },
+#define N_TPSTAT 18
+ { "_tp_stat" },
+#define N_ESISSTAT 19
+ { "_esis_stat"},
+#define N_NIMP 20
+ { "_nimp"},
+#define N_RTREE 21
+ { "_rt_tables"},
+#define N_CLTP 22
+ { "_cltb"},
+#define N_CLTPSTAT 23
+ { "_cltpstat"},
+#define N_NFILE 24
+ { "_nfile" },
+#define N_FILE 25
+ { "_file" },
+#define N_IGMPSTAT 26
+ { "_igmpstat" },
+#define N_MRTPROTO 27
+ { "_ip_mrtproto" },
+#define N_MRTSTAT 28
+ { "_mrtstat" },
+#define N_MFCHASHTBL 29
+ { "_mfchashtbl" },
+#define N_MFCHASH 30
+ { "_mfchash" },
+#define N_VIFTABLE 31
+ { "_viftable" },
+ "",
+};
+
+struct protox {
+ u_char pr_index; /* index into nlist of cb head */
+ u_char pr_sindex; /* index into nlist of stat block */
+ u_char pr_wanted; /* 1 if wanted, 0 otherwise */
+ void (*pr_cblocks)(); /* control blocks printing routine */
+ void (*pr_stats)(); /* statistics printing routine */
+ char *pr_name; /* well-known name */
+} protox[] = {
+ { N_TCBTABLE, N_TCPSTAT, 1, protopr,
+ tcp_stats, "tcp" },
+ { N_UDBTABLE, N_UDPSTAT, 1, protopr,
+ udp_stats, "udp" },
+ { -1, N_IPSTAT, 1, 0,
+ ip_stats, "ip" },
+ { -1, N_ICMPSTAT, 1, 0,
+ icmp_stats, "icmp" },
+ { -1, N_IGMPSTAT, 1, 0,
+ igmp_stats, "igmp" },
+ { -1, -1, 0, 0,
+ 0, 0 }
+};
+
+struct protox nsprotox[] = {
+ { N_IDP, N_IDPSTAT, 1, nsprotopr,
+ idp_stats, "idp" },
+ { N_IDP, N_SPPSTAT, 1, nsprotopr,
+ spp_stats, "spp" },
+ { -1, N_NSERR, 1, 0,
+ nserr_stats, "ns_err" },
+ { -1, -1, 0, 0,
+ 0, 0 }
+};
+
+struct protox isoprotox[] = {
+ { ISO_TP, N_TPSTAT, 1, iso_protopr,
+ tp_stats, "tp" },
+ { N_CLTP, N_CLTPSTAT, 1, iso_protopr,
+ cltp_stats, "cltp" },
+ { -1, N_CLNPSTAT, 1, 0,
+ clnp_stats, "clnp"},
+ { -1, N_ESISSTAT, 1, 0,
+ esis_stats, "esis"},
+ { -1, -1, 0, 0,
+ 0, 0 }
+};
+
+struct protox *protoprotox[] = { protox, nsprotox, isoprotox, NULL };
+
+static void printproto __P((struct protox *, char *));
+static void usage __P((void));
+static struct protox *name2protox __P((char *));
+static struct protox *knownname __P((char *));
+
+kvm_t *kvmd;
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ register struct protoent *p;
+ register struct protox *tp; /* for printing cblocks & stats */
+ register char *cp;
+ int ch;
+ char *nlistf = NULL, *memf = NULL;
+ char buf[_POSIX2_LINE_MAX];
+
+ if (cp = rindex(argv[0], '/'))
+ prog = cp + 1;
+ else
+ prog = argv[0];
+ af = AF_UNSPEC;
+
+ while ((ch = getopt(argc, argv, "Aadf:ghI:iM:mN:np:rstuw:")) != EOF)
+ switch(ch) {
+ case 'A':
+ Aflag = 1;
+ break;
+ case 'a':
+ aflag = 1;
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'f':
+ if (strcmp(optarg, "ns") == 0)
+ af = AF_NS;
+ else if (strcmp(optarg, "inet") == 0)
+ af = AF_INET;
+ else if (strcmp(optarg, "unix") == 0)
+ af = AF_UNIX;
+ else if (strcmp(optarg, "iso") == 0)
+ af = AF_ISO;
+ else {
+ (void)fprintf(stderr,
+ "%s: %s: unknown address family\n",
+ prog, optarg);
+ exit(1);
+ }
+ break;
+ case 'g':
+ gflag = 1;
+ break;
+ case 'I': {
+ char *cp;
+
+ iflag = 1;
+ for (cp = interface = optarg; isalpha(*cp); cp++)
+ continue;
+ unit = atoi(cp);
+ *cp = '\0';
+ break;
+ }
+ case 'i':
+ iflag = 1;
+ break;
+ case 'M':
+ memf = optarg;
+ break;
+ case 'm':
+ mflag = 1;
+ break;
+ case 'N':
+ nlistf = optarg;
+ break;
+ case 'n':
+ nflag = 1;
+ break;
+ case 'p':
+ if ((tp = name2protox(optarg)) == NULL) {
+ (void)fprintf(stderr,
+ "%s: %s: unknown or uninstrumented protocol\n",
+ prog, optarg);
+ exit(1);
+ }
+ pflag = 1;
+ break;
+ case 'r':
+ rflag = 1;
+ break;
+ case 's':
+ ++sflag;
+ break;
+ case 't':
+ tflag = 1;
+ break;
+ case 'u':
+ af = AF_UNIX;
+ break;
+ case 'w':
+ interval = atoi(optarg);
+ iflag = 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;
+ }
+ if (*argv) {
+ nlistf = *argv;
+ if (*++argv)
+ memf = *argv;
+ }
+ }
+#endif
+
+ /*
+ * Discard setgid privileges if not the running kernel so that bad
+ * guys can't print interesting stuff from kernel memory.
+ */
+ if (nlistf != NULL || memf != NULL)
+ setgid(getgid());
+
+ if ((kvmd = kvm_open(nlistf, memf, NULL, O_RDONLY, prog)) == NULL) {
+ fprintf(stderr, "%s: kvm_open: %s\n", prog, buf);
+ exit(1);
+ }
+ if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) {
+ if (nlistf)
+ fprintf(stderr, "%s: %s: no namelist\n", prog, nlistf);
+ else
+ fprintf(stderr, "%s: no namelist\n", prog);
+ exit(1);
+ }
+ if (mflag) {
+ mbpr(nl[N_MBSTAT].n_value);
+ exit(0);
+ }
+ if (pflag) {
+ if (tp->pr_stats)
+ (*tp->pr_stats)(nl[tp->pr_sindex].n_value,
+ tp->pr_name);
+ else
+ printf("%s: no stats routine\n", tp->pr_name);
+ exit(0);
+ }
+ /*
+ * Keep file descriptors open to avoid overhead
+ * of open/close on each call to get* routines.
+ */
+ sethostent(1);
+ setnetent(1);
+ if (iflag) {
+ intpr(interval, nl[N_IFNET].n_value);
+ exit(0);
+ }
+ if (rflag) {
+ if (sflag)
+ rt_stats(nl[N_RTSTAT].n_value);
+ else
+ routepr(nl[N_RTREE].n_value);
+ exit(0);
+ }
+ if (gflag) {
+ if (sflag)
+ mrt_stats(nl[N_MRTPROTO].n_value,
+ nl[N_MRTSTAT].n_value);
+ else
+ mroutepr(nl[N_MRTPROTO].n_value,
+ nl[N_MFCHASHTBL].n_value,
+ nl[N_MFCHASH].n_value,
+ nl[N_VIFTABLE].n_value);
+ exit(0);
+ }
+ if (af == AF_INET || af == AF_UNSPEC) {
+ setprotoent(1);
+ setservent(1);
+ /* ugh, this is O(MN) ... why do we do this? */
+ while (p = getprotoent()) {
+ for (tp = protox; tp->pr_name; tp++)
+ if (strcmp(tp->pr_name, p->p_name) == 0)
+ break;
+ if (tp->pr_name == 0 || tp->pr_wanted == 0)
+ continue;
+ printproto(tp, p->p_name);
+ }
+ endprotoent();
+ }
+ if (af == AF_NS || af == AF_UNSPEC)
+ for (tp = nsprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+ if (af == AF_ISO || af == AF_UNSPEC)
+ for (tp = isoprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+ if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag)
+ unixpr(nl[N_UNIXSW].n_value);
+ 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)();
+ u_long off;
+
+ if (sflag) {
+ pr = tp->pr_stats;
+ off = nl[tp->pr_sindex].n_value;
+ } else {
+ pr = tp->pr_cblocks;
+ off = nl[tp->pr_index].n_value;
+ }
+ if (pr != NULL && (off || af != AF_UNSPEC))
+ (*pr)(off, name);
+}
+
+/*
+ * Read kernel memory, return 0 on success.
+ */
+int
+kread(addr, buf, size)
+ u_long addr;
+ char *buf;
+ int size;
+{
+
+ if (kvm_read(kvmd, addr, buf, size) != size) {
+ /* XXX this duplicates kvm_read's error printout */
+ (void)fprintf(stderr, "%s: kvm_read %s\n", prog,
+ kvm_geterr(kvmd));
+ return (-1);
+ }
+ return (0);
+}
+
+char *
+plural(n)
+ int n;
+{
+ return (n != 1 ? "s" : "");
+}
+
+char *
+plurales(n)
+ int n;
+{
+ return (n != 1 ? "es" : "");
+}
+
+/*
+ * Find the protox for the given "well-known" name.
+ */
+static struct protox *
+knownname(name)
+ 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(name)
+ 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))
+ return (tp);
+
+ setprotoent(1); /* make protocol lookup cheaper */
+ while (p = getprotoent()) {
+ /* 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);
+}
+
+static void
+usage()
+{
+ (void)fprintf(stderr,
+"usage: %s [-Aan] [-f address_family] [-M core] [-N system]\n", prog);
+ (void)fprintf(stderr,
+" %s [-ghimnrs] [-f address_family] [-M core] [-N system]\n", prog);
+ (void)fprintf(stderr,
+" %s [-n] [-I interface] [-M core] [-N system] [-w wait]\n", prog);
+ (void)fprintf(stderr,
+" %s [-M core] [-N system] [-p protocol]\n", prog);
+ exit(1);
+}
diff --git a/usr.bin/netstat/mbuf.c b/usr.bin/netstat/mbuf.c
new file mode 100644
index 00000000000..cd521471e91
--- /dev/null
+++ b/usr.bin/netstat/mbuf.c
@@ -0,0 +1,121 @@
+/* $NetBSD: mbuf.c,v 1.8 1995/10/03 21:42:41 thorpej 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.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "from: @(#)mbuf.c 8.1 (Berkeley) 6/6/93";
+#else
+static char *rcsid = "$NetBSD: mbuf.c,v 1.8 1995/10/03 21:42:41 thorpej Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/mbuf.h>
+
+#include <stdio.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_FTABLE, "fragment reassembly queue headers" }, /* XXX */
+ { MT_SONAME, "socket names and addresses" },
+ { MT_SOOPTS, "socket options" },
+ { 0, 0 }
+};
+
+int nmbtypes = sizeof(mbstat.m_mtypes) / sizeof(short);
+bool seen[256]; /* "have we seen this type yet?" */
+
+/*
+ * Print mbuf statistics.
+ */
+void
+mbpr(mbaddr)
+ u_long mbaddr;
+{
+ register int totmem, totfree, totmbufs;
+ register int i;
+ register struct mbtypes *mp;
+
+ if (nmbtypes != 256) {
+ fprintf(stderr,
+ "%s: unexpected change to mbstat; check source\n", prog);
+ return;
+ }
+ if (mbaddr == 0) {
+ fprintf(stderr, "%s: mbstat: symbol not in namelist\n", prog);
+ return;
+ }
+ if (kread(mbaddr, (char *)&mbstat, sizeof (mbstat)))
+ return;
+ totmbufs = 0;
+ for (mp = mbtypes; mp->mt_name; mp++)
+ totmbufs += mbstat.m_mtypes[mp->mt_type];
+ printf("%u mbufs in use:\n", totmbufs);
+ 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);
+ }
+ printf("%u/%u mapped pages in use\n",
+ mbstat.m_clusters - mbstat.m_clfree, mbstat.m_clusters);
+ totmem = totmbufs * MSIZE + mbstat.m_clusters * MCLBYTES;
+ totfree = mbstat.m_clfree * MCLBYTES;
+ printf("%u Kbytes allocated to network (%d%% in use)\n",
+ totmem / 1024, (totmem - totfree) * 100 / totmem);
+ printf("%u requests for memory denied\n", mbstat.m_drops);
+ printf("%u requests for memory delayed\n", mbstat.m_wait);
+ printf("%u calls to protocol drain routines\n", mbstat.m_drain);
+}
diff --git a/usr.bin/netstat/mroute.c b/usr.bin/netstat/mroute.c
new file mode 100644
index 00000000000..a398f6858dd
--- /dev/null
+++ b/usr.bin/netstat/mroute.c
@@ -0,0 +1,260 @@
+/* $NetBSD: mroute.c,v 1.9 1995/10/03 21:42:42 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1989 Stephen Deering
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Stephen Deering of Stanford University.
+ *
+ * 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.
+ *
+ * from: @(#)mroute.c 8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * Print DVMRP multicast routing structures and statistics.
+ *
+ * MROUTING 1.0
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/igmp.h>
+#define _KERNEL
+#include <netinet/ip_mroute.h>
+#undef _KERNEL
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "netstat.h"
+
+char *
+pktscale(n)
+ u_long n;
+{
+ static char buf[8];
+ char t;
+
+ if (n < 1024)
+ t = ' ';
+ else if (n < 1024 * 1024) {
+ t = 'k';
+ n /= 1024;
+ } else {
+ t = 'm';
+ n /= 1048576;
+ }
+
+ sprintf(buf, "%u%c", n, t);
+ return (buf);
+}
+
+void
+mroutepr(mrpaddr, mfchashtbladdr, mfchashaddr, vifaddr)
+ u_long mrpaddr, mfchashtbladdr, mfchashaddr, vifaddr;
+{
+ u_int mrtproto;
+ LIST_HEAD(, mfc) *mfchashtbl;
+ u_long mfchash;
+ struct vif viftable[MAXVIFS];
+ struct mfc *mfcp, mfc;
+ register struct vif *v;
+ register vifi_t vifi;
+ struct in_addr *grp;
+ int i;
+ int banner_printed;
+ int saved_nflag;
+ int numvifs;
+ int nmfc; /* No. of cache entries */
+
+ if (mrpaddr == 0) {
+ printf("ip_mrtproto: symbol not in namelist\n");
+ return;
+ }
+
+ kread(mrpaddr, (char *)&mrtproto, sizeof(mrtproto));
+ switch (mrtproto) {
+ case 0:
+ printf("no multicast routing compiled into this system\n");
+ return;
+
+ case IGMP_DVMRP:
+ break;
+
+ default:
+ printf("multicast routing protocol %u, unknown\n", mrtproto);
+ return;
+ }
+
+ if (mfchashtbladdr == 0) {
+ printf("mfchashtbl: symbol not in namelist\n");
+ return;
+ }
+ if (mfchashaddr == 0) {
+ printf("mfchash: symbol not in namelist\n");
+ return;
+ }
+ if (vifaddr == 0) {
+ printf("viftable: symbol not in namelist\n");
+ return;
+ }
+
+ saved_nflag = nflag;
+ nflag = 1;
+
+ kread(vifaddr, (char *)&viftable, sizeof(viftable));
+ banner_printed = 0;
+ numvifs = 0;
+
+ for (vifi = 0, v = viftable; vifi < MAXVIFS; ++vifi, ++v) {
+ if (v->v_lcl_addr.s_addr == 0)
+ continue;
+ numvifs = vifi;
+
+ if (!banner_printed) {
+ printf("\nVirtual Interface Table\n %s%s",
+ "Vif Thresh Limit Local-Address ",
+ "Remote-Address Pkt_in Pkt_out\n");
+ banner_printed = 1;
+ }
+
+ printf(" %3u %3u %5u %-15.15s",
+ vifi, v->v_threshold, v->v_rate_limit,
+ routename(v->v_lcl_addr.s_addr));
+ printf(" %-15.15s %6u %7u\n", (v->v_flags & VIFF_TUNNEL) ?
+ routename(v->v_rmt_addr.s_addr) : "",
+ v->v_pkt_in, v->v_pkt_out);
+ }
+ if (!banner_printed)
+ printf("\nVirtual Interface Table is empty\n");
+
+ kread(mfchashtbladdr, (char *)&mfchashtbl, sizeof(mfchashtbl));
+ kread(mfchashaddr, (char *)&mfchash, sizeof(mfchash));
+ banner_printed = 0;
+ nmfc = 0;
+
+ for (i = 0; i <= mfchash; ++i) {
+ kread((u_long)&mfchashtbl[i], (char *)&mfcp, sizeof(mfcp));
+
+ for (; mfcp != 0; mfcp = mfc.mfc_hash.le_next) {
+ if (!banner_printed) {
+ printf("\nMulticast Forwarding Cache\n %s%s",
+ "Hash Origin Mcastgroup ",
+ "Traffic In-Vif Out-Vifs/Forw-ttl\n");
+ banner_printed = 1;
+ }
+
+ kread((u_long)mfcp, (char *)&mfc, sizeof(mfc));
+ printf(" %3u %-15.15s",
+ i, routename(mfc.mfc_origin.s_addr));
+ printf(" %-15.15s %7s %3u ",
+ routename(mfc.mfc_mcastgrp.s_addr),
+ pktscale(mfc.mfc_pkt_cnt), mfc.mfc_parent);
+ for (vifi = 0; vifi <= numvifs; ++vifi)
+ if (mfc.mfc_ttls[vifi])
+ printf(" %u/%u", vifi, mfc.mfc_ttls[vifi]);
+
+ printf("\n");
+ nmfc++;
+ }
+ }
+ if (!banner_printed)
+ printf("\nMulticast Forwarding Cache is empty\n");
+ else
+ printf("\nTotal no. of entries in cache: %d\n", nmfc);
+
+ printf("\n");
+ nflag = saved_nflag;
+}
+
+
+void
+mrt_stats(mrpaddr, mstaddr)
+ u_long mrpaddr, mstaddr;
+{
+ u_int mrtproto;
+ struct mrtstat mrtstat;
+
+ if (mrpaddr == 0) {
+ printf("ip_mrtproto: symbol not in namelist\n");
+ return;
+ }
+
+ kread(mrpaddr, (char *)&mrtproto, sizeof(mrtproto));
+ switch (mrtproto) {
+ case 0:
+ printf("no multicast routing compiled into this system\n");
+ return;
+
+ case IGMP_DVMRP:
+ break;
+
+ default:
+ printf("multicast routing protocol %u, unknown\n", mrtproto);
+ return;
+ }
+
+ if (mstaddr == 0) {
+ printf("mrtstat: symbol not in namelist\n");
+ return;
+ }
+
+ kread(mstaddr, (char *)&mrtstat, sizeof(mrtstat));
+ printf("multicast routing:\n");
+ printf("\t%d datagram%s with no route for origin\n",
+ mrtstat.mrts_no_route, plural(mrtstat.mrts_no_route));
+ printf("\t%d upcall%s made to mrouted\n",
+ mrtstat.mrts_upcalls, plural(mrtstat.mrts_upcalls));
+ printf("\t%d datagram%s with malformed tunnel options\n",
+ mrtstat.mrts_bad_tunnel, plural(mrtstat.mrts_bad_tunnel));
+ printf("\t%d datagram%s with no room for tunnel options\n",
+ mrtstat.mrts_cant_tunnel, plural(mrtstat.mrts_cant_tunnel));
+ printf("\t%d datagram%s arrived on wrong interface\n",
+ mrtstat.mrts_wrong_if, plural(mrtstat.mrts_wrong_if));
+ printf("\t%d datagram%s dropped due to upcall Q overflow\n",
+ mrtstat.mrts_upq_ovflw, plural(mrtstat.mrts_upq_ovflw));
+ printf("\t%d datagram%s dropped due to upcall socket overflow\n",
+ mrtstat.mrts_upq_sockfull, plural(mrtstat.mrts_upq_sockfull));
+ printf("\t%d datagram%s cleaned up by the cache\n",
+ mrtstat.mrts_cache_cleanups, plural(mrtstat.mrts_cache_cleanups));
+ printf("\t%d datagram%s dropped selectively by ratelimiter\n",
+ mrtstat.mrts_drop_sel, plural(mrtstat.mrts_drop_sel));
+ printf("\t%d datagram%s dropped - bucket Q overflow\n",
+ mrtstat.mrts_q_overflow, plural(mrtstat.mrts_q_overflow));
+ printf("\t%d datagram%s dropped - larger than bkt size\n",
+ mrtstat.mrts_pkt2large, plural(mrtstat.mrts_pkt2large));
+}
diff --git a/usr.bin/netstat/netstat.1 b/usr.bin/netstat/netstat.1
new file mode 100644
index 00000000000..9fd19213077
--- /dev/null
+++ b/usr.bin/netstat/netstat.1
@@ -0,0 +1,296 @@
+.\" $NetBSD: netstat.1,v 1.11 1995/10/03 21:42:43 thorpej Exp $
+.\"
+.\" 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.
+.\"
+.\" from: @(#)netstat.1 8.8 (Berkeley) 4/18/94
+.\"
+.Dd April 18, 1994
+.Dt NETSTAT 1
+.Os BSD 4.2
+.Sh NAME
+.Nm netstat
+.Nd show network status
+.Sh SYNOPSIS
+.Nm netstat
+.Op Fl Aan
+.Op Fl f Ar address_family
+.Op Fl M Ar core
+.Op Fl N Ar system
+.Nm netstat
+.Op Fl dghimnrs
+.Op Fl f Ar address_family
+.Op Fl M Ar core
+.Op Fl N Ar system
+.Nm netstat
+.Op Fl dn
+.Op Fl I Ar interface
+.Op Fl M Ar core
+.Op Fl N Ar system
+.Op Fl w Ar wait
+.Nm netstat
+.Op Fl p Ar protocol
+.Op Fl M Ar core
+.Op Fl N Ar system
+.Sh DESCRIPTION
+The
+.Nm netstat
+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 netstat
+will continuously display the information regarding packet
+traffic on the configured network interfaces.
+The fourth form displays statistics about the named protocol.
+.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; 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.
+.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 ns ,
+for
+.Dv AF_NS ,
+.Ar iso ,
+for
+.Dv AF_ISO ,
+and
+.Ar unix ,
+for
+.Dv AF_UNIX .
+.It Fl g
+Show information related to multicast (group address) routing.
+By default, show the IP Multicast virtual-interface and routing tables.
+If the
+.Fl s
+option is also present, show multicast routing statistics.
+.It Fl h
+Show the state of the
+.Tn IMP
+host table (obsolete).
+.It Fl I Ar interface
+Show information about the specified interface;
+used with a
+.Ar wait
+interval as described below.
+.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.
+.It Fl M
+Extract values associated with the name list from the specified core
+instead of the default
+.Pa /dev/kmem .
+.It Fl m
+Show statistics recorded by the memory management routines
+(the network manages a private pool of memory buffers).
+.It Fl N
+Extract the name list from the specified system instead of the default
+.Pa /netbsd .
+.It Fl n
+Show network addresses as numbers (normally
+.Nm netstat
+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 .
+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 s
+Show per-protocol statistics.
+If this option is repeated, counters with a value of zero are suppressed.
+.It Fl r
+Show the routing tables.
+When
+.Fl s
+is also present, show routing statistics instead.
+.It Fl w Ar wait
+Show network interface statistics at intervals of
+.Ar wait
+seconds.
+.El
+.Pp
+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 ``host.port'' or ``network.port''
+if a socket's address specifies a network but no specific host address.
+When known the host and network addresses are displayed symbolically
+according to the data bases
+.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 ``dot format,''
+refer to
+.Xr inet 3 ) .
+Unspecified,
+or ``wildcard'', addresses and ports appear as ``*''.
+.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 (``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_PROTO2 Protocol specific routing flag #1
+2 RTF_PROTO1 Protocol specific routing flag #2
+B RTF_BLACKHOLE Just discard pkts (during updates)
+C RTF_CLONING 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)
+L RTF_LLINFO Valid protocol to link address translation.
+M RTF_MODIFIED Modified dynamically (by redirect)
+R RTF_REJECT Host or net unreachable
+S RTF_STATIC Manually added
+U RTF_UP Route usable
+X RTF_XRESOLVE External daemon translates proto to link address
+.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 mtu entry shows the mtu associated with
+that route. This mtu value is used as the basis for the TCP maximum
+segment size. A
+.Sq -
+indicates that the mtu for this route has not been set, and a default
+TCP maximum segment size will be used. The interface entry indicates
+the network interface utilized for the route.
+.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.
+An obsolescent version of this option used a numeric parameter
+with no option, and is currently supported for backward compatibility.
+This display consists of a column for the primary interface (the first
+interface found during autoconfiguration) and a column summarizing
+information for all interfaces.
+The primary interface may be replaced with another interface with the
+.Fl I
+option.
+The first line of each screen of information contains a summary since the
+system was last rebooted. Subsequent lines of output show values
+accumulated over the preceding interval.
+.Sh SEE ALSO
+.Xr nfsstat 1 ,
+.Xr ps 1 ,
+.Xr hosts 5 ,
+.Xr networks 5 ,
+.Xr protocols 5 ,
+.Xr services 5 ,
+.Xr trpt 8 ,
+.Xr trsp 8 ,
+.Xr iostat 8 ,
+.Xr vmstat 8
+.Sh HISTORY
+The
+.Nm netstat
+command appeared in
+.Bx 4.2 .
+.\" .Sh FILES
+.\" .Bl -tag -width /dev/kmem -compact
+.\" .It Pa /netbsd
+.\" default kernel namelist
+.\" .It Pa /dev/kmem
+.\" default memory file
+.\" .El
+.Sh BUGS
+The notion of errors is ill-defined.
diff --git a/usr.bin/netstat/netstat.h b/usr.bin/netstat/netstat.h
new file mode 100644
index 00000000000..aaaae7b225a
--- /dev/null
+++ b/usr.bin/netstat/netstat.h
@@ -0,0 +1,111 @@
+/* $NetBSD: netstat.h,v 1.5 1995/10/03 21:42:45 thorpej Exp $ */
+
+/*
+ * 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.
+ *
+ * from: @(#)netstat.h 8.2 (Berkeley) 1/4/94
+ */
+
+#include <sys/cdefs.h>
+
+int Aflag; /* show addresses of protocol control block */
+int aflag; /* show all sockets (including servers) */
+int dflag; /* show i/f dropped packets */
+int gflag; /* show group (multicast) routing or stats */
+int iflag; /* show interfaces */
+int mflag; /* show memory stats */
+int nflag; /* show addresses numerically */
+int pflag; /* show given protocol */
+int rflag; /* show routing tables (or routing stats) */
+int sflag; /* show protocol statistics */
+int tflag; /* show i/f watchdog timers */
+
+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 */
+
+char *prog; /* program name */
+
+
+int kread __P((u_long addr, char *buf, int size));
+char *plural __P((int));
+char *plurales __P((int));
+
+void protopr __P((u_long, char *));
+void tcp_stats __P((u_long, char *));
+void udp_stats __P((u_long, char *));
+void ip_stats __P((u_long, char *));
+void icmp_stats __P((u_long, char *));
+void igmp_stats __P((u_long, char *));
+void protopr __P((u_long, char *));
+
+void mbpr(u_long);
+
+void hostpr __P((u_long, u_long));
+void impstats __P((u_long, u_long));
+
+void intpr __P((int, u_long));
+
+void pr_rthdr __P(());
+void pr_family __P((int));
+void rt_stats __P((u_long));
+char *ns_phost __P((struct sockaddr *));
+void upHex __P((char *));
+
+char *routename __P((u_int32_t));
+char *netname __P((u_int32_t, u_int32_t));
+char *ns_print __P((struct sockaddr *));
+void routepr __P((u_long));
+
+void nsprotopr __P((u_long, char *));
+void spp_stats __P((u_long, char *));
+void idp_stats __P((u_long, char *));
+void nserr_stats __P((u_long, char *));
+
+void intpr __P((int, u_long));
+
+void unixpr __P((u_long));
+
+void esis_stats __P((u_long, char *));
+void clnp_stats __P((u_long, char *));
+void cltp_stats __P((u_long, char *));
+void iso_protopr __P((u_long, char *));
+void iso_protopr1 __P((u_long, int));
+void tp_protopr __P((u_long, char *));
+void tp_inproto __P((u_long));
+void tp_stats __P((caddr_t, caddr_t));
+
+void mroutepr __P((u_long, u_long, u_long, u_long));
+void mrt_stats __P((u_long, u_long));
diff --git a/usr.bin/netstat/ns.c b/usr.bin/netstat/ns.c
new file mode 100644
index 00000000000..d9c8cf5a52d
--- /dev/null
+++ b/usr.bin/netstat/ns.c
@@ -0,0 +1,357 @@
+/* $NetBSD: ns.c,v 1.8 1995/10/03 21:42:46 thorpej 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.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "from: @(#)ns.c 8.1 (Berkeley) 6/6/93";
+#else
+static char *rcsid = "$NetBSD: ns.c,v 1.8 1995/10/03 21:42:46 thorpej Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+
+#include <net/route.h>
+#include <net/if.h>
+
+#include <netinet/tcp_fsm.h>
+
+#include <netns/ns.h>
+#include <netns/ns_pcb.h>
+#include <netns/idp.h>
+#include <netns/idp_var.h>
+#include <netns/ns_error.h>
+#include <netns/sp.h>
+#include <netns/spidp.h>
+#include <netns/spp_timer.h>
+#include <netns/spp_var.h>
+#define SANAMES
+#include <netns/spp_debug.h>
+
+#include <nlist.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include "netstat.h"
+
+struct nspcb nspcb;
+struct sppcb sppcb;
+struct socket sockb;
+
+static char *ns_prpr __P((struct ns_addr *));
+static void ns_erputil __P((int, int));
+
+static int first = 1;
+
+/*
+ * Print a summary of connections related to a Network Systems
+ * protocol. For SPP, also give state of connection.
+ * Listening processes (aflag) are suppressed unless the
+ * -a (all) flag is specified.
+ */
+
+void
+nsprotopr(off, name)
+ u_long off;
+ char *name;
+{
+ struct nspcb cb;
+ register struct nspcb *prev, *next;
+ int isspp;
+
+ if (off == 0)
+ return;
+ isspp = strcmp(name, "spp") == 0;
+ kread(off, (char *)&cb, sizeof (struct nspcb));
+ nspcb = cb;
+ prev = (struct nspcb *)off;
+ if (nspcb.nsp_next == (struct nspcb *)off)
+ return;
+ for (;nspcb.nsp_next != (struct nspcb *)off; prev = next) {
+ u_long ppcb;
+
+ next = nspcb.nsp_next;
+ kread((u_long)next, (char *)&nspcb, sizeof (nspcb));
+ if (nspcb.nsp_prev != prev) {
+ printf("???\n");
+ break;
+ }
+ if (!aflag && ns_nullhost(nspcb.nsp_faddr) ) {
+ continue;
+ }
+ kread((u_long)nspcb.nsp_socket,
+ (char *)&sockb, sizeof (sockb));
+ ppcb = (u_long) nspcb.nsp_pcb;
+ if (ppcb) {
+ if (isspp) {
+ kread(ppcb, (char *)&sppcb, sizeof (sppcb));
+ } else continue;
+ } else
+ if (isspp) continue;
+ if (first) {
+ printf("Active NS connections");
+ if (aflag)
+ printf(" (including servers)");
+ putchar('\n');
+ if (Aflag)
+ printf("%-8.8s ", "PCB");
+ printf(Aflag ?
+ "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %s\n" :
+ "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %s\n",
+ "Proto", "Recv-Q", "Send-Q",
+ "Local Address", "Foreign Address", "(state)");
+ first = 0;
+ }
+ if (Aflag)
+ printf("%8x ", ppcb);
+ printf("%-5.5s %6d %6d ", name, sockb.so_rcv.sb_cc,
+ sockb.so_snd.sb_cc);
+ printf(" %-22.22s", ns_prpr(&nspcb.nsp_laddr));
+ printf(" %-22.22s", ns_prpr(&nspcb.nsp_faddr));
+ if (isspp) {
+ extern char *tcpstates[];
+ if (sppcb.s_state >= TCP_NSTATES)
+ printf(" %d", sppcb.s_state);
+ else
+ printf(" %s", tcpstates[sppcb.s_state]);
+ }
+ putchar('\n');
+ prev = next;
+ }
+}
+#define ANY(x,y,z) \
+ ((x) ? printf("\t%d %s%s%s -- %s\n",x,y,plural(x),z,"x") : 0)
+
+/*
+ * Dump SPP statistics structure.
+ */
+void
+spp_stats(off, name)
+ u_long off;
+ char *name;
+{
+ struct spp_istat spp_istat;
+#define sppstat spp_istat.newstats
+
+ if (off == 0)
+ return;
+ kread(off, (char *)&spp_istat, sizeof (spp_istat));
+ printf("%s:\n", name);
+ ANY(spp_istat.nonucn, "connection", " dropped due to no new sockets ");
+ ANY(spp_istat.gonawy, "connection", " terminated due to our end dying");
+ ANY(spp_istat.nonucn, "connection",
+ " dropped due to inability to connect");
+ ANY(spp_istat.noconn, "connection",
+ " dropped due to inability to connect");
+ ANY(spp_istat.notme, "connection",
+ " incompleted due to mismatched id's");
+ ANY(spp_istat.wrncon, "connection", " dropped due to mismatched id's");
+ ANY(spp_istat.bdreas, "packet", " dropped out of sequence");
+ ANY(spp_istat.lstdup, "packet", " duplicating the highest packet");
+ ANY(spp_istat.notyet, "packet", " refused as exceeding allocation");
+ ANY(sppstat.spps_connattempt, "connection", " initiated");
+ ANY(sppstat.spps_accepts, "connection", " accepted");
+ ANY(sppstat.spps_connects, "connection", " established");
+ ANY(sppstat.spps_drops, "connection", " dropped");
+ ANY(sppstat.spps_conndrops, "embryonic connection", " dropped");
+ ANY(sppstat.spps_closed, "connection", " closed (includes drops)");
+ ANY(sppstat.spps_segstimed, "packet", " where we tried to get rtt");
+ ANY(sppstat.spps_rttupdated, "time", " we got rtt");
+ ANY(sppstat.spps_delack, "delayed ack", " sent");
+ ANY(sppstat.spps_timeoutdrop, "connection", " dropped in rxmt timeout");
+ ANY(sppstat.spps_rexmttimeo, "retransmit timeout", "");
+ ANY(sppstat.spps_persisttimeo, "persist timeout", "");
+ ANY(sppstat.spps_keeptimeo, "keepalive timeout", "");
+ ANY(sppstat.spps_keepprobe, "keepalive probe", " sent");
+ ANY(sppstat.spps_keepdrops, "connection", " dropped in keepalive");
+ ANY(sppstat.spps_sndtotal, "total packet", " sent");
+ ANY(sppstat.spps_sndpack, "data packet", " sent");
+ ANY(sppstat.spps_sndbyte, "data byte", " sent");
+ ANY(sppstat.spps_sndrexmitpack, "data packet", " retransmitted");
+ ANY(sppstat.spps_sndrexmitbyte, "data byte", " retransmitted");
+ ANY(sppstat.spps_sndacks, "ack-only packet", " sent");
+ ANY(sppstat.spps_sndprobe, "window probe", " sent");
+ ANY(sppstat.spps_sndurg, "packet", " sent with URG only");
+ ANY(sppstat.spps_sndwinup, "window update-only packet", " sent");
+ ANY(sppstat.spps_sndctrl, "control (SYN|FIN|RST) packet", " sent");
+ ANY(sppstat.spps_sndvoid, "request", " to send a non-existant packet");
+ ANY(sppstat.spps_rcvtotal, "total packet", " received");
+ ANY(sppstat.spps_rcvpack, "packet", " received in sequence");
+ ANY(sppstat.spps_rcvbyte, "byte", " received in sequence");
+ ANY(sppstat.spps_rcvbadsum, "packet", " received with ccksum errs");
+ ANY(sppstat.spps_rcvbadoff, "packet", " received with bad offset");
+ ANY(sppstat.spps_rcvshort, "packet", " received too short");
+ ANY(sppstat.spps_rcvduppack, "duplicate-only packet", " received");
+ ANY(sppstat.spps_rcvdupbyte, "duplicate-only byte", " received");
+ ANY(sppstat.spps_rcvpartduppack, "packet", " with some duplicate data");
+ ANY(sppstat.spps_rcvpartdupbyte, "dup. byte", " in part-dup. packet");
+ ANY(sppstat.spps_rcvoopack, "out-of-order packet", " received");
+ ANY(sppstat.spps_rcvoobyte, "out-of-order byte", " received");
+ ANY(sppstat.spps_rcvpackafterwin, "packet", " with data after window");
+ ANY(sppstat.spps_rcvbyteafterwin, "byte", " rcvd after window");
+ ANY(sppstat.spps_rcvafterclose, "packet", " rcvd after 'close'");
+ ANY(sppstat.spps_rcvwinprobe, "rcvd window probe packet", "");
+ ANY(sppstat.spps_rcvdupack, "rcvd duplicate ack", "");
+ ANY(sppstat.spps_rcvacktoomuch, "rcvd ack", " for unsent data");
+ ANY(sppstat.spps_rcvackpack, "rcvd ack packet", "");
+ ANY(sppstat.spps_rcvackbyte, "byte", " acked by rcvd acks");
+ ANY(sppstat.spps_rcvwinupd, "rcvd window update packet", "");
+}
+#undef ANY
+#define ANY(x,y,z) ((x) ? printf("\t%d %s%s%s\n",x,y,plural(x),z) : 0)
+
+/*
+ * Dump IDP statistics structure.
+ */
+void
+idp_stats(off, name)
+ u_long off;
+ char *name;
+{
+ struct idpstat idpstat;
+
+ if (off == 0)
+ return;
+ kread(off, (char *)&idpstat, sizeof (idpstat));
+ printf("%s:\n", name);
+ ANY(idpstat.idps_toosmall, "packet", " smaller than a header");
+ ANY(idpstat.idps_tooshort, "packet", " smaller than advertised");
+ ANY(idpstat.idps_badsum, "packet", " with bad checksums");
+}
+
+static struct {
+ u_short code;
+ char *name;
+ char *where;
+} ns_errnames[] = {
+ {0, "Unspecified Error", " at Destination"},
+ {1, "Bad Checksum", " at Destination"},
+ {2, "No Listener", " at Socket"},
+ {3, "Packet", " Refused due to lack of space at Destination"},
+ {01000, "Unspecified Error", " while gatewayed"},
+ {01001, "Bad Checksum", " while gatewayed"},
+ {01002, "Packet", " forwarded too many times"},
+ {01003, "Packet", " too large to be forwarded"},
+ {-1, 0, 0},
+};
+
+/*
+ * Dump NS Error statistics structure.
+ */
+/*ARGSUSED*/
+void
+nserr_stats(off, name)
+ u_long off;
+ char *name;
+{
+ struct ns_errstat ns_errstat;
+ register int j;
+ register int histoprint = 1;
+ int z;
+
+ if (off == 0)
+ return;
+ kread(off, (char *)&ns_errstat, sizeof (ns_errstat));
+ printf("NS error statistics:\n");
+ ANY(ns_errstat.ns_es_error, "call", " to ns_error");
+ ANY(ns_errstat.ns_es_oldshort, "error",
+ " ignored due to insufficient addressing");
+ ANY(ns_errstat.ns_es_oldns_err, "error request",
+ " in response to error packets");
+ ANY(ns_errstat.ns_es_tooshort, "error packet",
+ " received incomplete");
+ ANY(ns_errstat.ns_es_badcode, "error packet",
+ " received of unknown type");
+ for(j = 0; j < NS_ERR_MAX; j ++) {
+ z = ns_errstat.ns_es_outhist[j];
+ if (z && histoprint) {
+ printf("Output Error Histogram:\n");
+ histoprint = 0;
+ }
+ ns_erputil(z, ns_errstat.ns_es_codes[j]);
+
+ }
+ histoprint = 1;
+ for(j = 0; j < NS_ERR_MAX; j ++) {
+ z = ns_errstat.ns_es_inhist[j];
+ if (z && histoprint) {
+ printf("Input Error Histogram:\n");
+ histoprint = 0;
+ }
+ ns_erputil(z, ns_errstat.ns_es_codes[j]);
+ }
+}
+
+static void
+ns_erputil(z, c)
+ int z, c;
+{
+ int j;
+ char codebuf[30];
+ char *name, *where;
+
+ for(j = 0;; j ++) {
+ if ((name = ns_errnames[j].name) == 0)
+ break;
+ if (ns_errnames[j].code == c)
+ break;
+ }
+ if (name == 0) {
+ if (c > 01000)
+ where = "in transit";
+ else
+ where = "at destination";
+ sprintf(codebuf, "Unknown XNS error code 0%o", c);
+ name = codebuf;
+ } else
+ where = ns_errnames[j].where;
+ ANY(z, name, where);
+}
+
+static struct sockaddr_ns ssns = {AF_NS};
+
+static
+char *ns_prpr(x)
+ struct ns_addr *x;
+{
+ struct sockaddr_ns *sns = &ssns;
+
+ sns->sns_addr = *x;
+ return(ns_print((struct sockaddr *)sns));
+}
diff --git a/usr.bin/netstat/route.c b/usr.bin/netstat/route.c
new file mode 100644
index 00000000000..fe8555aa5d7
--- /dev/null
+++ b/usr.bin/netstat/route.c
@@ -0,0 +1,676 @@
+/* $NetBSD: route.c,v 1.14 1995/10/03 21:42:47 thorpej 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.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "from: @(#)route.c 8.3 (Berkeley) 3/9/94";
+#else
+static char *rcsid = "$NetBSD: route.c,v 1.14 1995/10/03 21:42:47 thorpej Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/mbuf.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#define _KERNEL
+#include <net/route.h>
+#undef _KERNEL
+#include <netinet/in.h>
+
+#include <netns/ns.h>
+
+#include <sys/sysctl.h>
+
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "netstat.h"
+
+#define kget(p, d) (kread((u_long)(p), (char *)&(d), sizeof (d)))
+
+/*
+ * Definitions for showing gateway flags.
+ */
+struct bits {
+ short 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_DONE, 'd' }, /* Completed -- for routing messages only */
+ { RTF_MASK, 'm' }, /* Mask Present -- for routing messages only */
+ { RTF_CLONING, 'C' },
+ { RTF_XRESOLVE, 'X' },
+ { RTF_LLINFO, 'L' },
+ { RTF_STATIC, 'S' },
+ { RTF_PROTO1, '1' },
+ { RTF_PROTO2, '2' },
+ { 0 }
+};
+
+static union {
+ struct sockaddr u_sa;
+ u_short u_data[128];
+} pt_u;
+
+int do_rtent = 0;
+struct rtentry rtentry;
+struct radix_node rnode;
+struct radix_mask rmask;
+
+int NewTree = 0;
+
+static struct sockaddr *kgetsa __P((struct sockaddr *));
+static void p_tree __P((struct radix_node *));
+static void p_rtnode __P(());
+static void ntreestuff __P(());
+static void np_rtentry __P((struct rt_msghdr *));
+static void p_sockaddr __P((struct sockaddr *, int, int));
+static void p_flags __P((int, char *));
+static void p_rtentry __P((struct rtentry *));
+
+/*
+ * Print routing tables.
+ */
+void
+routepr(rtree)
+ u_long rtree;
+{
+ struct radix_node_head *rnh, head;
+ int i;
+
+ printf("Routing tables\n");
+
+ if (Aflag == 0 && NewTree)
+ ntreestuff();
+ else {
+ if (rtree == 0) {
+ printf("rt_tables: symbol not in namelist\n");
+ return;
+ }
+
+ kget(rtree, rt_tables);
+ for (i = 0; i <= AF_MAX; i++) {
+ if ((rnh = rt_tables[i]) == 0)
+ continue;
+ kget(rnh, head);
+ if (i == AF_UNSPEC) {
+ if (Aflag && af == 0) {
+ printf("Netmasks:\n");
+ p_tree(head.rnh_treetop);
+ }
+ } else if (af == AF_UNSPEC || af == i) {
+ pr_family(i);
+ do_rtent = 1;
+ pr_rthdr();
+ p_tree(head.rnh_treetop);
+ }
+ }
+ }
+}
+
+/*
+ * Print address family header before a section of the routing table.
+ */
+void
+pr_family(af)
+ int af;
+{
+ char *afname;
+
+ switch (af) {
+ case AF_INET:
+ afname = "Internet";
+ break;
+ case AF_NS:
+ afname = "XNS";
+ break;
+ case AF_ISO:
+ afname = "ISO";
+ break;
+ case AF_CCITT:
+ afname = "X.25";
+ 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 */
+#define WID_DST 16 /* width of destination column */
+#define WID_GW 18 /* width of gateway column */
+
+/*
+ * Print header for routing table columns.
+ */
+void
+pr_rthdr()
+{
+
+ if (Aflag)
+ printf("%-8.8s ","Address");
+ printf("%-*.*s %-*.*s %-6.6s %6.6s%8.8s %6.6s %s\n",
+ WID_DST, WID_DST, "Destination",
+ WID_GW, WID_GW, "Gateway",
+ "Flags", "Refs", "Use", "Mtu", "Interface");
+}
+
+static struct sockaddr *
+kgetsa(dst)
+ register struct sockaddr *dst;
+{
+
+ kget(dst, pt_u.u_sa);
+ if (pt_u.u_sa.sa_len > sizeof (pt_u.u_sa))
+ kread((u_long)dst, (char *)pt_u.u_data, pt_u.u_sa.sa_len);
+ return (&pt_u.u_sa);
+}
+
+static void
+p_tree(rn)
+ struct radix_node *rn;
+{
+
+again:
+ kget(rn, rnode);
+ if (rnode.rn_b < 0) {
+ if (Aflag)
+ printf("%-8.8x ", rn);
+ if (rnode.rn_flags & RNF_ROOT) {
+ if (Aflag)
+ printf("(root node)%s",
+ rnode.rn_dupedkey ? " =>\n" : "\n");
+ } else if (do_rtent) {
+ kget(rn, rtentry);
+ p_rtentry(&rtentry);
+ if (Aflag)
+ p_rtnode();
+ } else {
+ p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_key),
+ 0, 44);
+ putchar('\n');
+ }
+ if (rn = rnode.rn_dupedkey)
+ goto again;
+ } else {
+ if (Aflag && do_rtent) {
+ printf("%-8.8x ", rn);
+ p_rtnode();
+ }
+ rn = rnode.rn_r;
+ p_tree(rnode.rn_l);
+ p_tree(rn);
+ }
+}
+
+char nbuf[20];
+
+static void
+p_rtnode()
+{
+ struct radix_mask *rm = rnode.rn_mklist;
+
+ if (rnode.rn_b < 0) {
+ if (rnode.rn_mask) {
+ printf("\t mask ");
+ p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_mask),
+ 0, -1);
+ } else if (rm == 0)
+ return;
+ } else {
+ sprintf(nbuf, "(%d)", rnode.rn_b);
+ printf("%6.6s %8.8x : %8.8x", nbuf, rnode.rn_l, rnode.rn_r);
+ }
+ while (rm) {
+ kget(rm, rmask);
+ sprintf(nbuf, " %d refs, ", rmask.rm_refs);
+ printf(" mk = %8.8x {(%d),%s",
+ rm, -1 - rmask.rm_b, rmask.rm_refs ? nbuf : " ");
+ p_sockaddr(kgetsa((struct sockaddr *)rmask.rm_mask), 0, -1);
+ putchar('}');
+ if (rm = rmask.rm_mklist)
+ printf(" ->");
+ }
+ putchar('\n');
+}
+
+static void
+ntreestuff()
+{
+ size_t needed;
+ int mib[6];
+ char *buf, *next, *lim;
+ register struct rt_msghdr *rtm;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = 0;
+ mib[4] = NET_RT_DUMP;
+ mib[5] = 0;
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ { perror("route-sysctl-estimate"); exit(1);}
+ if ((buf = malloc(needed)) == 0)
+ { printf("out of space\n"); exit(1);}
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+ { perror("sysctl of routing table"); exit(1);}
+ lim = buf + needed;
+ for (next = buf; next < lim; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)next;
+ np_rtentry(rtm);
+ }
+}
+
+static void
+np_rtentry(rtm)
+ register struct rt_msghdr *rtm;
+{
+ register struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
+#ifdef notdef
+ static int masks_done, banner_printed;
+#endif
+ static int old_af;
+ int af = 0, interesting = RTF_UP | RTF_GATEWAY | RTF_HOST;
+
+#ifdef notdef
+ /* for the moment, netmasks are skipped over */
+ if (!banner_printed) {
+ printf("Netmasks:\n");
+ banner_printed = 1;
+ }
+ if (masks_done == 0) {
+ if (rtm->rtm_addrs != RTA_DST ) {
+ masks_done = 1;
+ af = sa->sa_family;
+ }
+ } else
+#endif
+ af = sa->sa_family;
+ if (af != old_af) {
+ pr_family(af);
+ old_af = af;
+ }
+ if (rtm->rtm_addrs == RTA_DST)
+ p_sockaddr(sa, 0, 36);
+ else {
+ p_sockaddr(sa, rtm->rtm_flags, 16);
+ if (sa->sa_len == 0)
+ sa->sa_len = sizeof(long);
+ sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
+ p_sockaddr(sa, 0, 18);
+ }
+ p_flags(rtm->rtm_flags & interesting, "%-6.6s ");
+ putchar('\n');
+}
+
+static void
+p_sockaddr(sa, flags, width)
+ struct sockaddr *sa;
+ int flags, width;
+{
+ char workbuf[128], *cplim;
+ register char *cp = workbuf;
+
+ switch(sa->sa_family) {
+ case AF_INET:
+ {
+ register struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+
+ cp = (sin->sin_addr.s_addr == 0) ? "default" :
+ ((flags & RTF_HOST) ?
+ routename(sin->sin_addr.s_addr) :
+ netname(sin->sin_addr.s_addr, INADDR_ANY));
+ break;
+ }
+
+ case AF_NS:
+ cp = ns_print(sa);
+ break;
+
+ case AF_LINK:
+ {
+ register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
+
+ if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 &&
+ sdl->sdl_slen == 0)
+ (void) sprintf(workbuf, "link#%d", sdl->sdl_index);
+ else switch (sdl->sdl_type) {
+ case IFT_ETHER:
+ {
+ register int i;
+ register u_char *lla = (u_char *)sdl->sdl_data +
+ sdl->sdl_nlen;
+
+ cplim = "";
+ for (i = 0; i < sdl->sdl_alen; i++, lla++) {
+ cp += sprintf(cp, "%s%x", cplim, *lla);
+ cplim = ":";
+ }
+ cp = workbuf;
+ break;
+ }
+ default:
+ cp = link_ntoa(sdl);
+ break;
+ }
+ break;
+ }
+
+ default:
+ {
+ register u_char *s = (u_char *)sa->sa_data, *slim;
+
+ slim = sa->sa_len + (u_char *) sa;
+ cplim = cp + sizeof(workbuf) - 6;
+ cp += sprintf(cp, "(%d)", sa->sa_family);
+ while (s < slim && cp < cplim) {
+ cp += sprintf(cp, " %02x", *s++);
+ if (s < slim)
+ cp += sprintf(cp, "%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(f, format)
+ register int f;
+ char *format;
+{
+ char name[33], *flags;
+ register 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);
+}
+
+static void
+p_rtentry(rt)
+ register struct rtentry *rt;
+{
+ static struct ifnet ifnet, *lastif;
+ static char name[16];
+
+ p_sockaddr(kgetsa(rt_key(rt)), rt->rt_flags, WID_DST);
+ p_sockaddr(kgetsa(rt->rt_gateway), RTF_HOST, WID_GW);
+ p_flags(rt->rt_flags, "%-6.6s ");
+ printf("%6d %8d ", rt->rt_refcnt, rt->rt_use);
+ if (rt->rt_rmx.rmx_mtu)
+ printf("%6d ", rt->rt_rmx.rmx_mtu);
+ else
+ printf("%6s ", "-");
+ if (rt->rt_ifp) {
+ if (rt->rt_ifp != lastif) {
+ kget(rt->rt_ifp, ifnet);
+ kread((u_long)ifnet.if_name, name, 16);
+ lastif = rt->rt_ifp;
+ }
+ printf(" %.15s%d%s", name, ifnet.if_unit,
+ rt->rt_nodes[0].rn_dupedkey ? " =>" : "");
+ }
+ putchar('\n');
+}
+
+char *
+routename(in)
+ u_int32_t in;
+{
+ register char *cp;
+ static char line[MAXHOSTNAMELEN + 1];
+ struct hostent *hp;
+ static char domain[MAXHOSTNAMELEN + 1];
+ static int first = 1;
+
+ if (first) {
+ first = 0;
+ if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
+ (cp = index(domain, '.')))
+ (void) strcpy(domain, cp + 1);
+ else
+ domain[0] = 0;
+ }
+ cp = 0;
+ if (!nflag) {
+ hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
+ AF_INET);
+ if (hp) {
+ if ((cp = index(hp->h_name, '.')) &&
+ !strcmp(cp + 1, domain))
+ *cp = 0;
+ cp = hp->h_name;
+ }
+ }
+ if (cp)
+ strncpy(line, cp, sizeof(line) - 1);
+ else {
+#define C(x) ((x) & 0xff)
+ in = ntohl(in);
+ sprintf(line, "%u.%u.%u.%u",
+ C(in >> 24), C(in >> 16), C(in >> 8), C(in));
+ }
+ return (line);
+}
+
+/*
+ * 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(in, mask)
+ u_int32_t in, mask;
+{
+ char *cp = 0;
+ static char line[MAXHOSTNAMELEN + 1];
+ struct netent *np = 0;
+ u_int32_t net;
+ int subnetshift;
+
+ in = ntohl(in);
+ mask = ntohl(mask);
+ if (!nflag && in != INADDR_ANY) {
+ if (mask == INADDR_ANY) {
+ if (IN_CLASSA(in)) {
+ mask = IN_CLASSA_NET;
+ subnetshift = 8;
+ } else if (IN_CLASSB(in)) {
+ mask = IN_CLASSB_NET;
+ subnetshift = 8;
+ } else {
+ mask = IN_CLASSC_NET;
+ subnetshift = 4;
+ }
+ /*
+ * If there are more bits than the standard mask
+ * would suggest, subnets must be in use.
+ * Guess at the subnet mask, assuming reasonable
+ * width subnet fields.
+ */
+ while (in &~ mask)
+ mask = (long)mask >> subnetshift;
+ }
+ net = in & mask;
+ while ((mask & 1) == 0)
+ mask >>= 1, net >>= 1;
+ np = getnetbyaddr(net, AF_INET);
+ if (np)
+ cp = np->n_name;
+ }
+ if (cp)
+ strncpy(line, cp, sizeof(line) - 1);
+ else if ((in & 0xffffff) == 0)
+ sprintf(line, "%u", C(in >> 24));
+ else if ((in & 0xffff) == 0)
+ sprintf(line, "%u.%u", C(in >> 24) , C(in >> 16));
+ else if ((in & 0xff) == 0)
+ sprintf(line, "%u.%u.%u", C(in >> 24), C(in >> 16), C(in >> 8));
+ else
+ sprintf(line, "%u.%u.%u.%u", C(in >> 24),
+ C(in >> 16), C(in >> 8), C(in));
+ return (line);
+}
+
+/*
+ * Print routing statistics
+ */
+void
+rt_stats(off)
+ u_long off;
+{
+ struct rtstat rtstat;
+
+ if (off == 0) {
+ printf("rtstat: symbol not in namelist\n");
+ return;
+ }
+ kread(off, (char *)&rtstat, sizeof (rtstat));
+ printf("routing:\n");
+ printf("\t%u bad routing redirect%s\n",
+ rtstat.rts_badredirect, plural(rtstat.rts_badredirect));
+ printf("\t%u dynamically created route%s\n",
+ rtstat.rts_dynamic, plural(rtstat.rts_dynamic));
+ printf("\t%u new gateway%s due to redirects\n",
+ rtstat.rts_newgateway, plural(rtstat.rts_newgateway));
+ printf("\t%u destination%s found unreachable\n",
+ rtstat.rts_unreach, plural(rtstat.rts_unreach));
+ printf("\t%u use%s of a wildcard route\n",
+ rtstat.rts_wildcard, plural(rtstat.rts_wildcard));
+}
+short ns_nullh[] = {0,0,0};
+short ns_bh[] = {-1,-1,-1};
+
+char *
+ns_print(sa)
+ register struct sockaddr *sa;
+{
+ register struct sockaddr_ns *sns = (struct sockaddr_ns*)sa;
+ struct ns_addr work;
+ union { union ns_net net_e; u_long long_e; } net;
+ u_short port;
+ static char mybuf[50], cport[10], chost[25];
+ char *host = "";
+ register char *p; register u_char *q;
+
+ work = sns->sns_addr;
+ port = ntohs(work.x_port);
+ work.x_port = 0;
+ net.net_e = work.x_net;
+ if (ns_nullhost(work) && net.long_e == 0) {
+ if (port ) {
+ sprintf(mybuf, "*.%xH", port);
+ upHex(mybuf);
+ } else
+ sprintf(mybuf, "*.*");
+ return (mybuf);
+ }
+
+ if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) {
+ host = "any";
+ } else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) {
+ host = "*";
+ } else {
+ q = work.x_host.c_host;
+ sprintf(chost, "%02x%02x%02x%02x%02x%02xH",
+ q[0], q[1], q[2], q[3], q[4], q[5]);
+ for (p = chost; *p == '0' && p < chost + 12; p++)
+ continue;
+ host = p;
+ }
+ if (port)
+ sprintf(cport, ".%xH", htons(port));
+ else
+ *cport = 0;
+
+ sprintf(mybuf,"%xH.%s%s", ntohl(net.long_e), host, cport);
+ upHex(mybuf);
+ return(mybuf);
+}
+
+char *
+ns_phost(sa)
+ struct sockaddr *sa;
+{
+ register struct sockaddr_ns *sns = (struct sockaddr_ns *)sa;
+ struct sockaddr_ns work;
+ static union ns_net ns_zeronet;
+ char *p;
+
+ work = *sns;
+ work.sns_addr.x_port = 0;
+ work.sns_addr.x_net = ns_zeronet;
+
+ p = ns_print((struct sockaddr *)&work);
+ if (strncmp("0H.", p, 3) == 0) p += 3;
+ return(p);
+}
+
+void
+upHex(p0)
+ char *p0;
+{
+ register char *p = p0;
+ for (; *p; p++) switch (*p) {
+
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ *p += ('A' - 'a');
+ }
+}
diff --git a/usr.bin/netstat/unix.c b/usr.bin/netstat/unix.c
new file mode 100644
index 00000000000..6b6388b5b4e
--- /dev/null
+++ b/usr.bin/netstat/unix.c
@@ -0,0 +1,140 @@
+/* $NetBSD: unix.c,v 1.13 1995/10/03 21:42:48 thorpej 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.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "from: @(#)unix.c 8.1 (Berkeley) 6/6/93";
+#else
+static char *rcsid = "$NetBSD: unix.c,v 1.13 1995/10/03 21:42:48 thorpej Exp $";
+#endif
+#endif /* not lint */
+
+/*
+ * Display protocol blocks in the unix domain.
+ */
+#include <sys/param.h>
+#include <sys/protosw.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>
+#define _KERNEL
+struct uio;
+struct proc;
+#include <sys/file.h>
+
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <kvm.h>
+#include "netstat.h"
+
+static void unixdomainpr __P((struct socket *, caddr_t));
+
+static struct file *file, *fileNFILE;
+static int nfiles;
+extern kvm_t *kvmd;
+
+void
+unixpr(off)
+ u_long off;
+{
+ register struct file *fp;
+ struct socket sock, *so = &sock;
+ char *filebuf;
+ struct protosw *unixsw = (struct protosw *)off;
+
+ filebuf = (char *)kvm_getfiles(kvmd, KERN_FILE, 0, &nfiles);
+ if (filebuf == 0) {
+ printf("Out of memory (file table).\n");
+ return;
+ }
+ file = (struct file *)(filebuf + sizeof(fp));
+ fileNFILE = file + nfiles;
+ for (fp = file; fp < fileNFILE; fp++) {
+ if (fp->f_count == 0 || fp->f_type != DTYPE_SOCKET)
+ continue;
+ if (kread((u_long)fp->f_data, (char *)so, sizeof (*so)))
+ continue;
+ /* kludge */
+ if (so->so_proto >= unixsw && so->so_proto <= unixsw + 2)
+ if (so->so_pcb)
+ unixdomainpr(so, fp->f_data);
+ }
+}
+
+static char *socktype[] =
+ { "#0", "stream", "dgram", "raw", "rdm", "seqpacket" };
+
+static void
+unixdomainpr(so, soaddr)
+ register struct socket *so;
+ caddr_t soaddr;
+{
+ struct unpcb unpcb, *unp = &unpcb;
+ struct mbuf mbuf, *m;
+ struct sockaddr_un *sa;
+ static int first = 1;
+
+ if (kread((u_long)so->so_pcb, (char *)unp, sizeof (*unp)))
+ return;
+ if (unp->unp_addr) {
+ m = &mbuf;
+ if (kread((u_long)unp->unp_addr, (char *)m, sizeof (*m)))
+ m = (struct mbuf *)0;
+ sa = (struct sockaddr_un *)(m->m_dat);
+ } else
+ m = (struct mbuf *)0;
+ if (first) {
+ printf("Active UNIX domain sockets\n");
+ printf(
+"%-8.8s %-6.6s %-6.6s %-6.6s %8.8s %8.8s %8.8s %8.8s Addr\n",
+ "Address", "Type", "Recv-Q", "Send-Q",
+ "Inode", "Conn", "Refs", "Nextref");
+ first = 0;
+ }
+ printf("%8x %-6.6s %6d %6d %8x %8x %8x %8x",
+ soaddr, socktype[so->so_type], so->so_rcv.sb_cc, so->so_snd.sb_cc,
+ unp->unp_vnode, unp->unp_conn,
+ unp->unp_refs, unp->unp_nextref);
+ if (m)
+ printf(" %.*s",
+ m->m_len - (int)(sizeof(*sa) - sizeof(sa->sun_path)),
+ sa->sun_path);
+ putchar('\n');
+}