From f1710b69d4ea496c3af76b46d7bec67b20dab1be Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Fri, 7 Sep 2012 12:50:18 -0500 Subject: netstat: New command - Almost completely compiles Currently disable in Makefile until all builds. Adding it so others can assist in debugging issues. --- freebsd-userspace/commands/usr.bin/netstat/atalk.c | 293 +++++ freebsd-userspace/commands/usr.bin/netstat/bpf.c | 158 +++ freebsd-userspace/commands/usr.bin/netstat/if.c | 735 +++++++++++ freebsd-userspace/commands/usr.bin/netstat/inet.c | 1291 ++++++++++++++++++++ freebsd-userspace/commands/usr.bin/netstat/inet6.c | 1159 ++++++++++++++++++ freebsd-userspace/commands/usr.bin/netstat/ipsec.c | 481 ++++++++ freebsd-userspace/commands/usr.bin/netstat/ipx.c | 354 ++++++ freebsd-userspace/commands/usr.bin/netstat/main.c | 805 ++++++++++++ freebsd-userspace/commands/usr.bin/netstat/mbuf.c | 323 +++++ .../commands/usr.bin/netstat/mroute.c | 391 ++++++ .../commands/usr.bin/netstat/mroute6.c | 268 ++++ .../commands/usr.bin/netstat/netgraph.c | 196 +++ .../commands/usr.bin/netstat/netstat.1 | 523 ++++++++ .../commands/usr.bin/netstat/netstat.h | 167 +++ freebsd-userspace/commands/usr.bin/netstat/pfkey.c | 184 +++ freebsd-userspace/commands/usr.bin/netstat/route.c | 1167 ++++++++++++++++++ freebsd-userspace/commands/usr.bin/netstat/sctp.c | 703 +++++++++++ freebsd-userspace/commands/usr.bin/netstat/unix.c | 294 +++++ 18 files changed, 9492 insertions(+) create mode 100644 freebsd-userspace/commands/usr.bin/netstat/atalk.c create mode 100644 freebsd-userspace/commands/usr.bin/netstat/bpf.c create mode 100644 freebsd-userspace/commands/usr.bin/netstat/if.c create mode 100644 freebsd-userspace/commands/usr.bin/netstat/inet.c create mode 100644 freebsd-userspace/commands/usr.bin/netstat/inet6.c create mode 100644 freebsd-userspace/commands/usr.bin/netstat/ipsec.c create mode 100644 freebsd-userspace/commands/usr.bin/netstat/ipx.c create mode 100644 freebsd-userspace/commands/usr.bin/netstat/main.c create mode 100644 freebsd-userspace/commands/usr.bin/netstat/mbuf.c create mode 100644 freebsd-userspace/commands/usr.bin/netstat/mroute.c create mode 100644 freebsd-userspace/commands/usr.bin/netstat/mroute6.c create mode 100644 freebsd-userspace/commands/usr.bin/netstat/netgraph.c create mode 100644 freebsd-userspace/commands/usr.bin/netstat/netstat.1 create mode 100644 freebsd-userspace/commands/usr.bin/netstat/netstat.h create mode 100644 freebsd-userspace/commands/usr.bin/netstat/pfkey.c create mode 100644 freebsd-userspace/commands/usr.bin/netstat/route.c create mode 100644 freebsd-userspace/commands/usr.bin/netstat/sctp.c create mode 100644 freebsd-userspace/commands/usr.bin/netstat/unix.c diff --git a/freebsd-userspace/commands/usr.bin/netstat/atalk.c b/freebsd-userspace/commands/usr.bin/netstat/atalk.c new file mode 100644 index 00000000..2c7e7a18 --- /dev/null +++ b/freebsd-userspace/commands/usr.bin/netstat/atalk.c @@ -0,0 +1,293 @@ +/*- + * 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. + */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)atalk.c 1.1 (Whistle) 6/6/96"; +#endif /* not lint */ +#endif + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#ifdef __rtems__ +#include +#else +#include +#endif + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include "netstat.h" + +struct ddpcb ddpcb; +struct socket sockb; + +static int first = 1; + +/* + * Print a summary of connections related to a Network Systems + * protocol. For XXX, also give state of connection. + * Listening processes (aflag) are suppressed unless the + * -a (all) flag is specified. + */ + +static const char * +at_pr_net(struct sockaddr_at *sat, int numeric) +{ +static char mybuf[50]; + + if (!numeric) { + switch(sat->sat_addr.s_net) { + case 0xffff: + return "????"; + case ATADDR_ANYNET: + return("*"); + } + } + sprintf(mybuf,"%hu",ntohs(sat->sat_addr.s_net)); + return mybuf; +} + +static const char * +at_pr_host(struct sockaddr_at *sat, int numeric) +{ +static char mybuf[50]; + + if (!numeric) { + switch(sat->sat_addr.s_node) { + case ATADDR_BCAST: + return "bcast"; + case ATADDR_ANYNODE: + return("*"); + } + } + sprintf(mybuf,"%d",(unsigned int)sat->sat_addr.s_node); + return mybuf; +} + +static const char * +at_pr_port(struct sockaddr_at *sat) +{ +static char mybuf[50]; + struct servent *serv; + + switch(sat->sat_port) { + case ATADDR_ANYPORT: + return("*"); + case 0xff: + return "????"; + default: + if (numeric_port) { + (void)snprintf(mybuf, sizeof(mybuf), "%d", + (unsigned int)sat->sat_port); + } else { + serv = getservbyport(sat->sat_port, "ddp"); + if (serv == NULL) + (void)snprintf(mybuf, sizeof(mybuf), "%d", + (unsigned int) sat->sat_port); + else + (void) snprintf(mybuf, sizeof(mybuf), "%s", + serv->s_name); + } + } + return mybuf; +} + +static char * +at_pr_range(struct sockaddr_at *sat) +{ +static char mybuf[50]; + + if(sat->sat_range.r_netrange.nr_firstnet + != sat->sat_range.r_netrange.nr_lastnet) { + sprintf(mybuf,"%d-%d", + ntohs(sat->sat_range.r_netrange.nr_firstnet), + ntohs(sat->sat_range.r_netrange.nr_lastnet)); + } else { + sprintf(mybuf,"%d", + ntohs(sat->sat_range.r_netrange.nr_firstnet)); + } + return mybuf; +} + + +/* what == 0 for addr only == 3 */ +/* 1 for net */ +/* 2 for host */ +/* 4 for port */ +/* 8 for numeric only */ +char * +atalk_print(struct sockaddr *sa, int what) +{ + struct sockaddr_at *sat = (struct sockaddr_at *)sa; + static char mybuf[50]; + int numeric = (what & 0x08); + + mybuf[0] = 0; + switch (what & 0x13) { + case 0: + mybuf[0] = 0; + break; + case 1: + sprintf(mybuf,"%s",at_pr_net(sat, numeric)); + break; + case 2: + sprintf(mybuf,"%s",at_pr_host(sat, numeric)); + break; + case 3: + sprintf(mybuf,"%s.%s", + at_pr_net(sat, numeric), + at_pr_host(sat, numeric)); + break; + case 0x10: + sprintf(mybuf,"%s", at_pr_range(sat)); + } + if (what & 4) { + sprintf(mybuf+strlen(mybuf),".%s",at_pr_port(sat)); + } + return mybuf; +} + +char * +atalk_print2(struct sockaddr *sa, struct sockaddr *mask, int what) +{ + int n; + static char buf[100]; + struct sockaddr_at *sat1, *sat2; + struct sockaddr_at thesockaddr; + struct sockaddr *sa2; + + sat1 = (struct sockaddr_at *)sa; + sat2 = (struct sockaddr_at *)mask; + sa2 = (struct sockaddr *)&thesockaddr; + + thesockaddr.sat_addr.s_net = sat1->sat_addr.s_net & sat2->sat_addr.s_net; + snprintf(buf, sizeof(buf), "%s", atalk_print(sa2, 1 |(what & 8))); + if(sat2->sat_addr.s_net != 0xFFFF) { + thesockaddr.sat_addr.s_net = sat1->sat_addr.s_net | ~sat2->sat_addr.s_net; + n = strlen(buf); + snprintf(buf + n, sizeof(buf) - n, "-%s", atalk_print(sa2, 1 |(what & 8))); + } + if(what & 2) { + n = strlen(buf); + snprintf(buf + n, sizeof(buf) - n, ".%s", atalk_print(sa, what & (~1))); + } + return(buf); +} + +void +atalkprotopr(u_long off __unused, const char *name, int af1 __unused, + int proto __unused) +{ + struct ddpcb *this, *next; + + if (off == 0) + return; + kread(off, (char *)&this, sizeof (struct ddpcb *)); + for ( ; this != NULL; this = next) { + kread((u_long)this, (char *)&ddpcb, sizeof (ddpcb)); + next = ddpcb.ddp_next; +#if 0 + if (!aflag && atalk_nullhost(ddpcb.ddp_lsat) ) { + continue; + } +#endif + kread((u_long)ddpcb.ddp_socket, (char *)&sockb, sizeof (sockb)); + if (first) { + printf("Active ATALK 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("%8lx ", (u_long) this); + printf("%-5.5s %6u %6u ", name, sockb.so_rcv.sb_cc, + sockb.so_snd.sb_cc); + printf(Aflag?" %-18.18s":" %-22.22s", atalk_print( + (struct sockaddr *)&ddpcb.ddp_lsat,7)); + printf(Aflag?" %-18.18s":" %-22.22s", atalk_print( + (struct sockaddr *)&ddpcb.ddp_fsat,7)); + putchar('\n'); + } +} + +#define ANY(x,y,z) if (x || sflag <= 1) \ + printf("\t%lu %s%s%s\n",x,y,plural(x),z) + +/* + * Dump DDP statistics structure. + */ +void +ddp_stats(u_long off __unused, const char *name, int af1 __unused, + int proto __unused) +{ + struct ddpstat ddpstat; + + if (off == 0) + return; + kread(off, (char *)&ddpstat, sizeof (ddpstat)); + printf("%s:\n", name); + ANY(ddpstat.ddps_short, "packet", " with short headers "); + ANY(ddpstat.ddps_long, "packet", " with long headers "); + ANY(ddpstat.ddps_nosum, "packet", " with no checksum "); + ANY(ddpstat.ddps_tooshort, "packet", " too short "); + ANY(ddpstat.ddps_badsum, "packet", " with bad checksum "); + ANY(ddpstat.ddps_toosmall, "packet", " with not enough data "); + ANY(ddpstat.ddps_forward, "packet", " forwarded "); + ANY(ddpstat.ddps_encap, "packet", " encapsulated "); + ANY(ddpstat.ddps_cantforward, "packet", " rcvd for unreachable dest "); + ANY(ddpstat.ddps_nosockspace, "packet", " dropped due to no socket space "); +} diff --git a/freebsd-userspace/commands/usr.bin/netstat/bpf.c b/freebsd-userspace/commands/usr.bin/netstat/bpf.c new file mode 100644 index 00000000..3e3053d7 --- /dev/null +++ b/freebsd-userspace/commands/usr.bin/netstat/bpf.c @@ -0,0 +1,158 @@ +/*- + * Copyright (c) 2005 Christian S.J. Peron + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#ifdef __rtems__ +#include +#else +#include +#endif +#include +#include +#include +#include +#ifndef __rtems__ +#include +#endif + +#include +#ifdef __rtems__ +#include +#include +#include +#else +#include +#include +#include +#endif +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "netstat.h" + +/* print bpf stats */ + +static char * +bpf_pidname(pid_t pid) +{ +#ifdef __rtems__ + return "rtems"; +#else + struct kinfo_proc newkp; + int error, mib[4]; + size_t size; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = pid; + size = sizeof(newkp); + error = sysctl(mib, 4, &newkp, &size, NULL, 0); + if (error < 0) { + warn("kern.proc.pid failed"); + return (strdup("??????")); + } + return (strdup(newkp.ki_comm)); +#endif +} + +static void +bpf_flags(struct xbpf_d *bd, char *flagbuf) +{ + + *flagbuf++ = bd->bd_promisc ? 'p' : '-'; + *flagbuf++ = bd->bd_immediate ? 'i' : '-'; + *flagbuf++ = bd->bd_hdrcmplt ? '-' : 'f'; + *flagbuf++ = (bd->bd_direction == BPF_D_IN) ? '-' : + ((bd->bd_direction == BPF_D_OUT) ? 'o' : 's'); + *flagbuf++ = bd->bd_feedback ? 'b' : '-'; + *flagbuf++ = bd->bd_async ? 'a' : '-'; + *flagbuf++ = bd->bd_locked ? 'l' : '-'; + *flagbuf++ = '\0'; +} + +void +bpf_stats(char *ifname) +{ + struct xbpf_d *d, *bd, zerostat; + char *pname, flagbuf[12]; + size_t size; + + if (zflag) { + bzero(&zerostat, sizeof(zerostat)); + if (sysctlbyname("net.bpf.stats", NULL, NULL, + &zerostat, sizeof(zerostat)) < 0) + warn("failed to zero bpf counters"); + return; + } + if (sysctlbyname("net.bpf.stats", NULL, &size, + NULL, 0) < 0) { + warn("net.bpf.stats"); + return; + } + if (size == 0) + return; + bd = malloc(size); + if (bd == NULL) { + warn("malloc failed"); + return; + } + if (sysctlbyname("net.bpf.stats", bd, &size, + NULL, 0) < 0) { + warn("net.bpf.stats"); + free(bd); + return; + } + (void) printf("%5s %6s %7s %9s %9s %9s %5s %5s %s\n", + "Pid", "Netif", "Flags", "Recv", "Drop", "Match", "Sblen", + "Hblen", "Command"); + for (d = &bd[0]; d < &bd[size / sizeof(*d)]; d++) { + if (d->bd_structsize != sizeof(*d)) { + warnx("bpf_stats_extended: version mismatch"); + return; + } + if (ifname && strcmp(ifname, d->bd_ifname) != 0) + continue; + bpf_flags(d, flagbuf); + pname = bpf_pidname(d->bd_pid); + (void) printf("%5d %6s %7s %9ju %9ju %9ju %5d %5d %s\n", + d->bd_pid, d->bd_ifname, flagbuf, + d->bd_rcount, d->bd_dcount, d->bd_fcount, + d->bd_slen, d->bd_hlen, pname); + free(pname); + } + free(bd); +} diff --git a/freebsd-userspace/commands/usr.bin/netstat/if.c b/freebsd-userspace/commands/usr.bin/netstat/if.c new file mode 100644 index 00000000..d91db8c1 --- /dev/null +++ b/freebsd-userspace/commands/usr.bin/netstat/if.c @@ -0,0 +1,735 @@ +/*- + * 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. + */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)if.c 8.3 (Berkeley) 4/28/95"; +#endif /* not lint */ +#endif + +#include +__FBSDID("$FreeBSD$"); + +#include +#ifdef __rtems__ +#include +#else +#include +#endif +#include +#include +#include +#include + +#include +#ifdef __rtems__ +#include +#else +#include +#endif +#include +#include +#include +#ifdef __rtems__ +#include +#include +#include +#include +/* IPX not on RTEMS */ +/* #include */ +/* #include */ +#else +#include +#include +#include +#include +#include +#include +#endif +#include + +#include +#include +#ifdef __rtems__ +/* apparently libutil.h is not needed */ +#else +#include +#endif +#include +#include +#include +#include +#include +#include + +#include "netstat.h" + +#define YES 1 +#define NO 0 + +static void sidewaysintpr(int, u_long); +static void catchalarm(int); + +#ifdef INET6 +static char ntop_buf[INET6_ADDRSTRLEN]; /* for inet_ntop() */ +#endif + +/* + * Dump pfsync statistics structure. + */ +void +pfsync_stats(u_long off, const char *name, int af1 __unused, int proto __unused) +{ + struct pfsyncstats pfsyncstat, zerostat; + size_t len = sizeof(struct pfsyncstats); + + if (live) { + if (zflag) + memset(&zerostat, 0, len); + if (sysctlbyname("net.inet.pfsync.stats", &pfsyncstat, &len, + zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { + if (errno != ENOENT) + warn("sysctl: net.inet.pfsync.stats"); + return; + } + } else + kread(off, &pfsyncstat, len); + + printf("%s:\n", name); + +#define p(f, m) if (pfsyncstat.f || sflag <= 1) \ + printf(m, (uintmax_t)pfsyncstat.f, plural(pfsyncstat.f)) +#define p2(f, m) if (pfsyncstat.f || sflag <= 1) \ + printf(m, (uintmax_t)pfsyncstat.f) + + p(pfsyncs_ipackets, "\t%ju packet%s received (IPv4)\n"); + p(pfsyncs_ipackets6, "\t%ju packet%s received (IPv6)\n"); + p(pfsyncs_badif, "\t\t%ju packet%s discarded for bad interface\n"); + p(pfsyncs_badttl, "\t\t%ju packet%s discarded for bad ttl\n"); + p(pfsyncs_hdrops, "\t\t%ju packet%s shorter than header\n"); + p(pfsyncs_badver, "\t\t%ju packet%s discarded for bad version\n"); + p(pfsyncs_badauth, "\t\t%ju packet%s discarded for bad HMAC\n"); + p(pfsyncs_badact,"\t\t%ju packet%s discarded for bad action\n"); + p(pfsyncs_badlen, "\t\t%ju packet%s discarded for short packet\n"); + p(pfsyncs_badval, "\t\t%ju state%s discarded for bad values\n"); + p(pfsyncs_stale, "\t\t%ju stale state%s\n"); + p(pfsyncs_badstate, "\t\t%ju failed state lookup/insert%s\n"); + p(pfsyncs_opackets, "\t%ju packet%s sent (IPv4)\n"); + p(pfsyncs_opackets6, "\t%ju packet%s sent (IPv6)\n"); + p2(pfsyncs_onomem, "\t\t%ju send failed due to mbuf memory error\n"); + p2(pfsyncs_oerrors, "\t\t%ju send error\n"); +#undef p +#undef p2 +} + +/* + * Display a formatted value, or a '-' in the same space. + */ +static void +show_stat(const char *fmt, int width, u_long value, short showvalue) +{ + const char *lsep, *rsep; + char newfmt[32]; + + lsep = ""; + if (strncmp(fmt, "LS", 2) == 0) { + lsep = " "; + fmt += 2; + } + rsep = " "; + if (strncmp(fmt, "NRS", 3) == 0) { + rsep = ""; + fmt += 3; + } + if (showvalue == 0) { + /* Print just dash. */ + sprintf(newfmt, "%s%%%ds%s", lsep, width, rsep); + printf(newfmt, "-"); + return; + } + + if (hflag) { + char buf[5]; + + /* Format in human readable form. */ + humanize_number(buf, sizeof(buf), (int64_t)value, "", + HN_AUTOSCALE, HN_NOSPACE | HN_DECIMAL); + sprintf(newfmt, "%s%%%ds%s", lsep, width, rsep); + printf(newfmt, buf); + } else { + /* Construct the format string. */ + sprintf(newfmt, "%s%%%d%s%s", lsep, width, fmt, rsep); + printf(newfmt, value); + } +} + +/* + * Print a description of the network interfaces. + */ +void +intpr(int interval1, u_long ifnetaddr, void (*pfunc)(char *)) +{ + struct ifnet ifnet; + struct ifnethead ifnethead; + union { + struct ifaddr ifa; + struct in_ifaddr in; +#ifdef INET6 + struct in6_ifaddr in6; +#endif + struct ipx_ifaddr ipx; + } ifaddr; + u_long ifaddraddr; + u_long ifaddrfound; + u_long ifnetfound; + u_long opackets; + u_long ipackets; + u_long obytes; + u_long ibytes; + u_long omcasts; + u_long imcasts; + u_long oerrors; + u_long ierrors; + u_long idrops; + u_long collisions; + short timer; + int drops; + struct sockaddr *sa = NULL; + char name[IFNAMSIZ]; + short network_layer; + short link_layer; + + if (ifnetaddr == 0) { + printf("ifnet: symbol not defined\n"); + return; + } + if (interval1) { + sidewaysintpr(interval1, ifnetaddr); + return; + } + if (kread(ifnetaddr, (char *)&ifnethead, sizeof ifnethead) != 0) + return; + ifnetaddr = (u_long)TAILQ_FIRST(&ifnethead); + if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet) != 0) + return; + + if (!pfunc) { + if (Wflag) + printf("%-7.7s", "Name"); + else + printf("%-5.5s", "Name"); + printf(" %5.5s %-13.13s %-17.17s %8.8s %5.5s %5.5s", + "Mtu", "Network", "Address", "Ipkts", "Ierrs", "Idrop"); + if (bflag) + printf(" %10.10s","Ibytes"); + printf(" %8.8s %5.5s", "Opkts", "Oerrs"); + if (bflag) + printf(" %10.10s","Obytes"); + printf(" %5s", "Coll"); + if (tflag) + printf(" %s", "Time"); + if (dflag) + printf(" %s", "Drop"); + putchar('\n'); + } + ifaddraddr = 0; + while (ifnetaddr || ifaddraddr) { + struct sockaddr_in *sockin; +#ifdef INET6 + struct sockaddr_in6 *sockin6; +#endif + char *cp; + int n, m; + + network_layer = 0; + link_layer = 0; + + if (ifaddraddr == 0) { + ifnetfound = ifnetaddr; + if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet) != 0) + return; + strlcpy(name, ifnet.if_xname, sizeof(name)); + ifnetaddr = (u_long)TAILQ_NEXT(&ifnet, if_link); + if (interface != 0 && strcmp(name, interface) != 0) + continue; + cp = index(name, '\0'); + + if (pfunc) { + (*pfunc)(name); + continue; + } + + if ((ifnet.if_flags&IFF_UP) == 0) + *cp++ = '*'; + *cp = '\0'; + ifaddraddr = (u_long)TAILQ_FIRST(&ifnet.if_addrhead); + } + ifaddrfound = ifaddraddr; + + /* + * Get the interface stats. These may get + * overriden below on a per-interface basis. + */ + opackets = ifnet.if_opackets; + ipackets = ifnet.if_ipackets; + obytes = ifnet.if_obytes; + ibytes = ifnet.if_ibytes; + omcasts = ifnet.if_omcasts; + imcasts = ifnet.if_imcasts; + oerrors = ifnet.if_oerrors; + ierrors = ifnet.if_ierrors; + idrops = ifnet.if_iqdrops; + collisions = ifnet.if_collisions; + timer = ifnet.if_timer; + drops = ifnet.if_snd.ifq_drops; + + if (ifaddraddr == 0) { + if (Wflag) + printf("%-7.7s", name); + else + printf("%-5.5s", name); + printf(" %5lu ", ifnet.if_mtu); + printf("%-13.13s ", "none"); + printf("%-17.17s ", "none"); + } else { + if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr) + != 0) { + ifaddraddr = 0; + continue; + } +#define CP(x) ((char *)(x)) + cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) + + CP(&ifaddr); + sa = (struct sockaddr *)cp; + if (af != AF_UNSPEC && sa->sa_family != af) { + ifaddraddr = + (u_long)TAILQ_NEXT(&ifaddr.ifa, ifa_link); + continue; + } + if (Wflag) + printf("%-7.7s", name); + else + printf("%-5.5s", name); + printf(" %5lu ", ifnet.if_mtu); + switch (sa->sa_family) { + case AF_UNSPEC: + printf("%-13.13s ", "none"); + printf("%-15.15s ", "none"); + break; + case AF_INET: + sockin = (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("%-13.13s ", netname(in.s_addr, + ifaddr.in.ia_subnetmask)); +#else + printf("%-13.13s ", + netname(htonl(ifaddr.in.ia_subnet), + ifaddr.in.ia_subnetmask)); +#endif + printf("%-17.17s ", + routename(sockin->sin_addr.s_addr)); + + network_layer = 1; + break; +#ifdef INET6 + case AF_INET6: + sockin6 = (struct sockaddr_in6 *)sa; + printf("%-13.13s ", + netname6(&ifaddr.in6.ia_addr, + &ifaddr.in6.ia_prefixmask.sin6_addr)); + printf("%-17.17s ", + inet_ntop(AF_INET6, + &sockin6->sin6_addr, + ntop_buf, sizeof(ntop_buf))); + + network_layer = 1; + break; +#endif /*INET6*/ + case AF_IPX: + { + struct sockaddr_ipx *sipx = + (struct sockaddr_ipx *)sa; + u_long net; + char netnum[10]; + + *(union ipx_net *) &net = sipx->sipx_addr.x_net; + sprintf(netnum, "%lx", (u_long)ntohl(net)); + printf("ipx:%-8s ", netnum); +/* printf("ipx:%-8s ", netname(net, 0L)); */ + printf("%-17s ", + ipx_phost((struct sockaddr *)sipx)); + } + + network_layer = 1; + break; + + case AF_APPLETALK: + printf("atalk:%-12.12s ",atalk_print(sa,0x10) ); + printf("%-11.11s ",atalk_print(sa,0x0b) ); + break; + case AF_LINK: + { + struct sockaddr_dl *sdl = + (struct sockaddr_dl *)sa; + char linknum[10]; + cp = (char *)LLADDR(sdl); + n = sdl->sdl_alen; + sprintf(linknum, "", sdl->sdl_index); + m = printf("%-13.13s ", linknum); + } + goto hexprint; + default: + m = printf("(%d)", sa->sa_family); + for (cp = sa->sa_len + (char *)sa; + --cp > sa->sa_data && (*cp == 0);) {} + n = cp - sa->sa_data + 1; + cp = sa->sa_data; + hexprint: + while (--n >= 0) + m += printf("%02x%c", *cp++ & 0xff, + n > 0 ? ':' : ' '); + m = 32 - m; + while (m-- > 0) + putchar(' '); + + link_layer = 1; + break; + } + + /* + * Fixup the statistics for interfaces that + * update stats for their network addresses + */ + if (network_layer) { + opackets = ifaddr.in.ia_ifa.if_opackets; + ipackets = ifaddr.in.ia_ifa.if_ipackets; + obytes = ifaddr.in.ia_ifa.if_obytes; + ibytes = ifaddr.in.ia_ifa.if_ibytes; + } + + ifaddraddr = (u_long)TAILQ_NEXT(&ifaddr.ifa, ifa_link); + } + + show_stat("lu", 8, ipackets, link_layer|network_layer); + show_stat("lu", 5, ierrors, link_layer); + show_stat("lu", 5, idrops, link_layer); + if (bflag) + show_stat("lu", 10, ibytes, link_layer|network_layer); + + show_stat("lu", 8, opackets, link_layer|network_layer); + show_stat("lu", 5, oerrors, link_layer); + if (bflag) + show_stat("lu", 10, obytes, link_layer|network_layer); + + show_stat("NRSlu", 5, collisions, link_layer); + if (tflag) + show_stat("LSd", 4, timer, link_layer); + if (dflag) + show_stat("LSd", 4, drops, link_layer); + putchar('\n'); + + if (aflag && ifaddrfound) { + /* + * Print family's multicast addresses + */ + struct ifmultiaddr *multiaddr; + struct ifmultiaddr ifma; + union { + struct sockaddr sa; + struct sockaddr_in in; +#ifdef INET6 + struct sockaddr_in6 in6; +#endif /* INET6 */ + struct sockaddr_dl dl; + } msa; + const char *fmt; + + TAILQ_FOREACH(multiaddr, &ifnet.if_multiaddrs, ifma_link) { + if (kread((u_long)multiaddr, (char *)&ifma, + sizeof ifma) != 0) + break; + multiaddr = &ifma; + if (kread((u_long)ifma.ifma_addr, (char *)&msa, + sizeof msa) != 0) + break; + if (msa.sa.sa_family != sa->sa_family) + continue; + + fmt = 0; + switch (msa.sa.sa_family) { + case AF_INET: + fmt = routename(msa.in.sin_addr.s_addr); + break; +#ifdef INET6 + case AF_INET6: + printf("%*s %-19.19s(refs: %d)\n", + Wflag ? 27 : 25, "", + inet_ntop(AF_INET6, + &msa.in6.sin6_addr, + ntop_buf, + sizeof(ntop_buf)), + ifma.ifma_refcount); + break; +#endif /* INET6 */ + case AF_LINK: + switch (msa.dl.sdl_type) { + case IFT_ETHER: + case IFT_FDDI: + fmt = ether_ntoa( + (struct ether_addr *) + LLADDR(&msa.dl)); + break; + } + break; + } + if (fmt) { + printf("%*s %-17.17s", + Wflag ? 27 : 25, "", fmt); + if (msa.sa.sa_family == AF_LINK) { + printf(" %8lu", imcasts); + printf("%*s", + bflag ? 17 : 6, ""); + printf(" %8lu", omcasts); + } + putchar('\n'); + } + } + } + } +} + +struct iftot { + SLIST_ENTRY(iftot) chain; + char ift_name[IFNAMSIZ]; /* interface name */ + u_long ift_ip; /* input packets */ + u_long ift_ie; /* input errors */ + u_long ift_id; /* input drops */ + u_long ift_op; /* output packets */ + u_long ift_oe; /* output errors */ + u_long ift_co; /* collisions */ + u_int ift_dr; /* drops */ + u_long ift_ib; /* input bytes */ + u_long ift_ob; /* output bytes */ +}; + +u_char signalled; /* set if alarm goes off "early" */ + +/* + * Print a running summary of interface statistics. + * Repeat display every interval1 seconds, showing statistics + * collected over that interval. Assumes that interval1 is non-zero. + * First line printed at top of screen is always cumulative. + * XXX - should be rewritten to use ifmib(4). + */ +static void +sidewaysintpr(int interval1, u_long off) +{ + struct ifnet ifnet; + u_long firstifnet; + struct ifnethead ifnethead; + struct itimerval interval_it; + struct iftot *iftot, *ip, *ipn, *total, *sum, *interesting; + int line; + int oldmask, first; + u_long interesting_off; + + if (kread(off, (char *)&ifnethead, sizeof ifnethead) != 0) + return; + firstifnet = (u_long)TAILQ_FIRST(&ifnethead); + + if ((iftot = malloc(sizeof(struct iftot))) == NULL) { + printf("malloc failed\n"); + exit(1); + } + memset(iftot, 0, sizeof(struct iftot)); + + interesting = NULL; + interesting_off = 0; + for (off = firstifnet, ip = iftot; off;) { + char name[IFNAMSIZ]; + + if (kread(off, (char *)&ifnet, sizeof ifnet) != 0) + break; + strlcpy(name, ifnet.if_xname, sizeof(name)); + if (interface && strcmp(name, interface) == 0) { + interesting = ip; + interesting_off = off; + } + snprintf(ip->ift_name, sizeof(ip->ift_name), "(%s)", name);; + if ((ipn = malloc(sizeof(struct iftot))) == NULL) { + printf("malloc failed\n"); + exit(1); + } + memset(ipn, 0, sizeof(struct iftot)); + SLIST_NEXT(ip, chain) = ipn; + ip = ipn; + off = (u_long)TAILQ_NEXT(&ifnet, if_link); + } + if (interface && interesting == NULL) + errx(1, "%s: unknown interface", interface); + if ((total = malloc(sizeof(struct iftot))) == NULL) { + printf("malloc failed\n"); + exit(1); + } + memset(total, 0, sizeof(struct iftot)); + if ((sum = malloc(sizeof(struct iftot))) == NULL) { + printf("malloc failed\n"); + exit(1); + } + memset(sum, 0, sizeof(struct iftot)); + + (void)signal(SIGALRM, catchalarm); + signalled = NO; + interval_it.it_interval.tv_sec = interval1; + interval_it.it_interval.tv_usec = 0; + interval_it.it_value = interval_it.it_interval; + setitimer(ITIMER_REAL, &interval_it, NULL); + first = 1; +banner: + printf("%17s %14s %16s", "input", + interesting ? interesting->ift_name : "(Total)", "output"); + putchar('\n'); + printf("%10s %5s %5s %10s %10s %5s %10s %5s", + "packets", "errs", "idrops", "bytes", "packets", "errs", "bytes", + "colls"); + if (dflag) + printf(" %5.5s", "drops"); + putchar('\n'); + fflush(stdout); + line = 0; +loop: + if (interesting != NULL) { + ip = interesting; + if (kread(interesting_off, (char *)&ifnet, sizeof ifnet) != 0) { + printf("???\n"); + exit(1); + }; + if (!first) { + show_stat("lu", 10, ifnet.if_ipackets - ip->ift_ip, 1); + show_stat("lu", 5, ifnet.if_ierrors - ip->ift_ie, 1); + show_stat("lu", 5, ifnet.if_iqdrops - ip->ift_id, 1); + show_stat("lu", 10, ifnet.if_ibytes - ip->ift_ib, 1); + show_stat("lu", 10, ifnet.if_opackets - ip->ift_op, 1); + show_stat("lu", 5, ifnet.if_oerrors - ip->ift_oe, 1); + show_stat("lu", 10, ifnet.if_obytes - ip->ift_ob, 1); + show_stat("NRSlu", 5, + ifnet.if_collisions - ip->ift_co, 1); + if (dflag) + show_stat("LSu", 5, + ifnet.if_snd.ifq_drops - ip->ift_dr, 1); + } + ip->ift_ip = ifnet.if_ipackets; + ip->ift_ie = ifnet.if_ierrors; + ip->ift_id = ifnet.if_iqdrops; + ip->ift_ib = ifnet.if_ibytes; + ip->ift_op = ifnet.if_opackets; + ip->ift_oe = ifnet.if_oerrors; + ip->ift_ob = ifnet.if_obytes; + ip->ift_co = ifnet.if_collisions; + ip->ift_dr = ifnet.if_snd.ifq_drops; + } else { + sum->ift_ip = 0; + sum->ift_ie = 0; + sum->ift_id = 0; + sum->ift_ib = 0; + sum->ift_op = 0; + sum->ift_oe = 0; + sum->ift_ob = 0; + sum->ift_co = 0; + sum->ift_dr = 0; + for (off = firstifnet, ip = iftot; + off && SLIST_NEXT(ip, chain) != NULL; + ip = SLIST_NEXT(ip, chain)) { + if (kread(off, (char *)&ifnet, sizeof ifnet) != 0) { + off = 0; + continue; + } + sum->ift_ip += ifnet.if_ipackets; + sum->ift_ie += ifnet.if_ierrors; + sum->ift_id += ifnet.if_iqdrops; + sum->ift_ib += ifnet.if_ibytes; + sum->ift_op += ifnet.if_opackets; + sum->ift_oe += ifnet.if_oerrors; + sum->ift_ob += ifnet.if_obytes; + sum->ift_co += ifnet.if_collisions; + sum->ift_dr += ifnet.if_snd.ifq_drops; + off = (u_long)TAILQ_NEXT(&ifnet, if_link); + } + if (!first) { + show_stat("lu", 10, sum->ift_ip - total->ift_ip, 1); + show_stat("lu", 5, sum->ift_ie - total->ift_ie, 1); + show_stat("lu", 5, sum->ift_id - total->ift_id, 1); + show_stat("lu", 10, sum->ift_ib - total->ift_ib, 1); + show_stat("lu", 10, sum->ift_op - total->ift_op, 1); + show_stat("lu", 5, sum->ift_oe - total->ift_oe, 1); + show_stat("lu", 10, sum->ift_ob - total->ift_ob, 1); + show_stat("NRSlu", 5, sum->ift_co - total->ift_co, 1); + if (dflag) + show_stat("LSu", 5, + sum->ift_dr - total->ift_dr, 1); + } + *total = *sum; + } + if (!first) + putchar('\n'); + fflush(stdout); + if ((noutputs != 0) && (--noutputs == 0)) + exit(0); + oldmask = sigblock(sigmask(SIGALRM)); + while (!signalled) + sigpause(0); + signalled = NO; + sigsetmask(oldmask); + line++; + first = 0; + if (line == 21) + goto banner; + else + goto loop; + /*NOTREACHED*/ +} + +/* + * Set a flag to indicate that a signal from the periodic itimer has been + * caught. + */ +static void +catchalarm(int signo __unused) +{ + signalled = YES; +} diff --git a/freebsd-userspace/commands/usr.bin/netstat/inet.c b/freebsd-userspace/commands/usr.bin/netstat/inet.c new file mode 100644 index 00000000..37b650c5 --- /dev/null +++ b/freebsd-userspace/commands/usr.bin/netstat/inet.c @@ -0,0 +1,1291 @@ +/*- + * Copyright (c) 1983, 1988, 1993, 1995 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)inet.c 8.5 (Berkeley) 5/24/95"; +#endif /* not lint */ +#endif + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#ifdef __rtems__ +#include +#include +#else +#include +#include +#endif +#include +#include +#include + +#include +#include +#include +#include +#include +#ifdef __rtems__ +#include +#else +#include +#endif +#ifdef INET6 +#include +#endif /* INET6 */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define TCPSTATES +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "netstat.h" + +char *inetname(struct in_addr *); +void inetprint(struct in_addr *, int, const char *, int); +#ifdef INET6 +static int udp_done, tcp_done; +#endif /* INET6 */ + +static int +pcblist_sysctl(int proto, char **bufp, int istcp) +{ + const char *mibvar; + char *buf; + size_t len; + + switch (proto) { + case IPPROTO_TCP: + mibvar = "net.inet.tcp.pcblist"; + break; + case IPPROTO_UDP: + mibvar = "net.inet.udp.pcblist"; + break; + case IPPROTO_DIVERT: + mibvar = "net.inet.divert.pcblist"; + break; + default: + mibvar = "net.inet.raw.pcblist"; + break; + } + + len = 0; + if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) { + if (errno != ENOENT) + warn("sysctl: %s", mibvar); + return (0); + } + if ((buf = malloc(len)) == 0) { + warnx("malloc %lu bytes", (u_long)len); + return (0); + } + if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) { + warn("sysctl: %s", mibvar); + free(buf); + return (0); + } + *bufp = buf; + return (1); +} + +/* + * Copied directly from uipc_socket2.c. We leave out some fields that are in + * nested structures that aren't used to avoid extra work. + */ +static void +sbtoxsockbuf(struct sockbuf *sb, struct xsockbuf *xsb) +{ + xsb->sb_cc = sb->sb_cc; + xsb->sb_hiwat = sb->sb_hiwat; + xsb->sb_mbcnt = sb->sb_mbcnt; + xsb->sb_mcnt = sb->sb_mcnt; + xsb->sb_ccnt = sb->sb_ccnt; + xsb->sb_mbmax = sb->sb_mbmax; + xsb->sb_lowat = sb->sb_lowat; + xsb->sb_flags = sb->sb_flags; + xsb->sb_timeo = sb->sb_timeo; +} + +int +sotoxsocket(struct socket *so, struct xsocket *xso) +{ + struct protosw proto; + struct domain domain; + + bzero(xso, sizeof *xso); + xso->xso_len = sizeof *xso; + xso->xso_so = so; + xso->so_type = so->so_type; + xso->so_options = so->so_options; + xso->so_linger = so->so_linger; + xso->so_state = so->so_state; + xso->so_pcb = so->so_pcb; + if (kread((uintptr_t)so->so_proto, &proto, sizeof(proto)) != 0) + return (-1); + xso->xso_protocol = proto.pr_protocol; + if (kread((uintptr_t)proto.pr_domain, &domain, sizeof(domain)) != 0) + return (-1); + xso->xso_family = domain.dom_family; + xso->so_qlen = so->so_qlen; + xso->so_incqlen = so->so_incqlen; + xso->so_qlimit = so->so_qlimit; + xso->so_timeo = so->so_timeo; + xso->so_error = so->so_error; + xso->so_oobmark = so->so_oobmark; + sbtoxsockbuf(&so->so_snd, &xso->so_snd); + sbtoxsockbuf(&so->so_rcv, &xso->so_rcv); + return (0); +} + +static int +pcblist_kvm(u_long off, char **bufp, int istcp) +{ + struct inpcbinfo pcbinfo; + struct inpcbhead listhead; + struct inpcb *inp; + struct xinpcb xi; + struct xinpgen xig; + struct xtcpcb xt; + struct socket so; + struct xsocket *xso; + char *buf, *p; + size_t len; + + if (off == 0) + return (0); + kread(off, &pcbinfo, sizeof(pcbinfo)); + if (istcp) + len = 2 * sizeof(xig) + + (pcbinfo.ipi_count + pcbinfo.ipi_count / 8) * + sizeof(struct xtcpcb); + else + len = 2 * sizeof(xig) + + (pcbinfo.ipi_count + pcbinfo.ipi_count / 8) * + sizeof(struct xinpcb); + if ((buf = malloc(len)) == 0) { + warnx("malloc %lu bytes", (u_long)len); + return (0); + } + p = buf; + +#define COPYOUT(obj, size) do { \ + if (len < (size)) { \ + warnx("buffer size exceeded"); \ + goto fail; \ + } \ + bcopy((obj), p, (size)); \ + len -= (size); \ + p += (size); \ +} while (0) + +#define KREAD(off, buf, len) do { \ + if (kread((uintptr_t)(off), (buf), (len)) != 0) \ + goto fail; \ +} while (0) + + /* Write out header. */ + xig.xig_len = sizeof xig; + xig.xig_count = pcbinfo.ipi_count; + xig.xig_gen = pcbinfo.ipi_gencnt; + xig.xig_sogen = 0; + COPYOUT(&xig, sizeof xig); + + /* Walk the PCB list. */ + xt.xt_len = sizeof xt; + xi.xi_len = sizeof xi; + if (istcp) + xso = &xt.xt_socket; + else + xso = &xi.xi_socket; + KREAD(pcbinfo.ipi_listhead, &listhead, sizeof(listhead)); + LIST_FOREACH(inp, &listhead, inp_list) { + if (istcp) { + KREAD(inp, &xt.xt_inp, sizeof(*inp)); + inp = &xt.xt_inp; + } else { + KREAD(inp, &xi.xi_inp, sizeof(*inp)); + inp = &xi.xi_inp; + } + + if (inp->inp_gencnt > pcbinfo.ipi_gencnt) + continue; + + if (istcp) { + if (inp->inp_ppcb == NULL) + bzero(&xt.xt_tp, sizeof xt.xt_tp); + else if (inp->inp_flags & INP_TIMEWAIT) { + bzero(&xt.xt_tp, sizeof xt.xt_tp); + xt.xt_tp.t_state = TCPS_TIME_WAIT; + } else + KREAD(inp->inp_ppcb, &xt.xt_tp, + sizeof xt.xt_tp); + } + if (inp->inp_socket) { + KREAD(inp->inp_socket, &so, sizeof(so)); + if (sotoxsocket(&so, xso) != 0) + goto fail; + } else { + bzero(xso, sizeof(*xso)); + if (istcp) + xso->xso_protocol = IPPROTO_TCP; + } + if (istcp) + COPYOUT(&xt, sizeof xt); + else + COPYOUT(&xi, sizeof xi); + } + + /* Reread the pcbinfo and write out the footer. */ + kread(off, &pcbinfo, sizeof(pcbinfo)); + xig.xig_count = pcbinfo.ipi_count; + xig.xig_gen = pcbinfo.ipi_gencnt; + COPYOUT(&xig, sizeof xig); + + *bufp = buf; + return (1); + +fail: + free(buf); + return (0); +#undef COPYOUT +#undef KREAD +} + +/* + * 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(u_long off, const char *name, int af1, int proto) +{ + int istcp; + static int first = 1; + char *buf; + const char *vchar; + struct tcpcb *tp = NULL; + struct inpcb *inp; + struct xinpgen *xig, *oxig; + struct xsocket *so; + + istcp = 0; + switch (proto) { + case IPPROTO_TCP: +#ifdef INET6 + if (tcp_done != 0) + return; + else + tcp_done = 1; +#endif + istcp = 1; + break; + case IPPROTO_UDP: +#ifdef INET6 + if (udp_done != 0) + return; + else + udp_done = 1; +#endif + break; + } + if (live) { + if (!pcblist_sysctl(proto, &buf, istcp)) + return; + } else { + if (!pcblist_kvm(off, &buf, istcp)) + return; + } + + oxig = xig = (struct xinpgen *)buf; + for (xig = (struct xinpgen *)((char *)xig + xig->xig_len); + xig->xig_len > sizeof(struct xinpgen); + xig = (struct xinpgen *)((char *)xig + xig->xig_len)) { + if (istcp) { + tp = &((struct xtcpcb *)xig)->xt_tp; + inp = &((struct xtcpcb *)xig)->xt_inp; + so = &((struct xtcpcb *)xig)->xt_socket; + } else { + inp = &((struct xinpcb *)xig)->xi_inp; + so = &((struct xinpcb *)xig)->xi_socket; + } + + /* Ignore sockets for protocols other than the desired one. */ + if (so->xso_protocol != proto) + continue; + + /* Ignore PCBs which were freed during copyout. */ + if (inp->inp_gencnt > oxig->xig_gen) + continue; + + if ((af1 == AF_INET && (inp->inp_vflag & INP_IPV4) == 0) +#ifdef INET6 + || (af1 == AF_INET6 && (inp->inp_vflag & INP_IPV6) == 0) +#endif /* INET6 */ + || (af1 == AF_UNSPEC && ((inp->inp_vflag & INP_IPV4) == 0 +#ifdef INET6 + && (inp->inp_vflag & INP_IPV6) == 0 +#endif /* INET6 */ + )) + ) + continue; + if (!aflag && + ( + (istcp && tp->t_state == TCPS_LISTEN) + || (af1 == AF_INET && + inet_lnaof(inp->inp_laddr) == INADDR_ANY) +#ifdef INET6 + || (af1 == AF_INET6 && + IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) +#endif /* INET6 */ + || (af1 == AF_UNSPEC && + (((inp->inp_vflag & INP_IPV4) != 0 && + inet_lnaof(inp->inp_laddr) == INADDR_ANY) +#ifdef INET6 + || ((inp->inp_vflag & INP_IPV6) != 0 && + IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) +#endif + )) + )) + continue; + + if (first) { + if (!Lflag) { + printf("Active Internet connections"); + if (aflag) + printf(" (including servers)"); + } else + printf( + "Current listen queue sizes (qlen/incqlen/maxqlen)"); + putchar('\n'); + if (Aflag) + printf("%-8.8s ", "Tcpcb"); + if (Lflag) + printf("%-5.5s %-14.14s %-22.22s\n", + "Proto", "Listen", "Local Address"); + else { + printf((Aflag && !Wflag) ? + "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s" : + "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s", + "Proto", "Recv-Q", "Send-Q", + "Local Address", "Foreign Address"); + if (xflag) + printf("%-6.6s %-6.6s %-6.6s %-6.6s %-6.6s %-6.6s %-6.6s %-6.6s %-6.6s %-6.6s %-6.6s %-6.6s %s\n", + "R-MBUF", "S-MBUF", "R-CLUS", + "S-CLUS", "R-HIWA", "S-HIWA", + "R-LOWA", "S-LOWA", "R-BCNT", + "S-BCNT", "R-BMAX", "S-BMAX", + "(state)"); + else + printf("(state)\n"); + } + first = 0; + } + if (Lflag && so->so_qlimit == 0) + continue; + if (Aflag) { + if (istcp) + printf("%8lx ", (u_long)inp->inp_ppcb); + else + printf("%8lx ", (u_long)so->so_pcb); + } +#ifdef INET6 + if ((inp->inp_vflag & INP_IPV6) != 0) + vchar = ((inp->inp_vflag & INP_IPV4) != 0) ? + "46" : "6 "; + else +#endif + vchar = ((inp->inp_vflag & INP_IPV4) != 0) ? + "4 " : " "; + printf("%-3.3s%-2.2s ", name, vchar); + if (Lflag) { + char buf1[15]; + + snprintf(buf1, 15, "%d/%d/%d", so->so_qlen, + so->so_incqlen, so->so_qlimit); + printf("%-14.14s ", buf1); + } else { + printf("%6u %6u ", so->so_rcv.sb_cc, so->so_snd.sb_cc); + } + if (numeric_port) { + if (inp->inp_vflag & INP_IPV4) { + inetprint(&inp->inp_laddr, (int)inp->inp_lport, + name, 1); + if (!Lflag) + inetprint(&inp->inp_faddr, + (int)inp->inp_fport, name, 1); + } +#ifdef INET6 + else if (inp->inp_vflag & INP_IPV6) { + inet6print(&inp->in6p_laddr, + (int)inp->inp_lport, name, 1); + if (!Lflag) + inet6print(&inp->in6p_faddr, + (int)inp->inp_fport, name, 1); + } /* else nothing printed now */ +#endif /* INET6 */ + } else if (inp->inp_flags & INP_ANONPORT) { + if (inp->inp_vflag & INP_IPV4) { + inetprint(&inp->inp_laddr, (int)inp->inp_lport, + name, 1); + if (!Lflag) + inetprint(&inp->inp_faddr, + (int)inp->inp_fport, name, 0); + } +#ifdef INET6 + else if (inp->inp_vflag & INP_IPV6) { + inet6print(&inp->in6p_laddr, + (int)inp->inp_lport, name, 1); + if (!Lflag) + inet6print(&inp->in6p_faddr, + (int)inp->inp_fport, name, 0); + } /* else nothing printed now */ +#endif /* INET6 */ + } else { + if (inp->inp_vflag & INP_IPV4) { + inetprint(&inp->inp_laddr, (int)inp->inp_lport, + name, 0); + if (!Lflag) + inetprint(&inp->inp_faddr, + (int)inp->inp_fport, name, + inp->inp_lport != inp->inp_fport); + } +#ifdef INET6 + else if (inp->inp_vflag & INP_IPV6) { + inet6print(&inp->in6p_laddr, + (int)inp->inp_lport, name, 0); + if (!Lflag) + inet6print(&inp->in6p_faddr, + (int)inp->inp_fport, name, + inp->inp_lport != inp->inp_fport); + } /* else nothing printed now */ +#endif /* INET6 */ + } + if (xflag) { + if (Lflag) + printf("%21s %6u %6u %6u %6u %6u %6u %6u %6u %6u %6u %6u %6u ", + " ", + so->so_rcv.sb_mcnt, so->so_snd.sb_mcnt, + so->so_rcv.sb_ccnt, so->so_snd.sb_ccnt, + so->so_rcv.sb_hiwat, so->so_snd.sb_hiwat, + so->so_rcv.sb_lowat, so->so_snd.sb_lowat, + so->so_rcv.sb_mbcnt, so->so_snd.sb_mbcnt, + so->so_rcv.sb_mbmax, so->so_snd.sb_mbmax); + else + printf("%6u %6u %6u %6u %6u %6u %6u %6u %6u %6u %6u %6u ", + so->so_rcv.sb_mcnt, so->so_snd.sb_mcnt, + so->so_rcv.sb_ccnt, so->so_snd.sb_ccnt, + so->so_rcv.sb_hiwat, so->so_snd.sb_hiwat, + so->so_rcv.sb_lowat, so->so_snd.sb_lowat, + so->so_rcv.sb_mbcnt, so->so_snd.sb_mbcnt, + so->so_rcv.sb_mbmax, so->so_snd.sb_mbmax); + } + if (istcp && !Lflag) { + if (tp->t_state < 0 || tp->t_state >= TCP_NSTATES) + printf("%d", tp->t_state); + else { + printf("%s", tcpstates[tp->t_state]); +#if defined(TF_NEEDSYN) && defined(TF_NEEDFIN) + /* Show T/TCP `hidden state' */ + if (tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN)) + putchar('*'); +#endif /* defined(TF_NEEDSYN) && defined(TF_NEEDFIN) */ + } + } + putchar('\n'); + } + if (xig != oxig && xig->xig_gen != oxig->xig_gen) { + if (oxig->xig_count > xig->xig_count) { + printf("Some %s sockets may have been deleted.\n", + name); + } else if (oxig->xig_count < xig->xig_count) { + printf("Some %s sockets may have been created.\n", + name); + } else { + printf( + "Some %s sockets may have been created or deleted.\n", + name); + } + } + free(buf); +} + +/* + * Dump TCP statistics structure. + */ +void +tcp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) +{ + struct tcpstat tcpstat, zerostat; + size_t len = sizeof tcpstat; + +#ifdef INET6 + if (tcp_done != 0) + return; + else + tcp_done = 1; +#endif + + if (live) { + if (zflag) + memset(&zerostat, 0, len); + if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, + zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { + warn("sysctl: net.inet.tcp.stats"); + return; + } + } else + kread(off, &tcpstat, len); + + printf ("%s:\n", name); + +#define p(f, m) if (tcpstat.f || sflag <= 1) \ + printf(m, tcpstat.f, plural(tcpstat.f)) +#define p1a(f, m) if (tcpstat.f || sflag <= 1) \ + printf(m, 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 p2a(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \ + printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2) +#define p3(f, m) if (tcpstat.f || sflag <= 1) \ + printf(m, tcpstat.f, pluralies(tcpstat.f)) + + p(tcps_sndtotal, "\t%lu packet%s sent\n"); + p2(tcps_sndpack,tcps_sndbyte, "\t\t%lu data packet%s (%lu byte%s)\n"); + p2(tcps_sndrexmitpack, tcps_sndrexmitbyte, + "\t\t%lu data packet%s (%lu byte%s) retransmitted\n"); + p(tcps_sndrexmitbad, + "\t\t%lu data packet%s unnecessarily retransmitted\n"); + p(tcps_mturesent, "\t\t%lu resend%s initiated by MTU discovery\n"); + p2a(tcps_sndacks, tcps_delack, + "\t\t%lu ack-only packet%s (%lu delayed)\n"); + p(tcps_sndurg, "\t\t%lu URG only packet%s\n"); + p(tcps_sndprobe, "\t\t%lu window probe packet%s\n"); + p(tcps_sndwinup, "\t\t%lu window update packet%s\n"); + p(tcps_sndctrl, "\t\t%lu control packet%s\n"); + p(tcps_rcvtotal, "\t%lu packet%s received\n"); + p2(tcps_rcvackpack, tcps_rcvackbyte, + "\t\t%lu ack%s (for %lu byte%s)\n"); + p(tcps_rcvdupack, "\t\t%lu duplicate ack%s\n"); + p(tcps_rcvacktoomuch, "\t\t%lu ack%s for unsent data\n"); + p2(tcps_rcvpack, tcps_rcvbyte, + "\t\t%lu packet%s (%lu byte%s) received in-sequence\n"); + p2(tcps_rcvduppack, tcps_rcvdupbyte, + "\t\t%lu completely duplicate packet%s (%lu byte%s)\n"); + p(tcps_pawsdrop, "\t\t%lu old duplicate packet%s\n"); + p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte, + "\t\t%lu packet%s with some dup. data (%lu byte%s duped)\n"); + p2(tcps_rcvoopack, tcps_rcvoobyte, + "\t\t%lu out-of-order packet%s (%lu byte%s)\n"); + p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin, + "\t\t%lu packet%s (%lu byte%s) of data after window\n"); + p(tcps_rcvwinprobe, "\t\t%lu window probe%s\n"); + p(tcps_rcvwinupd, "\t\t%lu window update packet%s\n"); + p(tcps_rcvafterclose, "\t\t%lu packet%s received after close\n"); + p(tcps_rcvbadsum, "\t\t%lu discarded for bad checksum%s\n"); + p(tcps_rcvbadoff, "\t\t%lu discarded for bad header offset field%s\n"); + p1a(tcps_rcvshort, "\t\t%lu discarded because packet too short\n"); + p1a(tcps_rcvmemdrop, "\t\t%lu discarded due to memory problems\n"); + p(tcps_connattempt, "\t%lu connection request%s\n"); + p(tcps_accepts, "\t%lu connection accept%s\n"); + p(tcps_badsyn, "\t%lu bad connection attempt%s\n"); + p(tcps_listendrop, "\t%lu listen queue overflow%s\n"); + p(tcps_badrst, "\t%lu ignored RSTs in the window%s\n"); + p(tcps_connects, "\t%lu connection%s established (including accepts)\n"); + p2(tcps_closed, tcps_drops, + "\t%lu connection%s closed (including %lu drop%s)\n"); + p(tcps_cachedrtt, "\t\t%lu connection%s updated cached RTT on close\n"); + p(tcps_cachedrttvar, + "\t\t%lu connection%s updated cached RTT variance on close\n"); + p(tcps_cachedssthresh, + "\t\t%lu connection%s updated cached ssthresh on close\n"); + p(tcps_conndrops, "\t%lu embryonic connection%s dropped\n"); + p2(tcps_rttupdated, tcps_segstimed, + "\t%lu segment%s updated rtt (of %lu attempt%s)\n"); + p(tcps_rexmttimeo, "\t%lu retransmit timeout%s\n"); + p(tcps_timeoutdrop, "\t\t%lu connection%s dropped by rexmit timeout\n"); + p(tcps_persisttimeo, "\t%lu persist timeout%s\n"); + p(tcps_persistdrop, "\t\t%lu connection%s dropped by persist timeout\n"); + p(tcps_finwait2_drops, + "\t%lu Connection%s (fin_wait_2) dropped because of timeout\n"); + p(tcps_keeptimeo, "\t%lu keepalive timeout%s\n"); + p(tcps_keepprobe, "\t\t%lu keepalive probe%s sent\n"); + p(tcps_keepdrops, "\t\t%lu connection%s dropped by keepalive\n"); + p(tcps_predack, "\t%lu correct ACK header prediction%s\n"); + p(tcps_preddat, "\t%lu correct data packet header prediction%s\n"); + + p3(tcps_sc_added, "\t%lu syncache entr%s added\n"); + p1a(tcps_sc_retransmitted, "\t\t%lu retransmitted\n"); + p1a(tcps_sc_dupsyn, "\t\t%lu dupsyn\n"); + p1a(tcps_sc_dropped, "\t\t%lu dropped\n"); + p1a(tcps_sc_completed, "\t\t%lu completed\n"); + p1a(tcps_sc_bucketoverflow, "\t\t%lu bucket overflow\n"); + p1a(tcps_sc_cacheoverflow, "\t\t%lu cache overflow\n"); + p1a(tcps_sc_reset, "\t\t%lu reset\n"); + p1a(tcps_sc_stale, "\t\t%lu stale\n"); + p1a(tcps_sc_aborted, "\t\t%lu aborted\n"); + p1a(tcps_sc_badack, "\t\t%lu badack\n"); + p1a(tcps_sc_unreach, "\t\t%lu unreach\n"); + p(tcps_sc_zonefail, "\t\t%lu zone failure%s\n"); + p(tcps_sc_sendcookie, "\t%lu cookie%s sent\n"); + p(tcps_sc_recvcookie, "\t%lu cookie%s received\n"); + + p(tcps_sack_recovery_episode, "\t%lu SACK recovery episode%s\n"); + p(tcps_sack_rexmits, + "\t%lu segment rexmit%s in SACK recovery episodes\n"); + p(tcps_sack_rexmit_bytes, + "\t%lu byte rexmit%s in SACK recovery episodes\n"); + p(tcps_sack_rcv_blocks, + "\t%lu SACK option%s (SACK blocks) received\n"); + p(tcps_sack_send_blocks, "\t%lu SACK option%s (SACK blocks) sent\n"); + p1a(tcps_sack_sboverflow, "\t%lu SACK scoreboard overflow\n"); + + p(tcps_ecn_ce, "\t%lu packet%s with ECN CE bit set\n"); + p(tcps_ecn_ect0, "\t%lu packet%s with ECN ECT(0) bit set\n"); + p(tcps_ecn_ect1, "\t%lu packet%s with ECN ECT(1) bit set\n"); + p(tcps_ecn_shs, "\t%lu successful ECN handshake%s\n"); + p(tcps_ecn_rcwnd, "\t%lu time%s ECN reduced the congestion window\n"); +#undef p +#undef p1a +#undef p2 +#undef p2a +#undef p3 +} + +/* + * Dump UDP statistics structure. + */ +void +udp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) +{ + struct udpstat udpstat, zerostat; + size_t len = sizeof udpstat; + u_long delivered; + +#ifdef INET6 + if (udp_done != 0) + return; + else + udp_done = 1; +#endif + + if (live) { + if (zflag) + memset(&zerostat, 0, len); + if (sysctlbyname("net.inet.udp.stats", &udpstat, &len, + zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { + warn("sysctl: net.inet.udp.stats"); + return; + } + } else + kread(off, &udpstat, len); + + printf("%s:\n", name); +#define p(f, m) if (udpstat.f || sflag <= 1) \ + printf(m, udpstat.f, plural(udpstat.f)) +#define p1a(f, m) if (udpstat.f || sflag <= 1) \ + printf(m, udpstat.f) + p(udps_ipackets, "\t%lu datagram%s received\n"); + p1a(udps_hdrops, "\t%lu with incomplete header\n"); + p1a(udps_badlen, "\t%lu with bad data length field\n"); + p1a(udps_badsum, "\t%lu with bad checksum\n"); + p1a(udps_nosum, "\t%lu with no checksum\n"); + p1a(udps_noport, "\t%lu dropped due to no socket\n"); + p(udps_noportbcast, + "\t%lu broadcast/multicast datagram%s undelivered\n"); + p1a(udps_fullsock, "\t%lu dropped due to full socket buffers\n"); + p1a(udpps_pcbhashmiss, "\t%lu not for hashed pcb\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%lu delivered\n", delivered); + p(udps_opackets, "\t%lu datagram%s output\n"); + /* the next statistic is cumulative in udps_noportbcast */ + p(udps_filtermcast, + "\t%lu time%s multicast source filter matched\n"); +#undef p +#undef p1a +} + +/* + * Dump CARP statistics structure. + */ +void +carp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) +{ + struct carpstats carpstat, zerostat; + size_t len = sizeof(struct carpstats); + + if (live) { + if (zflag) + memset(&zerostat, 0, len); + if (sysctlbyname("net.inet.carp.stats", &carpstat, &len, + zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { + if (errno != ENOENT) + warn("sysctl: net.inet.carp.stats"); + return; + } + } else { + if (off == 0) + return; + kread(off, &carpstat, len); + } + + printf("%s:\n", name); + +#define p(f, m) if (carpstat.f || sflag <= 1) \ + printf(m, (uintmax_t)carpstat.f, plural(carpstat.f)) +#define p2(f, m) if (carpstat.f || sflag <= 1) \ + printf(m, (uintmax_t)carpstat.f) + + p(carps_ipackets, "\t%ju packet%s received (IPv4)\n"); + p(carps_ipackets6, "\t%ju packet%s received (IPv6)\n"); + p(carps_badttl, "\t\t%ju packet%s discarded for wrong TTL\n"); + p(carps_hdrops, "\t\t%ju packet%s shorter than header\n"); + p(carps_badsum, "\t\t%ju discarded for bad checksum%s\n"); + p(carps_badver, "\t\t%ju discarded packet%s with a bad version\n"); + p2(carps_badlen, "\t\t%ju discarded because packet too short\n"); + p2(carps_badauth, "\t\t%ju discarded for bad authentication\n"); + p2(carps_badvhid, "\t\t%ju discarded for bad vhid\n"); + p2(carps_badaddrs, "\t\t%ju discarded because of a bad address list\n"); + p(carps_opackets, "\t%ju packet%s sent (IPv4)\n"); + p(carps_opackets6, "\t%ju packet%s sent (IPv6)\n"); + p2(carps_onomem, "\t\t%ju send failed due to mbuf memory error\n"); +#if notyet + p(carps_ostates, "\t\t%s state update%s sent\n"); +#endif +#undef p +#undef p2 +} + +/* + * Dump IP statistics structure. + */ +void +ip_stats(u_long off, const char *name, int af1 __unused, int proto __unused) +{ + struct ipstat ipstat, zerostat; + size_t len = sizeof ipstat; + + if (live) { + if (zflag) + memset(&zerostat, 0, len); + if (sysctlbyname("net.inet.ip.stats", &ipstat, &len, + zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { + warn("sysctl: net.inet.ip.stats"); + return; + } + } else + kread(off, &ipstat, len); + + printf("%s:\n", name); + +#define p(f, m) if (ipstat.f || sflag <= 1) \ + printf(m, ipstat.f, plural(ipstat.f)) +#define p1a(f, m) if (ipstat.f || sflag <= 1) \ + printf(m, ipstat.f) + + p(ips_total, "\t%lu total packet%s received\n"); + p(ips_badsum, "\t%lu bad header checksum%s\n"); + p1a(ips_toosmall, "\t%lu with size smaller than minimum\n"); + p1a(ips_tooshort, "\t%lu with data size < data length\n"); + p1a(ips_toolong, "\t%lu with ip length > max ip packet size\n"); + p1a(ips_badhlen, "\t%lu with header length < data size\n"); + p1a(ips_badlen, "\t%lu with data length < header length\n"); + p1a(ips_badoptions, "\t%lu with bad options\n"); + p1a(ips_badvers, "\t%lu with incorrect version number\n"); + p(ips_fragments, "\t%lu fragment%s received\n"); + p(ips_fragdropped, "\t%lu fragment%s dropped (dup or out of space)\n"); + p(ips_fragtimeout, "\t%lu fragment%s dropped after timeout\n"); + p(ips_reassembled, "\t%lu packet%s reassembled ok\n"); + p(ips_delivered, "\t%lu packet%s for this host\n"); + p(ips_noproto, "\t%lu packet%s for unknown/unsupported protocol\n"); + p(ips_forward, "\t%lu packet%s forwarded"); + p(ips_fastforward, " (%lu packet%s fast forwarded)"); + if (ipstat.ips_forward || sflag <= 1) + putchar('\n'); + p(ips_cantforward, "\t%lu packet%s not forwardable\n"); + p(ips_notmember, + "\t%lu packet%s received for unknown multicast group\n"); + p(ips_redirectsent, "\t%lu redirect%s sent\n"); + p(ips_localout, "\t%lu packet%s sent from this host\n"); + p(ips_rawout, "\t%lu packet%s sent with fabricated ip header\n"); + p(ips_odropped, + "\t%lu output packet%s dropped due to no bufs, etc.\n"); + p(ips_noroute, "\t%lu output packet%s discarded due to no route\n"); + p(ips_fragmented, "\t%lu output datagram%s fragmented\n"); + p(ips_ofragments, "\t%lu fragment%s created\n"); + p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n"); + p(ips_nogif, "\t%lu tunneling packet%s that can't find gif\n"); + p(ips_badaddr, "\t%lu datagram%s with bad address in header\n"); +#undef p +#undef p1a +} + +/* + * Dump ARP statistics structure. + */ +void +arp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) +{ + struct arpstat arpstat, zerostat; + size_t len = sizeof(arpstat); + + if (live) { + if (zflag) + memset(&zerostat, 0, len); + if (sysctlbyname("net.link.ether.arp.stats", &arpstat, &len, + zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { + warn("sysctl: net.link.ether.arp.stats"); + return; + } + } else + kread(off, &arpstat, len); + + printf("%s:\n", name); + +#define p(f, m) if (arpstat.f || sflag <= 1) \ + printf(m, arpstat.f, plural(arpstat.f)) +#define p2(f, m) if (arpstat.f || sflag <= 1) \ + printf(m, arpstat.f, pluralies(arpstat.f)) + + p(txrequests, "\t%lu ARP request%s sent\n"); + p2(txreplies, "\t%lu ARP repl%s sent\n"); + p(rxrequests, "\t%lu ARP request%s received\n"); + p2(rxreplies, "\t%lu ARP repl%s received\n"); + p(received, "\t%lu ARP packet%s received\n"); + p(dropped, "\t%lu total packet%s dropped due to no ARP entry\n"); + p(timeouts, "\t%lu ARP entry%s timed out\n"); + p(dupips, "\t%lu Duplicate IP%s seen\n"); +#undef p +#undef p2 +} + + + +static const char *icmpnames[ICMP_MAXTYPE + 1] = { + "echo reply", /* RFC 792 */ + "#1", + "#2", + "destination unreachable", /* RFC 792 */ + "source quench", /* RFC 792 */ + "routing redirect", /* RFC 792 */ + "#6", + "#7", + "echo", /* RFC 792 */ + "router advertisement", /* RFC 1256 */ + "router solicitation", /* RFC 1256 */ + "time exceeded", /* RFC 792 */ + "parameter problem", /* RFC 792 */ + "time stamp", /* RFC 792 */ + "time stamp reply", /* RFC 792 */ + "information request", /* RFC 792 */ + "information request reply", /* RFC 792 */ + "address mask request", /* RFC 950 */ + "address mask reply", /* RFC 950 */ + "#19", + "#20", + "#21", + "#22", + "#23", + "#24", + "#25", + "#26", + "#27", + "#28", + "#29", + "icmp traceroute", /* RFC 1393 */ + "datagram conversion error", /* RFC 1475 */ + "mobile host redirect", + "IPv6 where-are-you", + "IPv6 i-am-here", + "mobile registration req", + "mobile registration reply", + "domain name request", /* RFC 1788 */ + "domain name reply", /* RFC 1788 */ + "icmp SKIP", + "icmp photuris", /* RFC 2521 */ +}; + +/* + * Dump ICMP statistics. + */ +void +icmp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) +{ + struct icmpstat icmpstat, zerostat; + int i, first; + size_t len; + + len = sizeof icmpstat; + if (live) { + if (zflag) + memset(&zerostat, 0, len); + if (sysctlbyname("net.inet.icmp.stats", &icmpstat, &len, + zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { + warn("sysctl: net.inet.icmp.stats"); + return; + } + } else + kread(off, &icmpstat, len); + + printf("%s:\n", name); + +#define p(f, m) if (icmpstat.f || sflag <= 1) \ + printf(m, icmpstat.f, plural(icmpstat.f)) +#define p1a(f, m) if (icmpstat.f || sflag <= 1) \ + printf(m, icmpstat.f) +#define p2(f, m) if (icmpstat.f || sflag <= 1) \ + printf(m, icmpstat.f, plurales(icmpstat.f)) + + p(icps_error, "\t%lu call%s to icmp_error\n"); + p(icps_oldicmp, + "\t%lu error%s not generated in response to an icmp message\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; + } + if (icmpnames[i] != NULL) + printf("\t\t%s: %lu\n", icmpnames[i], + icmpstat.icps_outhist[i]); + else + printf("\t\tunknown ICMP #%d: %lu\n", i, + icmpstat.icps_outhist[i]); + } + p(icps_badcode, "\t%lu message%s with bad code fields\n"); + p(icps_tooshort, "\t%lu message%s less than the minimum length\n"); + p(icps_checksum, "\t%lu message%s with bad checksum\n"); + p(icps_badlen, "\t%lu message%s with bad length\n"); + p1a(icps_bmcastecho, "\t%lu multicast echo requests ignored\n"); + p1a(icps_bmcasttstamp, "\t%lu multicast timestamp requests ignored\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; + } + if (icmpnames[i] != NULL) + printf("\t\t%s: %lu\n", icmpnames[i], + icmpstat.icps_inhist[i]); + else + printf("\t\tunknown ICMP #%d: %lu\n", i, + icmpstat.icps_inhist[i]); + } + p(icps_reflect, "\t%lu message response%s generated\n"); + p2(icps_badaddr, "\t%lu invalid return address%s\n"); + p(icps_noroute, "\t%lu no return route%s\n"); +#undef p +#undef p1a +#undef p2 + if (live) { + len = sizeof i; + if (sysctlbyname("net.inet.icmp.maskrepl", &i, &len, NULL, 0) < + 0) + return; + printf("\tICMP address mask responses are %sabled\n", + i ? "en" : "dis"); + } +} + +#ifndef BURN_BRIDGES +/* + * Dump IGMP statistics structure (pre 8.x kernel). + */ +static void +igmp_stats_live_old(u_long off, const char *name) +{ + struct oigmpstat oigmpstat, zerostat; + size_t len = sizeof(oigmpstat); + + if (zflag) + memset(&zerostat, 0, len); + if (sysctlbyname("net.inet.igmp.stats", &oigmpstat, &len, + zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { + warn("sysctl: net.inet.igmp.stats"); + return; + } + + printf("%s:\n", name); + +#define p(f, m) if (oigmpstat.f || sflag <= 1) \ + printf(m, oigmpstat.f, plural(oigmpstat.f)) +#define py(f, m) if (oigmpstat.f || sflag <= 1) \ + printf(m, oigmpstat.f, oigmpstat.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 +} +#endif /* !BURN_BRIDGES */ + +/* + * Dump IGMP statistics structure. + */ +void +igmp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) +{ + struct igmpstat igmpstat, zerostat; + size_t len; + +#ifndef BURN_BRIDGES + if (live) { + /* + * Detect if we are being run against a pre-IGMPv3 kernel. + * We cannot do this for a core file as the legacy + * struct igmpstat has no size field, nor does it + * export it in any readily-available symbols. + */ + len = 0; + if (sysctlbyname("net.inet.igmp.stats", NULL, &len, NULL, + 0) < 0) { + warn("sysctl: net.inet.igmp.stats"); + return; + } + if (len < sizeof(igmpstat)) { + igmp_stats_live_old(off, name); + return; + } + } +#endif /* !BURN_BRIDGES */ + + len = sizeof(igmpstat); + if (live) { + if (zflag) + memset(&zerostat, 0, len); + if (sysctlbyname("net.inet.igmp.stats", &igmpstat, &len, + zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { + warn("sysctl: net.inet.igmp.stats"); + return; + } + } else { + len = sizeof(igmpstat); + kread(off, &igmpstat, len); + } + + if (igmpstat.igps_version != IGPS_VERSION_3) { + warnx("%s: version mismatch (%d != %d)", __func__, + igmpstat.igps_version, IGPS_VERSION_3); + } + if (igmpstat.igps_len != IGPS_VERSION3_LEN) { + warnx("%s: size mismatch (%d != %d)", __func__, + igmpstat.igps_len, IGPS_VERSION3_LEN); + } + + printf("%s:\n", name); + +#define p64(f, m) if (igmpstat.f || sflag <= 1) \ + printf(m, (uintmax_t) igmpstat.f, plural(igmpstat.f)) +#define py64(f, m) if (igmpstat.f || sflag <= 1) \ + printf(m, (uintmax_t) igmpstat.f, pluralies(igmpstat.f)) + p64(igps_rcv_total, "\t%ju message%s received\n"); + p64(igps_rcv_tooshort, "\t%ju message%s received with too few bytes\n"); + p64(igps_rcv_badttl, "\t%ju message%s received with wrong TTL\n"); + p64(igps_rcv_badsum, "\t%ju message%s received with bad checksum\n"); + py64(igps_rcv_v1v2_queries, "\t%ju V1/V2 membership quer%s received\n"); + py64(igps_rcv_v3_queries, "\t%ju V3 membership quer%s received\n"); + py64(igps_rcv_badqueries, + "\t%ju membership quer%s received with invalid field(s)\n"); + py64(igps_rcv_gen_queries, "\t%ju general quer%s received\n"); + py64(igps_rcv_group_queries, "\t%ju group quer%s received\n"); + py64(igps_rcv_gsr_queries, "\t%ju group-source quer%s received\n"); + py64(igps_drop_gsr_queries, "\t%ju group-source quer%s dropped\n"); + p64(igps_rcv_reports, "\t%ju membership report%s received\n"); + p64(igps_rcv_badreports, + "\t%ju membership report%s received with invalid field(s)\n"); + p64(igps_rcv_ourreports, +"\t%ju membership report%s received for groups to which we belong\n"); + p64(igps_rcv_nora, "\t%ju V3 report%s received without Router Alert\n"); + p64(igps_snd_reports, "\t%ju membership report%s sent\n"); +#undef p64 +#undef py64 +} + +/* + * Dump PIM statistics structure. + */ +void +pim_stats(u_long off __unused, const char *name, int af1 __unused, + int proto __unused) +{ + struct pimstat pimstat, zerostat; + size_t len = sizeof pimstat; + + if (live) { + if (zflag) + memset(&zerostat, 0, len); + if (sysctlbyname("net.inet.pim.stats", &pimstat, &len, + zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { + if (errno != ENOENT) + warn("sysctl: net.inet.pim.stats"); + return; + } + } else { + if (off == 0) + return; + kread(off, &pimstat, len); + } + + printf("%s:\n", name); + +#define p(f, m) if (pimstat.f || sflag <= 1) \ + printf(m, (uintmax_t)pimstat.f, plural(pimstat.f)) +#define py(f, m) if (pimstat.f || sflag <= 1) \ + printf(m, (uintmax_t)pimstat.f, pimstat.f != 1 ? "ies" : "y") + p(pims_rcv_total_msgs, "\t%ju message%s received\n"); + p(pims_rcv_total_bytes, "\t%ju byte%s received\n"); + p(pims_rcv_tooshort, "\t%ju message%s received with too few bytes\n"); + p(pims_rcv_badsum, "\t%ju message%s received with bad checksum\n"); + p(pims_rcv_badversion, "\t%ju message%s received with bad version\n"); + p(pims_rcv_registers_msgs, "\t%ju data register message%s received\n"); + p(pims_rcv_registers_bytes, "\t%ju data register byte%s received\n"); + p(pims_rcv_registers_wrongiif, + "\t%ju data register message%s received on wrong iif\n"); + p(pims_rcv_badregisters, "\t%ju bad register%s received\n"); + p(pims_snd_registers_msgs, "\t%ju data register message%s sent\n"); + p(pims_snd_registers_bytes, "\t%ju data register byte%s sent\n"); +#undef p +#undef py +} + +/* + * Pretty print an Internet address (net address + port). + */ +void +inetprint(struct in_addr *in, int port, const char *proto, int num_port) +{ + struct servent *sp = 0; + char line[80], *cp; + int width; + + if (Wflag) + sprintf(line, "%s.", inetname(in)); + else + sprintf(line, "%.*s.", (Aflag && !num_port) ? 12 : 16, inetname(in)); + cp = index(line, '\0'); + if (!num_port && port) + sp = getservbyport((int)port, proto); + if (sp || port == 0) + sprintf(cp, "%.15s ", sp ? sp->s_name : "*"); + else + sprintf(cp, "%d ", ntohs((u_short)port)); + width = (Aflag && !Wflag) ? 18 : 22; + if (Wflag) + printf("%-*s ", width, line); + else + printf("%-*.*s ", width, width, line); +} + +/* + * Construct an Internet address representation. + * If numeric_addr has been supplied, give + * numeric value, otherwise try for symbolic name. + */ +char * +inetname(struct in_addr *inp) +{ + char *cp; + static char line[MAXHOSTNAMELEN]; + struct hostent *hp; + struct netent *np; + + cp = 0; + if (!numeric_addr && inp->s_addr != INADDR_ANY) { + int net = inet_netof(*inp); + int lna = inet_lnaof(*inp); + + if (lna == INADDR_ANY) { + np = getnetbyaddr(net, AF_INET); + if (np) + cp = np->n_name; + } + if (cp == 0) { + hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET); + if (hp) { + cp = hp->h_name; + trimdomain(cp, strlen(cp)); + } + } + } + if (inp->s_addr == INADDR_ANY) + strcpy(line, "*"); + else if (cp) { + strlcpy(line, cp, sizeof(line)); + } else { + inp->s_addr = ntohl(inp->s_addr); +#define C(x) ((u_int)((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/freebsd-userspace/commands/usr.bin/netstat/inet6.c b/freebsd-userspace/commands/usr.bin/netstat/inet6.c new file mode 100644 index 00000000..254868d5 --- /dev/null +++ b/freebsd-userspace/commands/usr.bin/netstat/inet6.c @@ -0,0 +1,1159 @@ +/* BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp */ +/*- + * Copyright (c) 1983, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)inet6.c 8.4 (Berkeley) 4/20/94"; +#endif /* not lint */ +#endif + +#include +__FBSDID("$FreeBSD$"); + +#ifdef INET6 +#include +#include +#include +#include +#include +#ifdef __rtems__ +#include +#else +#include +#endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include "netstat.h" + +struct socket sockb; + +char *inet6name(struct in6_addr *); + +static char ntop_buf[INET6_ADDRSTRLEN]; + +static const char *ip6nh[] = { + "hop by hop", + "ICMP", + "IGMP", + "#3", + "IP", + "#5", + "TCP", + "#7", + "#8", + "#9", + "#10", + "#11", + "#12", + "#13", + "#14", + "#15", + "#16", + "UDP", + "#18", + "#19", + "#20", + "#21", + "IDP", + "#23", + "#24", + "#25", + "#26", + "#27", + "#28", + "TP", + "#30", + "#31", + "#32", + "#33", + "#34", + "#35", + "#36", + "#37", + "#38", + "#39", + "#40", + "IP6", + "#42", + "routing", + "fragment", + "#45", + "#46", + "#47", + "#48", + "#49", + "ESP", + "AH", + "#52", + "#53", + "#54", + "#55", + "#56", + "#57", + "ICMP6", + "no next header", + "destination option", + "#61", + "mobility", + "#63", + "#64", + "#65", + "#66", + "#67", + "#68", + "#69", + "#70", + "#71", + "#72", + "#73", + "#74", + "#75", + "#76", + "#77", + "#78", + "#79", + "ISOIP", + "#81", + "#82", + "#83", + "#84", + "#85", + "#86", + "#87", + "#88", + "OSPF", + "#80", + "#91", + "#92", + "#93", + "#94", + "#95", + "#96", + "Ethernet", + "#98", + "#99", + "#100", + "#101", + "#102", + "PIM", + "#104", + "#105", + "#106", + "#107", + "#108", + "#109", + "#110", + "#111", + "#112", + "#113", + "#114", + "#115", + "#116", + "#117", + "#118", + "#119", + "#120", + "#121", + "#122", + "#123", + "#124", + "#125", + "#126", + "#127", + "#128", + "#129", + "#130", + "#131", + "#132", + "#133", + "#134", + "#135", + "#136", + "#137", + "#138", + "#139", + "#140", + "#141", + "#142", + "#143", + "#144", + "#145", + "#146", + "#147", + "#148", + "#149", + "#150", + "#151", + "#152", + "#153", + "#154", + "#155", + "#156", + "#157", + "#158", + "#159", + "#160", + "#161", + "#162", + "#163", + "#164", + "#165", + "#166", + "#167", + "#168", + "#169", + "#170", + "#171", + "#172", + "#173", + "#174", + "#175", + "#176", + "#177", + "#178", + "#179", + "#180", + "#181", + "#182", + "#183", + "#184", + "#185", + "#186", + "#187", + "#188", + "#189", + "#180", + "#191", + "#192", + "#193", + "#194", + "#195", + "#196", + "#197", + "#198", + "#199", + "#200", + "#201", + "#202", + "#203", + "#204", + "#205", + "#206", + "#207", + "#208", + "#209", + "#210", + "#211", + "#212", + "#213", + "#214", + "#215", + "#216", + "#217", + "#218", + "#219", + "#220", + "#221", + "#222", + "#223", + "#224", + "#225", + "#226", + "#227", + "#228", + "#229", + "#230", + "#231", + "#232", + "#233", + "#234", + "#235", + "#236", + "#237", + "#238", + "#239", + "#240", + "#241", + "#242", + "#243", + "#244", + "#245", + "#246", + "#247", + "#248", + "#249", + "#250", + "#251", + "#252", + "#253", + "#254", + "#255", +}; + +static char *srcrule_str[] = { + "first candidate", + "same address", + "appropriate scope", + "deprecated address", + "home address", + "outgoing interface", + "matching label", + "public/temporary address", + "alive interface", + "preferred interface", + "rule #10", + "rule #11", + "rule #12", + "rule #13", + "longest match", + "rule #15", +}; + +/* + * Dump IP6 statistics structure. + */ +void +ip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) +{ + struct ip6stat ip6stat; + int first, i; + size_t len; + + len = sizeof ip6stat; + if (live) { + memset(&ip6stat, 0, len); + if (sysctlbyname("net.inet6.ip6.stats", &ip6stat, &len, NULL, + 0) < 0) { + if (errno != ENOENT) + warn("sysctl: net.inet6.ip6.stats"); + return; + } + } else + kread(off, &ip6stat, len); + + printf("%s:\n", name); + +#define p(f, m) if (ip6stat.f || sflag <= 1) \ + printf(m, (uintmax_t)ip6stat.f, plural(ip6stat.f)) +#define p1a(f, m) if (ip6stat.f || sflag <= 1) \ + printf(m, (uintmax_t)ip6stat.f) + + p(ip6s_total, "\t%ju total packet%s received\n"); + p1a(ip6s_toosmall, "\t%ju with size smaller than minimum\n"); + p1a(ip6s_tooshort, "\t%ju with data size < data length\n"); + p1a(ip6s_badoptions, "\t%ju with bad options\n"); + p1a(ip6s_badvers, "\t%ju with incorrect version number\n"); + p(ip6s_fragments, "\t%ju fragment%s received\n"); + p(ip6s_fragdropped, "\t%ju fragment%s dropped (dup or out of space)\n"); + p(ip6s_fragtimeout, "\t%ju fragment%s dropped after timeout\n"); + p(ip6s_fragoverflow, "\t%ju fragment%s that exceeded limit\n"); + p(ip6s_reassembled, "\t%ju packet%s reassembled ok\n"); + p(ip6s_delivered, "\t%ju packet%s for this host\n"); + p(ip6s_forward, "\t%ju packet%s forwarded\n"); + p(ip6s_cantforward, "\t%ju packet%s not forwardable\n"); + p(ip6s_redirectsent, "\t%ju redirect%s sent\n"); + p(ip6s_localout, "\t%ju packet%s sent from this host\n"); + p(ip6s_rawout, "\t%ju packet%s sent with fabricated ip header\n"); + p(ip6s_odropped, "\t%ju output packet%s dropped due to no bufs, etc.\n"); + p(ip6s_noroute, "\t%ju output packet%s discarded due to no route\n"); + p(ip6s_fragmented, "\t%ju output datagram%s fragmented\n"); + p(ip6s_ofragments, "\t%ju fragment%s created\n"); + p(ip6s_cantfrag, "\t%ju datagram%s that can't be fragmented\n"); + p(ip6s_badscope, "\t%ju packet%s that violated scope rules\n"); + p(ip6s_notmember, "\t%ju multicast packet%s which we don't join\n"); + for (first = 1, i = 0; i < 256; i++) + if (ip6stat.ip6s_nxthist[i] != 0) { + if (first) { + printf("\tInput histogram:\n"); + first = 0; + } + printf("\t\t%s: %ju\n", ip6nh[i], + (uintmax_t)ip6stat.ip6s_nxthist[i]); + } + printf("\tMbuf statistics:\n"); + printf("\t\t%ju one mbuf\n", (uintmax_t)ip6stat.ip6s_m1); + for (first = 1, i = 0; i < 32; i++) { + char ifbuf[IFNAMSIZ]; + if (ip6stat.ip6s_m2m[i] != 0) { + if (first) { + printf("\t\ttwo or more mbuf:\n"); + first = 0; + } + printf("\t\t\t%s= %ju\n", + if_indextoname(i, ifbuf), + (uintmax_t)ip6stat.ip6s_m2m[i]); + } + } + printf("\t\t%ju one ext mbuf\n", + (uintmax_t)ip6stat.ip6s_mext1); + printf("\t\t%ju two or more ext mbuf\n", + (uintmax_t)ip6stat.ip6s_mext2m); + p(ip6s_exthdrtoolong, + "\t%ju packet%s whose headers are not continuous\n"); + p(ip6s_nogif, "\t%ju tunneling packet%s that can't find gif\n"); + p(ip6s_toomanyhdr, + "\t%ju packet%s discarded because of too many headers\n"); + + /* for debugging source address selection */ +#define PRINT_SCOPESTAT(s,i) do {\ + switch(i) { /* XXX hardcoding in each case */\ + case 1:\ + p(s, "\t\t%ju node-local%s\n");\ + break;\ + case 2:\ + p(s,"\t\t%ju link-local%s\n");\ + break;\ + case 5:\ + p(s,"\t\t%ju site-local%s\n");\ + break;\ + case 14:\ + p(s,"\t\t%ju global%s\n");\ + break;\ + default:\ + printf("\t\t%ju addresses scope=%x\n",\ + (uintmax_t)ip6stat.s, i);\ + }\ + } while (0); + + p(ip6s_sources_none, + "\t%ju failure%s of source address selection\n"); + for (first = 1, i = 0; i < 16; i++) { + if (ip6stat.ip6s_sources_sameif[i]) { + if (first) { + printf("\tsource addresses on an outgoing I/F\n"); + first = 0; + } + PRINT_SCOPESTAT(ip6s_sources_sameif[i], i); + } + } + for (first = 1, i = 0; i < 16; i++) { + if (ip6stat.ip6s_sources_otherif[i]) { + if (first) { + printf("\tsource addresses on a non-outgoing I/F\n"); + first = 0; + } + PRINT_SCOPESTAT(ip6s_sources_otherif[i], i); + } + } + for (first = 1, i = 0; i < 16; i++) { + if (ip6stat.ip6s_sources_samescope[i]) { + if (first) { + printf("\tsource addresses of same scope\n"); + first = 0; + } + PRINT_SCOPESTAT(ip6s_sources_samescope[i], i); + } + } + for (first = 1, i = 0; i < 16; i++) { + if (ip6stat.ip6s_sources_otherscope[i]) { + if (first) { + printf("\tsource addresses of a different scope\n"); + first = 0; + } + PRINT_SCOPESTAT(ip6s_sources_otherscope[i], i); + } + } + for (first = 1, i = 0; i < 16; i++) { + if (ip6stat.ip6s_sources_deprecated[i]) { + if (first) { + printf("\tdeprecated source addresses\n"); + first = 0; + } + PRINT_SCOPESTAT(ip6s_sources_deprecated[i], i); + } + } + + printf("\tSource addresses selection rule applied:\n"); + for (i = 0; i < 16; i++) { + if (ip6stat.ip6s_sources_rule[i]) + printf("\t\t%ju %s\n", + (uintmax_t)ip6stat.ip6s_sources_rule[i], + srcrule_str[i]); + } +#undef p +#undef p1a +} + +/* + * Dump IPv6 per-interface statistics based on RFC 2465. + */ +void +ip6_ifstats(char *ifname) +{ + struct in6_ifreq ifr; + int s; +#define p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \ + printf(m, (uintmax_t)ifr.ifr_ifru.ifru_stat.f, plural(ifr.ifr_ifru.ifru_stat.f)) +#define p_5(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \ + printf(m, (uintmax_t)ip6stat.f) + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + perror("Warning: socket(AF_INET6)"); + return; + } + + strcpy(ifr.ifr_name, ifname); + printf("ip6 on %s:\n", ifr.ifr_name); + + if (ioctl(s, SIOCGIFSTAT_IN6, (char *)&ifr) < 0) { + perror("Warning: ioctl(SIOCGIFSTAT_IN6)"); + goto end; + } + + p(ifs6_in_receive, "\t%ju total input datagram%s\n"); + p(ifs6_in_hdrerr, "\t%ju datagram%s with invalid header received\n"); + p(ifs6_in_toobig, "\t%ju datagram%s exceeded MTU received\n"); + p(ifs6_in_noroute, "\t%ju datagram%s with no route received\n"); + p(ifs6_in_addrerr, "\t%ju datagram%s with invalid dst received\n"); + p(ifs6_in_protounknown, "\t%ju datagram%s with unknown proto received\n"); + p(ifs6_in_truncated, "\t%ju truncated datagram%s received\n"); + p(ifs6_in_discard, "\t%ju input datagram%s discarded\n"); + p(ifs6_in_deliver, + "\t%ju datagram%s delivered to an upper layer protocol\n"); + p(ifs6_out_forward, "\t%ju datagram%s forwarded to this interface\n"); + p(ifs6_out_request, + "\t%ju datagram%s sent from an upper layer protocol\n"); + p(ifs6_out_discard, "\t%ju total discarded output datagram%s\n"); + p(ifs6_out_fragok, "\t%ju output datagram%s fragmented\n"); + p(ifs6_out_fragfail, "\t%ju output datagram%s failed on fragment\n"); + p(ifs6_out_fragcreat, "\t%ju output datagram%s succeeded on fragment\n"); + p(ifs6_reass_reqd, "\t%ju incoming datagram%s fragmented\n"); + p(ifs6_reass_ok, "\t%ju datagram%s reassembled\n"); + p(ifs6_reass_fail, "\t%ju datagram%s failed on reassembly\n"); + p(ifs6_in_mcast, "\t%ju multicast datagram%s received\n"); + p(ifs6_out_mcast, "\t%ju multicast datagram%s sent\n"); + + end: + close(s); + +#undef p +#undef p_5 +} + +static const char *icmp6names[] = { + "#0", + "unreach", + "packet too big", + "time exceed", + "parameter problem", + "#5", + "#6", + "#7", + "#8", + "#9", + "#10", + "#11", + "#12", + "#13", + "#14", + "#15", + "#16", + "#17", + "#18", + "#19", + "#20", + "#21", + "#22", + "#23", + "#24", + "#25", + "#26", + "#27", + "#28", + "#29", + "#30", + "#31", + "#32", + "#33", + "#34", + "#35", + "#36", + "#37", + "#38", + "#39", + "#40", + "#41", + "#42", + "#43", + "#44", + "#45", + "#46", + "#47", + "#48", + "#49", + "#50", + "#51", + "#52", + "#53", + "#54", + "#55", + "#56", + "#57", + "#58", + "#59", + "#60", + "#61", + "#62", + "#63", + "#64", + "#65", + "#66", + "#67", + "#68", + "#69", + "#70", + "#71", + "#72", + "#73", + "#74", + "#75", + "#76", + "#77", + "#78", + "#79", + "#80", + "#81", + "#82", + "#83", + "#84", + "#85", + "#86", + "#87", + "#88", + "#89", + "#80", + "#91", + "#92", + "#93", + "#94", + "#95", + "#96", + "#97", + "#98", + "#99", + "#100", + "#101", + "#102", + "#103", + "#104", + "#105", + "#106", + "#107", + "#108", + "#109", + "#110", + "#111", + "#112", + "#113", + "#114", + "#115", + "#116", + "#117", + "#118", + "#119", + "#120", + "#121", + "#122", + "#123", + "#124", + "#125", + "#126", + "#127", + "echo", + "echo reply", + "multicast listener query", + "MLDv1 listener report", + "MLDv1 listener done", + "router solicitation", + "router advertisement", + "neighbor solicitation", + "neighbor advertisement", + "redirect", + "router renumbering", + "node information request", + "node information reply", + "inverse neighbor solicitation", + "inverse neighbor advertisement", + "MLDv2 listener report", + "#144", + "#145", + "#146", + "#147", + "#148", + "#149", + "#150", + "#151", + "#152", + "#153", + "#154", + "#155", + "#156", + "#157", + "#158", + "#159", + "#160", + "#161", + "#162", + "#163", + "#164", + "#165", + "#166", + "#167", + "#168", + "#169", + "#170", + "#171", + "#172", + "#173", + "#174", + "#175", + "#176", + "#177", + "#178", + "#179", + "#180", + "#181", + "#182", + "#183", + "#184", + "#185", + "#186", + "#187", + "#188", + "#189", + "#180", + "#191", + "#192", + "#193", + "#194", + "#195", + "#196", + "#197", + "#198", + "#199", + "#200", + "#201", + "#202", + "#203", + "#204", + "#205", + "#206", + "#207", + "#208", + "#209", + "#210", + "#211", + "#212", + "#213", + "#214", + "#215", + "#216", + "#217", + "#218", + "#219", + "#220", + "#221", + "#222", + "#223", + "#224", + "#225", + "#226", + "#227", + "#228", + "#229", + "#230", + "#231", + "#232", + "#233", + "#234", + "#235", + "#236", + "#237", + "#238", + "#239", + "#240", + "#241", + "#242", + "#243", + "#244", + "#245", + "#246", + "#247", + "#248", + "#249", + "#250", + "#251", + "#252", + "#253", + "#254", + "#255", +}; + +/* + * Dump ICMP6 statistics. + */ +void +icmp6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) +{ + struct icmp6stat icmp6stat; + int i, first; + size_t len; + + len = sizeof icmp6stat; + if (live) { + memset(&icmp6stat, 0, len); + if (sysctlbyname("net.inet6.icmp6.stats", &icmp6stat, &len, + NULL, 0) < 0) { + if (errno != ENOENT) + warn("sysctl: net.inet6.icmp6.stats"); + return; + } + } else + kread(off, &icmp6stat, len); + + printf("%s:\n", name); + +#define p(f, m) if (icmp6stat.f || sflag <= 1) \ + printf(m, (uintmax_t)icmp6stat.f, plural(icmp6stat.f)) +#define p_5(f, m) if (icmp6stat.f || sflag <= 1) \ + printf(m, (uintmax_t)icmp6stat.f) + + p(icp6s_error, "\t%ju call%s to icmp6_error\n"); + p(icp6s_canterror, + "\t%ju error%s not generated in response to an icmp6 message\n"); + p(icp6s_toofreq, + "\t%ju error%s not generated because of rate limitation\n"); +#define NELEM (int)(sizeof(icmp6stat.icp6s_outhist)/sizeof(icmp6stat.icp6s_outhist[0])) + for (first = 1, i = 0; i < NELEM; i++) + if (icmp6stat.icp6s_outhist[i] != 0) { + if (first) { + printf("\tOutput histogram:\n"); + first = 0; + } + printf("\t\t%s: %ju\n", icmp6names[i], + (uintmax_t)icmp6stat.icp6s_outhist[i]); + } +#undef NELEM + p(icp6s_badcode, "\t%ju message%s with bad code fields\n"); + p(icp6s_tooshort, "\t%ju message%s < minimum length\n"); + p(icp6s_checksum, "\t%ju bad checksum%s\n"); + p(icp6s_badlen, "\t%ju message%s with bad length\n"); +#define NELEM (int)(sizeof(icmp6stat.icp6s_inhist)/sizeof(icmp6stat.icp6s_inhist[0])) + for (first = 1, i = 0; i < NELEM; i++) + if (icmp6stat.icp6s_inhist[i] != 0) { + if (first) { + printf("\tInput histogram:\n"); + first = 0; + } + printf("\t\t%s: %ju\n", icmp6names[i], + (uintmax_t)icmp6stat.icp6s_inhist[i]); + } +#undef NELEM + printf("\tHistogram of error messages to be generated:\n"); + p_5(icp6s_odst_unreach_noroute, "\t\t%ju no route\n"); + p_5(icp6s_odst_unreach_admin, "\t\t%ju administratively prohibited\n"); + p_5(icp6s_odst_unreach_beyondscope, "\t\t%ju beyond scope\n"); + p_5(icp6s_odst_unreach_addr, "\t\t%ju address unreachable\n"); + p_5(icp6s_odst_unreach_noport, "\t\t%ju port unreachable\n"); + p_5(icp6s_opacket_too_big, "\t\t%ju packet too big\n"); + p_5(icp6s_otime_exceed_transit, "\t\t%ju time exceed transit\n"); + p_5(icp6s_otime_exceed_reassembly, "\t\t%ju time exceed reassembly\n"); + p_5(icp6s_oparamprob_header, "\t\t%ju erroneous header field\n"); + p_5(icp6s_oparamprob_nextheader, "\t\t%ju unrecognized next header\n"); + p_5(icp6s_oparamprob_option, "\t\t%ju unrecognized option\n"); + p_5(icp6s_oredirect, "\t\t%ju redirect\n"); + p_5(icp6s_ounknown, "\t\t%ju unknown\n"); + + p(icp6s_reflect, "\t%ju message response%s generated\n"); + p(icp6s_nd_toomanyopt, "\t%ju message%s with too many ND options\n"); + p(icp6s_nd_badopt, "\t%ju message%s with bad ND options\n"); + p(icp6s_badns, "\t%ju bad neighbor solicitation message%s\n"); + p(icp6s_badna, "\t%ju bad neighbor advertisement message%s\n"); + p(icp6s_badrs, "\t%ju bad router solicitation message%s\n"); + p(icp6s_badra, "\t%ju bad router advertisement message%s\n"); + p(icp6s_badredirect, "\t%ju bad redirect message%s\n"); + p(icp6s_pmtuchg, "\t%ju path MTU change%s\n"); +#undef p +#undef p_5 +} + +/* + * Dump ICMPv6 per-interface statistics based on RFC 2466. + */ +void +icmp6_ifstats(char *ifname) +{ + struct in6_ifreq ifr; + int s; +#define p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \ + printf(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f, plural(ifr.ifr_ifru.ifru_icmp6stat.f)) +#define p2(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \ + printf(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f, pluralies(ifr.ifr_ifru.ifru_icmp6stat.f)) + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + perror("Warning: socket(AF_INET6)"); + return; + } + + strcpy(ifr.ifr_name, ifname); + printf("icmp6 on %s:\n", ifr.ifr_name); + + if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) { + perror("Warning: ioctl(SIOCGIFSTAT_ICMP6)"); + goto end; + } + + p(ifs6_in_msg, "\t%ju total input message%s\n"); + p(ifs6_in_error, "\t%ju total input error message%s\n"); + p(ifs6_in_dstunreach, "\t%ju input destination unreachable error%s\n"); + p(ifs6_in_adminprohib, "\t%ju input administratively prohibited error%s\n"); + p(ifs6_in_timeexceed, "\t%ju input time exceeded error%s\n"); + p(ifs6_in_paramprob, "\t%ju input parameter problem error%s\n"); + p(ifs6_in_pkttoobig, "\t%ju input packet too big error%s\n"); + p(ifs6_in_echo, "\t%ju input echo request%s\n"); + p2(ifs6_in_echoreply, "\t%ju input echo repl%s\n"); + p(ifs6_in_routersolicit, "\t%ju input router solicitation%s\n"); + p(ifs6_in_routeradvert, "\t%ju input router advertisement%s\n"); + p(ifs6_in_neighborsolicit, "\t%ju input neighbor solicitation%s\n"); + p(ifs6_in_neighboradvert, "\t%ju input neighbor advertisement%s\n"); + p(ifs6_in_redirect, "\t%ju input redirect%s\n"); + p2(ifs6_in_mldquery, "\t%ju input MLD quer%s\n"); + p(ifs6_in_mldreport, "\t%ju input MLD report%s\n"); + p(ifs6_in_mlddone, "\t%ju input MLD done%s\n"); + + p(ifs6_out_msg, "\t%ju total output message%s\n"); + p(ifs6_out_error, "\t%ju total output error message%s\n"); + p(ifs6_out_dstunreach, "\t%ju output destination unreachable error%s\n"); + p(ifs6_out_adminprohib, "\t%ju output administratively prohibited error%s\n"); + p(ifs6_out_timeexceed, "\t%ju output time exceeded error%s\n"); + p(ifs6_out_paramprob, "\t%ju output parameter problem error%s\n"); + p(ifs6_out_pkttoobig, "\t%ju output packet too big error%s\n"); + p(ifs6_out_echo, "\t%ju output echo request%s\n"); + p2(ifs6_out_echoreply, "\t%ju output echo repl%s\n"); + p(ifs6_out_routersolicit, "\t%ju output router solicitation%s\n"); + p(ifs6_out_routeradvert, "\t%ju output router advertisement%s\n"); + p(ifs6_out_neighborsolicit, "\t%ju output neighbor solicitation%s\n"); + p(ifs6_out_neighboradvert, "\t%ju output neighbor advertisement%s\n"); + p(ifs6_out_redirect, "\t%ju output redirect%s\n"); + p2(ifs6_out_mldquery, "\t%ju output MLD quer%s\n"); + p(ifs6_out_mldreport, "\t%ju output MLD report%s\n"); + p(ifs6_out_mlddone, "\t%ju output MLD done%s\n"); + + end: + close(s); +#undef p +} + +/* + * Dump PIM statistics structure. + */ +void +pim6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) +{ + struct pim6stat pim6stat, zerostat; + size_t len = sizeof pim6stat; + + if (live) { + if (zflag) + memset(&zerostat, 0, len); + if (sysctlbyname("net.inet6.pim.stats", &pim6stat, &len, + zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { + if (errno != ENOENT) + warn("sysctl: net.inet6.pim.stats"); + return; + } + } else { + if (off == 0) + return; + kread(off, &pim6stat, len); + } + + printf("%s:\n", name); + +#define p(f, m) if (pim6stat.f || sflag <= 1) \ + printf(m, (uintmax_t)pim6stat.f, plural(pim6stat.f)) + p(pim6s_rcv_total, "\t%ju message%s received\n"); + p(pim6s_rcv_tooshort, "\t%ju message%s received with too few bytes\n"); + p(pim6s_rcv_badsum, "\t%ju message%s received with bad checksum\n"); + p(pim6s_rcv_badversion, "\t%ju message%s received with bad version\n"); + p(pim6s_rcv_registers, "\t%ju register%s received\n"); + p(pim6s_rcv_badregisters, "\t%ju bad register%s received\n"); + p(pim6s_snd_registers, "\t%ju register%s sent\n"); +#undef p +} + +/* + * Dump raw ip6 statistics structure. + */ +void +rip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) +{ + struct rip6stat rip6stat; + u_quad_t delivered; + size_t len; + + len = sizeof(rip6stat); + if (live) { + if (sysctlbyname("net.inet6.ip6.rip6stats", &rip6stat, &len, + NULL, 0) < 0) { + if (errno != ENOENT) + warn("sysctl: net.inet6.ip6.rip6stats"); + return; + } + } else + kread(off, &rip6stat, len); + + printf("%s:\n", name); + +#define p(f, m) if (rip6stat.f || sflag <= 1) \ + printf(m, (uintmax_t)rip6stat.f, plural(rip6stat.f)) + p(rip6s_ipackets, "\t%ju message%s received\n"); + p(rip6s_isum, "\t%ju checksum calculation%s on inbound\n"); + p(rip6s_badsum, "\t%ju message%s with bad checksum\n"); + p(rip6s_nosock, "\t%ju message%s dropped due to no socket\n"); + p(rip6s_nosockmcast, + "\t%ju multicast message%s dropped due to no socket\n"); + p(rip6s_fullsock, + "\t%ju message%s dropped due to full socket buffers\n"); + delivered = rip6stat.rip6s_ipackets - + rip6stat.rip6s_badsum - + rip6stat.rip6s_nosock - + rip6stat.rip6s_nosockmcast - + rip6stat.rip6s_fullsock; + if (delivered || sflag <= 1) + printf("\t%ju delivered\n", (uintmax_t)delivered); + p(rip6s_opackets, "\t%ju datagram%s output\n"); +#undef p +} + +/* + * Pretty print an Internet address (net address + port). + * Take numeric_addr and numeric_port into consideration. + */ +#define GETSERVBYPORT6(port, proto, ret)\ +{\ + if (strcmp((proto), "tcp6") == 0)\ + (ret) = getservbyport((int)(port), "tcp");\ + else if (strcmp((proto), "udp6") == 0)\ + (ret) = getservbyport((int)(port), "udp");\ + else\ + (ret) = getservbyport((int)(port), (proto));\ +}; + +void +inet6print(struct in6_addr *in6, int port, const char *proto, int numeric) +{ + struct servent *sp = 0; + char line[80], *cp; + int width; + + sprintf(line, "%.*s.", Wflag ? 39 : + (Aflag && !numeric) ? 12 : 16, inet6name(in6)); + cp = index(line, '\0'); + if (!numeric && port) + GETSERVBYPORT6(port, proto, sp); + if (sp || port == 0) + sprintf(cp, "%.15s", sp ? sp->s_name : "*"); + else + sprintf(cp, "%d", ntohs((u_short)port)); + width = Wflag ? 45 : Aflag ? 18 : 22; + printf("%-*.*s ", width, width, line); +} + +/* + * Construct an Internet address representation. + * If the numeric_addr has been supplied, give + * numeric value, otherwise try for symbolic name. + */ + +char * +inet6name(struct in6_addr *in6p) +{ + char *cp; + static char line[50]; + struct hostent *hp; + static char domain[MAXHOSTNAMELEN]; + static int first = 1; + + if (first && !numeric_addr) { + first = 0; + if (gethostname(domain, MAXHOSTNAMELEN) == 0 && + (cp = index(domain, '.'))) + (void) strcpy(domain, cp + 1); + else + domain[0] = 0; + } + cp = 0; + if (!numeric_addr && !IN6_IS_ADDR_UNSPECIFIED(in6p)) { + hp = gethostbyaddr((char *)in6p, sizeof(*in6p), AF_INET6); + if (hp) { + if ((cp = index(hp->h_name, '.')) && + !strcmp(cp + 1, domain)) + *cp = 0; + cp = hp->h_name; + } + } + if (IN6_IS_ADDR_UNSPECIFIED(in6p)) + strcpy(line, "*"); + else if (cp) + strcpy(line, cp); + else + sprintf(line, "%s", + inet_ntop(AF_INET6, (void *)in6p, ntop_buf, + sizeof(ntop_buf))); + return (line); +} +#endif /*INET6*/ diff --git a/freebsd-userspace/commands/usr.bin/netstat/ipsec.c b/freebsd-userspace/commands/usr.bin/netstat/ipsec.c new file mode 100644 index 00000000..a6ef510c --- /dev/null +++ b/freebsd-userspace/commands/usr.bin/netstat/ipsec.c @@ -0,0 +1,481 @@ +/* $KAME: ipsec.c,v 1.33 2003/07/25 09:54:32 itojun Exp $ */ + +/*- + * Copyright (c) 2005 NTT Multimedia Communications Laboratories, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/*- + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/*- + * Copyright (c) 1983, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)inet.c 8.5 (Berkeley) 5/24/95"; +#endif /* not lint */ +#endif + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include + +#ifdef IPSEC +#ifdef __rtems__ +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif +#endif + +#include +#include +#include +#include +#include "netstat.h" + +#ifdef IPSEC +struct val2str { + int val; + const char *str; +}; + +static struct val2str ipsec_ahnames[] = { + { SADB_AALG_NONE, "none", }, + { SADB_AALG_MD5HMAC, "hmac-md5", }, + { SADB_AALG_SHA1HMAC, "hmac-sha1", }, + { SADB_X_AALG_MD5, "md5", }, + { SADB_X_AALG_SHA, "sha", }, + { SADB_X_AALG_NULL, "null", }, +#ifdef SADB_X_AALG_SHA2_256 + { SADB_X_AALG_SHA2_256, "hmac-sha2-256", }, +#endif +#ifdef SADB_X_AALG_SHA2_384 + { SADB_X_AALG_SHA2_384, "hmac-sha2-384", }, +#endif +#ifdef SADB_X_AALG_SHA2_512 + { SADB_X_AALG_SHA2_512, "hmac-sha2-512", }, +#endif +#ifdef SADB_X_AALG_RIPEMD160HMAC + { SADB_X_AALG_RIPEMD160HMAC, "hmac-ripemd160", }, +#endif +#ifdef SADB_X_AALG_AES_XCBC_MAC + { SADB_X_AALG_AES_XCBC_MAC, "aes-xcbc-mac", }, +#endif + { -1, NULL }, +}; + +static struct val2str ipsec_espnames[] = { + { SADB_EALG_NONE, "none", }, + { SADB_EALG_DESCBC, "des-cbc", }, + { SADB_EALG_3DESCBC, "3des-cbc", }, + { SADB_EALG_NULL, "null", }, + { SADB_X_EALG_CAST128CBC, "cast128-cbc", }, + { SADB_X_EALG_BLOWFISHCBC, "blowfish-cbc", }, +#ifdef SADB_X_EALG_RIJNDAELCBC + { SADB_X_EALG_RIJNDAELCBC, "rijndael-cbc", }, +#endif +#ifdef SADB_X_EALG_AESCTR + { SADB_X_EALG_AESCTR, "aes-ctr", }, +#endif + { -1, NULL }, +}; + +static struct val2str ipsec_compnames[] = { + { SADB_X_CALG_NONE, "none", }, + { SADB_X_CALG_OUI, "oui", }, + { SADB_X_CALG_DEFLATE, "deflate", }, + { SADB_X_CALG_LZS, "lzs", }, + { -1, NULL }, +}; + +static void ipsec_hist(const u_quad_t *hist, size_t histmax, + const struct val2str *name, const char *title); +static void print_ipsecstats(const struct ipsecstat *ipsecstat); + + +/* + * Dump IPSEC statistics structure. + */ +static void +ipsec_hist(const u_quad_t *hist, size_t histmax, const struct val2str *name, + const char *title) +{ + int first; + size_t proto; + const struct val2str *p; + + first = 1; + for (proto = 0; proto < histmax; proto++) { + if (hist[proto] <= 0) + continue; + if (first) { + printf("\t%s histogram:\n", title); + first = 0; + } + for (p = name; p && p->str; p++) { + if (p->val == (int)proto) + break; + } + if (p && p->str) { + printf("\t\t%s: %ju\n", p->str, (uintmax_t)hist[proto]); + } else { + printf("\t\t#%ld: %ju\n", (long)proto, + (uintmax_t)hist[proto]); + } + } +} + +static void +print_ipsecstats(const struct ipsecstat *ipsecstat) +{ +#define p(f, m) if (ipsecstat->f || sflag <= 1) \ + printf(m, (uintmax_t)ipsecstat->f, plural(ipsecstat->f)) +#define pes(f, m) if (ipsecstat->f || sflag <= 1) \ + printf(m, (uintmax_t)ipsecstat->f, plurales(ipsecstat->f)) +#define hist(f, n, t) \ + ipsec_hist((f), sizeof(f)/sizeof(f[0]), (n), (t)); + + p(in_success, "\t%ju inbound packet%s processed successfully\n"); + p(in_polvio, "\t%ju inbound packet%s violated process security " + "policy\n"); + p(in_nosa, "\t%ju inbound packet%s with no SA available\n"); + p(in_inval, "\t%ju invalid inbound packet%s\n"); + p(in_nomem, "\t%ju inbound packet%s failed due to insufficient memory\n"); + p(in_badspi, "\t%ju inbound packet%s failed getting SPI\n"); + p(in_ahreplay, "\t%ju inbound packet%s failed on AH replay check\n"); + p(in_espreplay, "\t%ju inbound packet%s failed on ESP replay check\n"); + p(in_ahauthsucc, "\t%ju inbound packet%s considered authentic\n"); + p(in_ahauthfail, "\t%ju inbound packet%s failed on authentication\n"); + hist(ipsecstat->in_ahhist, ipsec_ahnames, "AH input"); + hist(ipsecstat->in_esphist, ipsec_espnames, "ESP input"); + hist(ipsecstat->in_comphist, ipsec_compnames, "IPComp input"); + + p(out_success, "\t%ju outbound packet%s processed successfully\n"); + p(out_polvio, "\t%ju outbound packet%s violated process security " + "policy\n"); + p(out_nosa, "\t%ju outbound packet%s with no SA available\n"); + p(out_inval, "\t%ju invalid outbound packet%s\n"); + p(out_nomem, "\t%ju outbound packet%s failed due to insufficient memory\n"); + p(out_noroute, "\t%ju outbound packet%s with no route\n"); + hist(ipsecstat->out_ahhist, ipsec_ahnames, "AH output"); + hist(ipsecstat->out_esphist, ipsec_espnames, "ESP output"); + hist(ipsecstat->out_comphist, ipsec_compnames, "IPComp output"); + p(spdcachelookup, "\t%ju SPD cache lookup%s\n"); + pes(spdcachemiss, "\t%ju SPD cache miss%s\n"); +#undef pes +#undef hist + p(ips_in_polvio, "\t%ju inbound packet%s violated process " + "security policy\n"); + p(ips_out_polvio, "\t%ju outbound packet%s violated process " + "security policy\n"); + p(ips_out_nosa, "\t%ju outbound packet%s with no SA available\n"); + p(ips_out_nomem, "\t%ju outbound packet%s failed due to " + "insufficient memory\n"); + p(ips_out_noroute, "\t%ju outbound packet%s with no route " + "available\n"); + p(ips_out_inval, "\t%ju invalid outbound packet%s\n"); + p(ips_out_bundlesa, "\t%ju outbound packet%s with bundled SAs\n"); + p(ips_mbcoalesced, "\t%ju mbuf%s coalesced during clone\n"); + p(ips_clcoalesced, "\t%ju cluster%s coalesced during clone\n"); + p(ips_clcopied, "\t%ju cluster%s copied during clone\n"); + p(ips_mbinserted, "\t%ju mbuf%s inserted during makespace\n"); +#undef p +} + +void +ipsec_stats(u_long off, const char *name, int af1 __unused, int proto __unused) +{ + struct ipsecstat ipsecstat; + + if (off == 0) + return; + printf ("%s:\n", name); + kread(off, (char *)&ipsecstat, sizeof(ipsecstat)); + + print_ipsecstats(&ipsecstat); +} + + +static void ipsec_hist_new(const u_int32_t *hist, size_t histmax, + const struct val2str *name, const char *title); +static void print_ahstats(const struct ahstat *ahstat); +static void print_espstats(const struct espstat *espstat); +static void print_ipcompstats(const struct ipcompstat *ipcompstat); + +/* + * Dump IPSEC statistics structure. + */ +static void +ipsec_hist_new(const u_int32_t *hist, size_t histmax, + const struct val2str *name, const char *title) +{ + int first; + size_t proto; + const struct val2str *p; + + first = 1; + for (proto = 0; proto < histmax; proto++) { + if (hist[proto] <= 0) + continue; + if (first) { + printf("\t%s histogram:\n", title); + first = 0; + } + for (p = name; p && p->str; p++) { + if (p->val == (int)proto) + break; + } + if (p && p->str) { + printf("\t\t%s: %u\n", p->str, hist[proto]); + } else { + printf("\t\t#%lu: %u\n", (unsigned long)proto, + hist[proto]); + } + } +} + +static void +print_ahstats(const struct ahstat *ahstat) +{ +#define p32(f, m) if (ahstat->f || sflag <= 1) \ + printf("\t%u" m, (unsigned int)ahstat->f, plural(ahstat->f)) +#define p64(f, m) if (ahstat->f || sflag <= 1) \ + printf("\t%ju" m, (uintmax_t)ahstat->f, plural(ahstat->f)) +#define hist(f, n, t) \ + ipsec_hist_new((f), sizeof(f)/sizeof(f[0]), (n), (t)); + + p32(ahs_hdrops, " packet%s shorter than header shows\n"); + p32(ahs_nopf, " packet%s dropped; protocol family not supported\n"); + p32(ahs_notdb, " packet%s dropped; no TDB\n"); + p32(ahs_badkcr, " packet%s dropped; bad KCR\n"); + p32(ahs_qfull, " packet%s dropped; queue full\n"); + p32(ahs_noxform, " packet%s dropped; no transform\n"); + p32(ahs_wrap, " replay counter wrap%s\n"); + p32(ahs_badauth, " packet%s dropped; bad authentication detected\n"); + p32(ahs_badauthl, " packet%s dropped; bad authentication length\n"); + p32(ahs_replay, " possible replay packet%s detected\n"); + p32(ahs_input, " packet%s in\n"); + p32(ahs_output, " packet%s out\n"); + p32(ahs_invalid, " packet%s dropped; invalid TDB\n"); + p64(ahs_ibytes, " byte%s in\n"); + p64(ahs_obytes, " byte%s out\n"); + p32(ahs_toobig, " packet%s dropped; larger than IP_MAXPACKET\n"); + p32(ahs_pdrops, " packet%s blocked due to policy\n"); + p32(ahs_crypto, " crypto processing failure%s\n"); + p32(ahs_tunnel, " tunnel sanity check failure%s\n"); + hist(ahstat->ahs_hist, ipsec_ahnames, "AH output"); + +#undef p32 +#undef p64 +#undef hist +} + +void +ah_stats(u_long off, const char *name, int family __unused, int proto __unused) +{ + struct ahstat ahstat; + + if (off == 0) + return; + printf ("%s:\n", name); + kread(off, (char *)&ahstat, sizeof(ahstat)); + + print_ahstats(&ahstat); +} + +static void +print_espstats(const struct espstat *espstat) +{ +#define p32(f, m) if (espstat->f || sflag <= 1) \ + printf("\t%u" m, (unsigned int)espstat->f, plural(espstat->f)) +#define p64(f, m) if (espstat->f || sflag <= 1) \ + printf("\t%ju" m, (uintmax_t)espstat->f, plural(espstat->f)) +#define hist(f, n, t) \ + ipsec_hist_new((f), sizeof(f)/sizeof(f[0]), (n), (t)); + + p32(esps_hdrops, " packet%s shorter than header shows\n"); + p32(esps_nopf, " packet%s dropped; protocol family not supported\n"); + p32(esps_notdb, " packet%s dropped; no TDB\n"); + p32(esps_badkcr, " packet%s dropped; bad KCR\n"); + p32(esps_qfull, " packet%s dropped; queue full\n"); + p32(esps_noxform, " packet%s dropped; no transform\n"); + p32(esps_badilen, " packet%s dropped; bad ilen\n"); + p32(esps_wrap, " replay counter wrap%s\n"); + p32(esps_badenc, " packet%s dropped; bad encryption detected\n"); + p32(esps_badauth, " packet%s dropped; bad authentication detected\n"); + p32(esps_replay, " possible replay packet%s detected\n"); + p32(esps_input, " packet%s in\n"); + p32(esps_output, " packet%s out\n"); + p32(esps_invalid, " packet%s dropped; invalid TDB\n"); + p64(esps_ibytes, " byte%s in\n"); + p64(esps_obytes, " byte%s out\n"); + p32(esps_toobig, " packet%s dropped; larger than IP_MAXPACKET\n"); + p32(esps_pdrops, " packet%s blocked due to policy\n"); + p32(esps_crypto, " crypto processing failure%s\n"); + p32(esps_tunnel, " tunnel sanity check failure%s\n"); + hist(espstat->esps_hist, ipsec_espnames, "ESP output"); + +#undef p32 +#undef p64 +#undef hist +} + +void +esp_stats(u_long off, const char *name, int family __unused, int proto __unused) +{ + struct espstat espstat; + + if (off == 0) + return; + printf ("%s:\n", name); + kread(off, (char *)&espstat, sizeof(espstat)); + + print_espstats(&espstat); +} + +static void +print_ipcompstats(const struct ipcompstat *ipcompstat) +{ + uint32_t version; +#define p32(f, m) if (ipcompstat->f || sflag <= 1) \ + printf("\t%u" m, (unsigned int)ipcompstat->f, plural(ipcompstat->f)) +#define p64(f, m) if (ipcompstat->f || sflag <= 1) \ + printf("\t%ju" m, (uintmax_t)ipcompstat->f, plural(ipcompstat->f)) +#define hist(f, n, t) \ + ipsec_hist_new((f), sizeof(f)/sizeof(f[0]), (n), (t)); + +#ifndef IPCOMPSTAT_VERSION + version = 0; +#else + version = ipcompstat->version; +#endif + p32(ipcomps_hdrops, " packet%s shorter than header shows\n"); + p32(ipcomps_nopf, " packet%s dropped; protocol family not supported\n"); + p32(ipcomps_notdb, " packet%s dropped; no TDB\n"); + p32(ipcomps_badkcr, " packet%s dropped; bad KCR\n"); + p32(ipcomps_qfull, " packet%s dropped; queue full\n"); + p32(ipcomps_noxform, " packet%s dropped; no transform\n"); + p32(ipcomps_wrap, " replay counter wrap%s\n"); + p32(ipcomps_input, " packet%s in\n"); + p32(ipcomps_output, " packet%s out\n"); + p32(ipcomps_invalid, " packet%s dropped; invalid TDB\n"); + p64(ipcomps_ibytes, " byte%s in\n"); + p64(ipcomps_obytes, " byte%s out\n"); + p32(ipcomps_toobig, " packet%s dropped; larger than IP_MAXPACKET\n"); + p32(ipcomps_pdrops, " packet%s blocked due to policy\n"); + p32(ipcomps_crypto, " crypto processing failure%s\n"); + hist(ipcompstat->ipcomps_hist, ipsec_compnames, "COMP output"); + if (version >= 1) { + p32(ipcomps_threshold, " packet%s sent uncompressed; size < compr. algo. threshold\n"); + p32(ipcomps_uncompr, " packet%s sent uncompressed; compression was useless\n"); + } + +#undef p32 +#undef p64 +#undef hist +} + +void +ipcomp_stats(u_long off, const char *name, int family __unused, + int proto __unused) +{ + struct ipcompstat ipcompstat; + + if (off == 0) + return; + printf ("%s:\n", name); + kread(off, (char *)&ipcompstat, sizeof(ipcompstat)); + + print_ipcompstats(&ipcompstat); +} + +#endif /*IPSEC*/ diff --git a/freebsd-userspace/commands/usr.bin/netstat/ipx.c b/freebsd-userspace/commands/usr.bin/netstat/ipx.c new file mode 100644 index 00000000..b78b1514 --- /dev/null +++ b/freebsd-userspace/commands/usr.bin/netstat/ipx.c @@ -0,0 +1,354 @@ +/*- + * Copyright (c) 2004, Robert N. M. Watson + * 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. + */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)ns.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ +#endif + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#ifdef __rtems__ +#include +#else +#include +#endif + +#include + +#define TCPSTATES +#include + +#include +#include +#include +#ifdef IPXERRORMSGS +#include +#endif +#include +#include +#include +#define SANAMES +#include + +#include +#include +#include +#include +#include +#include "netstat.h" + +static char *ipx_prpr(struct ipx_addr *); + +/* + * Print a summary of connections related to a Network Systems + * protocol. For SPX, also give state of connection. + * Listening processes (aflag) are suppressed unless the + * -a (all) flag is specified. + */ + +void +ipxprotopr(u_long off, const char *name, int af1 __unused, int proto __unused) +{ + struct ipxpcbhead cb; + struct ipxpcb *ipxp; + struct ipxpcb ipxpcb; + struct spxpcb spxpcb; + struct socket sockb; + static int first = 1; + int isspx; + + if (off == 0) + return; + + isspx = strcmp(name, "spx") == 0; + kread(off, (char *)&cb, sizeof (struct ipxpcbhead)); + ipxp = LIST_FIRST(&cb); + while (ipxp != NULL) { + u_long ppcb; + + kread((u_long)ipxp, (char *)&ipxpcb, sizeof (ipxpcb)); + ipxp = LIST_NEXT(&ipxpcb, ipxp_list); + + if (!aflag && ipx_nullhost(ipxpcb.ipxp_faddr) ) { + continue; + } + kread((u_long)ipxpcb.ipxp_socket, + (char *)&sockb, sizeof (sockb)); + ppcb = (u_long) ipxpcb.ipxp_pcb; + if (ppcb) { + if (isspx) { + kread(ppcb, (char *)&spxpcb, sizeof (spxpcb)); + } else continue; + } else + if (isspx) continue; + if (first) { + printf("Active IPX 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("%8lx ", ppcb); + printf("%-5.5s %6u %6u ", name, sockb.so_rcv.sb_cc, + sockb.so_snd.sb_cc); + printf(Aflag?" %-18.18s":" %-22.22s", ipx_prpr(&ipxpcb.ipxp_laddr)); + printf(Aflag?" %-18.18s":" %-22.22s", ipx_prpr(&ipxpcb.ipxp_faddr)); + if (isspx) { + if (spxpcb.s_state >= TCP_NSTATES) + printf(" %d", spxpcb.s_state); + else + printf(" %s", tcpstates[spxpcb.s_state]); + } + putchar('\n'); + } +} + +#define ANY(x,y,z) \ + if (x || sflag <= 1) printf("\t%u %s%s%s\n", x, y, plural(x), z) +#define ANYl(x,y,z) \ + if (x || sflag <= 1) printf("\t%lu %s%s%s\n", x, y, plural(x), z) + +/* + * Dump SPX statistics structure. + */ +void +spx_stats(u_long off, const char *name, int af1 __unused, int proto __unused) +{ + struct spx_istat spx_istat; +#define spxstat spx_istat.newstats + + if (off == 0) + return; + kread(off, (char *)&spx_istat, sizeof (spx_istat)); + printf("%s:\n", name); + ANY(spx_istat.nonucn, "connection", " dropped due to no new sockets "); + ANY(spx_istat.gonawy, "connection", " terminated due to our end dying"); + ANY(spx_istat.nonucn, "connection", + " dropped due to inability to connect"); + ANY(spx_istat.noconn, "connection", + " dropped due to inability to connect"); + ANY(spx_istat.notme, "connection", + " incompleted due to mismatched id's"); + ANY(spx_istat.wrncon, "connection", " dropped due to mismatched id's"); + ANY(spx_istat.bdreas, "packet", " dropped out of sequence"); + ANY(spx_istat.lstdup, "packet", " duplicating the highest packet"); + ANY(spx_istat.notyet, "packet", " refused as exceeding allocation"); + ANYl(spxstat.spxs_connattempt, "connection", " initiated"); + ANYl(spxstat.spxs_accepts, "connection", " accepted"); + ANYl(spxstat.spxs_connects, "connection", " established"); + ANYl(spxstat.spxs_drops, "connection", " dropped"); + ANYl(spxstat.spxs_conndrops, "embryonic connection", " dropped"); + ANYl(spxstat.spxs_closed, "connection", " closed (includes drops)"); + ANYl(spxstat.spxs_segstimed, "packet", " where we tried to get rtt"); + ANYl(spxstat.spxs_rttupdated, "time", " we got rtt"); + ANYl(spxstat.spxs_delack, "delayed ack", " sent"); + ANYl(spxstat.spxs_timeoutdrop, "connection", + " dropped in rxmt timeout"); + ANYl(spxstat.spxs_rexmttimeo, "retransmit timeout", ""); + ANYl(spxstat.spxs_persisttimeo, "persist timeout", ""); + ANYl(spxstat.spxs_keeptimeo, "keepalive timeout", ""); + ANYl(spxstat.spxs_keepprobe, "keepalive probe", " sent"); + ANYl(spxstat.spxs_keepdrops, "connection", " dropped in keepalive"); + ANYl(spxstat.spxs_sndtotal, "total packet", " sent"); + ANYl(spxstat.spxs_sndpack, "data packet", " sent"); + ANYl(spxstat.spxs_sndbyte, "data byte", " sent"); + ANYl(spxstat.spxs_sndrexmitpack, "data packet", " retransmitted"); + ANYl(spxstat.spxs_sndrexmitbyte, "data byte", " retransmitted"); + ANYl(spxstat.spxs_sndacks, "ack-only packet", " sent"); + ANYl(spxstat.spxs_sndprobe, "window probe", " sent"); + ANYl(spxstat.spxs_sndurg, "packet", " sent with URG only"); + ANYl(spxstat.spxs_sndwinup, "window update-only packet", " sent"); + ANYl(spxstat.spxs_sndctrl, "control (SYN|FIN|RST) packet", " sent"); + ANYl(spxstat.spxs_sndvoid, "request", " to send a non-existant packet"); + ANYl(spxstat.spxs_rcvtotal, "total packet", " received"); + ANYl(spxstat.spxs_rcvpack, "packet", " received in sequence"); + ANYl(spxstat.spxs_rcvbyte, "byte", " received in sequence"); + ANYl(spxstat.spxs_rcvbadsum, "packet", " received with ccksum errs"); + ANYl(spxstat.spxs_rcvbadoff, "packet", " received with bad offset"); + ANYl(spxstat.spxs_rcvshort, "packet", " received too short"); + ANYl(spxstat.spxs_rcvduppack, "duplicate-only packet", " received"); + ANYl(spxstat.spxs_rcvdupbyte, "duplicate-only byte", " received"); + ANYl(spxstat.spxs_rcvpartduppack, "packet", + " with some duplicate data"); + ANYl(spxstat.spxs_rcvpartdupbyte, "dup. byte", " in part-dup. packet"); + ANYl(spxstat.spxs_rcvoopack, "out-of-order packet", " received"); + ANYl(spxstat.spxs_rcvoobyte, "out-of-order byte", " received"); + ANYl(spxstat.spxs_rcvpackafterwin, "packet", " with data after window"); + ANYl(spxstat.spxs_rcvbyteafterwin, "byte", " rcvd after window"); + ANYl(spxstat.spxs_rcvafterclose, "packet", " rcvd after 'close'"); + ANYl(spxstat.spxs_rcvwinprobe, "rcvd window probe packet", ""); + ANYl(spxstat.spxs_rcvdupack, "rcvd duplicate ack", ""); + ANYl(spxstat.spxs_rcvacktoomuch, "rcvd ack", " for unsent data"); + ANYl(spxstat.spxs_rcvackpack, "rcvd ack packet", ""); + ANYl(spxstat.spxs_rcvackbyte, "byte", " acked by rcvd acks"); + ANYl(spxstat.spxs_rcvwinupd, "rcvd window update packet", ""); +} + +/* + * Dump IPX statistics structure. + */ +void +ipx_stats(u_long off, const char *name, int af1 __unused, int proto __unused) +{ + struct ipxstat ipxstat; + + if (off == 0) + return; + kread(off, (char *)&ipxstat, sizeof (ipxstat)); + printf("%s:\n", name); + ANYl(ipxstat.ipxs_total, "total packet", " received"); + ANYl(ipxstat.ipxs_badsum, "packet", " with bad checksums"); + ANYl(ipxstat.ipxs_tooshort, "packet", " smaller than advertised"); + ANYl(ipxstat.ipxs_toosmall, "packet", " smaller than a header"); + ANYl(ipxstat.ipxs_forward, "packet", " forwarded"); + ANYl(ipxstat.ipxs_cantforward, "packet", " not forwardable"); + ANYl(ipxstat.ipxs_delivered, "packet", " for this host"); + ANYl(ipxstat.ipxs_localout, "packet", " sent from this host"); + ANYl(ipxstat.ipxs_odropped, "packet", " dropped due to no bufs, etc."); + ANYl(ipxstat.ipxs_noroute, "packet", " discarded due to no route"); + ANYl(ipxstat.ipxs_mtutoosmall, "packet", " too big"); +} + +#ifdef IPXERRORMSGS +static struct { + u_short code; + char *name; + char *where; +} ipx_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 IPX Error statistics structure. + */ +/*ARGSUSED*/ +void +ipxerr_stats(u_long off, const char *name, int af __unused, int proto __unused) +{ + struct ipx_errstat ipx_errstat; + int j; + int histoprint = 1; + int z; + + if (off == 0) + return; + kread(off, (char *)&ipx_errstat, sizeof (ipx_errstat)); + printf("IPX error statistics:\n"); + ANY(ipx_errstat.ipx_es_error, "call", " to ipx_error"); + ANY(ipx_errstat.ipx_es_oldshort, "error", + " ignored due to insufficient addressing"); + ANY(ipx_errstat.ipx_es_oldipx_err, "error request", + " in response to error packets"); + ANY(ipx_errstat.ipx_es_tooshort, "error packet", + " received incomplete"); + ANY(ipx_errstat.ipx_es_badcode, "error packet", + " received of unknown type"); + for(j = 0; j < IPX_ERR_MAX; j ++) { + z = ipx_errstat.ipx_es_outhist[j]; + if (z && histoprint) { + printf("Output Error Histogram:\n"); + histoprint = 0; + } + ipx_erputil(z, ipx_errstat.ipx_es_codes[j]); + } + histoprint = 1; + for(j = 0; j < IPX_ERR_MAX; j ++) { + z = ipx_errstat.ipx_es_inhist[j]; + if (z && histoprint) { + printf("Input Error Histogram:\n"); + histoprint = 0; + } + ipx_erputil(z, ipx_errstat.ipx_es_codes[j]); + } +} + +static void +ipx_erputil(int z, int c) +{ + int j; + char codebuf[30]; + char *name, *where; + + for(j = 0;; j ++) { + if ((name = ipx_errnames[j].name) == 0) + break; + if (ipx_errnames[j].code == c) + break; + } + if (name == 0) { + if (c > 01000) + where = "in transit"; + else + where = "at destination"; + sprintf(codebuf, "Unknown IPX error code 0%o", c); + name = codebuf; + } else + where = ipx_errnames[j].where; + ANY(z, name, where); +} +#endif /* IPXERRORMSGS */ + +static struct sockaddr_ipx ssipx = { .sipx_family = AF_IPX }; + +static +char *ipx_prpr(struct ipx_addr *x) +{ + struct sockaddr_ipx *sipx = &ssipx; + + sipx->sipx_addr = *x; + return(ipx_print((struct sockaddr *)sipx)); +} diff --git a/freebsd-userspace/commands/usr.bin/netstat/main.c b/freebsd-userspace/commands/usr.bin/netstat/main.c new file mode 100644 index 00000000..09b26a26 --- /dev/null +++ b/freebsd-userspace/commands/usr.bin/netstat/main.c @@ -0,0 +1,805 @@ +/*- + * Copyright (c) 1983, 1988, 1993 + * Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +char const copyright[] = +"@(#) Copyright (c) 1983, 1988, 1993\n\ + Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 3/1/94"; +#endif /* not lint */ +#endif + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#ifdef __rtems__ +#include +#else +#include +#endif +#include +#include + +#include + +#ifdef NETGRAPH +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "netstat.h" + +static struct nlist nl[] = { +#define N_IFNET 0 + { .n_name = "_ifnet" }, +#define N_RTSTAT 1 + { .n_name = "_rtstat" }, +#define N_RTREE 2 + { .n_name = "_rt_tables"}, +#define N_MRTSTAT 3 + { .n_name = "_mrtstat" }, +#define N_MFCHASHTBL 4 + { .n_name = "_mfchashtbl" }, +#define N_VIFTABLE 5 + { .n_name = "_viftable" }, +#define N_IPX 6 + { .n_name = "_ipxpcb_list"}, +#define N_IPXSTAT 7 + { .n_name = "_ipxstat"}, +#define N_SPXSTAT 8 + { .n_name = "_spx_istat"}, +#define N_DDPSTAT 9 + { .n_name = "_ddpstat"}, +#define N_DDPCB 10 + { .n_name = "_ddpcb"}, +#define N_NGSOCKS 11 + { .n_name = "_ngsocklist"}, +#define N_IP6STAT 12 + { .n_name = "_ip6stat" }, +#define N_ICMP6STAT 13 + { .n_name = "_icmp6stat" }, +#define N_IPSECSTAT 14 + { .n_name = "_ipsec4stat" }, +#define N_IPSEC6STAT 15 + { .n_name = "_ipsec6stat" }, +#define N_PIM6STAT 16 + { .n_name = "_pim6stat" }, +#define N_MRT6STAT 17 + { .n_name = "_mrt6stat" }, +#define N_MF6CTABLE 18 + { .n_name = "_mf6ctable" }, +#define N_MIF6TABLE 19 + { .n_name = "_mif6table" }, +#define N_PFKEYSTAT 20 + { .n_name = "_pfkeystat" }, +#define N_MBSTAT 21 + { .n_name = "_mbstat" }, +#define N_MBTYPES 22 + { .n_name = "_mbtypes" }, +#define N_NMBCLUSTERS 23 + { .n_name = "_nmbclusters" }, +#define N_NMBUFS 24 + { .n_name = "_nmbufs" }, +#define N_MBHI 25 + { .n_name = "_mbuf_hiwm" }, +#define N_CLHI 26 + { .n_name = "_clust_hiwm" }, +#define N_NCPUS 27 + { .n_name = "_smp_cpus" }, +#define N_PAGESZ 28 + { .n_name = "_pagesize" }, +#define N_MBPSTAT 29 + { .n_name = "_mb_statpcpu" }, +#define N_RTTRASH 30 + { .n_name = "_rttrash" }, +#define N_MBLO 31 + { .n_name = "_mbuf_lowm" }, +#define N_CLLO 32 + { .n_name = "_clust_lowm" }, +#define N_CARPSTAT 33 + { .n_name = "_carpstats" }, +#define N_PFSYNCSTAT 34 + { .n_name = "_pfsyncstats" }, +#define N_AHSTAT 35 + { .n_name = "_ahstat" }, +#define N_ESPSTAT 36 + { .n_name = "_espstat" }, +#define N_IPCOMPSTAT 37 + { .n_name = "_ipcompstat" }, +#define N_TCPSTAT 38 + { .n_name = "_tcpstat" }, +#define N_UDPSTAT 39 + { .n_name = "_udpstat" }, +#define N_IPSTAT 40 + { .n_name = "_ipstat" }, +#define N_ICMPSTAT 41 + { .n_name = "_icmpstat" }, +#define N_IGMPSTAT 42 + { .n_name = "_igmpstat" }, +#define N_PIMSTAT 43 + { .n_name = "_pimstat" }, +#define N_TCBINFO 44 + { .n_name = "_tcbinfo" }, +#define N_UDBINFO 45 + { .n_name = "_udbinfo" }, +#define N_DIVCBINFO 46 + { .n_name = "_divcbinfo" }, +#define N_RIPCBINFO 47 + { .n_name = "_ripcbinfo" }, +#define N_UNP_COUNT 48 + { .n_name = "_unp_count" }, +#define N_UNP_GENCNT 49 + { .n_name = "_unp_gencnt" }, +#define N_UNP_DHEAD 50 + { .n_name = "_unp_dhead" }, +#define N_UNP_SHEAD 51 + { .n_name = "_unp_shead" }, +#define N_RIP6STAT 52 + { .n_name = "_rip6stat" }, +#define N_SCTPSTAT 53 + { .n_name = "_sctpstat" }, +#define N_MFCTABLESIZE 54 + { .n_name = "_mfctablesize" }, +#define N_ARPSTAT 55 + { .n_name = "_arpstat" }, + { .n_name = NULL }, +}; + +struct protox { + int pr_index; /* index into nlist of cb head */ + int pr_sindex; /* index into nlist of stat block */ + u_char pr_wanted; /* 1 if wanted, 0 otherwise */ + void (*pr_cblocks)(u_long, const char *, int, int); + /* control blocks printing routine */ + void (*pr_stats)(u_long, const char *, int, int); + /* statistics printing routine */ + void (*pr_istats)(char *); /* per/if statistics printing routine */ + const char *pr_name; /* well-known name */ + int pr_usesysctl; /* non-zero if we use sysctl, not kvm */ + int pr_protocol; +} protox[] = { + { N_TCBINFO, N_TCPSTAT, 1, protopr, + tcp_stats, NULL, "tcp", 1, IPPROTO_TCP }, + { N_UDBINFO, N_UDPSTAT, 1, protopr, + udp_stats, NULL, "udp", 1, IPPROTO_UDP }, +#ifdef SCTP + { -1, N_SCTPSTAT, 1, sctp_protopr, + sctp_stats, NULL, "sctp", 1, IPPROTO_SCTP }, +#endif + { N_DIVCBINFO, -1, 1, protopr, + NULL, NULL, "divert", 1, IPPROTO_DIVERT }, + { N_RIPCBINFO, N_IPSTAT, 1, protopr, + ip_stats, NULL, "ip", 1, IPPROTO_RAW }, + { N_RIPCBINFO, N_ICMPSTAT, 1, protopr, + icmp_stats, NULL, "icmp", 1, IPPROTO_ICMP }, + { N_RIPCBINFO, N_IGMPSTAT, 1, protopr, + igmp_stats, NULL, "igmp", 1, IPPROTO_IGMP }, +#ifdef IPSEC + { -1, N_IPSECSTAT, 1, NULL, /* keep as compat */ + ipsec_stats, NULL, "ipsec", 0, 0}, + { -1, N_AHSTAT, 1, NULL, + ah_stats, NULL, "ah", 0, 0}, + { -1, N_ESPSTAT, 1, NULL, + esp_stats, NULL, "esp", 0, 0}, + { -1, N_IPCOMPSTAT, 1, NULL, + ipcomp_stats, NULL, "ipcomp", 0, 0}, +#endif + { N_RIPCBINFO, N_PIMSTAT, 1, protopr, + pim_stats, NULL, "pim", 1, IPPROTO_PIM }, + { -1, N_CARPSTAT, 1, NULL, + carp_stats, NULL, "carp", 1, 0 }, + { -1, N_PFSYNCSTAT, 1, NULL, + pfsync_stats, NULL, "pfsync", 1, 0 }, + { -1, N_ARPSTAT, 1, NULL, + arp_stats, NULL, "arp", 1, 0 }, + { -1, -1, 0, NULL, + NULL, NULL, NULL, 0, 0 } +}; + +#ifdef INET6 +struct protox ip6protox[] = { + { N_TCBINFO, N_TCPSTAT, 1, protopr, + tcp_stats, NULL, "tcp", 1, IPPROTO_TCP }, + { N_UDBINFO, N_UDPSTAT, 1, protopr, + udp_stats, NULL, "udp", 1, IPPROTO_UDP }, + { N_RIPCBINFO, N_IP6STAT, 1, protopr, + ip6_stats, ip6_ifstats, "ip6", 1, IPPROTO_RAW }, + { N_RIPCBINFO, N_ICMP6STAT, 1, protopr, + icmp6_stats, icmp6_ifstats, "icmp6", 1, IPPROTO_ICMPV6 }, +#ifdef IPSEC + { -1, N_IPSEC6STAT, 1, NULL, + ipsec_stats, NULL, "ipsec6", 0, 0 }, +#endif +#ifdef notyet + { -1, N_PIM6STAT, 1, NULL, + pim6_stats, NULL, "pim6", 1, 0 }, +#endif + { -1, N_RIP6STAT, 1, NULL, + rip6_stats, NULL, "rip6", 1, 0 }, + { -1, -1, 0, NULL, + NULL, NULL, NULL, 0, 0 } +}; +#endif /*INET6*/ + +#ifdef IPSEC +struct protox pfkeyprotox[] = { + { -1, N_PFKEYSTAT, 1, NULL, + pfkey_stats, NULL, "pfkey", 0, 0 }, + { -1, -1, 0, NULL, + NULL, NULL, NULL, 0, 0 } +}; +#endif + +struct protox atalkprotox[] = { + { N_DDPCB, N_DDPSTAT, 1, atalkprotopr, + ddp_stats, NULL, "ddp", 0, 0 }, + { -1, -1, 0, NULL, + NULL, NULL, NULL, 0, 0 } +}; +#ifdef NETGRAPH +struct protox netgraphprotox[] = { + { N_NGSOCKS, -1, 1, netgraphprotopr, + NULL, NULL, "ctrl", 0, 0 }, + { N_NGSOCKS, -1, 1, netgraphprotopr, + NULL, NULL, "data", 0, 0 }, + { -1, -1, 0, NULL, + NULL, NULL, NULL, 0, 0 } +}; +#endif +#ifdef IPX +struct protox ipxprotox[] = { + { N_IPX, N_IPXSTAT, 1, ipxprotopr, + ipx_stats, NULL, "ipx", 0, 0 }, + { N_IPX, N_SPXSTAT, 1, ipxprotopr, + spx_stats, NULL, "spx", 0, 0 }, + { -1, -1, 0, NULL, + NULL, NULL, 0, 0, 0 } +}; +#endif + +struct protox *protoprotox[] = { + protox, +#ifdef INET6 + ip6protox, +#endif +#ifdef IPSEC + pfkeyprotox, +#endif +#ifdef IPX + ipxprotox, +#endif + atalkprotox, NULL }; + +static void printproto(struct protox *, const char *); +static void usage(void); +static struct protox *name2protox(const char *); +static struct protox *knownname(const char *); + +static kvm_t *kvmd; +static char *nlistf = NULL, *memf = NULL; + +int Aflag; /* show addresses of protocol control block */ +int aflag; /* show all sockets (including servers) */ +int Bflag; /* show information about bpf consumers */ +int bflag; /* show i/f total bytes in/out */ +int dflag; /* show i/f dropped packets */ +int gflag; /* show group (multicast) routing or stats */ +int hflag; /* show counters in human readable format */ +int iflag; /* show interfaces */ +int Lflag; /* show size of listen queues */ +int mflag; /* show memory stats */ +int noutputs = 0; /* how much outputs before we exit */ +int numeric_addr; /* show addresses numerically */ +int numeric_port; /* show ports numerically */ +static 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 Wflag; /* wide display */ +int xflag; /* extra information, includes all socket buffer info */ +int zflag; /* zero stats */ + +int interval; /* repeat interval for i/f stats */ + +char *interface; /* desired i/f for stats, or NULL for all i/fs */ +int unit; /* unit number for above */ + +int af; /* address family */ +int live; /* true if we are examining a live system */ + +int +main(int argc, char *argv[]) +{ + struct protox *tp = NULL; /* for printing cblocks & stats */ + int ch; + + af = AF_UNSPEC; + + while ((ch = getopt(argc, argv, "AaBbdf:ghI:iLlM:mN:np:q:rSstuWw:xz")) != -1) + switch(ch) { + case 'A': + Aflag = 1; + break; + case 'a': + aflag = 1; + break; + case 'B': + Bflag = 1; + break; + case 'b': + bflag = 1; + break; + case 'd': + dflag = 1; + break; + case 'f': + if (strcmp(optarg, "ipx") == 0) + af = AF_IPX; + else if (strcmp(optarg, "inet") == 0) + af = AF_INET; +#ifdef INET6 + else if (strcmp(optarg, "inet6") == 0) + af = AF_INET6; +#endif +#ifdef IPSEC + else if (strcmp(optarg, "pfkey") == 0) + af = PF_KEY; +#endif + else if (strcmp(optarg, "unix") == 0) + af = AF_UNIX; + else if (strcmp(optarg, "atalk") == 0) + af = AF_APPLETALK; +#ifdef NETGRAPH + else if (strcmp(optarg, "ng") == 0 + || strcmp(optarg, "netgraph") == 0) + af = AF_NETGRAPH; +#endif + else if (strcmp(optarg, "link") == 0) + af = AF_LINK; + else { + errx(1, "%s: unknown address family", optarg); + } + break; + case 'g': + gflag = 1; + break; + case 'h': + hflag = 1; + break; + case 'I': { + char *cp; + + iflag = 1; + for (cp = interface = optarg; isalpha(*cp); cp++) + continue; + unit = atoi(cp); + break; + } + case 'i': + iflag = 1; + break; + case 'L': + Lflag = 1; + break; + case 'M': + memf = optarg; + break; + case 'm': + mflag = 1; + break; + case 'N': + nlistf = optarg; + break; + case 'n': + numeric_addr = numeric_port = 1; + break; + case 'p': + if ((tp = name2protox(optarg)) == NULL) { + errx(1, + "%s: unknown or uninstrumented protocol", + optarg); + } + pflag = 1; + break; + case 'q': + noutputs = atoi(optarg); + if (noutputs != 0) + noutputs++; + break; + case 'r': + rflag = 1; + break; + case 's': + ++sflag; + break; + case 'S': + numeric_addr = 1; + break; + case 't': + tflag = 1; + break; + case 'u': + af = AF_UNIX; + break; + case 'W': + case 'l': + Wflag = 1; + break; + case 'w': + interval = atoi(optarg); + iflag = 1; + break; + case 'x': + xflag = 1; + break; + case 'z': + zflag = 1; + break; + case '?': + default: + usage(); + } + argv += optind; + argc -= optind; + +#define BACKWARD_COMPATIBILITY +#ifdef BACKWARD_COMPATIBILITY + if (*argv) { + if (isdigit(**argv)) { + interval = atoi(*argv); + if (interval <= 0) + usage(); + ++argv; + iflag = 1; + } + 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. + */ + live = (nlistf == NULL && memf == NULL); + if (!live) + setgid(getgid()); + + if (Bflag) { + if (!live) + usage(); + bpf_stats(interface); + exit(0); + } + if (mflag) { + if (!live) { + if (kread(0, NULL, 0) == 0) + mbpr(kvmd, nl[N_MBSTAT].n_value); + } else + mbpr(NULL, 0); + exit(0); + } +#if 0 + /* + * Keep file descriptors open to avoid overhead + * of open/close on each call to get* routines. + */ + sethostent(1); + setnetent(1); +#else + /* + * This does not make sense any more with DNS being default over + * the files. Doing a setXXXXent(1) causes a tcp connection to be + * used for the queries, which is slower. + */ +#endif + kread(0, NULL, 0); + if (iflag && !sflag) { + intpr(interval, nl[N_IFNET].n_value, NULL); + exit(0); + } + if (rflag) { + if (sflag) + rt_stats(nl[N_RTSTAT].n_value, nl[N_RTTRASH].n_value); + else + routepr(nl[N_RTREE].n_value); + exit(0); + } + if (gflag) { + if (sflag) { + if (af == AF_INET || af == AF_UNSPEC) + mrt_stats(nl[N_MRTSTAT].n_value); +#ifdef INET6 + if (af == AF_INET6 || af == AF_UNSPEC) + mrt6_stats(nl[N_MRT6STAT].n_value); +#endif + } else { + if (af == AF_INET || af == AF_UNSPEC) + mroutepr(nl[N_MFCHASHTBL].n_value, + nl[N_MFCTABLESIZE].n_value, + nl[N_VIFTABLE].n_value); +#ifdef INET6 + if (af == AF_INET6 || af == AF_UNSPEC) + mroute6pr(nl[N_MF6CTABLE].n_value, + nl[N_MIF6TABLE].n_value); +#endif + } + exit(0); + } + + if (tp) { + printproto(tp, tp->pr_name); + exit(0); + } + if (af == AF_INET || af == AF_UNSPEC) + for (tp = protox; tp->pr_name; tp++) + printproto(tp, tp->pr_name); +#ifdef INET6 + if (af == AF_INET6 || af == AF_UNSPEC) + for (tp = ip6protox; tp->pr_name; tp++) + printproto(tp, tp->pr_name); +#endif /*INET6*/ +#ifdef IPSEC + if (af == PF_KEY || af == AF_UNSPEC) + for (tp = pfkeyprotox; tp->pr_name; tp++) + printproto(tp, tp->pr_name); +#endif /*IPSEC*/ +#ifdef IPX + if (af == AF_IPX || af == AF_UNSPEC) { + for (tp = ipxprotox; tp->pr_name; tp++) + printproto(tp, tp->pr_name); + } +#endif /* IPX */ + if (af == AF_APPLETALK || af == AF_UNSPEC) + for (tp = atalkprotox; tp->pr_name; tp++) + printproto(tp, tp->pr_name); +#ifdef NETGRAPH + if (af == AF_NETGRAPH || af == AF_UNSPEC) + for (tp = netgraphprotox; tp->pr_name; tp++) + printproto(tp, tp->pr_name); +#endif /* NETGRAPH */ + if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag) + unixpr(nl[N_UNP_COUNT].n_value, nl[N_UNP_GENCNT].n_value, + nl[N_UNP_DHEAD].n_value, nl[N_UNP_SHEAD].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) + struct protox *tp; + const char *name; +{ + void (*pr)(u_long, const char *, int, int); + u_long off; + + if (sflag) { + if (iflag) { + if (tp->pr_istats) + intpr(interval, nl[N_IFNET].n_value, + tp->pr_istats); + else if (pflag) + printf("%s: no per-interface stats routine\n", + tp->pr_name); + return; + } else { + pr = tp->pr_stats; + if (!pr) { + if (pflag) + printf("%s: no stats routine\n", + tp->pr_name); + return; + } + if (tp->pr_usesysctl && live) + off = 0; + else if (tp->pr_sindex < 0) { + if (pflag) + printf( + "%s: stats routine doesn't work on cores\n", + tp->pr_name); + return; + } else + off = nl[tp->pr_sindex].n_value; + } + } else { + pr = tp->pr_cblocks; + if (!pr) { + if (pflag) + printf("%s: no PCB routine\n", tp->pr_name); + return; + } + if (tp->pr_usesysctl && live) + off = 0; + else if (tp->pr_index < 0) { + if (pflag) + printf( + "%s: PCB routine doesn't work on cores\n", + tp->pr_name); + return; + } else + off = nl[tp->pr_index].n_value; + } + if (pr != NULL && (off || (live && tp->pr_usesysctl) || + af != AF_UNSPEC)) + (*pr)(off, name, af, tp->pr_protocol); +} + +/* + * Read kernel memory, return 0 on success. + */ +int +kread(u_long addr, void *buf, size_t size) +{ + char errbuf[_POSIX2_LINE_MAX]; + + if (kvmd == NULL) { + kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); + setgid(getgid()); + if (kvmd != NULL) { + if (kvm_nlist(kvmd, nl) < 0) { + if (nlistf) + errx(1, "%s: kvm_nlist: %s", nlistf, + kvm_geterr(kvmd)); + else + errx(1, "kvm_nlist: %s", kvm_geterr(kvmd)); + } + + if (nl[0].n_type == 0) { + if (nlistf) + errx(1, "%s: no namelist", nlistf); + else + errx(1, "no namelist"); + } + } else { + warnx("kvm not available: %s", errbuf); + return(-1); + } + } + if (!buf) + return (0); + if (kvm_read(kvmd, addr, buf, size) != (ssize_t)size) { + warnx("%s", kvm_geterr(kvmd)); + return (-1); + } + return (0); +} + +const char * +plural(uintmax_t n) +{ + return (n != 1 ? "s" : ""); +} + +const char * +plurales(uintmax_t n) +{ + return (n != 1 ? "es" : ""); +} + +const char * +pluralies(uintmax_t n) +{ + return (n != 1 ? "ies" : "y"); +} + +/* + * Find the protox for the given "well-known" name. + */ +static struct protox * +knownname(const 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(const char *name) +{ + struct protox *tp; + char **alias; /* alias from p->aliases */ + struct protoent *p; + + /* + * Try to find the name in the list of "well-known" names. If that + * fails, check if name is an alias for an Internet protocol. + */ + if ((tp = knownname(name)) != NULL) + return (tp); + + setprotoent(1); /* make protocol lookup cheaper */ + while ((p = getprotoent()) != NULL) { + /* assert: name not same as p->name */ + for (alias = p->p_aliases; *alias; alias++) + if (strcmp(name, *alias) == 0) { + endprotoent(); + return (knownname(p->p_name)); + } + } + endprotoent(); + return (NULL); +} + +static void +usage(void) +{ + (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", +"usage: netstat [-AaLnSWx] [-f protocol_family | -p protocol]\n" +" [-M core] [-N system]", +" netstat -i | -I interface [-abdhntW] [-f address_family]\n" +" [-M core] [-N system]", +" netstat -w wait [-I interface] [-d] [-M core] [-N system] [-q howmany]", +" netstat -s [-s] [-z] [-f protocol_family | -p protocol]\n" +" [-M core] [-N system]", +" netstat -i | -I interface -s [-f protocol_family | -p protocol]\n" +" [-M core] [-N system]", +" netstat -m [-M core] [-N system]", +" netstat -B [-I interface]", +" netstat -r [-AanW] [-f address_family] [-M core] [-N system]", +" netstat -rs [-s] [-M core] [-N system]", +" netstat -g [-W] [-f address_family] [-M core] [-N system]", +" netstat -gs [-s] [-f address_family] [-M core] [-N system]"); + exit(1); +} diff --git a/freebsd-userspace/commands/usr.bin/netstat/mbuf.c b/freebsd-userspace/commands/usr.bin/netstat/mbuf.c new file mode 100644 index 00000000..dd105259 --- /dev/null +++ b/freebsd-userspace/commands/usr.bin/netstat/mbuf.c @@ -0,0 +1,323 @@ +/*- + * Copyright (c) 1983, 1988, 1993 + * The Regents of the University of California. + * Copyright (c) 2005 Robert N. M. Watson + * 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. + */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)mbuf.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ +#endif + +#include +__FBSDID("$FreeBSD$"); + +#include +#ifdef __rtems__ +#include +#include +#include +#else +#include +#include +#endif +#include +#include +#include + +#include +#ifdef __rtems__ +/* XXX what to do? */ +#else +#include +#include +#endif +#include +#include +#include +#include +#include "netstat.h" + +/* + * Print mbuf statistics. + */ +void +mbpr(void *kvmd, u_long mbaddr) +{ + struct memory_type_list *mtlp; + struct memory_type *mtp; + uintmax_t mbuf_count, mbuf_bytes, mbuf_free, mbuf_failures, mbuf_size; + uintmax_t cluster_count, cluster_bytes, cluster_limit, cluster_free; + uintmax_t cluster_failures, cluster_size; + uintmax_t packet_count, packet_bytes, packet_free, packet_failures; + uintmax_t tag_count, tag_bytes; + uintmax_t jumbop_count, jumbop_bytes, jumbop_limit, jumbop_free; + uintmax_t jumbop_failures, jumbop_size; + uintmax_t jumbo9_count, jumbo9_bytes, jumbo9_limit, jumbo9_free; + uintmax_t jumbo9_failures, jumbo9_size; + uintmax_t jumbo16_count, jumbo16_bytes, jumbo16_limit, jumbo16_free; + uintmax_t jumbo16_failures, jumbo16_size; + uintmax_t bytes_inuse, bytes_incache, bytes_total; + int nsfbufs, nsfbufspeak, nsfbufsused; + struct mbstat mbstat; + size_t mlen; + int error; + + mtlp = memstat_mtl_alloc(); + if (mtlp == NULL) { + warn("memstat_mtl_alloc"); + return; + } + + /* + * Use memstat_*_all() because some mbuf-related memory is in uma(9), + * and some malloc(9). + */ + if (live) { + if (memstat_sysctl_all(mtlp, 0) < 0) { + warnx("memstat_sysctl_all: %s", + memstat_strerror(memstat_mtl_geterror(mtlp))); + goto out; + } + } else { + if (memstat_kvm_all(mtlp, kvmd) < 0) { + error = memstat_mtl_geterror(mtlp); + if (error == MEMSTAT_ERROR_KVM) + warnx("memstat_kvm_all: %s", + kvm_geterr(kvmd)); + else + warnx("memstat_kvm_all: %s", + memstat_strerror(error)); + goto out; + } + } + + mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_MEM_NAME); + if (mtp == NULL) { + warnx("memstat_mtl_find: zone %s not found", MBUF_MEM_NAME); + goto out; + } + mbuf_count = memstat_get_count(mtp); + mbuf_bytes = memstat_get_bytes(mtp); + mbuf_free = memstat_get_free(mtp); + mbuf_failures = memstat_get_failures(mtp); + mbuf_size = memstat_get_size(mtp); + + mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_PACKET_MEM_NAME); + if (mtp == NULL) { + warnx("memstat_mtl_find: zone %s not found", + MBUF_PACKET_MEM_NAME); + goto out; + } + packet_count = memstat_get_count(mtp); + packet_bytes = memstat_get_bytes(mtp); + packet_free = memstat_get_free(mtp); + packet_failures = memstat_get_failures(mtp); + + mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_CLUSTER_MEM_NAME); + if (mtp == NULL) { + warnx("memstat_mtl_find: zone %s not found", + MBUF_CLUSTER_MEM_NAME); + goto out; + } + cluster_count = memstat_get_count(mtp); + cluster_bytes = memstat_get_bytes(mtp); + cluster_limit = memstat_get_countlimit(mtp); + cluster_free = memstat_get_free(mtp); + cluster_failures = memstat_get_failures(mtp); + cluster_size = memstat_get_size(mtp); + + mtp = memstat_mtl_find(mtlp, ALLOCATOR_MALLOC, MBUF_TAG_MEM_NAME); + if (mtp == NULL) { + warnx("memstat_mtl_find: malloc type %s not found", + MBUF_TAG_MEM_NAME); + goto out; + } + tag_count = memstat_get_count(mtp); + tag_bytes = memstat_get_bytes(mtp); + + mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_JUMBOP_MEM_NAME); + if (mtp == NULL) { + warnx("memstat_mtl_find: zone %s not found", + MBUF_JUMBOP_MEM_NAME); + goto out; + } + jumbop_count = memstat_get_count(mtp); + jumbop_bytes = memstat_get_bytes(mtp); + jumbop_limit = memstat_get_countlimit(mtp); + jumbop_free = memstat_get_free(mtp); + jumbop_failures = memstat_get_failures(mtp); + jumbop_size = memstat_get_size(mtp); + + mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_JUMBO9_MEM_NAME); + if (mtp == NULL) { + warnx("memstat_mtl_find: zone %s not found", + MBUF_JUMBO9_MEM_NAME); + goto out; + } + jumbo9_count = memstat_get_count(mtp); + jumbo9_bytes = memstat_get_bytes(mtp); + jumbo9_limit = memstat_get_countlimit(mtp); + jumbo9_free = memstat_get_free(mtp); + jumbo9_failures = memstat_get_failures(mtp); + jumbo9_size = memstat_get_size(mtp); + + mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_JUMBO16_MEM_NAME); + if (mtp == NULL) { + warnx("memstat_mtl_find: zone %s not found", + MBUF_JUMBO16_MEM_NAME); + goto out; + } + jumbo16_count = memstat_get_count(mtp); + jumbo16_bytes = memstat_get_bytes(mtp); + jumbo16_limit = memstat_get_countlimit(mtp); + jumbo16_free = memstat_get_free(mtp); + jumbo16_failures = memstat_get_failures(mtp); + jumbo16_size = memstat_get_size(mtp); + + printf("%ju/%ju/%ju mbufs in use (current/cache/total)\n", + mbuf_count + packet_count, mbuf_free + packet_free, + mbuf_count + packet_count + mbuf_free + packet_free); + + printf("%ju/%ju/%ju/%ju mbuf clusters in use " + "(current/cache/total/max)\n", + cluster_count - packet_free, cluster_free + packet_free, + cluster_count + cluster_free, cluster_limit); + + printf("%ju/%ju mbuf+clusters out of packet secondary zone in use " + "(current/cache)\n", + packet_count, packet_free); + + printf("%ju/%ju/%ju/%ju %juk (page size) jumbo clusters in use " + "(current/cache/total/max)\n", + jumbop_count, jumbop_free, jumbop_count + jumbop_free, + jumbop_limit, jumbop_size / 1024); + + printf("%ju/%ju/%ju/%ju 9k jumbo clusters in use " + "(current/cache/total/max)\n", + jumbo9_count, jumbo9_free, jumbo9_count + jumbo9_free, + jumbo9_limit); + + printf("%ju/%ju/%ju/%ju 16k jumbo clusters in use " + "(current/cache/total/max)\n", + jumbo16_count, jumbo16_free, jumbo16_count + jumbo16_free, + jumbo16_limit); + +#if 0 + printf("%ju mbuf tags in use\n", tag_count); +#endif + + /*- + * Calculate in-use bytes as: + * - straight mbuf memory + * - mbuf memory in packets + * - the clusters attached to packets + * - and the rest of the non-packet-attached clusters. + * - m_tag memory + * This avoids counting the clusters attached to packets in the cache. + * This currently excludes sf_buf space. + */ + bytes_inuse = + mbuf_bytes + /* straight mbuf memory */ + packet_bytes + /* mbufs in packets */ + (packet_count * cluster_size) + /* clusters in packets */ + /* other clusters */ + ((cluster_count - packet_count - packet_free) * cluster_size) + + tag_bytes + + (jumbop_count * jumbop_size) + /* jumbo clusters */ + (jumbo9_count * jumbo9_size) + + (jumbo16_count * jumbo16_size); + + /* + * Calculate in-cache bytes as: + * - cached straught mbufs + * - cached packet mbufs + * - cached packet clusters + * - cached straight clusters + * This currently excludes sf_buf space. + */ + bytes_incache = + (mbuf_free * mbuf_size) + /* straight free mbufs */ + (packet_free * mbuf_size) + /* mbufs in free packets */ + (packet_free * cluster_size) + /* clusters in free packets */ + (cluster_free * cluster_size) + /* free clusters */ + (jumbop_free * jumbop_size) + /* jumbo clusters */ + (jumbo9_free * jumbo9_size) + + (jumbo16_free * jumbo16_size); + + /* + * Total is bytes in use + bytes in cache. This doesn't take into + * account various other misc data structures, overhead, etc, but + * gives the user something useful despite that. + */ + bytes_total = bytes_inuse + bytes_incache; + + printf("%juK/%juK/%juK bytes allocated to network " + "(current/cache/total)\n", bytes_inuse / 1024, + bytes_incache / 1024, bytes_total / 1024); + + printf("%ju/%ju/%ju requests for mbufs denied (mbufs/clusters/" + "mbuf+clusters)\n", mbuf_failures, cluster_failures, + packet_failures); + + printf("%ju/%ju/%ju requests for jumbo clusters denied " + "(%juk/9k/16k)\n", jumbop_failures, jumbo9_failures, + jumbo16_failures, jumbop_size / 1024); + + if (live) { + mlen = sizeof(nsfbufs); + if (!sysctlbyname("kern.ipc.nsfbufs", &nsfbufs, &mlen, NULL, + 0) && + !sysctlbyname("kern.ipc.nsfbufsused", &nsfbufsused, + &mlen, NULL, 0) && + !sysctlbyname("kern.ipc.nsfbufspeak", &nsfbufspeak, + &mlen, NULL, 0)) + printf("%d/%d/%d sfbufs in use (current/peak/max)\n", + nsfbufsused, nsfbufspeak, nsfbufs); + mlen = sizeof(mbstat); + if (sysctlbyname("kern.ipc.mbstat", &mbstat, &mlen, NULL, 0)) { + warn("kern.ipc.mbstat"); + goto out; + } + } else { + if (kread(mbaddr, (char *)&mbstat, sizeof mbstat) != 0) + goto out; + } + printf("%lu requests for sfbufs denied\n", mbstat.sf_allocfail); + printf("%lu requests for sfbufs delayed\n", mbstat.sf_allocwait); + printf("%lu requests for I/O initiated by sendfile\n", + mbstat.sf_iocnt); + printf("%lu calls to protocol drain routines\n", mbstat.m_drain); +out: + memstat_mtl_free(mtlp); +} diff --git a/freebsd-userspace/commands/usr.bin/netstat/mroute.c b/freebsd-userspace/commands/usr.bin/netstat/mroute.c new file mode 100644 index 00000000..7669ff07 --- /dev/null +++ b/freebsd-userspace/commands/usr.bin/netstat/mroute.c @@ -0,0 +1,391 @@ +/*- + * 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. + * + * @(#)mroute.c 8.2 (Berkeley) 4/28/95 + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * Print multicast routing structures and statistics. + * + * MROUTING 1.0 + */ + +#include +#include +#include +#include +#include +#ifdef __rtems__ +#include +#else +#include +#endif +#ifdef __rtems__ +#include +#else +#include +#endif +#include + +#include +#include +#include +#include + +#define _KERNEL 1 +#ifdef __rtems__ +#include +#else +#include +#endif +#undef _KERNEL + +#include +#include +#include +#include +#include "netstat.h" + + +static void print_bw_meter(struct bw_meter *, int *); +static void print_mfc(struct mfc *, int, int *); + +static void +print_bw_meter(struct bw_meter *bw_meter, int *banner_printed) +{ + char s0[256], s1[256], s2[256], s3[256]; + struct timeval now, end, delta; + + gettimeofday(&now, NULL); + + if (! *banner_printed) { + printf(" Bandwidth Meters\n"); + printf(" %-30s", "Measured(Start|Packets|Bytes)"); + printf(" %s", "Type"); + printf(" %-30s", "Thresh(Interval|Packets|Bytes)"); + printf(" Remain"); + printf("\n"); + *banner_printed = 1; + } + + /* The measured values */ + if (bw_meter->bm_flags & BW_METER_UNIT_PACKETS) + sprintf(s1, "%ju", (uintmax_t)bw_meter->bm_measured.b_packets); + else + sprintf(s1, "?"); + if (bw_meter->bm_flags & BW_METER_UNIT_BYTES) + sprintf(s2, "%ju", (uintmax_t)bw_meter->bm_measured.b_bytes); + else + sprintf(s2, "?"); + sprintf(s0, "%lu.%lu|%s|%s", + (u_long)bw_meter->bm_start_time.tv_sec, + (u_long)bw_meter->bm_start_time.tv_usec, + s1, s2); + printf(" %-30s", s0); + + /* The type of entry */ + sprintf(s0, "%s", "?"); + if (bw_meter->bm_flags & BW_METER_GEQ) + sprintf(s0, "%s", ">="); + else if (bw_meter->bm_flags & BW_METER_LEQ) + sprintf(s0, "%s", "<="); + printf(" %-3s", s0); + + /* The threshold values */ + if (bw_meter->bm_flags & BW_METER_UNIT_PACKETS) + sprintf(s1, "%ju", (uintmax_t)bw_meter->bm_threshold.b_packets); + else + sprintf(s1, "?"); + if (bw_meter->bm_flags & BW_METER_UNIT_BYTES) + sprintf(s2, "%ju", (uintmax_t)bw_meter->bm_threshold.b_bytes); + else + sprintf(s2, "?"); + sprintf(s0, "%lu.%lu|%s|%s", + (u_long)bw_meter->bm_threshold.b_time.tv_sec, + (u_long)bw_meter->bm_threshold.b_time.tv_usec, + s1, s2); + printf(" %-30s", s0); + + /* Remaining time */ + timeradd(&bw_meter->bm_start_time, + &bw_meter->bm_threshold.b_time, &end); + if (timercmp(&now, &end, <=)) { + timersub(&end, &now, &delta); + sprintf(s3, "%lu.%lu", + (u_long)delta.tv_sec, + (u_long)delta.tv_usec); + } else { + /* Negative time */ + timersub(&now, &end, &delta); + sprintf(s3, "-%lu.%lu", + (u_long)delta.tv_sec, + (u_long)delta.tv_usec); + } + printf(" %s", s3); + + printf("\n"); +} + +static void +print_mfc(struct mfc *m, int maxvif, int *banner_printed) +{ + struct bw_meter bw_meter, *bwm; + int bw_banner_printed; + int error; + vifi_t vifi; + + bw_banner_printed = 0; + + if (! *banner_printed) { + printf("\nIPv4 Multicast Forwarding Table\n" + " Origin Group " + " Packets In-Vif Out-Vifs:Ttls\n"); + *banner_printed = 1; + } + + printf(" %-15.15s", routename(m->mfc_origin.s_addr)); + printf(" %-15.15s", routename(m->mfc_mcastgrp.s_addr)); + printf(" %9lu", m->mfc_pkt_cnt); + printf(" %3d ", m->mfc_parent); + for (vifi = 0; vifi <= maxvif; vifi++) { + if (m->mfc_ttls[vifi] > 0) + printf(" %u:%u", vifi, m->mfc_ttls[vifi]); + } + printf("\n"); + + /* + * XXX We break the rules and try to use KVM to read the + * bandwidth meters, they are not retrievable via sysctl yet. + */ + bwm = m->mfc_bw_meter; + while (bwm != NULL) { + error = kread((u_long)bwm, (char *)&bw_meter, + sizeof(bw_meter)); + if (error) + break; + print_bw_meter(&bw_meter, &bw_banner_printed); + bwm = bw_meter.bm_mfc_next; + } +} + +void +mroutepr(u_long pmfchashtbl, u_long pmfctablesize, u_long pviftbl) +{ + struct vif viftable[MAXVIFS]; + struct vif *v; + struct mfc *m; + int banner_printed; + int saved_numeric_addr; + size_t len; + vifi_t vifi, maxvif; + + saved_numeric_addr = numeric_addr; + numeric_addr = 1; + + /* + * TODO: + * The VIF table will move to hanging off the struct if_info for + * each IPv4 configured interface. Currently it is statically + * allocated, and retrieved either using KVM or an opaque SYSCTL. + * + * This can't happen until the API documented in multicast(4) + * is itself refactored. The historical reason why VIFs use + * a separate ifindex space is entirely due to the legacy + * capability of the MROUTING code to create IPIP tunnels on + * the fly to support DVMRP. When gif(4) became available, this + * functionality was deprecated, as PIM does not use it. + */ + maxvif = 0; + + len = sizeof(viftable); + if (live) { + if (sysctlbyname("net.inet.ip.viftable", viftable, &len, NULL, + 0) < 0) { + warn("sysctl: net.inet.ip.viftable"); + return; + } + } else + kread(pviftbl, (char *)viftable, sizeof(viftable)); + + banner_printed = 0; + for (vifi = 0, v = viftable; vifi < MAXVIFS; ++vifi, ++v) { + if (v->v_lcl_addr.s_addr == 0) + continue; + + maxvif = vifi; + if (!banner_printed) { + printf("\nIPv4 Virtual Interface Table\n" + " Vif Thresh Local-Address " + "Remote-Address Pkts-In Pkts-Out\n"); + banner_printed = 1; + } + + printf(" %2u %6u %-15.15s", + /* opposite math of add_vif() */ + vifi, v->v_threshold, + routename(v->v_lcl_addr.s_addr)); + printf(" %-15.15s", (v->v_flags & VIFF_TUNNEL) ? + routename(v->v_rmt_addr.s_addr) : ""); + + printf(" %9lu %9lu\n", v->v_pkt_in, v->v_pkt_out); + } + if (!banner_printed) + printf("\nIPv4 Virtual Interface Table is empty\n"); + + banner_printed = 0; + + /* + * TODO: + * The MFC table will move into the AF_INET radix trie in future. + * In 8.x, it becomes a dynamically allocated structure referenced + * by a hashed LIST, allowing more than 256 entries w/o kernel tuning. + * + * If retrieved via opaque SYSCTL, the kernel will coalesce it into + * a static table for us. + * If retrieved via KVM, the hash list pointers must be followed. + */ + if (live) { + struct mfc *mfctable; + + len = 0; + if (sysctlbyname("net.inet.ip.mfctable", NULL, &len, NULL, + 0) < 0) { + warn("sysctl: net.inet.ip.mfctable"); + return; + } + + mfctable = malloc(len); + if (mfctable == NULL) { + warnx("malloc %lu bytes", (u_long)len); + return; + } + if (sysctlbyname("net.inet.ip.mfctable", mfctable, &len, NULL, + 0) < 0) { + free(mfctable); + warn("sysctl: net.inet.ip.mfctable"); + return; + } + + m = mfctable; + while (len >= sizeof(*m)) { + print_mfc(m++, maxvif, &banner_printed); + len -= sizeof(*m); + } + if (len != 0) + warnx("print_mfc: %lu trailing bytes", (u_long)len); + + free(mfctable); + } else { + LIST_HEAD(, mfc) *mfchashtbl; + u_long i, mfctablesize; + struct mfc mfc; + int error; + + error = kread(pmfctablesize, (char *)&mfctablesize, + sizeof(u_long)); + if (error) { + warn("kread: mfctablesize"); + return; + } + + len = sizeof(*mfchashtbl) * mfctablesize; + mfchashtbl = malloc(len); + if (mfchashtbl == NULL) { + warnx("malloc %lu bytes", (u_long)len); + return; + } + kread(pmfchashtbl, (char *)&mfchashtbl, len); + + for (i = 0; i < mfctablesize; i++) { + LIST_FOREACH(m, &mfchashtbl[i], mfc_hash) { + kread((u_long)m, (char *)&mfc, sizeof(mfc)); + print_mfc(m, maxvif, &banner_printed); + } + } + + free(mfchashtbl); + } + + if (!banner_printed) + printf("\nIPv4 Multicast Forwarding Table is empty\n"); + + printf("\n"); + numeric_addr = saved_numeric_addr; +} + +void +mrt_stats(u_long mstaddr) +{ + struct mrtstat mrtstat; + size_t len = sizeof mrtstat; + + if (live) { + if (sysctlbyname("net.inet.ip.mrtstat", &mrtstat, &len, NULL, + 0) < 0) { + warn("sysctl: net.inet.ip.mrtstat"); + return; + } + } else + kread(mstaddr, (char *)&mrtstat, sizeof(mrtstat)); + + printf("IPv4 multicast forwarding:\n"); + +#define p(f, m) if (mrtstat.f || sflag <= 1) \ + printf(m, mrtstat.f, plural(mrtstat.f)) +#define p2(f, m) if (mrtstat.f || sflag <= 1) \ + printf(m, mrtstat.f, plurales(mrtstat.f)) + + p(mrts_mfc_lookups, "\t%lu multicast forwarding cache lookup%s\n"); + p2(mrts_mfc_misses, "\t%lu multicast forwarding cache miss%s\n"); + p(mrts_upcalls, "\t%lu upcall%s to multicast routing daemon\n"); + p(mrts_upq_ovflw, "\t%lu upcall queue overflow%s\n"); + p(mrts_upq_sockfull, + "\t%lu upcall%s dropped due to full socket buffer\n"); + p(mrts_cache_cleanups, "\t%lu cache cleanup%s\n"); + p(mrts_no_route, "\t%lu datagram%s with no route for origin\n"); + p(mrts_bad_tunnel, "\t%lu datagram%s arrived with bad tunneling\n"); + p(mrts_cant_tunnel, "\t%lu datagram%s could not be tunneled\n"); + p(mrts_wrong_if, "\t%lu datagram%s arrived on wrong interface\n"); + p(mrts_drop_sel, "\t%lu datagram%s selectively dropped\n"); + p(mrts_q_overflow, "\t%lu datagram%s dropped due to queue overflow\n"); + p(mrts_pkt2large, "\t%lu datagram%s dropped for being too large\n"); + +#undef p2 +#undef p +} diff --git a/freebsd-userspace/commands/usr.bin/netstat/mroute6.c b/freebsd-userspace/commands/usr.bin/netstat/mroute6.c new file mode 100644 index 00000000..cd7d8d25 --- /dev/null +++ b/freebsd-userspace/commands/usr.bin/netstat/mroute6.c @@ -0,0 +1,268 @@ +/*- + * Copyright (C) 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/*- + * Copyright (c) 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. + * + * @(#)mroute.c 8.2 (Berkeley) 4/28/95 + */ + +#include +__FBSDID("$FreeBSD$"); + +#ifdef INET6 +#include +#include +#include +#include +#include +#ifdef __rtems__ +#include +#else +#include +#endif +#ifdef __rtems__ +#include +#else +#include +#endif +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#define KERNEL 1 +#include +#undef KERNEL + +#include "netstat.h" + +#define WID_ORG (Wflag ? 39 : (numeric_addr ? 29 : 18)) /* width of origin column */ +#define WID_GRP (Wflag ? 18 : (numeric_addr ? 16 : 18)) /* width of group column */ + +void +mroute6pr(u_long mfcaddr, u_long mifaddr) +{ + struct mf6c *mf6ctable[MF6CTBLSIZ], *mfcp; + struct mif6 mif6table[MAXMIFS]; + struct mf6c mfc; + struct rtdetq rte, *rtep; + struct mif6 *mifp; + mifi_t mifi; + int i; + int banner_printed; + int saved_numeric_addr; + mifi_t maxmif = 0; + long int waitings; + size_t len; + + len = sizeof(mif6table); + if (live) { + if (sysctlbyname("net.inet6.ip6.mif6table", mif6table, &len, + NULL, 0) < 0) { + warn("sysctl: net.inet6.ip6.mif6table"); + return; + } + } else + kread(mifaddr, (char *)mif6table, sizeof(mif6table)); + + saved_numeric_addr = numeric_addr; + numeric_addr = 1; + banner_printed = 0; + + for (mifi = 0, mifp = mif6table; mifi < MAXMIFS; ++mifi, ++mifp) { + struct ifnet ifnet; + char ifname[IFNAMSIZ]; + + if (mifp->m6_ifp == NULL) + continue; + + /* XXX KVM */ + kread((u_long)mifp->m6_ifp, (char *)&ifnet, sizeof(ifnet)); + + maxmif = mifi; + if (!banner_printed) { + printf("\nIPv6 Multicast Interface Table\n" + " Mif Rate PhyIF " + "Pkts-In Pkts-Out\n"); + banner_printed = 1; + } + + printf(" %2u %4d", + mifi, mifp->m6_rate_limit); + printf(" %5s", (mifp->m6_flags & MIFF_REGISTER) ? + "reg0" : if_indextoname(ifnet.if_index, ifname)); + + printf(" %9ju %9ju\n", (uintmax_t)mifp->m6_pkt_in, + (uintmax_t)mifp->m6_pkt_out); + } + if (!banner_printed) + printf("\nIPv6 Multicast Interface Table is empty\n"); + + len = sizeof(mf6ctable); + if (live) { + if (sysctlbyname("net.inet6.ip6.mf6ctable", mf6ctable, &len, + NULL, 0) < 0) { + warn("sysctl: net.inet6.ip6.mf6ctable"); + return; + } + } else + kread(mfcaddr, (char *)mf6ctable, sizeof(mf6ctable)); + + banner_printed = 0; + + for (i = 0; i < MF6CTBLSIZ; ++i) { + mfcp = mf6ctable[i]; + while(mfcp) { + kread((u_long)mfcp, (char *)&mfc, sizeof(mfc)); + if (!banner_printed) { + printf ("\nIPv6 Multicast Forwarding Cache\n"); + printf(" %-*.*s %-*.*s %s", + WID_ORG, WID_ORG, "Origin", + WID_GRP, WID_GRP, "Group", + " Packets Waits In-Mif Out-Mifs\n"); + banner_printed = 1; + } + + printf(" %-*.*s", WID_ORG, WID_ORG, + routename6(&mfc.mf6c_origin)); + printf(" %-*.*s", WID_GRP, WID_GRP, + routename6(&mfc.mf6c_mcastgrp)); + printf(" %9ju", (uintmax_t)mfc.mf6c_pkt_cnt); + + for (waitings = 0, rtep = mfc.mf6c_stall; rtep; ) { + waitings++; + /* XXX KVM */ + kread((u_long)rtep, (char *)&rte, sizeof(rte)); + rtep = rte.next; + } + printf(" %3ld", waitings); + + if (mfc.mf6c_parent == MF6C_INCOMPLETE_PARENT) + printf(" --- "); + else + printf(" %3d ", mfc.mf6c_parent); + for (mifi = 0; mifi <= maxmif; mifi++) { + if (IF_ISSET(mifi, &mfc.mf6c_ifset)) + printf(" %u", mifi); + } + printf("\n"); + + mfcp = mfc.mf6c_next; + } + } + if (!banner_printed) + printf("\nIPv6 Multicast Forwarding Table is empty\n"); + + printf("\n"); + numeric_addr = saved_numeric_addr; +} + +void +mrt6_stats(u_long mstaddr) +{ + struct mrt6stat mrtstat; + size_t len = sizeof mrtstat; + + if (live) { + if (sysctlbyname("net.inet6.ip6.mrt6stat", &mrtstat, &len, + NULL, 0) < 0) { + warn("sysctl: net.inet6.ip6.mrt6stat"); + return; + } + } else + kread(mstaddr, (char *)&mrtstat, sizeof(mrtstat)); + + printf("IPv6 multicast forwarding:\n"); + +#define p(f, m) if (mrtstat.f || sflag <= 1) \ + printf(m, (uintmax_t)mrtstat.f, plural(mrtstat.f)) +#define p2(f, m) if (mrtstat.f || sflag <= 1) \ + printf(m, (uintmax_t)mrtstat.f, plurales(mrtstat.f)) + + p(mrt6s_mfc_lookups, "\t%ju multicast forwarding cache lookup%s\n"); + p2(mrt6s_mfc_misses, "\t%ju multicast forwarding cache miss%s\n"); + p(mrt6s_upcalls, "\t%ju upcall%s to multicast routing daemon\n"); + p(mrt6s_upq_ovflw, "\t%ju upcall queue overflow%s\n"); + p(mrt6s_upq_sockfull, + "\t%ju upcall%s dropped due to full socket buffer\n"); + p(mrt6s_cache_cleanups, "\t%ju cache cleanup%s\n"); + p(mrt6s_no_route, "\t%ju datagram%s with no route for origin\n"); + p(mrt6s_bad_tunnel, "\t%ju datagram%s arrived with bad tunneling\n"); + p(mrt6s_cant_tunnel, "\t%ju datagram%s could not be tunneled\n"); + p(mrt6s_wrong_if, "\t%ju datagram%s arrived on wrong interface\n"); + p(mrt6s_drop_sel, "\t%ju datagram%s selectively dropped\n"); + p(mrt6s_q_overflow, + "\t%ju datagram%s dropped due to queue overflow\n"); + p(mrt6s_pkt2large, "\t%ju datagram%s dropped for being too large\n"); + +#undef p2 +#undef p +} +#endif /*INET6*/ diff --git a/freebsd-userspace/commands/usr.bin/netstat/netgraph.c b/freebsd-userspace/commands/usr.bin/netstat/netgraph.c new file mode 100644 index 00000000..06a244ff --- /dev/null +++ b/freebsd-userspace/commands/usr.bin/netstat/netgraph.c @@ -0,0 +1,196 @@ +/*- + * Copyright (c) 1996-1999 Whistle Communications, Inc. + * All rights reserved. + * + * Subject to the following obligations and disclaimer of warranty, use and + * redistribution of this software, in source or object code forms, with or + * without modifications are expressly permitted by Whistle Communications; + * provided, however, that: + * 1. Any and all reproductions of the source or object code must include the + * copyright notice above and the following disclaimer of warranties; and + * 2. No rights are granted, in any manner or form, to use Whistle + * Communications, Inc. trademarks, including the mark "WHISTLE + * COMMUNICATIONS" on advertising, endorsements, or otherwise except as + * such appears in the above copyright notice or in the software. + * + * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND + * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO + * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, + * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. + * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY + * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS + * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. + * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES + * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING + * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#ifdef __rtems__ +#include +#include +#else +#include +#include +#endif + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "netstat.h" + +static int first = 1; +static int csock = -1; + +void +netgraphprotopr(u_long off, const char *name, int af1 __unused, + int proto __unused) +{ + struct ngpcb *this, *next; + struct ngpcb ngpcb; + struct ngsock info; + struct socket sockb; + int debug = 1; + + /* If symbol not found, try looking in the KLD module */ + if (off == 0) { + const char *const modname = "ng_socket.ko"; +/* XXX We should get "mpath" from "sysctl kern.module_path" */ + const char *mpath[] = { "/", "/boot/", "/modules/", NULL }; + struct nlist sym[] = { { .n_name = "_ngsocklist" }, + { .n_name = NULL } }; + const char **pre; + struct kld_file_stat ks; + int fileid; + + /* Can't do this for core dumps. */ + if (!live) + return; + + /* See if module is loaded */ + if ((fileid = kldfind(modname)) < 0) { + if (debug) + warn("kldfind(%s)", modname); + return; + } + + /* Get module info */ + memset(&ks, 0, sizeof(ks)); + ks.version = sizeof(struct kld_file_stat); + if (kldstat(fileid, &ks) < 0) { + if (debug) + warn("kldstat(%d)", fileid); + return; + } + + /* Get symbol table from module file */ + for (pre = mpath; *pre; pre++) { + char path[MAXPATHLEN]; + + snprintf(path, sizeof(path), "%s%s", *pre, modname); + if (nlist(path, sym) == 0) + break; + } + + /* Did we find it? */ + if (sym[0].n_value == 0) { + if (debug) + warnx("%s not found", modname); + return; + } + + /* Symbol found at load address plus symbol offset */ + off = (u_long) ks.address + sym[0].n_value; + } + + /* Get pointer to first socket */ + kread(off, (char *)&this, sizeof(this)); + + /* Get my own socket node */ + if (csock == -1) + NgMkSockNode(NULL, &csock, NULL); + + for (; this != NULL; this = next) { + u_char rbuf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)]; + struct ng_mesg *resp = (struct ng_mesg *) rbuf; + struct nodeinfo *ni = (struct nodeinfo *) resp->data; + char path[64]; + + /* Read in ngpcb structure */ + kread((u_long)this, (char *)&ngpcb, sizeof(ngpcb)); + next = LIST_NEXT(&ngpcb, socks); + + /* Read in socket structure */ + kread((u_long)ngpcb.ng_socket, (char *)&sockb, sizeof(sockb)); + + /* Check type of socket */ + if (strcmp(name, "ctrl") == 0 && ngpcb.type != NG_CONTROL) + continue; + if (strcmp(name, "data") == 0 && ngpcb.type != NG_DATA) + continue; + + /* Do headline */ + if (first) { + printf("Netgraph sockets\n"); + if (Aflag) + printf("%-8.8s ", "PCB"); + printf("%-5.5s %-6.6s %-6.6s %-14.14s %s\n", + "Type", "Recv-Q", "Send-Q", + "Node Address", "#Hooks"); + first = 0; + } + + /* Show socket */ + if (Aflag) + printf("%8lx ", (u_long) this); + printf("%-5.5s %6u %6u ", + name, sockb.so_rcv.sb_cc, sockb.so_snd.sb_cc); + + /* Get ngsock structure */ + if (ngpcb.sockdata == NULL) /* unconnected data socket */ + goto finish; + kread((u_long)ngpcb.sockdata, (char *)&info, sizeof(info)); + + /* Get info on associated node */ + if (info.node_id == 0 || csock == -1) + goto finish; + snprintf(path, sizeof(path), "[%x]:", info.node_id); + if (NgSendMsg(csock, path, + NGM_GENERIC_COOKIE, NGM_NODEINFO, NULL, 0) < 0) + goto finish; + if (NgRecvMsg(csock, resp, sizeof(rbuf), NULL) < 0) + goto finish; + + /* Display associated node info */ + if (*ni->name != '\0') + snprintf(path, sizeof(path), "%s:", ni->name); + printf("%-14.14s %4d", path, ni->hooks); +finish: + putchar('\n'); + } +} + diff --git a/freebsd-userspace/commands/usr.bin/netstat/netstat.1 b/freebsd-userspace/commands/usr.bin/netstat/netstat.1 new file mode 100644 index 00000000..872ff954 --- /dev/null +++ b/freebsd-userspace/commands/usr.bin/netstat/netstat.1 @@ -0,0 +1,523 @@ +.\" Copyright (c) 1983, 1990, 1992, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)netstat.1 8.8 (Berkeley) 4/18/94 +.\" $FreeBSD$ +.\" +.Dd January 10, 2010 +.Dt NETSTAT 1 +.Os +.Sh NAME +.Nm netstat +.Nd show network status +.Sh DESCRIPTION +The +.Nm +command symbolically displays the contents of various network-related +data structures. +There are a number of output formats, +depending on the options for the information presented. +.Bl -tag -width indent +.It Xo +.Bk -words +.Nm +.Op Fl AaLnSWx +.Op Fl f Ar protocol_family | Fl p Ar protocol +.Op Fl M Ar core +.Op Fl N Ar system +.Ek +.Xc +Display a list of active sockets +(protocol control blocks) +for each network protocol, +for a particular +.Ar protocol_family , +or for a single +.Ar protocol . +If +.Fl A +is also present, +show the address of a protocol control block (PCB) +associated with a socket; used for debugging. +If +.Fl a +is also present, +show the state of all sockets; +normally sockets used by server processes are not shown. +If +.Fl L +is also present, +show the size of the various listen queues. +The first count shows the number of unaccepted connections, +the second count shows the amount of unaccepted incomplete connections, +and the third count is the maximum number of queued connections. +If +.Fl S +is also present, +show network addresses as numbers (as with +.Fl n ) +but show ports symbolically. +If +.Fl x +is present display full socket buffer statistics for each internet socket. +.It Xo +.Bk -words +.Nm +.Fl i | I Ar interface +.Op Fl abdhntW +.Op Fl f Ar address_family +.Op Fl M Ar core +.Op Fl N Ar system +.Ek +.Xc +Show the state of all network interfaces or a single +.Ar interface +which have been auto-configured +(interfaces statically configured into a system, but not +located at boot time are not shown). +An asterisk +.Pq Dq Li * +after an interface name indicates that the interface is +.Dq down . +If +.Fl a +is also present, multicast addresses currently in use are shown +for each Ethernet interface and for each IP interface address. +Multicast addresses are shown on separate lines following the interface +address with which they are associated. +If +.Fl b +is also present, show the number of bytes in and out. +If +.Fl d +is also present, show the number of dropped packets. +If +.Fl h +is also present, print all counters in human readable form. +If +.Fl t +is also present, show the contents of watchdog timers. +If +.Fl W +is also present, print interface names using a wider field size. +.It Xo +.Bk -words +.Nm +.Fl w Ar wait +.Op Fl I Ar interface +.Op Fl d +.Op Fl M Ar core +.Op Fl N Ar system +.Op Fl q Ar howmany +.Ek +.Xc +At intervals of +.Ar wait +seconds, +display the information regarding packet +traffic on all configured network interfaces +or a single +.Ar interface . +If +.Fl q +is also present, exit after +.Ar howmany +outputs. +If +.Fl d +is also present, show the number of dropped packets. +.It Xo +.Bk -words +.Nm +.Fl s Op Fl s +.Op Fl z +.Op Fl f Ar protocol_family | Fl p Ar protocol +.Op Fl M Ar core +.Op Fl N Ar system +.Ek +.Xc +Display system-wide statistics for each network protocol, +for a particular +.Ar protocol_family , +or for a single +.Ar protocol . +If +.Fl s +is repeated, counters with a value of zero are suppressed. +If +.Fl z +is also present, reset statistic counters after displaying them. +.It Xo +.Bk -words +.Nm +.Fl i | I Ar interface Fl s +.Op Fl f Ar protocol_family | Fl p Ar protocol +.Op Fl M Ar core +.Op Fl N Ar system +.Ek +.Xc +Display per-interface statistics for each network protocol, +for a particular +.Ar protocol_family , +or for a single +.Ar protocol . +.It Xo +.Bk -words +.Nm +.Fl m +.Op Fl M Ar core +.Op Fl N Ar system +.Ek +.Xc +Show statistics recorded by the memory management routines +.Pq Xr mbuf 9 . +The network manages a private pool of memory buffers. +.It Xo +.Bk -words +.Nm +.Fl B +.Op Fl z +.Op Fl I Ar interface +.Ek +.Xc +Show statistics about +.Xr bpf 4 +peers. +This includes information like +how many packets have been matched, dropped and received by the +bpf device, also information about current buffer sizes and device +states. +.It Xo +.Bk -words +.Nm +.Fl r +.Op Fl AanW +.Op Fl f Ar address_family +.Op Fl M Ar core +.Op Fl N Ar system +.Ek +.Xc +Display the contents of all routing tables, +or a routing table for a particular +.Ar address_family . +If +.Fl A +is also present, +show the contents of the internal Patricia tree +structures; used for debugging. +If +.Fl a +is also present, +show protocol-cloned routes +(routes generated by an +.Dv RTF_PRCLONING +parent route); +normally these routes are not shown. +When +.Fl W +is also present, +show the path MTU +for each route, +and print interface +names with a wider +field size. +.It Xo +.Bk -words +.Nm +.Fl rs +.Op Fl s +.Op Fl M Ar core +.Op Fl N Ar system +.Ek +.Xc +Display routing statistics. +If +.Fl s +is repeated, counters with a value of zero are suppressed. +.It Xo +.Bk -words +.Nm +.Fl g +.Op Fl W +.Op Fl f Ar address_family +.Op Fl M Ar core +.Op Fl N Ar system +.Ek +.Xc +Display the contents of the multicast virtual interface tables, +and multicast forwarding caches. +Entries in these tables will appear only when the kernel is +actively forwarding multicast sessions. +This option is applicable only to the +.Cm inet +and +.Cm inet6 +address families. +.It Xo +.Bk -words +.Nm +.Fl gs +.Op Fl s +.Op Fl f Ar address_family +.Op Fl M Ar core +.Op Fl N Ar system +.Ek +.Xc +Show multicast routing statistics. +If +.Fl s +is repeated, counters with a value of zero are suppressed. +.El +.Pp +Some options have the general meaning: +.Bl -tag -width flag +.It Fl f Ar address_family , Fl p Ar protocol +Limit display to those records +of the specified +.Ar address_family +or a single +.Ar protocol . +The following address families and protocols are recognized: +.Pp +.Bl -tag -width ".Cm netgraph , ng Pq Dv AF_NETGRAPH" -compact +.It Em Family +.Em Protocols +.It Cm inet Pq Dv AF_INET +.Cm divert , icmp , igmp , ip , ipsec , pim, sctp , tcp , udp +.It Cm inet6 Pq Dv AF_INET6 +.Cm icmp6 , ip6 , ipsec6 , rip6 , tcp , udp +.It Cm pfkey Pq Dv PF_KEY +.Cm pfkey +.It Cm atalk Pq Dv AF_APPLETALK +.Cm ddp +.It Cm netgraph , ng Pq Dv AF_NETGRAPH +.Cm ctrl , data +.It Cm ipx Pq Dv AF_IPX +.Cm ipx , spx +.\".It Cm ns Pq Dv AF_NS +.\".Cm idp , ns_err , spp +.\".It Cm iso Pq Dv AF_ISO +.\".Cm clnp , cltp , esis , tp +.It Cm unix Pq Dv AF_UNIX +.It Cm link Pq Dv AF_LINK +.El +.Pp +The program will complain if +.Ar protocol +is unknown or if there is no statistics routine for it. +.It Fl M +Extract values associated with the name list from the specified core +instead of the default +.Pa /dev/kmem . +.It Fl N +Extract the name list from the specified system instead of the default, +which is the kernel image the system has booted from. +.It Fl n +Show network addresses and ports as numbers. +Normally +.Nm +attempts to resolve addresses and ports, +and display them symbolically. +.It Fl W +In certain displays, avoid truncating addresses even if this causes +some fields to overflow. +.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 +.Dq host.port +or +.Dq 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 databases +.Xr hosts 5 +and +.Xr networks 5 , +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 IPv4 +.Dq dot format , +refer to +.Xr inet 3 . +Unspecified, +or +.Dq wildcard , +addresses and ports appear as +.Dq Li * . +.Pp +The interface display provides a table of cumulative +statistics regarding packets transferred, errors, and collisions. +The network addresses of the interface +and the maximum transmission unit +.Pq Dq mtu +are also displayed. +.Pp +The routing table display indicates the available routes and their status. +Each route consists of a destination host or network, and a gateway to use +in forwarding packets. +The flags field shows a collection of information about the route stored +as binary choices. +The individual flags are discussed in more detail in the +.Xr route 8 +and +.Xr route 4 +manual pages. +The mapping between letters and flags is: +.Bl -column ".Li W" ".Dv RTF_WASCLONED" +.It Li 1 Ta Dv RTF_PROTO1 Ta "Protocol specific routing flag #1" +.It Li 2 Ta Dv RTF_PROTO2 Ta "Protocol specific routing flag #2" +.It Li 3 Ta Dv RTF_PROTO3 Ta "Protocol specific routing flag #3" +.It Li B Ta Dv RTF_BLACKHOLE Ta "Just discard pkts (during updates)" +.It Li b Ta Dv RTF_BROADCAST Ta "The route represents a broadcast address" +.It Li C Ta Dv RTF_CLONING Ta "Generate new routes on use" +.It Li c Ta Dv RTF_PRCLONING Ta "Protocol-specified generate new routes on use" +.It Li D Ta Dv RTF_DYNAMIC Ta "Created dynamically (by redirect)" +.It Li G Ta Dv RTF_GATEWAY Ta "Destination requires forwarding by intermediary" +.It Li H Ta Dv RTF_HOST Ta "Host entry (net otherwise)" +.It Li L Ta Dv RTF_LLINFO Ta "Valid protocol to link address translation" +.It Li M Ta Dv RTF_MODIFIED Ta "Modified dynamically (by redirect)" +.It Li R Ta Dv RTF_REJECT Ta "Host or net unreachable" +.It Li S Ta Dv RTF_STATIC Ta "Manually added" +.It Li U Ta Dv RTF_UP Ta "Route usable" +.It Li W Ta Dv RTF_WASCLONED Ta "Route was generated as a result of cloning" +.It Li X Ta Dv RTF_XRESOLVE Ta "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 interface entry indicates the network interface utilized for the route. +.Pp +When +.Nm +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. +By default, this display summarizes information for all interfaces. +Information for a specific interface may be displayed with the +.Fl I +option. +.Pp +The +.Xr bpf 4 +flags displayed when +.Nm +is invoked with the +.Fl B +option represent the underlying parameters of the bpf peer. +Each flag is +represented as a single lower case letter. +The mapping between the letters and flags in order of appearance are: +.Bl -column ".Li i" +.It Li p Ta Set if listening promiscuously +.It Li i Ta Dv BIOCIMMEDIATE No has been set on the device +.It Li f Ta Dv BIOCGHDRCMPLT No status: source link addresses are being +filled automatically +.It Li s Ta Dv BIOCGSEESENT No status: see packets originating locally and +remotely on the interface. +.It Li a Ta Packet reception generates a signal +.It Li l Ta Dv BIOCLOCK No status: descriptor has been locked +.El +.Pp +For more information about these flags, please refer to +.Xr bpf 4 . +.Pp +The +.Fl x +flag causes +.Nm +to output all the information recorded about data +stored in the socket buffers. +The fields are: +.Bl -column ".Li R-MBUF" +.It Li R-MBUF Ta Number of mbufs in the receive queue. +.It Li S-MBUF Ta Number of mbufs in the send queue. +.It Li R-CLUS Ta Number of clusters, of any type, in the receive +queue. +.It Li S-CLUS Ta Number of clusters, of any type, in the send queue. +.It Li R-HIWA Ta Receive buffer high water mark, in bytes. +.It Li S-HIWA Ta Send buffer high water mark, in bytes. +.It Li R-LOWA Ta Receive buffer low water mark, in bytes. +.It Li S-LOWA Ta Send buffer low water mark, in bytes. +.It Li R-BCNT Ta Receive buffer byte count. +.It Li S-BCNT Ta Send buffer byte count. +.It Li R-BMAX Ta Maximum bytes that can be used in the receive buffer. +.It Li S-BMAX Ta Maximum bytes that can be used in the send buffer. +.El +.Sh SEE ALSO +.Xr fstat 1 , +.Xr nfsstat 1 , +.Xr procstat 1 , +.Xr ps 1 , +.Xr sockstat 1 , +.Xr bpf 4 , +.Xr inet 4 , +.Xr route 4 , +.Xr unix 4 , +.Xr hosts 5 , +.Xr networks 5 , +.Xr protocols 5 , +.Xr services 5 , +.Xr iostat 8 , +.Xr route 8 , +.Xr trpt 8 , +.Xr vmstat 8 , +.Xr mbuf 9 +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.2 . +.Pp +IPv6 support was added by WIDE/KAME project. +.Sh BUGS +The notion of errors is ill-defined. diff --git a/freebsd-userspace/commands/usr.bin/netstat/netstat.h b/freebsd-userspace/commands/usr.bin/netstat/netstat.h new file mode 100644 index 00000000..75944645 --- /dev/null +++ b/freebsd-userspace/commands/usr.bin/netstat/netstat.h @@ -0,0 +1,167 @@ +/*- + * Copyright (c) 1992, 1993 + * Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)netstat.h 8.2 (Berkeley) 1/4/94 + * $FreeBSD$ + */ + +#include + +extern int Aflag; /* show addresses of protocol control block */ +extern int aflag; /* show all sockets (including servers) */ +extern int bflag; /* show i/f total bytes in/out */ +extern int dflag; /* show i/f dropped packets */ +extern int gflag; /* show group (multicast) routing or stats */ +extern int hflag; /* show counters in human readable format */ +extern int iflag; /* show interfaces */ +extern int Lflag; /* show size of listen queues */ +extern int mflag; /* show memory stats */ +extern int noutputs; /* how much outputs before we exit */ +extern int numeric_addr; /* show addresses numerically */ +extern int numeric_port; /* show ports numerically */ +extern int rflag; /* show routing tables (or routing stats) */ +extern int sflag; /* show protocol statistics */ +extern int tflag; /* show i/f watchdog timers */ +extern int Wflag; /* wide display */ +extern int xflag; /* extended display, includes all socket buffer info */ +extern int zflag; /* zero stats */ + +extern int interval; /* repeat interval for i/f stats */ + +extern char *interface; /* desired i/f for stats, or NULL for all i/fs */ +extern int unit; /* unit number for above */ + +extern int af; /* address family */ +extern int live; /* true if we are examining a live system */ + +int kread(u_long addr, void *buf, size_t size); +const char *plural(uintmax_t); +const char *plurales(uintmax_t); +const char *pluralies(uintmax_t); + +int sotoxsocket(struct socket *, struct xsocket *); +void protopr(u_long, const char *, int, int); +void tcp_stats(u_long, const char *, int, int); +void udp_stats(u_long, const char *, int, int); +#ifdef SCTP +void sctp_protopr(u_long, const char *, int, int); +void sctp_stats(u_long, const char *, int, int); +#endif +void arp_stats(u_long, const char *, int, int); +void ip_stats(u_long, const char *, int, int); +void icmp_stats(u_long, const char *, int, int); +void igmp_stats(u_long, const char *, int, int); +void pim_stats(u_long, const char *, int, int); +void carp_stats(u_long, const char *, int, int); +void pfsync_stats(u_long, const char *, int, int); +#ifdef IPSEC +void ipsec_stats(u_long, const char *, int, int); +void esp_stats(u_long, const char *, int, int); +void ah_stats(u_long, const char *, int, int); +void ipcomp_stats(u_long, const char *, int, int); +#endif + +#ifdef INET6 +void ip6_stats(u_long, const char *, int, int); +void ip6_ifstats(char *); +void icmp6_stats(u_long, const char *, int, int); +void icmp6_ifstats(char *); +void pim6_stats(u_long, const char *, int, int); +void rip6_stats(u_long, const char *, int, int); +void mroute6pr(u_long, u_long); +void mrt6_stats(u_long); + +struct sockaddr_in6; +struct in6_addr; +char *routename6(struct sockaddr_in6 *); +const char *netname6(struct sockaddr_in6 *, struct in6_addr *); +void inet6print(struct in6_addr *, int, const char *, int); +#endif /*INET6*/ + +#ifdef IPSEC +void pfkey_stats(u_long, const char *, int, int); +#endif + +void mbpr(void *, u_long); + +void hostpr(u_long, u_long); +void impstats(u_long, u_long); + +void intpr(int, u_long, void (*)(char *)); + +void pr_rthdr(int); +void pr_family(int); +void rt_stats(u_long, u_long); +char *ipx_pnet(struct sockaddr *); +char *ipx_phost(struct sockaddr *); +char *ns_phost(struct sockaddr *); +void upHex(char *); + +char *routename(in_addr_t); +char *netname(in_addr_t, u_long); +char *atalk_print(struct sockaddr *, int); +char *atalk_print2(struct sockaddr *, struct sockaddr *, int); +char *ipx_print(struct sockaddr *); +char *ns_print(struct sockaddr *); +void routepr(u_long); + +void ipxprotopr(u_long, const char *, int, int); +void spx_stats(u_long, const char *, int, int); +void ipx_stats(u_long, const char *, int, int); +void ipxerr_stats(u_long, const char *, int, int); + +void nsprotopr(u_long, const char *, int, int); +void spp_stats(u_long, const char *, int, int); +void idp_stats(u_long, const char *, int, int); +void nserr_stats(u_long, const char *, int, int); + +void atalkprotopr(u_long, const char *, int, int); +void ddp_stats(u_long, const char *, int, int); + +#ifdef NETGRAPH +void netgraphprotopr(u_long, const char *, int, int); +#endif + +void unixpr(u_long, u_long, u_long, u_long); + +void esis_stats(u_long, const char *, int, int); +void clnp_stats(u_long, const char *, int, int); +void cltp_stats(u_long, const char *, int, int); +void iso_protopr(u_long, const char *, int, int); +void iso_protopr1(u_long, int); +void tp_protopr(u_long, const char *, int, int); +void tp_inproto(u_long); +void tp_stats(caddr_t, caddr_t); + +void mroutepr(u_long, u_long, u_long); +void mrt_stats(u_long); +void bpf_stats(char *); diff --git a/freebsd-userspace/commands/usr.bin/netstat/pfkey.c b/freebsd-userspace/commands/usr.bin/netstat/pfkey.c new file mode 100644 index 00000000..7c5af07b --- /dev/null +++ b/freebsd-userspace/commands/usr.bin/netstat/pfkey.c @@ -0,0 +1,184 @@ +/* $NetBSD: inet.c,v 1.35.2.1 1999/04/29 14:57:08 perry Exp $ */ +/* $KAME: ipsec.c,v 1.25 2001/03/12 09:04:39 itojun Exp $ */ +/*- + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/*- + * Copyright (c) 1983, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)inet.c 8.5 (Berkeley) 5/24/95"; +#endif /* not lint */ +#endif + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include + +#ifdef IPSEC +#ifdef __rtems__ +#include +#else +#include +#endif +#endif + +#include +#include +#include +#include +#include "netstat.h" + +#ifdef IPSEC + +static const char *pfkey_msgtypenames[] = { + "reserved", "getspi", "update", "add", "delete", + "get", "acquire", "register", "expire", "flush", + "dump", "x_promisc", "x_pchange", "x_spdupdate", "x_spdadd", + "x_spddelete", "x_spdget", "x_spdacquire", "x_spddump", "x_spdflush", + "x_spdsetidx", "x_spdexpire", "x_spddelete2" +}; + +static const char *pfkey_msgtype_names (int); + + +static const char * +pfkey_msgtype_names(int x) +{ + const int max = + sizeof(pfkey_msgtypenames)/sizeof(pfkey_msgtypenames[0]); + static char buf[20]; + + if (x < max && pfkey_msgtypenames[x]) + return pfkey_msgtypenames[x]; + snprintf(buf, sizeof(buf), "#%d", x); + return buf; +} + +void +pfkey_stats(u_long off, const char *name, int family __unused, + int proto __unused) +{ + struct pfkeystat pfkeystat; + unsigned first, type; + + if (off == 0) + return; + printf ("%s:\n", name); + kread(off, (char *)&pfkeystat, sizeof(pfkeystat)); + +#define p(f, m) if (pfkeystat.f || sflag <= 1) \ + printf(m, (uintmax_t)pfkeystat.f, plural(pfkeystat.f)) + + /* userland -> kernel */ + p(out_total, "\t%ju request%s sent from userland\n"); + p(out_bytes, "\t%ju byte%s sent from userland\n"); + for (first = 1, type = 0; + type < sizeof(pfkeystat.out_msgtype)/sizeof(pfkeystat.out_msgtype[0]); + type++) { + if (pfkeystat.out_msgtype[type] <= 0) + continue; + if (first) { + printf("\thistogram by message type:\n"); + first = 0; + } + printf("\t\t%s: %ju\n", pfkey_msgtype_names(type), + (uintmax_t)pfkeystat.out_msgtype[type]); + } + p(out_invlen, "\t%ju message%s with invalid length field\n"); + p(out_invver, "\t%ju message%s with invalid version field\n"); + p(out_invmsgtype, "\t%ju message%s with invalid message type field\n"); + p(out_tooshort, "\t%ju message%s too short\n"); + p(out_nomem, "\t%ju message%s with memory allocation failure\n"); + p(out_dupext, "\t%ju message%s with duplicate extension\n"); + p(out_invexttype, "\t%ju message%s with invalid extension type\n"); + p(out_invsatype, "\t%ju message%s with invalid sa type\n"); + p(out_invaddr, "\t%ju message%s with invalid address extension\n"); + + /* kernel -> userland */ + p(in_total, "\t%ju request%s sent to userland\n"); + p(in_bytes, "\t%ju byte%s sent to userland\n"); + for (first = 1, type = 0; + type < sizeof(pfkeystat.in_msgtype)/sizeof(pfkeystat.in_msgtype[0]); + type++) { + if (pfkeystat.in_msgtype[type] <= 0) + continue; + if (first) { + printf("\thistogram by message type:\n"); + first = 0; + } + printf("\t\t%s: %ju\n", pfkey_msgtype_names(type), + (uintmax_t)pfkeystat.in_msgtype[type]); + } + p(in_msgtarget[KEY_SENDUP_ONE], + "\t%ju message%s toward single socket\n"); + p(in_msgtarget[KEY_SENDUP_ALL], + "\t%ju message%s toward all sockets\n"); + p(in_msgtarget[KEY_SENDUP_REGISTERED], + "\t%ju message%s toward registered sockets\n"); + p(in_nomem, "\t%ju message%s with memory allocation failure\n"); +#undef p +} +#endif /* IPSEC */ diff --git a/freebsd-userspace/commands/usr.bin/netstat/route.c b/freebsd-userspace/commands/usr.bin/netstat/route.c new file mode 100644 index 00000000..af60527d --- /dev/null +++ b/freebsd-userspace/commands/usr.bin/netstat/route.c @@ -0,0 +1,1167 @@ +/*- + * 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. + */ + +#if 0 +#ifndef lint +static char sccsid[] = "From: @(#)route.c 8.6 (Berkeley) 4/28/95"; +#endif /* not lint */ +#endif + +#include +__FBSDID("$FreeBSD$"); + +#include +#ifdef __rtems__ +#include +#else +#include +#endif +#include +#include +#include + +#include +#include +#ifdef __rtems__ +#include +#else +#include +#endif +#include +#include +#ifdef __rtems__ +#include +#else +#include +#endif +#include + +#include +#ifdef __rtems__ +/* no IPX on RTEMS */ +/* no AppleTalk on RTEMS */ +#else +#include +#include +#endif +#ifdef __rtems__ +/* why isn't this protected by a NETGRAPH define */ +#else +#include +#endif + +#include + +#include +#ifdef __rtems__ +/* apparently libutil.h is not needed */ +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include "netstat.h" + +#define kget(p, d) (kread((u_long)(p), (char *)&(d), sizeof (d))) + +/* + * Definitions for showing gateway flags. + */ +struct bits { + u_long 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_XRESOLVE, 'X' }, + { RTF_STATIC, 'S' }, + { RTF_PROTO1, '1' }, + { RTF_PROTO2, '2' }, + { RTF_PRCLONING,'c' }, + { RTF_PROTO3, '3' }, + { RTF_BLACKHOLE,'B' }, + { RTF_BROADCAST,'b' }, +#ifdef RTF_LLINFO + { RTF_LLINFO, 'L' }, +#endif +#ifdef RTF_WASCLONED + { RTF_WASCLONED,'W' }, +#endif +#ifdef RTF_CLONING + { RTF_CLONING, 'C' }, +#endif + { 0 , 0 } +}; + +typedef union { + long dummy; /* Helps align structure. */ + struct sockaddr u_sa; + u_short u_data[128]; +} sa_u; + +static sa_u pt_u; + +int fibnum; +int do_rtent = 0; +struct rtentry rtentry; +struct radix_node rnode; +struct radix_mask rmask; +struct radix_node_head **rt_tables; + +int NewTree = 0; + +struct timespec uptime; + +static struct sockaddr *kgetsa(struct sockaddr *); +static void size_cols(int ef, struct radix_node *rn); +static void size_cols_tree(struct radix_node *rn); +static void size_cols_rtentry(struct rtentry *rt); +static void p_tree(struct radix_node *); +static void p_rtnode(void); +static void ntreestuff(void); +static void np_rtentry(struct rt_msghdr *); +static void p_sockaddr(struct sockaddr *, struct sockaddr *, int, int); +static const char *fmt_sockaddr(struct sockaddr *sa, struct sockaddr *mask, + int flags); +static void p_flags(int, const char *); +static const char *fmt_flags(int f); +static void p_rtentry(struct rtentry *); +static void domask(char *, in_addr_t, u_long); + +/* + * Print routing tables. + */ +void +routepr(u_long rtree) +{ + struct radix_node_head **rnhp, *rnh, head; + size_t intsize; + int i; + int numfibs; + + intsize = sizeof(int); + if (sysctlbyname("net.my_fibnum", &fibnum, &intsize, NULL, 0) == -1) + fibnum = 0; + if (sysctlbyname("net.fibs", &numfibs, &intsize, NULL, 0) == -1) + numfibs = 1; + rt_tables = calloc(numfibs * (AF_MAX+1), + sizeof(struct radix_node_head *)); + if (rt_tables == NULL) + err(EX_OSERR, "memory allocation failed"); + /* + * Since kernel & userland use different timebase + * (time_uptime vs time_second) and we are reading kernel memory + * directly we should do rt_rmx.rmx_expire --> expire_time conversion. + */ +#ifdef __rtems__ +#warning "fix clock_gettime(CLOCK_UPTIME)" +#else + if (clock_gettime(CLOCK_UPTIME, &uptime) < 0) + err(EX_OSERR, "clock_gettime() failed"); +#endif + + printf("Routing tables\n"); + + if (Aflag == 0 && NewTree) + ntreestuff(); + else { + if (rtree == 0) { + printf("rt_tables: symbol not in namelist\n"); + return; + } + + if (kread((u_long)(rtree), (char *)(rt_tables), (numfibs * + (AF_MAX+1) * sizeof(struct radix_node_head *))) != 0) + return; + for (i = 0; i <= AF_MAX; i++) { + int tmpfib; + if (i != AF_INET) + tmpfib = 0; + else + tmpfib = fibnum; + rnhp = (struct radix_node_head **)*rt_tables; + /* Calculate the in-kernel address. */ + rnhp += tmpfib * (AF_MAX+1) + i; + /* Read the in kernel rhn pointer. */ + if (kget(rnhp, rnh) != 0) + continue; + if (rnh == NULL) + continue; + /* Read the rnh data. */ + if (kget(rnh, head) != 0) + continue; + if (i == AF_UNSPEC) { + if (Aflag && af == 0) { + printf("Netmasks:\n"); + p_tree(head.rnh_treetop); + } + } else if (af == AF_UNSPEC || af == i) { + size_cols(i, head.rnh_treetop); + pr_family(i); + do_rtent = 1; + pr_rthdr(i); + p_tree(head.rnh_treetop); + } + } + } +} + +/* + * Print address family header before a section of the routing table. + */ +void +pr_family(int af1) +{ + const char *afname; + + switch (af1) { + case AF_INET: + afname = "Internet"; + break; +#ifdef INET6 + case AF_INET6: + afname = "Internet6"; + break; +#endif /*INET6*/ + case AF_IPX: + afname = "IPX"; + break; + case AF_ISO: + afname = "ISO"; + break; + case AF_APPLETALK: + afname = "AppleTalk"; + break; + case AF_CCITT: + afname = "X.25"; + break; + case AF_NETGRAPH: + afname = "Netgraph"; + break; + default: + afname = NULL; + break; + } + if (afname) + printf("\n%s:\n", afname); + else + printf("\nProtocol Family %d:\n", af1); +} + +/* column widths; each followed by one space */ +#ifndef INET6 +#define WID_DST_DEFAULT(af) 18 /* width of destination column */ +#define WID_GW_DEFAULT(af) 18 /* width of gateway column */ +#define WID_IF_DEFAULT(af) (Wflag ? 8 : 6) /* width of netif column */ +#else +#define WID_DST_DEFAULT(af) \ + ((af) == AF_INET6 ? (numeric_addr ? 33: 18) : 18) +#define WID_GW_DEFAULT(af) \ + ((af) == AF_INET6 ? (numeric_addr ? 29 : 18) : 18) +#define WID_IF_DEFAULT(af) ((af) == AF_INET6 ? 8 : (Wflag ? 8 : 6)) +#endif /*INET6*/ + +static int wid_dst; +static int wid_gw; +static int wid_flags; +static int wid_refs; +static int wid_use; +static int wid_mtu; +static int wid_if; +static int wid_expire; + +static void +size_cols(int ef __unused, struct radix_node *rn) +{ + wid_dst = WID_DST_DEFAULT(ef); + wid_gw = WID_GW_DEFAULT(ef); + wid_flags = 6; + wid_refs = 6; + wid_use = 8; + wid_mtu = 6; + wid_if = WID_IF_DEFAULT(ef); + wid_expire = 6; + + if (Wflag) + size_cols_tree(rn); +} + +static void +size_cols_tree(struct radix_node *rn) +{ +again: + if (kget(rn, rnode) != 0) + return; + if (!(rnode.rn_flags & RNF_ACTIVE)) + return; + if (rnode.rn_bit < 0) { + if ((rnode.rn_flags & RNF_ROOT) == 0) { + if (kget(rn, rtentry) != 0) + return; + size_cols_rtentry(&rtentry); + } + if ((rn = rnode.rn_dupedkey)) + goto again; + } else { + rn = rnode.rn_right; + size_cols_tree(rnode.rn_left); + size_cols_tree(rn); + } +} + +static void +size_cols_rtentry(struct rtentry *rt) +{ + static struct ifnet ifnet, *lastif; + static char buffer[100]; + const char *bp; + struct sockaddr *sa; + sa_u addr, mask; + int len; + + bzero(&addr, sizeof(addr)); + if ((sa = kgetsa(rt_key(rt)))) + bcopy(sa, &addr, sa->sa_len); + bzero(&mask, sizeof(mask)); + if (rt_mask(rt) && (sa = kgetsa(rt_mask(rt)))) + bcopy(sa, &mask, sa->sa_len); + bp = fmt_sockaddr(&addr.u_sa, &mask.u_sa, rt->rt_flags); + len = strlen(bp); + wid_dst = MAX(len, wid_dst); + + bp = fmt_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST); + len = strlen(bp); + wid_gw = MAX(len, wid_gw); + + bp = fmt_flags(rt->rt_flags); + len = strlen(bp); + wid_flags = MAX(len, wid_flags); + + if (addr.u_sa.sa_family == AF_INET || Wflag) { + len = snprintf(buffer, sizeof(buffer), "%d", rt->rt_refcnt); + wid_refs = MAX(len, wid_refs); + len = snprintf(buffer, sizeof(buffer), "%lu", rt->rt_use); + wid_use = MAX(len, wid_use); + if (Wflag && rt->rt_rmx.rmx_mtu != 0) { + len = snprintf(buffer, sizeof(buffer), + "%lu", rt->rt_rmx.rmx_mtu); + wid_mtu = MAX(len, wid_mtu); + } + } + if (rt->rt_ifp) { + if (rt->rt_ifp != lastif) { + if (kget(rt->rt_ifp, ifnet) == 0) + len = strlen(ifnet.if_xname); + else + len = strlen("---"); + lastif = rt->rt_ifp; + wid_if = MAX(len, wid_if); + } + if (rt->rt_rmx.rmx_expire) { + time_t expire_time; + + if ((expire_time = + rt->rt_rmx.rmx_expire - uptime.tv_sec) > 0) { + len = snprintf(buffer, sizeof(buffer), "%d", + (int)expire_time); + wid_expire = MAX(len, wid_expire); + } + } + } +} + + +/* + * Print header for routing table columns. + */ +void +pr_rthdr(int af1) +{ + + if (Aflag) + printf("%-8.8s ","Address"); + if (af1 == AF_INET || Wflag) { + if (Wflag) { + printf("%-*.*s %-*.*s %-*.*s %*.*s %*.*s %*.*s %*.*s %*s\n", + wid_dst, wid_dst, "Destination", + wid_gw, wid_gw, "Gateway", + wid_flags, wid_flags, "Flags", + wid_refs, wid_refs, "Refs", + wid_use, wid_use, "Use", + wid_mtu, wid_mtu, "Mtu", + wid_if, wid_if, "Netif", + wid_expire, "Expire"); + } else { + printf("%-*.*s %-*.*s %-*.*s %*.*s %*.*s %*.*s %*s\n", + wid_dst, wid_dst, "Destination", + wid_gw, wid_gw, "Gateway", + wid_flags, wid_flags, "Flags", + wid_refs, wid_refs, "Refs", + wid_use, wid_use, "Use", + wid_if, wid_if, "Netif", + wid_expire, "Expire"); + } + } else { + printf("%-*.*s %-*.*s %-*.*s %*.*s %*s\n", + wid_dst, wid_dst, "Destination", + wid_gw, wid_gw, "Gateway", + wid_flags, wid_flags, "Flags", + wid_if, wid_if, "Netif", + wid_expire, "Expire"); + } +} + +static struct sockaddr * +kgetsa(struct sockaddr *dst) +{ + + if (kget(dst, pt_u.u_sa) != 0) + return (NULL); + 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(struct radix_node *rn) +{ + +again: + if (kget(rn, rnode) != 0) + return; + if (!(rnode.rn_flags & RNF_ACTIVE)) + return; + if (rnode.rn_bit < 0) { + if (Aflag) + printf("%-8.8lx ", (u_long)rn); + if (rnode.rn_flags & RNF_ROOT) { + if (Aflag) + printf("(root node)%s", + rnode.rn_dupedkey ? " =>\n" : "\n"); + } else if (do_rtent) { + if (kget(rn, rtentry) == 0) { + p_rtentry(&rtentry); + if (Aflag) + p_rtnode(); + } + } else { + p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_key), + NULL, 0, 44); + putchar('\n'); + } + if ((rn = rnode.rn_dupedkey)) + goto again; + } else { + if (Aflag && do_rtent) { + printf("%-8.8lx ", (u_long)rn); + p_rtnode(); + } + rn = rnode.rn_right; + p_tree(rnode.rn_left); + p_tree(rn); + } +} + +char nbuf[20]; + +static void +p_rtnode(void) +{ + struct radix_mask *rm = rnode.rn_mklist; + + if (rnode.rn_bit < 0) { + if (rnode.rn_mask) { + printf("\t mask "); + p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_mask), + NULL, 0, -1); + } else if (rm == 0) + return; + } else { + sprintf(nbuf, "(%d)", rnode.rn_bit); + printf("%6.6s %8.8lx : %8.8lx", nbuf, (u_long)rnode.rn_left, (u_long)rnode.rn_right); + } + while (rm) { + if (kget(rm, rmask) != 0) + break; + sprintf(nbuf, " %d refs, ", rmask.rm_refs); + printf(" mk = %8.8lx {(%d),%s", + (u_long)rm, -1 - rmask.rm_bit, rmask.rm_refs ? nbuf : " "); + if (rmask.rm_flags & RNF_NORMAL) { + struct radix_node rnode_aux; + printf(" , "); + if (kget(rmask.rm_leaf, rnode_aux) == 0) + p_sockaddr(kgetsa((struct sockaddr *)rnode_aux.rn_mask), + NULL, 0, -1); + else + p_sockaddr(NULL, NULL, 0, -1); + } else + p_sockaddr(kgetsa((struct sockaddr *)rmask.rm_mask), + NULL, 0, -1); + putchar('}'); + if ((rm = rmask.rm_mklist)) + printf(" ->"); + } + putchar('\n'); +} + +static void +ntreestuff(void) +{ + size_t needed; + int mib[6]; + char *buf, *next, *lim; + 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) { + err(1, "sysctl: net.route.0.0.dump estimate"); + } + + if ((buf = malloc(needed)) == 0) { + errx(2, "malloc(%lu)", (unsigned long)needed); + } + if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { + err(1, "sysctl: net.route.0.0.dump"); + } + lim = buf + needed; + for (next = buf; next < lim; next += rtm->rtm_msglen) { + rtm = (struct rt_msghdr *)next; + np_rtentry(rtm); + } +} + +static void +np_rtentry(struct rt_msghdr *rtm) +{ + struct sockaddr *sa = (struct sockaddr *)(rtm + 1); +#ifdef notdef + static int masks_done, banner_printed; +#endif + static int old_af; + int af1 = 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; + af1 = sa->sa_family; + } + } else +#endif + af1 = sa->sa_family; + if (af1 != old_af) { + pr_family(af1); + old_af = af1; + } + if (rtm->rtm_addrs == RTA_DST) + p_sockaddr(sa, NULL, 0, 36); + else { + p_sockaddr(sa, NULL, rtm->rtm_flags, 16); + sa = (struct sockaddr *)(SA_SIZE(sa) + (char *)sa); + p_sockaddr(sa, NULL, 0, 18); + } + p_flags(rtm->rtm_flags & interesting, "%-6.6s "); + putchar('\n'); +} + +static void +p_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags, int width) +{ + const char *cp; + + cp = fmt_sockaddr(sa, mask, flags); + + if (width < 0 ) + printf("%s ", cp); + else { + if (numeric_addr) + printf("%-*s ", width, cp); + else + printf("%-*.*s ", width, width, cp); + } +} + +static const char * +fmt_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags) +{ + static char workbuf[128]; + const char *cp; + + if (sa == NULL) + return ("null"); + + switch(sa->sa_family) { + case AF_INET: + { + struct sockaddr_in *sockin = (struct sockaddr_in *)sa; + + if ((sockin->sin_addr.s_addr == INADDR_ANY) && + mask && + ntohl(((struct sockaddr_in *)mask)->sin_addr.s_addr) + ==0L) + cp = "default" ; + else if (flags & RTF_HOST) + cp = routename(sockin->sin_addr.s_addr); + else if (mask) + cp = netname(sockin->sin_addr.s_addr, + ntohl(((struct sockaddr_in *)mask) + ->sin_addr.s_addr)); + else + cp = netname(sockin->sin_addr.s_addr, 0L); + break; + } + +#ifdef INET6 + case AF_INET6: + { + struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; + struct in6_addr *in6 = &sa6->sin6_addr; + + /* + * XXX: This is a special workaround for KAME kernels. + * sin6_scope_id field of SA should be set in the future. + */ + if (IN6_IS_ADDR_LINKLOCAL(in6) || + IN6_IS_ADDR_MC_LINKLOCAL(in6)) { + /* XXX: override is ok? */ + sa6->sin6_scope_id = (u_int32_t)ntohs(*(u_short *)&in6->s6_addr[2]); + *(u_short *)&in6->s6_addr[2] = 0; + } + + if (flags & RTF_HOST) + cp = routename6(sa6); + else if (mask) + cp = netname6(sa6, + &((struct sockaddr_in6 *)mask)->sin6_addr); + else { + cp = netname6(sa6, NULL); + } + break; + } +#endif /*INET6*/ + +#ifndef __rtems__ + case AF_IPX: + { + struct ipx_addr work = ((struct sockaddr_ipx *)sa)->sipx_addr; + if (ipx_nullnet(satoipx_addr(work))) + cp = "default"; + else + cp = ipx_print(sa); + break; + } + case AF_APPLETALK: + { + if (!(flags & RTF_HOST) && mask) + cp = atalk_print2(sa,mask,9); + else + cp = atalk_print(sa,11); + break; + } +#endif + case AF_NETGRAPH: + { +#ifdef __rtems__ + /* netgraph not supported yet */ + err(EX_OSERR, "memory allocation failed"); +#else + strlcpy(workbuf, ((struct sockaddr_ng *)sa)->sg_data, + sizeof(workbuf)); + cp = workbuf; +#endif + break; + } + + case AF_LINK: + { + struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; + + if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && + sdl->sdl_slen == 0) { + (void) sprintf(workbuf, "link#%d", sdl->sdl_index); + cp = workbuf; + } else + switch (sdl->sdl_type) { + + case IFT_ETHER: + case IFT_L2VLAN: + case IFT_BRIDGE: + if (sdl->sdl_alen == ETHER_ADDR_LEN) { + cp = ether_ntoa((struct ether_addr *) + (sdl->sdl_data + sdl->sdl_nlen)); + break; + } + /* FALLTHROUGH */ + default: + cp = link_ntoa(sdl); + break; + } + break; + } + + default: + { + u_char *s = (u_char *)sa->sa_data, *slim; + char *cq, *cqlim; + + cq = workbuf; + slim = sa->sa_len + (u_char *) sa; + cqlim = cq + sizeof(workbuf) - 6; + cq += sprintf(cq, "(%d)", sa->sa_family); + while (s < slim && cq < cqlim) { + cq += sprintf(cq, " %02x", *s++); + if (s < slim) + cq += sprintf(cq, "%02x", *s++); + } + cp = workbuf; + } + } + + return (cp); +} + +static void +p_flags(int f, const char *format) +{ + printf(format, fmt_flags(f)); +} + +static const char * +fmt_flags(int f) +{ + static char name[33]; + char *flags; + struct bits *p = bits; + + for (flags = name; p->b_mask; p++) + if (p->b_mask & f) + *flags++ = p->b_val; + *flags = '\0'; + return (name); +} + +static void +p_rtentry(struct rtentry *rt) +{ + static struct ifnet ifnet, *lastif; + static char buffer[128]; + static char prettyname[128]; + struct sockaddr *sa; + sa_u addr, mask; + + bzero(&addr, sizeof(addr)); + if ((sa = kgetsa(rt_key(rt)))) + bcopy(sa, &addr, sa->sa_len); + bzero(&mask, sizeof(mask)); + if (rt_mask(rt) && (sa = kgetsa(rt_mask(rt)))) + bcopy(sa, &mask, sa->sa_len); + p_sockaddr(&addr.u_sa, &mask.u_sa, rt->rt_flags, wid_dst); + p_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST, wid_gw); + snprintf(buffer, sizeof(buffer), "%%-%d.%ds ", wid_flags, wid_flags); + p_flags(rt->rt_flags, buffer); + if (addr.u_sa.sa_family == AF_INET || Wflag) { + printf("%*d %*lu ", wid_refs, rt->rt_refcnt, + wid_use, rt->rt_use); + if (Wflag) { + if (rt->rt_rmx.rmx_mtu != 0) + printf("%*lu ", wid_mtu, rt->rt_rmx.rmx_mtu); + else + printf("%*s ", wid_mtu, ""); + } + } + if (rt->rt_ifp) { + if (rt->rt_ifp != lastif) { + if (kget(rt->rt_ifp, ifnet) == 0) + strlcpy(prettyname, ifnet.if_xname, + sizeof(prettyname)); + else + strlcpy(prettyname, "---", sizeof(prettyname)); + lastif = rt->rt_ifp; + } + printf("%*.*s", wid_if, wid_if, prettyname); + if (rt->rt_rmx.rmx_expire) { + time_t expire_time; + + if ((expire_time = + rt->rt_rmx.rmx_expire - uptime.tv_sec) > 0) + printf(" %*d", wid_expire, (int)expire_time); + } + if (rt->rt_nodes[0].rn_dupedkey) + printf(" =>"); + } + putchar('\n'); +} + +char * +routename(in_addr_t in) +{ + char *cp; + static char line[MAXHOSTNAMELEN]; + struct hostent *hp; + + cp = 0; + if (!numeric_addr) { + hp = gethostbyaddr(&in, sizeof (struct in_addr), AF_INET); + if (hp) { + cp = hp->h_name; + trimdomain(cp, strlen(cp)); + } + } + if (cp) { + strlcpy(line, cp, sizeof(line)); + } else { +#define C(x) ((x) & 0xff) + in = ntohl(in); + sprintf(line, "%u.%u.%u.%u", + C(in >> 24), C(in >> 16), C(in >> 8), C(in)); + } + return (line); +} + +#define NSHIFT(m) ( \ + (m) == IN_CLASSA_NET ? IN_CLASSA_NSHIFT : \ + (m) == IN_CLASSB_NET ? IN_CLASSB_NSHIFT : \ + (m) == IN_CLASSC_NET ? IN_CLASSC_NSHIFT : \ + 0) + +static void +domask(char *dst, in_addr_t addr __unused, u_long mask) +{ + int b, i; + + if (mask == 0 || (!numeric_addr && NSHIFT(mask) != 0)) { + *dst = '\0'; + return; + } + i = 0; + for (b = 0; b < 32; b++) + if (mask & (1 << b)) { + int bb; + + i = b; + for (bb = b+1; bb < 32; bb++) + if (!(mask & (1 << bb))) { + i = -1; /* noncontig */ + break; + } + break; + } + if (i == -1) + sprintf(dst, "&0x%lx", mask); + else + sprintf(dst, "/%d", 32-i); +} + +/* + * Return the name of the network whose address is given. + * The address is assumed to be that of a net or subnet, not a host. + */ +char * +netname(in_addr_t in, u_long mask) +{ + char *cp = 0; + static char line[MAXHOSTNAMELEN]; + struct netent *np = 0; + in_addr_t i; + + i = ntohl(in); + if (!numeric_addr && i) { + np = getnetbyaddr(i >> NSHIFT(mask), AF_INET); + if (np != NULL) { + cp = np->n_name; + trimdomain(cp, strlen(cp)); + } + } + if (cp != NULL) { + strlcpy(line, cp, sizeof(line)); + } else { + inet_ntop(AF_INET, &in, line, sizeof(line) - 1); + } + domask(line + strlen(line), i, mask); + return (line); +} + +#undef NSHIFT + +#ifdef INET6 +const char * +netname6(struct sockaddr_in6 *sa6, struct in6_addr *mask) +{ + static char line[MAXHOSTNAMELEN]; + u_char *p = (u_char *)mask; + u_char *lim; + int masklen, illegal = 0, flag = 0; + + if (mask) { + for (masklen = 0, lim = p + 16; p < lim; p++) { + switch (*p) { + case 0xff: + masklen += 8; + break; + case 0xfe: + masklen += 7; + break; + case 0xfc: + masklen += 6; + break; + case 0xf8: + masklen += 5; + break; + case 0xf0: + masklen += 4; + break; + case 0xe0: + masklen += 3; + break; + case 0xc0: + masklen += 2; + break; + case 0x80: + masklen += 1; + break; + case 0x00: + break; + default: + illegal ++; + break; + } + } + if (illegal) + fprintf(stderr, "illegal prefixlen\n"); + } + else + masklen = 128; + + if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr)) + return("default"); + + if (numeric_addr) + flag |= NI_NUMERICHOST; + getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, sizeof(line), + NULL, 0, flag); + + if (numeric_addr) + sprintf(&line[strlen(line)], "/%d", masklen); + + return line; +} + +char * +routename6(struct sockaddr_in6 *sa6) +{ + static char line[MAXHOSTNAMELEN]; + int flag = 0; + /* use local variable for safety */ + struct sockaddr_in6 sa6_local; + + sa6_local.sin6_family = AF_INET6; + sa6_local.sin6_len = sizeof(sa6_local); + sa6_local.sin6_addr = sa6->sin6_addr; + sa6_local.sin6_scope_id = sa6->sin6_scope_id; + + if (numeric_addr) + flag |= NI_NUMERICHOST; + + getnameinfo((struct sockaddr *)&sa6_local, sa6_local.sin6_len, + line, sizeof(line), NULL, 0, flag); + + return line; +} +#endif /*INET6*/ + +/* + * Print routing statistics + */ +void +rt_stats(u_long rtsaddr, u_long rttaddr) +{ + struct rtstat rtstat; + int rttrash; + + if (rtsaddr == 0) { + printf("rtstat: symbol not in namelist\n"); + return; + } + if (rttaddr == 0) { + printf("rttrash: symbol not in namelist\n"); + return; + } + kread(rtsaddr, (char *)&rtstat, sizeof (rtstat)); + kread(rttaddr, (char *)&rttrash, sizeof (rttrash)); + printf("routing:\n"); + +#define p(f, m) if (rtstat.f || sflag <= 1) \ + printf(m, rtstat.f, plural(rtstat.f)) + + p(rts_badredirect, "\t%hu bad routing redirect%s\n"); + p(rts_dynamic, "\t%hu dynamically created route%s\n"); + p(rts_newgateway, "\t%hu new gateway%s due to redirects\n"); + p(rts_unreach, "\t%hu destination%s found unreachable\n"); + p(rts_wildcard, "\t%hu use%s of a wildcard route\n"); +#undef p + + if (rttrash || sflag <= 1) + printf("\t%u route%s not in table but not freed\n", + rttrash, plural(rttrash)); +} + +#ifndef __rtems__ +char * +ipx_print(struct sockaddr *sa) +{ + u_short port; + struct servent *sp = 0; + const char *net = "", *host = ""; + char *p; + u_char *q; + struct ipx_addr work = ((struct sockaddr_ipx *)sa)->sipx_addr; + static char mybuf[50]; + char cport[10], chost[15], cnet[15]; + + port = ntohs(work.x_port); + + if (ipx_nullnet(work) && ipx_nullhost(work)) { + + if (port) { + if (sp) + sprintf(mybuf, "*.%s", sp->s_name); + else + sprintf(mybuf, "*.%x", port); + } else + sprintf(mybuf, "*.*"); + + return (mybuf); + } + + if (ipx_wildnet(work)) + net = "any"; + else if (ipx_nullnet(work)) + net = "*"; + else { + q = work.x_net.c_net; + sprintf(cnet, "%02x%02x%02x%02x", + q[0], q[1], q[2], q[3]); + for (p = cnet; *p == '0' && p < cnet + 8; p++) + continue; + net = p; + } + + if (ipx_wildhost(work)) + host = "any"; + else if (ipx_nullhost(work)) + host = "*"; + else { + q = work.x_host.c_host; + sprintf(chost, "%02x%02x%02x%02x%02x%02x", + 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) { + if (strcmp(host, "*") == 0) + host = ""; + if (sp) + snprintf(cport, sizeof(cport), + "%s%s", *host ? "." : "", sp->s_name); + else + snprintf(cport, sizeof(cport), + "%s%x", *host ? "." : "", port); + } else + *cport = 0; + + snprintf(mybuf, sizeof(mybuf), "%s.%s%s", net, host, cport); + return(mybuf); +} + +char * +ipx_phost(struct sockaddr *sa) +{ + struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)sa; + struct sockaddr_ipx work; + static union ipx_net ipx_zeronet; + char *p; + struct ipx_addr in; + + work = *sipx; + in = work.sipx_addr; + + work.sipx_addr.x_port = 0; + work.sipx_addr.x_net = ipx_zeronet; + p = ipx_print((struct sockaddr *)&work); + if (strncmp("*.", p, 2) == 0) p += 2; + + return(p); +} +#endif + +void +upHex(char *p0) +{ + char *p = p0; + + for (; *p; p++) + switch (*p) { + + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + *p += ('A' - 'a'); + break; + } +} diff --git a/freebsd-userspace/commands/usr.bin/netstat/sctp.c b/freebsd-userspace/commands/usr.bin/netstat/sctp.c new file mode 100644 index 00000000..0c02db9f --- /dev/null +++ b/freebsd-userspace/commands/usr.bin/netstat/sctp.c @@ -0,0 +1,703 @@ +/*- + * Copyright (c) 2001-2007, by Weongyo Jeong. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * a) Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * b) 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. + * + * c) Neither the name of Cisco Systems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)sctp.c 0.1 (Berkeley) 4/18/2007"; +#endif /* not lint */ +#endif + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#ifdef __rtems__ +#include +#else +#include +#endif + +#include +#ifdef __rtems__ +#include +#include +#else +#include +#include +#endif +#include + +#include +#include +#ifdef __rtems__ +/* apparently libutil.h is not needed */ +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include "netstat.h" + +#ifdef SCTP + +void inetprint(struct in_addr *, int, const char *, int); +static void sctp_statesprint(uint32_t state); + +#define NETSTAT_SCTP_STATES_CLOSED 0x0 +#define NETSTAT_SCTP_STATES_BOUND 0x1 +#define NETSTAT_SCTP_STATES_LISTEN 0x2 +#define NETSTAT_SCTP_STATES_COOKIE_WAIT 0x3 +#define NETSTAT_SCTP_STATES_COOKIE_ECHOED 0x4 +#define NETSTAT_SCTP_STATES_ESTABLISHED 0x5 +#define NETSTAT_SCTP_STATES_SHUTDOWN_SENT 0x6 +#define NETSTAT_SCTP_STATES_SHUTDOWN_RECEIVED 0x7 +#define NETSTAT_SCTP_STATES_SHUTDOWN_ACK_SENT 0x8 +#define NETSTAT_SCTP_STATES_SHUTDOWN_PENDING 0x9 + +char *sctpstates[] = { + "CLOSED", + "BOUND", + "LISTEN", + "COOKIE_WAIT", + "COOKIE_ECHOED", + "ESTABLISHED", + "SHUTDOWN_SENT", + "SHUTDOWN_RECEIVED", + "SHUTDOWN_ACK_SENT", + "SHUTDOWN_PENDING" +}; + +LIST_HEAD(xladdr_list, xladdr_entry) xladdr_head; +struct xladdr_entry { + struct xsctp_laddr *xladdr; + LIST_ENTRY(xladdr_entry) xladdr_entries; +}; + +LIST_HEAD(xraddr_list, xraddr_entry) xraddr_head; +struct xraddr_entry { + struct xsctp_raddr *xraddr; + LIST_ENTRY(xraddr_entry) xraddr_entries; +}; + +static int +sctp_skip_xinpcb_ifneed(char *buf, const size_t buflen, size_t *offset) +{ + int exist_tcb = 0; + struct xsctp_tcb *xstcb; + struct xsctp_raddr *xraddr; + struct xsctp_laddr *xladdr; + + while (*offset < buflen) { + xladdr = (struct xsctp_laddr *)(buf + *offset); + *offset += sizeof(struct xsctp_laddr); + if (xladdr->last == 1) + break; + } + + while (*offset < buflen) { + xstcb = (struct xsctp_tcb *)(buf + *offset); + *offset += sizeof(struct xsctp_tcb); + if (xstcb->last == 1) + break; + + exist_tcb = 1; + + while (*offset < buflen) { + xladdr = (struct xsctp_laddr *)(buf + *offset); + *offset += sizeof(struct xsctp_laddr); + if (xladdr->last == 1) + break; + } + + while (*offset < buflen) { + xraddr = (struct xsctp_raddr *)(buf + *offset); + *offset += sizeof(struct xsctp_raddr); + if (xraddr->last == 1) + break; + } + } + + /* + * If Lflag is set, we don't care about the return value. + */ + if (Lflag) + return 0; + + return exist_tcb; +} + +static void +sctp_process_tcb(struct xsctp_tcb *xstcb, const char *name, + char *buf, const size_t buflen, size_t *offset, int *indent) +{ + int i, xl_total = 0, xr_total = 0, x_max; + struct sockaddr *sa; + struct xsctp_raddr *xraddr; + struct xsctp_laddr *xladdr; + struct xladdr_entry *prev_xl = NULL, *xl = NULL, *xl_tmp; + struct xraddr_entry *prev_xr = NULL, *xr = NULL, *xr_tmp; +#ifdef INET6 + struct sockaddr_in6 *in6; +#endif + + LIST_INIT(&xladdr_head); + LIST_INIT(&xraddr_head); + + /* + * Make `struct xladdr_list' list and `struct xraddr_list' list + * to handle the address flexibly. + */ + while (*offset < buflen) { + xladdr = (struct xsctp_laddr *)(buf + *offset); + *offset += sizeof(struct xsctp_laddr); + if (xladdr->last == 1) + break; + + prev_xl = xl; + xl = malloc(sizeof(struct xladdr_entry)); + if (xl == NULL) { + warnx("malloc %lu bytes", + (u_long)sizeof(struct xladdr_entry)); + goto out; + } + xl->xladdr = xladdr; + if (prev_xl == NULL) + LIST_INSERT_HEAD(&xladdr_head, xl, xladdr_entries); + else + LIST_INSERT_AFTER(prev_xl, xl, xladdr_entries); + xl_total++; + } + + while (*offset < buflen) { + xraddr = (struct xsctp_raddr *)(buf + *offset); + *offset += sizeof(struct xsctp_raddr); + if (xraddr->last == 1) + break; + + prev_xr = xr; + xr = malloc(sizeof(struct xraddr_entry)); + if (xr == NULL) { + warnx("malloc %lu bytes", + (u_long)sizeof(struct xraddr_entry)); + goto out; + } + xr->xraddr = xraddr; + if (prev_xr == NULL) + LIST_INSERT_HEAD(&xraddr_head, xr, xraddr_entries); + else + LIST_INSERT_AFTER(prev_xr, xr, xraddr_entries); + xr_total++; + } + + /* + * Let's print the address infos. + */ + xl = LIST_FIRST(&xladdr_head); + xr = LIST_FIRST(&xraddr_head); + x_max = (xl_total > xr_total) ? xl_total : xr_total; + for (i = 0; i < x_max; i++) { + if (((*indent == 0) && i > 0) || *indent > 0) + printf("%-11s ", " "); + + if (xl != NULL) { + sa = &(xl->xladdr->address.sa); + if ((sa->sa_family) == AF_INET) + inetprint(&((struct sockaddr_in *)sa)->sin_addr, + htons(xstcb->local_port), + name, numeric_port); +#ifdef INET6 + else { + in6 = (struct sockaddr_in6 *)sa; + inet6print(&in6->sin6_addr, + htons(xstcb->local_port), + name, numeric_port); + } +#endif + } + + if (xr != NULL && !Lflag) { + sa = &(xr->xraddr->address.sa); + if ((sa->sa_family) == AF_INET) + inetprint(&((struct sockaddr_in *)sa)->sin_addr, + htons(xstcb->remote_port), + name, numeric_port); +#ifdef INET6 + else { + in6 = (struct sockaddr_in6 *)sa; + inet6print(&in6->sin6_addr, + htons(xstcb->remote_port), + name, numeric_port); + } +#endif + } + + if (xl != NULL) + xl = LIST_NEXT(xl, xladdr_entries); + if (xr != NULL) + xr = LIST_NEXT(xr, xraddr_entries); + + if (i == 0 && !Lflag) + sctp_statesprint(xstcb->state); + + if (i < x_max) + putchar('\n'); + } + +out: + /* + * Free the list which be used to handle the address. + */ + xl = LIST_FIRST(&xladdr_head); + while (xl != NULL) { + xl_tmp = LIST_NEXT(xl, xladdr_entries); + free(xl); + xl = xl_tmp; + } + + xr = LIST_FIRST(&xraddr_head); + while (xr != NULL) { + xr_tmp = LIST_NEXT(xr, xraddr_entries); + free(xr); + xr = xr_tmp; + } +} + +#ifdef SCTP_DEBUG +uint32_t sctp_pdup[64]; +int sctp_pcnt = 0; +#endif + +static void +sctp_process_inpcb(struct xsctp_inpcb *xinpcb, const char *name, + char *buf, const size_t buflen, size_t *offset) +{ + int offset_backup, indent = 0, xladdr_total = 0, is_listening = 0; + static int first = 1; + char *tname; + struct xsctp_tcb *xstcb; + struct xsctp_laddr *xladdr; + struct sockaddr *sa; +#ifdef INET6 + struct sockaddr_in6 *in6; +#endif + + if ((xinpcb->flags & SCTP_PCB_FLAGS_TCPTYPE) == + SCTP_PCB_FLAGS_TCPTYPE && xinpcb->maxqlen > 0) + is_listening = 1; + + if (!Lflag && !is_listening && + !(xinpcb->flags & SCTP_PCB_FLAGS_CONNECTED)) { +#ifdef SCTP_DEBUG + int i, found = 0; + + for (i = 0; i < sctp_pcnt; i++) { + if (sctp_pdup[i] == xinpcb->flags) { + found = 1; + break; + } + } + if (!found) { + sctp_pdup[sctp_pcnt++] = xinpcb->flags; + if (sctp_pcnt >= 64) + sctp_pcnt = 0; + printf("[0x%08x]", xinpcb->flags); + } +#endif + offset_backup = *offset; + if (!sctp_skip_xinpcb_ifneed(buf, buflen, offset)) + return; + *offset = offset_backup; + } + + if (first) { + if (!Lflag) { + printf("Active SCTP associations"); + if (aflag) + printf(" (including servers)"); + } else + printf("Current listen queue sizes (qlen/maxqlen)"); + putchar('\n'); + if (Aflag) + printf("%-8.8s ", "Socket"); + if (Lflag) + printf("%-5.5s %-5.5s %-8.8s %-22.22s\n", + "Proto", "Type", "Listen", "Local Address"); + else + printf((Aflag && !Wflag) ? + "%-5.5s %-5.5s %-18.18s %-18.18s %s\n" : + "%-5.5s %-5.5s %-22.22s %-22.22s %s\n", + "Proto", "Type", + "Local Address", "Foreign Address", + "(state)"); + first = 0; + } + if (Lflag && xinpcb->maxqlen == 0) { + (int)sctp_skip_xinpcb_ifneed(buf, buflen, offset); + return; + } + if (Aflag) + printf("%8lx ", (u_long)xinpcb); + + printf("%-5.5s ", name); + + if (xinpcb->flags & SCTP_PCB_FLAGS_TCPTYPE) + tname = "1to1"; + else if (xinpcb->flags & SCTP_PCB_FLAGS_UDPTYPE) + tname = "1toN"; + else + return; + + printf("%-5.5s ", tname); + + if (Lflag) { + char buf1[9]; + + snprintf(buf1, 9, "%hu/%hu", xinpcb->qlen, xinpcb->maxqlen); + printf("%-8.8s ", buf1); + } + /* + * process the local address. This routine are used for Lflag. + */ + while (*offset < buflen) { + xladdr = (struct xsctp_laddr *)(buf + *offset); + *offset += sizeof(struct xsctp_laddr); + if (xladdr->last == 1) + break; + + if (!Lflag && !is_listening) + continue; + + if (xladdr_total != 0) + putchar('\n'); + if (xladdr_total > 0) + printf((Lflag) ? + "%-20.20s " : "%-11.11s ", " "); + + sa = &(xladdr->address.sa); + if ((sa->sa_family) == AF_INET) + inetprint(&((struct sockaddr_in *)sa)->sin_addr, + htons(xinpcb->local_port), name, numeric_port); +#ifdef INET6 + else { + in6 = (struct sockaddr_in6 *)sa; + inet6print(&in6->sin6_addr, + htons(xinpcb->local_port), name, numeric_port); + } +#endif + + if (!Lflag && xladdr_total == 0 && is_listening == 1) + printf("%-22.22s LISTEN", " "); + + xladdr_total++; + } + + xstcb = (struct xsctp_tcb *)(buf + *offset); + *offset += sizeof(struct xsctp_tcb); + while (xstcb->last == 0 && *offset < buflen) { + sctp_process_tcb(xstcb, name, buf, buflen, offset, &indent); + indent++; + xstcb = (struct xsctp_tcb *)(buf + *offset); + *offset += sizeof(struct xsctp_tcb); + } + + putchar('\n'); +} + +/* + * Print a summary of SCTP connections related to an Internet + * protocol. + */ +void +sctp_protopr(u_long off __unused, + const char *name, int af1, int proto) +{ + char *buf; + const char *mibvar = "net.inet.sctp.assoclist"; + size_t offset = 0; + size_t len = 0; + struct xsctp_inpcb *xinpcb; + + if (proto != IPPROTO_SCTP) + return; + + if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) { + if (errno != ENOENT) + warn("sysctl: %s", mibvar); + return; + } + if ((buf = malloc(len)) == 0) { + warnx("malloc %lu bytes", (u_long)len); + return; + } + if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) { + warn("sysctl: %s", mibvar); + free(buf); + return; + } + + xinpcb = (struct xsctp_inpcb *)(buf + offset); + offset += sizeof(struct xsctp_inpcb); + while (xinpcb->last == 0 && offset < len) { + sctp_process_inpcb(xinpcb, name, buf, (const size_t)len, + &offset); + + xinpcb = (struct xsctp_inpcb *)(buf + offset); + offset += sizeof(struct xsctp_inpcb); + } + + free(buf); +} + +static void +sctp_statesprint(uint32_t state) +{ + int idx; + + switch (state) { + case SCTP_STATE_COOKIE_WAIT: + idx = NETSTAT_SCTP_STATES_COOKIE_WAIT; + break; + case SCTP_STATE_COOKIE_ECHOED: + idx = NETSTAT_SCTP_STATES_COOKIE_ECHOED; + break; + case SCTP_STATE_OPEN: + idx = NETSTAT_SCTP_STATES_ESTABLISHED; + break; + case SCTP_STATE_SHUTDOWN_SENT: + idx = NETSTAT_SCTP_STATES_SHUTDOWN_SENT; + break; + case SCTP_STATE_SHUTDOWN_RECEIVED: + idx = NETSTAT_SCTP_STATES_SHUTDOWN_RECEIVED; + break; + case SCTP_STATE_SHUTDOWN_ACK_SENT: + idx = NETSTAT_SCTP_STATES_SHUTDOWN_ACK_SENT; + break; + case SCTP_STATE_SHUTDOWN_PENDING: + idx = NETSTAT_SCTP_STATES_SHUTDOWN_PENDING; + break; + default: + printf("UNKNOWN 0x%08x", state); + return; + } + + printf("%s", sctpstates[idx]); +} + +/* + * Dump SCTP statistics structure. + */ +void +sctp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) +{ + struct sctpstat sctpstat, zerostat; + size_t len = sizeof(sctpstat); + + if (live) { + if (zflag) + memset(&zerostat, 0, len); + if (sysctlbyname("net.inet.sctp.stats", &sctpstat, &len, + zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { + warn("sysctl: net.inet.sctp.stats"); + return; + } + } else + kread(off, &sctpstat, len); + + printf ("%s:\n", name); + +#define p(f, m) if (sctpstat.f || sflag <= 1) \ + printf(m, (uintmax_t)sctpstat.f, plural(sctpstat.f)) +#define p1a(f, m) if (sctpstat.f || sflag <= 1) \ + printf(m, (uintmax_t)sctpstat.f) + + /* + * input statistics + */ + p(sctps_recvpackets, "\t%ju input packet%s\n"); + p(sctps_recvdatagrams, "\t\t%ju datagram%s\n"); + p(sctps_recvpktwithdata, "\t\t%ju packet%s that had data\n"); + p(sctps_recvsacks, "\t\t%ju input SACK chunk%s\n"); + p(sctps_recvdata, "\t\t%ju input DATA chunk%s\n"); + p(sctps_recvdupdata, "\t\t%ju duplicate DATA chunk%s\n"); + p(sctps_recvheartbeat, "\t\t%ju input HB chunk%s\n"); + p(sctps_recvheartbeatack, "\t\t%ju HB-ACK chunk%s\n"); + p(sctps_recvecne, "\t\t%ju input ECNE chunk%s\n"); + p(sctps_recvauth, "\t\t%ju input AUTH chunk%s\n"); + p(sctps_recvauthmissing, "\t\t%ju chunk%s missing AUTH\n"); + p(sctps_recvivalhmacid, "\t\t%ju invalid HMAC id%s received\n"); + p(sctps_recvivalkeyid, "\t\t%ju invalid secret id%s received\n"); + p1a(sctps_recvauthfailed, "\t\t%ju auth failed\n"); + p1a(sctps_recvexpress, "\t\t%ju fast path receives all one chunk\n"); + p1a(sctps_recvexpressm, "\t\t%ju fast path multi-part data\n"); + + /* + * output statistics + */ + p(sctps_sendpackets, "\t%ju output packet%s\n"); + p(sctps_sendsacks, "\t\t%ju output SACK%s\n"); + p(sctps_senddata, "\t\t%ju output DATA chunk%s\n"); + p(sctps_sendretransdata, "\t\t%ju retransmitted DATA chunk%s\n"); + p(sctps_sendfastretrans, "\t\t%ju fast retransmitted DATA chunk%s\n"); + p(sctps_sendmultfastretrans, "\t\t%ju FR'%s that happened more " + "than once to same chunk\n"); + p(sctps_sendheartbeat, "\t\t%ju intput HB chunk%s\n"); + p(sctps_sendecne, "\t\t%ju output ECNE chunk%s\n"); + p(sctps_sendauth, "\t\t%ju output AUTH chunk%s\n"); + p1a(sctps_senderrors, "\t\t%ju ip_output error counter\n"); + + /* + * PCKDROPREP statistics + */ + printf("\tPacket drop statistics:\n"); + p1a(sctps_pdrpfmbox, "\t\t%ju from middle box\n"); + p1a(sctps_pdrpfehos, "\t\t%ju from end host\n"); + p1a(sctps_pdrpmbda, "\t\t%ju with data\n"); + p1a(sctps_pdrpmbct, "\t\t%ju non-data, non-endhost\n"); + p1a(sctps_pdrpbwrpt, "\t\t%ju non-endhost, bandwidth rep only\n"); + p1a(sctps_pdrpcrupt, "\t\t%ju not enough for chunk header\n"); + p1a(sctps_pdrpnedat, "\t\t%ju not enough data to confirm\n"); + p1a(sctps_pdrppdbrk, "\t\t%ju where process_chunk_drop said break\n"); + p1a(sctps_pdrptsnnf, "\t\t%ju failed to find TSN\n"); + p1a(sctps_pdrpdnfnd, "\t\t%ju attempt reverse TSN lookup\n"); + p1a(sctps_pdrpdiwnp, "\t\t%ju e-host confirms zero-rwnd\n"); + p1a(sctps_pdrpdizrw, "\t\t%ju midbox confirms no space\n"); + p1a(sctps_pdrpbadd, "\t\t%ju data did not match TSN\n"); + p(sctps_pdrpmark, "\t\t%ju TSN'%s marked for Fast Retran\n"); + + /* + * Timeouts + */ + printf("\tTimeouts:\n"); + p(sctps_timoiterator, "\t\t%ju iterator timer%s fired\n"); + p(sctps_timodata, "\t\t%ju T3 data time out%s\n"); + p(sctps_timowindowprobe, "\t\t%ju window probe (T3) timer%s fired\n"); + p(sctps_timoinit, "\t\t%ju INIT timer%s fired\n"); + p(sctps_timosack, "\t\t%ju sack timer%s fired\n"); + p(sctps_timoshutdown, "\t\t%ju shutdown timer%s fired\n"); + p(sctps_timoheartbeat, "\t\t%ju heartbeat timer%s fired\n"); + p1a(sctps_timocookie, "\t\t%ju a cookie timeout fired\n"); + p1a(sctps_timosecret, "\t\t%ju an endpoint changed its cookie" + "secret\n"); + p(sctps_timopathmtu, "\t\t%ju PMTU timer%s fired\n"); + p(sctps_timoshutdownack, "\t\t%ju shutdown ack timer%s fired\n"); + p(sctps_timoshutdownguard, "\t\t%ju shutdown guard timer%s fired\n"); + p(sctps_timostrmrst, "\t\t%ju stream reset timer%s fired\n"); + p(sctps_timoearlyfr, "\t\t%ju early FR timer%s fired\n"); + p1a(sctps_timoasconf, "\t\t%ju an asconf timer fired\n"); + p1a(sctps_timoautoclose, "\t\t%ju auto close timer fired\n"); + p(sctps_timoassockill, "\t\t%ju asoc free timer%s expired\n"); + p(sctps_timoinpkill, "\t\t%ju inp free timer%s expired\n"); + +#if 0 + /* + * Early fast retransmission counters + */ + p(sctps_earlyfrstart, "\t%ju TODO:sctps_earlyfrstart\n"); + p(sctps_earlyfrstop, "\t%ju TODO:sctps_earlyfrstop\n"); + p(sctps_earlyfrmrkretrans, "\t%ju TODO:sctps_earlyfrmrkretrans\n"); + p(sctps_earlyfrstpout, "\t%ju TODO:sctps_earlyfrstpout\n"); + p(sctps_earlyfrstpidsck1, "\t%ju TODO:sctps_earlyfrstpidsck1\n"); + p(sctps_earlyfrstpidsck2, "\t%ju TODO:sctps_earlyfrstpidsck2\n"); + p(sctps_earlyfrstpidsck3, "\t%ju TODO:sctps_earlyfrstpidsck3\n"); + p(sctps_earlyfrstpidsck4, "\t%ju TODO:sctps_earlyfrstpidsck4\n"); + p(sctps_earlyfrstrid, "\t%ju TODO:sctps_earlyfrstrid\n"); + p(sctps_earlyfrstrout, "\t%ju TODO:sctps_earlyfrstrout\n"); + p(sctps_earlyfrstrtmr, "\t%ju TODO:sctps_earlyfrstrtmr\n"); +#endif + + /* + * Others + */ + p1a(sctps_hdrops, "\t%ju packet shorter than header\n"); + p1a(sctps_badsum, "\t%ju checksum error\n"); + p1a(sctps_noport, "\t%ju no endpoint for port\n"); + p1a(sctps_badvtag, "\t%ju bad v-tag\n"); + p1a(sctps_badsid, "\t%ju bad SID\n"); + p1a(sctps_nomem, "\t%ju no memory\n"); + p1a(sctps_fastretransinrtt, "\t%ju number of multiple FR in a RTT " + "window\n"); +#if 0 + p(sctps_markedretrans, "\t%ju TODO:sctps_markedretrans\n"); +#endif + p1a(sctps_naglesent, "\t%ju RFC813 allowed sending\n"); + p1a(sctps_naglequeued, "\t%ju RFC813 does not allow sending\n"); + p1a(sctps_maxburstqueued, "\t%ju times max burst prohibited sending\n"); + p1a(sctps_ifnomemqueued, "\t%ju look ahead tells us no memory in " + "interface\n"); + p(sctps_windowprobed, "\t%ju number%s of window probes sent\n"); + p(sctps_lowlevelerr, "\t%ju time%s an output error to clamp " + "down on next user send\n"); + p(sctps_lowlevelerrusr, "\t%ju time%s sctp_senderrors were " + "caused from a user\n"); + p(sctps_datadropchklmt, "\t%ju number of in data drop%s due to " + "chunk limit reached\n"); + p(sctps_datadroprwnd, "\t%ju number of in data drop%s due to rwnd " + "limit reached\n"); + p(sctps_ecnereducedcwnd, "\t%ju time%s a ECN reduced " + "the cwnd\n"); + p1a(sctps_vtagexpress, "\t%ju used express lookup via vtag\n"); + p1a(sctps_vtagbogus, "\t%ju collision in express lookup\n"); + p(sctps_primary_randry, "\t%ju time%s the sender ran dry " + "of user data on primary\n"); + p1a(sctps_cmt_randry, "\t%ju same for above\n"); + p(sctps_slowpath_sack, "\t%ju sack%s the slow way\n"); + p(sctps_wu_sacks_sent, "\t%ju window update only sack%s sent\n"); + p(sctps_sends_with_flags, "\t%ju send%s with sinfo_flags !=0\n"); + p(sctps_sends_with_unord, "\t%ju unordered send%s\n"); + p(sctps_sends_with_eof, "\t%ju send%s with EOF flag set\n"); + p(sctps_sends_with_abort, "\t%ju send%s with ABORT flag set\n"); + p(sctps_protocol_drain_calls, "\t%ju time%s protocol drain called\n"); + p(sctps_protocol_drains_done, "\t%ju time%s we did a protocol " + "drain\n"); + p(sctps_read_peeks, "\t%ju time%s recv was called with peek\n"); + p(sctps_cached_chk, "\t%ju cached chunk%s used\n"); + p1a(sctps_cached_strmoq, "\t%ju cached stream oq's used\n"); + p(sctps_left_abandon, "\t%ju unread message%s abandonded by close\n"); + p1a(sctps_send_burst_avoid, "\t%ju send burst avoidance, already " + "max burst inflight to net\n"); + p1a(sctps_send_cwnd_avoid, "\t%ju send cwnd full avoidance, already " + "max burst inflight to net\n"); + p(sctps_fwdtsn_map_over, "\t%ju number of map array over-run%s via " + "fwd-tsn's\n"); + +#undef p +#undef p1a +} + +#endif /* SCTP */ diff --git a/freebsd-userspace/commands/usr.bin/netstat/unix.c b/freebsd-userspace/commands/usr.bin/netstat/unix.c new file mode 100644 index 00000000..17d52031 --- /dev/null +++ b/freebsd-userspace/commands/usr.bin/netstat/unix.c @@ -0,0 +1,294 @@ +/*- + * 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. + */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)unix.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ +#endif + +#include +__FBSDID("$FreeBSD$"); + +/* + * Display protocol blocks in the unix domain. + */ +#include +#include +#ifdef __rtems__ +#include +#else +#include +#endif +#include +#include +#ifdef __rtems__ +#include +#else +#include +#endif +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "netstat.h" + +static void unixdomainpr(struct xunpcb *, struct xsocket *); + +static const char *const socktype[] = + { "#0", "stream", "dgram", "raw", "rdm", "seqpacket" }; + +static int +pcblist_sysctl(int type, char **bufp) +{ + char *buf; + size_t len; + char mibvar[sizeof "net.local.seqpacket.pcblist"]; + + sprintf(mibvar, "net.local.%s.pcblist", socktype[type]); + + len = 0; + if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) { + if (errno != ENOENT) + warn("sysctl: %s", mibvar); + return (-1); + } + if ((buf = malloc(len)) == 0) { + warnx("malloc %lu bytes", (u_long)len); + return (-2); + } + if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) { + warn("sysctl: %s", mibvar); + free(buf); + return (-2); + } + *bufp = buf; + return (0); +} + +static int +pcblist_kvm(u_long count_off, u_long gencnt_off, u_long head_off, char **bufp) +{ + struct unp_head head; + struct unpcb *unp, unp_conn; + u_char sun_len; + struct socket so; + struct xunpgen xug; + struct xunpcb xu; + unp_gen_t unp_gencnt; + u_int unp_count; + char *buf, *p; + size_t len; + + if (count_off == 0 || gencnt_off == 0) + return (-2); + if (head_off == 0) + return (-1); + kread(count_off, &unp_count, sizeof(unp_count)); + len = 2 * sizeof(xug) + (unp_count + unp_count / 8) * sizeof(xu); + if ((buf = malloc(len)) == 0) { + warnx("malloc %lu bytes", (u_long)len); + return (-2); + } + p = buf; + +#define COPYOUT(obj, size) do { \ + if (len < (size)) { \ + warnx("buffer size exceeded"); \ + goto fail; \ + } \ + bcopy((obj), p, (size)); \ + len -= (size); \ + p += (size); \ +} while (0) + +#define KREAD(off, buf, len) do { \ + if (kread((uintptr_t)(off), (buf), (len)) != 0) \ + goto fail; \ +} while (0) + + /* Write out header. */ + kread(gencnt_off, &unp_gencnt, sizeof(unp_gencnt)); + xug.xug_len = sizeof xug; + xug.xug_count = unp_count; + xug.xug_gen = unp_gencnt; + xug.xug_sogen = 0; + COPYOUT(&xug, sizeof xug); + + /* Walk the PCB list. */ + xu.xu_len = sizeof xu; + KREAD(head_off, &head, sizeof(head)); + LIST_FOREACH(unp, &head, unp_link) { + xu.xu_unpp = unp; + KREAD(unp, &xu.xu_unp, sizeof (*unp)); + unp = &xu.xu_unp; + + if (unp->unp_gencnt > unp_gencnt) + continue; + if (unp->unp_addr != NULL) { + KREAD(unp->unp_addr, &sun_len, sizeof(sun_len)); + KREAD(unp->unp_addr, &xu.xu_addr, sun_len); + } + if (unp->unp_conn != NULL) { + KREAD(unp->unp_conn, &unp_conn, sizeof(unp_conn)); + if (unp_conn.unp_addr != NULL) { + KREAD(unp_conn.unp_addr, &sun_len, + sizeof(sun_len)); + KREAD(unp_conn.unp_addr, &xu.xu_caddr, sun_len); + } + } + KREAD(unp->unp_socket, &so, sizeof(so)); + if (sotoxsocket(&so, &xu.xu_socket) != 0) + goto fail; + COPYOUT(&xu, sizeof(xu)); + } + + /* Reread the counts and write the footer. */ + kread(count_off, &unp_count, sizeof(unp_count)); + kread(gencnt_off, &unp_gencnt, sizeof(unp_gencnt)); + xug.xug_count = unp_count; + xug.xug_gen = unp_gencnt; + COPYOUT(&xug, sizeof xug); + + *bufp = buf; + return (0); + +fail: + free(buf); + return (-1); +#undef COPYOUT +#undef KREAD +} + +void +unixpr(u_long count_off, u_long gencnt_off, u_long dhead_off, u_long shead_off) +{ + char *buf; + int ret, type; + struct xsocket *so; + struct xunpgen *xug, *oxug; + struct xunpcb *xunp; + + for (type = SOCK_STREAM; type <= SOCK_SEQPACKET; type++) { + if (live) + ret = pcblist_sysctl(type, &buf); + else + ret = pcblist_kvm(count_off, gencnt_off, + type == SOCK_STREAM ? shead_off : + (type == SOCK_DGRAM ? dhead_off : 0), &buf); + if (ret == -1) + continue; + if (ret < 0) + return; + + oxug = xug = (struct xunpgen *)buf; + for (xug = (struct xunpgen *)((char *)xug + xug->xug_len); + xug->xug_len > sizeof(struct xunpgen); + xug = (struct xunpgen *)((char *)xug + xug->xug_len)) { + xunp = (struct xunpcb *)xug; + so = &xunp->xu_socket; + + /* Ignore PCBs which were freed during copyout. */ + if (xunp->xu_unp.unp_gencnt > oxug->xug_gen) + continue; + unixdomainpr(xunp, so); + } + if (xug != oxug && xug->xug_gen != oxug->xug_gen) { + if (oxug->xug_count > xug->xug_count) { + printf("Some %s sockets may have been deleted.\n", + socktype[type]); + } else if (oxug->xug_count < xug->xug_count) { + printf("Some %s sockets may have been created.\n", + socktype[type]); + } else { + printf("Some %s sockets may have been created or deleted", + socktype[type]); + } + } + free(buf); + } +} + +static void +unixdomainpr(struct xunpcb *xunp, struct xsocket *so) +{ + struct unpcb *unp; + struct sockaddr_un *sa; + static int first = 1; + char buf1[15]; + + unp = &xunp->xu_unp; + if (unp->unp_addr) + sa = &xunp->xu_addr; + else + sa = (struct sockaddr_un *)0; + + if (first && !Lflag) { + 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; + } + + if (Lflag && so->so_qlimit == 0) + return; + + if (Lflag) { + snprintf(buf1, 15, "%d/%d/%d", so->so_qlen, + so->so_incqlen, so->so_qlimit); + printf("unix %-14.14s", buf1); + } else { + printf("%8lx %-6.6s %6u %6u %8lx %8lx %8lx %8lx", + (long)so->so_pcb, socktype[so->so_type], so->so_rcv.sb_cc, + so->so_snd.sb_cc, (long)unp->unp_vnode, (long)unp->unp_conn, + (long)LIST_FIRST(&unp->unp_refs), + (long)LIST_NEXT(unp, unp_reflink)); + } + if (sa) + printf(" %.*s", + (int)(sa->sun_len - offsetof(struct sockaddr_un, sun_path)), + sa->sun_path); + putchar('\n'); +} -- cgit v1.2.3