Index: atalk.c =================================================================== RCS file: /zork/cvs/src/usr.bin/netstat/atalk.c,v retrieving revision 1.25 diff -u -r1.25 atalk.c --- atalk.c 28 Jul 2006 16:09:18 -0000 1.25 +++ atalk.c 10 Jul 2007 01:38:42 -0000 @@ -217,7 +217,8 @@ } void -atalkprotopr(u_long off __unused, const char *name, int af1 __unused) +atalkprotopr(u_long off __unused, const char *name, int af1 __unused, + int proto __unused) { struct ddpcb *this, *next; @@ -266,7 +267,8 @@ * Dump DDP statistics structure. */ void -ddp_stats(u_long off __unused, const char *name, int af1 __unused) +ddp_stats(u_long off __unused, const char *name, int af1 __unused, + int proto __unused) { struct ddpstat ddpstat; Index: bpf.c =================================================================== RCS file: /zork/cvs/src/usr.bin/netstat/bpf.c,v retrieving revision 1.8 diff -u -r1.8 bpf.c --- bpf.c 26 Feb 2007 22:24:14 -0000 1.8 +++ bpf.c 10 Jul 2007 01:38:42 -0000 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include Index: if.c =================================================================== RCS file: /zork/cvs/src/usr.bin/netstat/if.c,v retrieving revision 1.68 diff -u -r1.68 if.c --- if.c 27 Feb 2007 05:10:36 -0000 1.68 +++ if.c 10 Jul 2007 01:38:42 -0000 @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -85,19 +86,22 @@ * Dump pfsync statistics structure. */ void -pfsync_stats(u_long off __unused, const char *name, int af1 __unused) +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 (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; - } + 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); Index: inet.c =================================================================== RCS file: /zork/cvs/src/usr.bin/netstat/inet.c,v retrieving revision 1.77 diff -u -r1.77 inet.c --- inet.c 12 Jun 2007 16:24:55 -0000 1.77 +++ inet.c 10 Jul 2007 02:48:46 -0000 @@ -42,6 +42,7 @@ #include #include +#include #include #include #include @@ -90,6 +91,208 @@ 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_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_vflag & 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. @@ -97,18 +300,16 @@ * -a (all) flag is specified. */ void -protopr(u_long proto, /* for sysctl version we pass proto # */ - const char *name, int af1) +protopr(u_long off, const char *name, int af1, int proto) { int istcp; static int first = 1; char *buf; - const char *mibvar, *vchar; + const char *vchar; struct tcpcb *tp = NULL; struct inpcb *inp; struct xinpgen *xig, *oxig; struct xsocket *so; - size_t len; istcp = 0; switch (proto) { @@ -120,7 +321,6 @@ tcp_done = 1; #endif istcp = 1; - mibvar = "net.inet.tcp.pcblist"; break; case IPPROTO_UDP: #ifdef INET6 @@ -129,29 +329,14 @@ else udp_done = 1; #endif - 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; } - 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; + if (live) { + if (!pcblist_sysctl(proto, &buf, istcp)) + return; + } else { + if (!pcblist_kvm(off, &buf, istcp)) + return; } oxig = xig = (struct xinpgen *)buf; @@ -168,7 +353,7 @@ } /* Ignore sockets for protocols other than the desired one. */ - if (so->xso_protocol != (int)proto) + if (so->xso_protocol != proto) continue; /* Ignore PCBs which were freed during copyout. */ @@ -347,18 +532,10 @@ * Dump TCP statistics structure. */ void -tcp_stats(u_long off __unused, const char *name, int af1 __unused) +tcp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct tcpstat tcpstat, zerostat; size_t len = sizeof tcpstat; - - 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; - } #ifdef INET6 if (tcp_done != 0) @@ -367,6 +544,17 @@ 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) \ @@ -480,20 +668,12 @@ * Dump UDP statistics structure. */ void -udp_stats(u_long off __unused, const char *name, int af1 __unused) +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; - 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; - } - #ifdef INET6 if (udp_done != 0) return; @@ -501,6 +681,17 @@ 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)) @@ -537,18 +728,24 @@ * Dump CARP statistics structure. */ void -carp_stats(u_long off __unused, const char *name, int af1 __unused) +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 (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; + 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); @@ -582,18 +779,21 @@ * Dump IP statistics structure. */ void -ip_stats(u_long off __unused, const char *name, int af1 __unused) +ip_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct ipstat ipstat, zerostat; size_t len = sizeof ipstat; - 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; - } + 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); @@ -687,26 +887,23 @@ * Dump ICMP statistics. */ void -icmp_stats(u_long off __unused, const char *name, int af1 __unused) +icmp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct icmpstat icmpstat, zerostat; int i, first; - int mib[4]; /* CTL_NET + PF_INET + IPPROTO_ICMP + req */ size_t len; - mib[0] = CTL_NET; - mib[1] = PF_INET; - mib[2] = IPPROTO_ICMP; - mib[3] = ICMPCTL_STATS; - len = sizeof icmpstat; - if (zflag) - memset(&zerostat, 0, len); - if (sysctl(mib, 4, &icmpstat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - warn("sysctl: net.inet.icmp.stats"); - return; - } + 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); @@ -758,30 +955,35 @@ #undef p #undef p1a #undef p2 - mib[3] = ICMPCTL_MASKREPL; - len = sizeof i; - if (sysctl(mib, 4, &i, &len, (void *)0, 0) < 0) - return; - printf("\tICMP address mask responses are %sabled\n", - i ? "en" : "dis"); + if (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"); + } } /* * Dump IGMP statistics structure. */ void -igmp_stats(u_long off __unused, const char *name, int af1 __unused) +igmp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct igmpstat igmpstat, zerostat; size_t len = sizeof igmpstat; - 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; - } + 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 + kread(off, &igmpstat, len); printf("%s:\n", name); @@ -806,18 +1008,25 @@ * Dump PIM statistics structure. */ void -pim_stats(u_long off __unused, const char *name, int af1 __unused) +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 (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; + 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); Index: inet6.c =================================================================== RCS file: /zork/cvs/src/usr.bin/netstat/inet6.c,v retrieving revision 1.28 diff -u -r1.28 inet6.c --- inet6.c 24 Feb 2007 21:58:30 -0000 1.28 +++ inet6.c 10 Jul 2007 01:38:42 -0000 @@ -362,22 +362,24 @@ * Dump IP6 statistics structure. */ void -ip6_stats(u_long off __unused, const char *name, int af1 __unused) +ip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct ip6stat ip6stat; int first, i; - int mib[4]; size_t len; - mib[0] = CTL_NET; - mib[1] = PF_INET6; - mib[2] = IPPROTO_IPV6; - mib[3] = IPV6CTL_STATS; - len = sizeof ip6stat; - memset(&ip6stat, 0, len); - if (sysctl(mib, 4, &ip6stat, &len, (void *)0, 0) < 0) - return; + if (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) \ @@ -842,22 +844,24 @@ * Dump ICMP6 statistics. */ void -icmp6_stats(u_long off __unused, const char *name, int af1 __unused) +icmp6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct icmp6stat icmp6stat; int i, first; - int mib[4]; size_t len; - mib[0] = CTL_NET; - mib[1] = PF_INET6; - mib[2] = IPPROTO_ICMPV6; - mib[3] = ICMPV6CTL_STATS; - len = sizeof icmp6stat; - memset(&icmp6stat, 0, len); - if (sysctl(mib, 4, &icmp6stat, &len, (void *)0, 0) < 0) - return; + if (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) \ @@ -994,20 +998,26 @@ * Dump PIM statistics structure. */ void -pim6_stats(u_long off __unused, const char *name, int af1 __unused) +pim6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct pim6stat pim6stat, zerostat; size_t len = sizeof pim6stat; - /* TODO put back the KVM functionality for -M switch ie coredumps. */ - 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; + 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) \ @@ -1026,24 +1036,22 @@ * Dump raw ip6 statistics structure. */ void -rip6_stats(u_long off __unused, const char *name, int af1 __unused) +rip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct rip6stat rip6stat; u_quad_t delivered; - int mib[4]; - size_t l; + size_t len; - mib[0] = CTL_NET; - mib[1] = PF_INET6; - mib[2] = IPPROTO_IPV6; - mib[3] = IPV6CTL_RIP6STATS; - l = sizeof(rip6stat); - if (sysctl(mib, 4, &rip6stat, &l, NULL, 0) < 0) { - /* Just shut up if the kernel doesn't have ipv6. */ - if (errno != ENOENT) - perror("Warning: sysctl(net.inet6.ip6.rip6stats)"); - return; - } + 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); Index: ipsec.c =================================================================== RCS file: /zork/cvs/src/usr.bin/netstat/ipsec.c,v retrieving revision 1.16 diff -u -r1.16 ipsec.c --- ipsec.c 1 Jul 2007 12:08:07 -0000 1.16 +++ ipsec.c 10 Jul 2007 01:38:42 -0000 @@ -101,6 +101,7 @@ #include #include #include +#include #include @@ -267,7 +268,7 @@ } void -ipsec_stats(u_long off, const char *name, int af1 __unused) +ipsec_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct ipsecstat ipsecstat; @@ -355,7 +356,7 @@ } void -ah_stats(u_long off, const char *name, int family __unused) +ah_stats(u_long off, const char *name, int family __unused, int proto __unused) { struct ahstat ahstat; @@ -405,7 +406,7 @@ } void -esp_stats(u_long off, const char *name, int family __unused) +esp_stats(u_long off, const char *name, int family __unused, int proto __unused) { struct espstat espstat; @@ -450,7 +451,8 @@ } void -ipcomp_stats(u_long off, const char *name, int family __unused) +ipcomp_stats(u_long off, const char *name, int family __unused, + int proto __unused) { struct ipcompstat ipcompstat; Index: ipx.c =================================================================== RCS file: /zork/cvs/src/usr.bin/netstat/ipx.c,v retrieving revision 1.25 diff -u -r1.25 ipx.c --- ipx.c 28 Jul 2006 16:16:40 -0000 1.25 +++ ipx.c 10 Jul 2007 01:38:42 -0000 @@ -82,7 +82,7 @@ */ void -ipxprotopr(u_long off, const char *name, int af1 __unused) +ipxprotopr(u_long off, const char *name, int af1 __unused, int proto __unused) { struct ipxpcbhead cb; struct ipxpcb *ipxp; @@ -155,7 +155,7 @@ * Dump SPX statistics structure. */ void -spx_stats(u_long off, const char *name, int af1 __unused) +spx_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct spx_istat spx_istat; #define spxstat spx_istat.newstats @@ -231,7 +231,7 @@ * Dump IPX statistics structure. */ void -ipx_stats(u_long off, const char *name, int af1 __unused) +ipx_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct ipxstat ipxstat; @@ -274,7 +274,7 @@ */ /*ARGSUSED*/ void -ipxerr_stats(u_long off, const char *name, int af __unused) +ipxerr_stats(u_long off, const char *name, int af __unused, int proto __unused) { struct ipx_errstat ipx_errstat; int j; Index: main.c =================================================================== RCS file: /zork/cvs/src/usr.bin/netstat/main.c,v retrieving revision 1.85 diff -u -r1.85 main.c --- main.c 1 Jul 2007 12:08:07 -0000 1.85 +++ main.c 10 Jul 2007 18:45:12 -0000 @@ -50,6 +50,7 @@ #include #include #include +#include #include @@ -141,121 +142,154 @@ { .n_name = "_carpstats" }, #define N_PFSYNCSTAT 34 { .n_name = "_pfsyncstats" }, -#define N_AHSTAT 36 +#define N_AHSTAT 35 { .n_name = "_ahstat" }, -#define N_ESPSTAT 37 +#define N_ESPSTAT 36 { .n_name = "_espstat" }, -#define N_IPCOMPSTAT 38 +#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" }, { .n_name = NULL }, }; struct protox { - u_char pr_index; /* index into nlist of cb head */ - u_char pr_sindex; /* index into nlist of stat block */ + 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); + void (*pr_cblocks)(u_long, const char *, int, int); /* control blocks printing routine */ - void (*pr_stats)(u_long, const char *, int); + 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 */ u_long pr_usesysctl; /* non-zero if we use sysctl, not kvm */ + int pr_protocol; } protox[] = { - { -1, -1, 1, protopr, - tcp_stats, NULL, "tcp", IPPROTO_TCP }, - { -1, -1, 1, protopr, - udp_stats, NULL, "udp", IPPROTO_UDP }, + { 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, -1, 1, sctp_protopr, - sctp_stats, NULL, "sctp", IPPROTO_SCTP }, + { -1, N_SCTPSTAT, 1, sctp_protopr, + sctp_stats, NULL, "sctp", 1, IPPROTO_SCTP }, #endif - { -1, -1, 1, protopr, - NULL, NULL, "divert",IPPROTO_DIVERT }, - { -1, -1, 1, protopr, - ip_stats, NULL, "ip", IPPROTO_RAW }, - { -1, -1, 1, protopr, - icmp_stats, NULL, "icmp", IPPROTO_ICMP }, - { -1, -1, 1, protopr, - igmp_stats, NULL, "igmp", IPPROTO_IGMP }, + { 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}, + ipsec_stats, NULL, "ipsec", 0, 0}, { -1, N_AHSTAT, 1, NULL, - ah_stats, NULL, "ah", 0}, + ah_stats, NULL, "ah", 0, 0}, { -1, N_ESPSTAT, 1, NULL, - esp_stats, NULL, "esp", 0}, + esp_stats, NULL, "esp", 0, 0}, { -1, N_IPCOMPSTAT, 1, NULL, - ipcomp_stats, NULL, "ipcomp", 0}, + ipcomp_stats, NULL, "ipcomp", 0, 0}, #endif - { -1, -1, 1, protopr, - pim_stats, NULL, "pim", IPPROTO_PIM }, - { -1, N_CARPSTAT, 1, 0, - carp_stats, NULL, "carp", 0}, - { -1, -1, 1, NULL, - pfsync_stats, NULL, "pfsync", 1}, + { 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, -1, 0, NULL, - NULL, NULL, NULL, 0 } + NULL, NULL, NULL, 0, 0 } }; #ifdef INET6 struct protox ip6protox[] = { - { -1, -1, 1, protopr, - tcp_stats, NULL, "tcp", IPPROTO_TCP }, - { -1, -1, 1, protopr, - udp_stats, NULL, "udp", IPPROTO_UDP }, - { -1, N_IP6STAT, 1, protopr, - ip6_stats, ip6_ifstats, "ip6", IPPROTO_RAW }, - { -1, N_ICMP6STAT, 1, protopr, - icmp6_stats, icmp6_ifstats, "icmp6",IPPROTO_ICMPV6 }, + { 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 }, + ipsec_stats, NULL, "ipsec6", 0, 0 }, #endif #ifdef notyet { -1, N_PIM6STAT, 1, NULL, - pim6_stats, NULL, "pim6", 0 }, + pim6_stats, NULL, "pim6", 1, 0 }, #endif - { -1, -1, 1, NULL, - rip6_stats, NULL, "rip6", 0 }, + { -1, N_RIP6STAT, 1, NULL, + rip6_stats, NULL, "rip6", 1, 0 }, { -1, -1, 0, NULL, - NULL, NULL, NULL, 0 } + NULL, NULL, NULL, 0, 0 } }; #endif /*INET6*/ #ifdef IPSEC struct protox pfkeyprotox[] = { { -1, N_PFKEYSTAT, 1, NULL, - pfkey_stats, NULL, "pfkey", 0 }, + pfkey_stats, NULL, "pfkey", 0, 0 }, { -1, -1, 0, NULL, - NULL, NULL, NULL, 0 } + NULL, NULL, NULL, 0, 0 } }; #endif struct protox atalkprotox[] = { { N_DDPCB, N_DDPSTAT, 1, atalkprotopr, - ddp_stats, NULL, "ddp", 0 }, + ddp_stats, NULL, "ddp", 0, 0 }, { -1, -1, 0, NULL, - NULL, NULL, NULL, 0 } + NULL, NULL, NULL, 0, 0 } }; struct protox netgraphprotox[] = { { N_NGSOCKS, -1, 1, netgraphprotopr, - NULL, NULL, "ctrl", 0 }, + NULL, NULL, "ctrl", 0, 0 }, { N_NGSOCKS, -1, 1, netgraphprotopr, - NULL, NULL, "data", 0 }, + NULL, NULL, "data", 0, 0 }, { -1, -1, 0, NULL, - NULL, NULL, NULL, 0 } + NULL, NULL, NULL, 0, 0 } }; #ifdef IPX struct protox ipxprotox[] = { { N_IPX, N_IPXSTAT, 1, ipxprotopr, - ipx_stats, NULL, "ipx", 0 }, + ipx_stats, NULL, "ipx", 0, 0 }, { N_IPX, N_SPXSTAT, 1, ipxprotopr, - spx_stats, NULL, "spx", 0 }, + spx_stats, NULL, "spx", 0, 0 }, { -1, -1, 0, NULL, - NULL, NULL, 0, 0 } + NULL, NULL, 0, 0, 0 } }; #endif @@ -305,6 +339,7 @@ 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[]) @@ -453,16 +488,19 @@ * Discard setgid privileges if not the running kernel so that bad * guys can't print interesting stuff from kernel memory. */ - if (nlistf != NULL || memf != NULL) + live = (nlistf == NULL && memf == NULL); + if (!live) setgid(getgid()); if (Bflag) { + if (!live) + usage(); bpf_stats(interface); exit(0); } if (mflag) { if (memf != NULL) { - if (kread(0, 0, 0) == 0) + if (kread(0, NULL, 0) == 0) mbpr(kvmd, nl[N_MBSTAT].n_value); } else mbpr(NULL, 0); @@ -482,13 +520,12 @@ * used for the queries, which is slower. */ #endif + kread(0, NULL, 0); if (iflag && !sflag) { - kread(0, 0, 0); intpr(interval, nl[N_IFNET].n_value, NULL); exit(0); } if (rflag) { - kread(0, 0, 0); if (sflag) rt_stats(nl[N_RTSTAT].n_value, nl[N_RTTRASH].n_value); else @@ -496,7 +533,6 @@ exit(0); } if (gflag) { - kread(0, 0, 0); if (sflag) { if (af == AF_INET || af == AF_UNSPEC) mrt_stats(nl[N_MRTSTAT].n_value); @@ -518,7 +554,6 @@ exit(0); } - kread(0, 0, 0); if (tp) { printproto(tp, tp->pr_name); exit(0); @@ -538,7 +573,6 @@ #endif /*IPSEC*/ #ifdef IPX if (af == AF_IPX || af == AF_UNSPEC) { - kread(0, 0, 0); for (tp = ipxprotox; tp->pr_name; tp++) printproto(tp, tp->pr_name); } @@ -550,7 +584,8 @@ for (tp = netgraphprotox; tp->pr_name; tp++) printproto(tp, tp->pr_name); if ((af == AF_UNIX || af == AF_UNSPEC) && !Lflag && !sflag) - unixpr(); + 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); } @@ -564,7 +599,7 @@ struct protox *tp; const char *name; { - void (*pr)(u_long, const char *, int); + void (*pr)(u_long, const char *, int, int); u_long off; if (sflag) { @@ -576,17 +611,24 @@ printf("%s: no per-interface stats routine\n", tp->pr_name); return; - } - else { + } else { pr = tp->pr_stats; if (!pr) { if (pflag) printf("%s: no stats routine\n", tp->pr_name); return; - } - off = tp->pr_usesysctl ? tp->pr_usesysctl - : nl[tp->pr_sindex].n_value; + } + 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; @@ -595,28 +637,36 @@ printf("%s: no PCB routine\n", tp->pr_name); return; } - off = tp->pr_usesysctl ? tp->pr_usesysctl - : nl[tp->pr_index].n_value; + 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 || af != AF_UNSPEC)) - (*pr)(off, name, af); + 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, char *buf, int size) +kread(u_long addr, void *buf, size_t size) { - if (kvmd == 0) { - /* - * XXX. - */ - kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf); + 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) + if (nlistf) errx(1, "%s: kvm_nlist: %s", nlistf, kvm_geterr(kvmd)); else @@ -624,20 +674,21 @@ } if (nl[0].n_type == 0) { - if(nlistf) + if (nlistf) errx(1, "%s: no namelist", nlistf); else errx(1, "no namelist"); } } else { - warnx("kvm not available"); + warnx("kvm not available: %s", errbuf); return(-1); } } if (!buf) return (0); - if (kvm_read(kvmd, addr, buf, size) != size) { + if (kvm_read(kvmd, addr, buf, size) != (ssize_t)size) { warnx("%s", kvm_geterr(kvmd)); + abort(); return (-1); } return (0); Index: mbuf.c =================================================================== RCS file: /zork/cvs/src/usr.bin/netstat/mbuf.c,v retrieving revision 1.52 diff -u -r1.52 mbuf.c --- mbuf.c 28 Jul 2006 16:09:18 -0000 1.52 +++ mbuf.c 10 Jul 2007 01:38:42 -0000 @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -80,9 +81,8 @@ int nsfbufs, nsfbufspeak, nsfbufsused; struct mbstat mbstat; size_t mlen; - int error, live; + int error; - live = (kvmd == NULL); mtlp = memstat_mtl_alloc(); if (mtlp == NULL) { warn("memstat_mtl_alloc"); Index: mcast.c =================================================================== RCS file: /zork/cvs/src/usr.bin/netstat/mcast.c,v retrieving revision 1.8 diff -u -r1.8 mcast.c --- mcast.c 10 Apr 2007 00:30:26 -0000 1.8 +++ mcast.c 10 Jul 2007 01:38:42 -0000 @@ -35,6 +35,7 @@ #include #include +#include #include #include Index: mroute.c =================================================================== RCS file: /zork/cvs/src/usr.bin/netstat/mroute.c,v retrieving revision 1.29 diff -u -r1.29 mroute.c --- mroute.c 24 Feb 2007 21:56:52 -0000 1.29 +++ mroute.c 10 Jul 2007 01:38:42 -0000 @@ -84,32 +84,24 @@ size_t len; len = sizeof(mfctable); - if (sysctlbyname("net.inet.ip.mfctable", mfctable, &len, NULL, 0) < 0) { - warn("sysctl: net.inet.ip.mfctable"); - if (mfcaddr == 0) { - printf("No IPv4 multicast forwarding configured in " - "the running system.\n"); + if (live) { + if (sysctlbyname("net.inet.ip.mfctable", mfctable, &len, NULL, + 0) < 0) { + warn("sysctl: net.inet.ip.mfctable"); return; } - /* - * XXX: Try KVM if the module is neither compiled nor loaded. - * The correct behaviour would be to always use KVM if - * the -M option is specified to netstat(1). - */ + } else kread(mfcaddr, (char *)mfctable, sizeof(mfctable)); - } len = sizeof(viftable); - if (sysctlbyname("net.inet.ip.viftable", viftable, &len, NULL, 0) < 0) { - warn("sysctl: net.inet.ip.viftable"); - if (vifaddr == 0) { - printf("No IPv4 multicast forwarding configured in " - "the running system.\n"); + if (live) { + if (sysctlbyname("net.inet.ip.viftable", viftable, &len, NULL, + 0) < 0) { + warn("sysctl: net.inet.ip.viftable"); return; } - /* XXX KVM */ + } else kread(vifaddr, (char *)viftable, sizeof(viftable)); - } saved_numeric_addr = numeric_addr; numeric_addr = 1; @@ -276,18 +268,15 @@ struct mrtstat mrtstat; size_t len = sizeof mrtstat; - if (sysctlbyname("net.inet.ip.mrtstat", &mrtstat, &len, - NULL, 0) < 0) { - warn("sysctl: net.inet.ip.mrtstat"); - /* Compatability with older kernels - candidate for removal */ - if (mstaddr == 0) { - printf("No IPv4 multicast forwarding configured in " - "the running system.\n"); + if (live) { + if (sysctlbyname("net.inet.ip.mrtstat", &mrtstat, &len, NULL, + 0) < 0) { + warn("sysctl: net.inet.ip.mrtstat"); return; } - /* XXX KVM */ + } else kread(mstaddr, (char *)&mrtstat, sizeof(mrtstat)); - } + printf("IPv4 multicast forwarding:\n"); #define p(f, m) if (mrtstat.f || sflag <= 1) \ Index: mroute6.c =================================================================== RCS file: /zork/cvs/src/usr.bin/netstat/mroute6.c,v retrieving revision 1.20 diff -u -r1.20 mroute6.c --- mroute6.c 24 Feb 2007 21:58:30 -0000 1.20 +++ mroute6.c 10 Jul 2007 01:38:42 -0000 @@ -116,16 +116,14 @@ size_t len; len = sizeof(mif6table); - if (sysctlbyname("net.inet6.ip6.mif6table", mif6table, &len, - NULL, 0) < 0) { - warn("sysctl: net.inet6.ip6.mif6table"); - if (mifaddr == 0) { - printf("No IPv6 multicast forwarding configured in " - "the running system.\n"); + 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; @@ -161,21 +159,14 @@ printf("\nIPv6 Multicast Interface Table is empty\n"); len = sizeof(mf6ctable); - if (sysctlbyname("net.inet6.ip6.mf6ctable", mf6ctable, &len, - NULL, 0) < 0) { - warn("sysctl: net.inet6.ip6.mf6ctable"); - if (mfcaddr == 0) { - printf("No IPv6 multicast forwarding configured in " - "the running system.\n"); + if (live) { + if (sysctlbyname("net.inet6.ip6.mf6ctable", mf6ctable, &len, + NULL, 0) < 0) { + warn("sysctl: net.inet6.ip6.mf6ctable"); return; } - /* - * XXX: Try KVM if the module is neither compiled nor loaded. - * The correct behaviour would be to always use KVM if - * the -M option is specified to netstat(1). - */ + } else kread(mfcaddr, (char *)mf6ctable, sizeof(mf6ctable)); - } banner_printed = 0; @@ -232,16 +223,15 @@ struct mrt6stat mrtstat; size_t len = sizeof mrtstat; - if (sysctlbyname("net.inet6.ip6.mrt6stat", &mrtstat, &len, - NULL, 0) < 0) { - warn("sysctl: net.inet6.ip6.mrt6stat"); - if (mstaddr == 0) { - printf("No IPv6 multicast forwarding configured in the " - "running system.\n"); + 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) \ Index: netgraph.c =================================================================== RCS file: /zork/cvs/src/usr.bin/netstat/netgraph.c,v retrieving revision 1.12 diff -u -r1.12 netgraph.c --- netgraph.c 28 Jul 2006 16:16:40 -0000 1.12 +++ netgraph.c 10 Jul 2007 01:38:42 -0000 @@ -62,7 +62,8 @@ static int csock = -1; void -netgraphprotopr(u_long off, const char *name, int af1 __unused) +netgraphprotopr(u_long off, const char *name, int af1 __unused, + int proto __unused) { struct ngpcb *this, *next; struct ngpcb ngpcb; @@ -81,6 +82,10 @@ 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) Index: netstat.h =================================================================== RCS file: /zork/cvs/src/usr.bin/netstat/netstat.h,v retrieving revision 1.50 diff -u -r1.50 netstat.h --- netstat.h 1 Jul 2007 12:08:07 -0000 1.50 +++ netstat.h 10 Jul 2007 01:38:42 -0000 @@ -59,39 +59,41 @@ 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, char *buf, int size); +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); -void protopr(u_long, const char *, int); -void tcp_stats(u_long, const char *, int); -void udp_stats(u_long, const char *, int); +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); -void sctp_stats(u_long, const char *, int); +void sctp_protopr(u_long, const char *, int, int); +void sctp_stats(u_long, const char *, int, int); #endif -void ip_stats(u_long, const char *, int); -void icmp_stats(u_long, const char *, int); -void igmp_stats(u_long, const char *, int); -void pim_stats(u_long, const char *, int); -void carp_stats (u_long, const char *, int); -void pfsync_stats (u_long, const char *, 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); -void esp_stats (u_long, const char *, int); -void ah_stats (u_long, const char *, int); -void ipcomp_stats (u_long, const char *, int); +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); +void ip6_stats(u_long, const char *, int, int); void ip6_ifstats(char *); -void icmp6_stats(u_long, const char *, int); +void icmp6_stats(u_long, const char *, int, int); void icmp6_ifstats(char *); -void pim6_stats(u_long, const char *, int); -void rip6_stats(u_long, const char *, int); +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); @@ -103,7 +105,7 @@ #endif /*INET6*/ #ifdef IPSEC -void pfkey_stats(u_long, const char *, int); +void pfkey_stats(u_long, const char *, int, int); #endif void mbpr(void *, u_long); @@ -129,29 +131,29 @@ char *ns_print(struct sockaddr *); void routepr(u_long); -void ipxprotopr(u_long, const char *, int); -void spx_stats(u_long, const char *, int); -void ipx_stats(u_long, const char *, int); -void ipxerr_stats(u_long, const char *, int); - -void nsprotopr(u_long, const char *, int); -void spp_stats(u_long, const char *, int); -void idp_stats(u_long, const char *, int); -void nserr_stats(u_long, const char *, int); - -void atalkprotopr(u_long, const char *, int); -void ddp_stats(u_long, const char *, int); - -void netgraphprotopr(u_long, const char *, int); - -void unixpr(void); - -void esis_stats(u_long, const char *, int); -void clnp_stats(u_long, const char *, int); -void cltp_stats(u_long, const char *, int); -void iso_protopr(u_long, const char *, int); +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); + +void netgraphprotopr(u_long, const char *, int, int); + +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); +void tp_protopr(u_long, const char *, int, int); void tp_inproto(u_long); void tp_stats(caddr_t, caddr_t); Index: pfkey.c =================================================================== RCS file: /zork/cvs/src/usr.bin/netstat/pfkey.c,v retrieving revision 1.4 diff -u -r1.4 pfkey.c --- pfkey.c 1 Jul 2007 12:08:07 -0000 1.4 +++ pfkey.c 10 Jul 2007 01:38:42 -0000 @@ -76,6 +76,7 @@ #include #include #include +#include #include @@ -116,7 +117,8 @@ } void -pfkey_stats(u_long off, const char *name, int family __unused) +pfkey_stats(u_long off, const char *name, int family __unused, + int proto __unused) { struct pfkeystat pfkeystat; unsigned first, type; Index: route.c =================================================================== RCS file: /zork/cvs/src/usr.bin/netstat/route.c,v retrieving revision 1.81 diff -u -r1.81 route.c --- route.c 14 Feb 2007 14:17:01 -0000 1.81 +++ route.c 10 Jul 2007 01:38:42 -0000 @@ -43,6 +43,7 @@ #include #include #include +#include #include #include Index: sctp.c =================================================================== RCS file: /zork/cvs/src/usr.bin/netstat/sctp.c,v retrieving revision 1.4 diff -u -r1.4 sctp.c --- sctp.c 17 Jun 2007 14:45:28 -0000 1.4 +++ sctp.c 10 Jul 2007 01:38:42 -0000 @@ -432,8 +432,8 @@ * protocol. */ void -sctp_protopr(u_long proto, - const char *name, int af1) +sctp_protopr(u_long off __unused, + const char *name, int af1, int proto) { char *buf; const char *mibvar = "net.inet.sctp.assoclist"; @@ -511,18 +511,21 @@ * Dump SCTP statistics structure. */ void -sctp_stats(u_long off __unused, const char *name, int af1 __unused) +sctp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct sctpstat sctpstat, zerostat; size_t len = sizeof(sctpstat); - 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; - } + 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); Index: unix.c =================================================================== RCS file: /zork/cvs/src/usr.bin/netstat/unix.c,v retrieving revision 1.19 diff -u -r1.19 unix.c --- unix.c 28 Jul 2006 16:09:19 -0000 1.19 +++ unix.c 10 Jul 2007 01:38:42 -0000 @@ -61,6 +61,7 @@ #include #include #include +#include #include #include "netstat.h" @@ -69,35 +70,148 @@ static const char *const socktype[] = { "#0", "stream", "dgram", "raw", "rdm", "seqpacket" }; -void -unixpr(void) +static int +pcblist_sysctl(int type, char **bufp) { char *buf; - int type; size_t len; - struct xsocket *so; - struct xunpgen *xug, *oxug; - struct xunpcb *xunp; char mibvar[sizeof "net.local.seqpacket.pcblist"]; - for (type = SOCK_STREAM; type <= SOCK_SEQPACKET; type++) { - sprintf(mibvar, "net.local.%s.pcblist", socktype[type]); + 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; - len = 0; - if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) { - if (errno != ENOENT) - warn("sysctl: %s", mibvar); + 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 ((buf = malloc(len)) == 0) { - warnx("malloc %lu bytes", (u_long)len); - return; + 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); + } } - if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) { - warn("sysctl: %s", mibvar); - free(buf); + 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);