#define _KERNEL_STRUCTURES
#include <sys/param.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/ethernet.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <arpa/inet.h>
#include <libutil.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "netstat.h"
#define YES 1
#define NO 0
static void sidewaysintpr (u_int, u_long, int);
static void catchalarm (int);
#ifdef INET6
static char ntop_buf[INET6_ADDRSTRLEN];
#endif
static void
show_stat(const char *fmt, int width, u_long value, short showvalue)
{
char newfmt[32];
if (! showvalue) {
sprintf(newfmt, "%%%ds", width);
printf(newfmt, "-");
return;
}
if (hflag) {
char buf[5];
humanize_number(buf, sizeof buf, (int64_t) value, "",
HN_AUTOSCALE,
HN_NOSPACE | HN_DECIMAL);
sprintf(newfmt, "%%%ds", width);
printf(newfmt, buf);
} else {
sprintf(newfmt, "%%%d%s", width, fmt);
printf(newfmt, value);
}
}
void
intpr(int interval1, u_long ifnetaddr, void (*pfunc)(char *), u_long ncpusaddr)
{
struct ifnet ifnet;
struct ifdata_pcpu ifdata;
struct ifaddr_container ifac;
struct ifnethead ifnethead;
union {
struct ifaddr ifa;
struct in_ifaddr in;
#ifdef INET6
struct in6_ifaddr in6;
#endif
} ifaddr;
u_long ifaddraddr;
u_long ifaddrcont_addr;
u_long ifaddrfound;
u_long ifdataaddr;
u_long opackets;
u_long ipackets;
u_long obytes;
u_long ibytes;
u_long oerrors;
u_long ierrors;
u_long collisions;
u_long oqdrops;
short timer;
struct sockaddr *sa = NULL;
char name[IFNAMSIZ];
short network_layer;
short link_layer;
int ncpus;
if (kread(ncpusaddr, (char *)&ncpus, sizeof(ncpus)))
return;
if (ifnetaddr == 0) {
printf("ifnet: symbol not defined\n");
return;
}
if (interval1) {
sidewaysintpr((unsigned)interval1, ifnetaddr, ncpus);
return;
}
if (kread(ifnetaddr, (char *)&ifnethead, sizeof ifnethead))
return;
ifnetaddr = (u_long)TAILQ_FIRST(&ifnethead);
if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet))
return;
if (!pfunc) {
printf("%-9.9s %-5.5s %-13.13s %-15.15s %8.8s %5.5s",
"Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs");
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(" %5s", "Time");
if (dflag)
printf(" %5s", "Drop");
putchar('\n');
}
ifaddraddr = 0;
ifaddrcont_addr = 0;
while (ifnetaddr || ifaddraddr) {
struct sockaddr_in *sin;
#ifdef INET6
struct sockaddr_in6 *sin6;
#endif
char *cp;
int n, m, cpu;
network_layer = 0;
link_layer = 0;
if (ifaddraddr == 0) {
struct ifaddrhead head;
if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet))
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 = strchr(name, '\0');
if (pfunc) {
(*pfunc)(name);
continue;
}
if ((ifnet.if_flags & IFF_UP) == 0)
*cp++ = '*';
*cp = '\0';
if (kread((u_long)ifnet.if_addrheads,
(char *)&head, sizeof(head)))
return;
ifaddrcont_addr = (u_long)TAILQ_FIRST(&head);
if (ifaddrcont_addr == 0) {
ifaddraddr = 0;
} else {
if (kread(ifaddrcont_addr, (char *)&ifac,
sizeof(ifac)))
return;
ifaddraddr = (u_long)ifac.ifa;
}
}
ifaddrfound = ifaddraddr;
ifdataaddr = (u_long)ifnet.if_data_pcpu;
if (kread(ifdataaddr, (char *)&ifdata, sizeof(ifdata)))
return;
opackets = ifdata.ifd_opackets;
ipackets = ifdata.ifd_ipackets;
obytes = ifdata.ifd_obytes;
ibytes = ifdata.ifd_ibytes;
oerrors = ifdata.ifd_oerrors;
ierrors = ifdata.ifd_ierrors;
collisions = ifdata.ifd_collisions;
oqdrops = ifdata.ifd_oqdrops;
for (cpu = 1; cpu < ncpus; ++cpu) {
if (kread(ifdataaddr + (cpu * sizeof(ifdata)),
(char *)&ifdata, sizeof(ifdata)))
return;
opackets += ifdata.ifd_opackets;
ipackets += ifdata.ifd_ipackets;
obytes += ifdata.ifd_obytes;
ibytes += ifdata.ifd_ibytes;
oerrors += ifdata.ifd_oerrors;
ierrors += ifdata.ifd_ierrors;
collisions += ifdata.ifd_collisions;
oqdrops += ifdata.ifd_oqdrops;
}
timer = ifnet.if_timer;
if (ifaddraddr == 0) {
printf("%-9.9s %-5lu ", name, ifnet.if_mtu);
printf("%-13.13s ", "none");
printf("%-15.15s ", "none");
} else {
if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) {
ifaddraddr = 0;
continue;
}
ifaddr.ifa.if_ipackets = ifac.ifa_ipackets;
ifaddr.ifa.if_ibytes = ifac.ifa_ibytes;
ifaddr.ifa.if_opackets = ifac.ifa_opackets;
ifaddr.ifa.if_obytes = ifac.ifa_obytes;
for (cpu = 1; cpu < ncpus; ++cpu) {
struct ifaddr_container nifac;
if (kread(ifaddrcont_addr +
(cpu * sizeof(nifac)),
(char *)&nifac, sizeof(nifac))) {
ifaddraddr = 0;
continue;
}
ifaddr.ifa.if_ipackets += nifac.ifa_ipackets;
ifaddr.ifa.if_ibytes += nifac.ifa_ibytes;
ifaddr.ifa.if_opackets += nifac.ifa_opackets;
ifaddr.ifa.if_obytes += nifac.ifa_obytes;
}
#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) {
ifaddrcont_addr =
(u_long)TAILQ_NEXT(&ifac, ifa_link);
if (ifaddrcont_addr == 0) {
ifaddraddr = 0;
} else {
if (kread(ifaddrcont_addr,
(char *)&ifac, sizeof(ifac))) {
ifaddraddr = 0;
continue;
}
ifaddraddr = (u_long)ifac.ifa;
}
continue;
}
printf("%-7.7s %-5lu ", name, ifnet.if_mtu);
switch (sa->sa_family) {
case AF_UNSPEC:
printf("%-13.13s ", "none");
printf("%-15.15s ", "none");
break;
case AF_INET:
sin = (struct sockaddr_in *)sa;
#ifdef notdef
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("%-15.15s ",
routename(sin->sin_addr.s_addr));
network_layer = 1;
break;
#ifdef INET6
case AF_INET6:
sin6 = (struct sockaddr_in6 *)sa;
printf("%-11.11s ",
netname6(&ifaddr.in6.ia_addr,
&ifaddr.in6.ia_prefixmask.sin6_addr));
printf("%-17.17s ",
inet_ntop(AF_INET6,
&sin6->sin6_addr,
ntop_buf, sizeof(ntop_buf)));
network_layer = 1;
break;
#endif
case AF_LINK:
{
struct sockaddr_dl *sdl =
(struct sockaddr_dl *)sa;
char linknum[10];
cp = (char *)LLADDR(sdl);
n = sdl->sdl_alen;
sprintf(linknum, "<Link#%hu>", sdl->sdl_index);
m = printf("%-11.11s ", linknum);
}
goto hexprint;
default:
m = printf("(%d)", sa->sa_family);
for (cp = sa->sa_len + (char *)sa;
--cp > sa->sa_data && (*cp == 0);) {}
n = cp - sa->sa_data + 1;
cp = sa->sa_data;
hexprint:
while (--n >= 0)
m += printf("%02x%c", *cp++ & 0xff,
n > 0 ? ':' : ' ');
m = 30 - m;
while (m-- > 0)
putchar(' ');
link_layer = 1;
break;
}
if (network_layer) {
opackets = ifaddr.ifa.if_opackets;
ipackets = ifaddr.ifa.if_ipackets;
obytes = ifaddr.ifa.if_obytes;
ibytes = ifaddr.ifa.if_ibytes;
}
ifaddrcont_addr =
(u_long)TAILQ_NEXT(&ifac, ifa_link);
if (ifaddrcont_addr == 0) {
ifaddraddr = 0;
} else {
if (kread(ifaddrcont_addr,
(char *)&ifac, sizeof(ifac))) {
ifaddraddr = 0;
} else {
ifaddraddr = (u_long)ifac.ifa;
}
}
}
show_stat("lu", 8, ipackets, link_layer|network_layer);
printf(" ");
show_stat("lu", 5, ierrors, link_layer);
printf(" ");
if (bflag) {
show_stat("lu", 10, ibytes, link_layer|network_layer);
printf(" ");
}
show_stat("lu", 8, opackets, link_layer|network_layer);
printf(" ");
show_stat("lu", 5, oerrors, link_layer);
printf(" ");
if (bflag) {
show_stat("lu", 10, obytes, link_layer|network_layer);
printf(" ");
}
show_stat("lu", 5, collisions, link_layer);
if (tflag) {
printf(" ");
show_stat("d", 5, timer, link_layer);
}
if (dflag) {
printf(" ");
show_stat("lu", 5, oqdrops, link_layer);
}
putchar('\n');
if (aflag && ifaddrfound) {
struct ifmultiaddr *multiaddr;
struct ifmultiaddr ifma;
union {
struct sockaddr sa;
struct sockaddr_in in;
#ifdef INET6
struct sockaddr_in6 in6;
#endif
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))
break;
multiaddr = &ifma;
if (kread((u_long)ifma.ifma_addr, (char *)&msa,
sizeof msa))
break;
if (msa.sa.sa_family != sa->sa_family)
continue;
fmt = NULL;
switch (msa.sa.sa_family) {
case AF_INET:
fmt = routename(msa.in.sin_addr.s_addr);
break;
#ifdef INET6
case AF_INET6:
printf("%23s %-19.19s(refs: %d)\n", "",
inet_ntop(AF_INET6,
&msa.in6.sin6_addr,
ntop_buf,
sizeof(ntop_buf)),
ifma.ifma_refcount);
break;
#endif
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("%23s %s\n", "", fmt);
}
}
}
}
struct iftot {
SLIST_ENTRY(iftot) chain;
char ift_name[IFNAMSIZ];
u_long ift_ip;
u_long ift_ie;
u_long ift_op;
u_long ift_oe;
u_long ift_co;
u_long ift_dr;
u_long ift_ib;
u_long ift_ob;
};
u_char signalled;
static void
sidewaysintpr(unsigned interval1, u_long off, int ncpus)
{
struct ifnet ifnet;
u_long firstifnet;
struct ifnethead ifnethead;
struct ifdata_pcpu ifdata;
struct iftot *iftot, *ip, *ipn, *total, *sum, *interesting;
int line, cpu;
int oldmask, first;
u_long interesting_off;
u_long ifdata_addr;
if (kread(off, (char *)&ifnethead, sizeof ifnethead))
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))
break;
strlcpy(name, ifnet.if_xname, sizeof(name));
if (interface && strcmp(name, interface) == 0) {
interesting = ip;
interesting_off = off;
}
snprintf(ip->ift_name, 16, "(%.13s)", 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 ((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;
(void)alarm(interval1);
first = 1;
banner:
printf("%17s %14s %16s", "input",
interesting ? interesting->ift_name : "(Total)", "output");
putchar('\n');
printf("%10s %5s %10s %10s %5s %10s %5s",
"packets", "errs", "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)) {
printf("???\n");
exit(1);
}
ifdata_addr = (u_long)ifnet.if_data_pcpu;
if (kread(ifdata_addr, (char *)&ifdata, sizeof(ifdata))) {
printf("ifdata 1\n");
exit(1);
}
ifnet.if_ipackets = ifdata.ifd_ipackets;
ifnet.if_ierrors = ifdata.ifd_ierrors;
ifnet.if_ibytes = ifdata.ifd_ibytes;
ifnet.if_opackets = ifdata.ifd_opackets;
ifnet.if_oerrors = ifdata.ifd_oerrors;
ifnet.if_obytes = ifdata.ifd_obytes;
ifnet.if_collisions = ifdata.ifd_collisions;
ifnet.if_oqdrops = ifdata.ifd_oqdrops;
for (cpu = 1; cpu < ncpus; ++cpu) {
if (kread(ifdata_addr + (cpu * sizeof(ifdata)),
(char *)&ifdata, sizeof(ifdata))) {
printf("ifdata 2\n");
exit(1);
}
ifnet.if_ipackets += ifdata.ifd_ipackets;
ifnet.if_ierrors += ifdata.ifd_ierrors;
ifnet.if_ibytes += ifdata.ifd_ibytes;
ifnet.if_opackets += ifdata.ifd_opackets;
ifnet.if_oerrors += ifdata.ifd_oerrors;
ifnet.if_obytes += ifdata.ifd_obytes;
ifnet.if_collisions += ifdata.ifd_collisions;
ifnet.if_oqdrops += ifdata.ifd_oqdrops;
}
if (!first) {
printf("%10lu %5lu %10lu %10lu %5lu %10lu %5lu",
ifnet.if_ipackets - ip->ift_ip,
ifnet.if_ierrors - ip->ift_ie,
ifnet.if_ibytes - ip->ift_ib,
ifnet.if_opackets - ip->ift_op,
ifnet.if_oerrors - ip->ift_oe,
ifnet.if_obytes - ip->ift_ob,
ifnet.if_collisions - ip->ift_co);
if (dflag)
printf(" %5lu", ifnet.if_oqdrops - ip->ift_dr);
}
ip->ift_ip = ifnet.if_ipackets;
ip->ift_ie = ifnet.if_ierrors;
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_oqdrops;
} else {
sum->ift_ip = 0;
sum->ift_ie = 0;
sum->ift_ib = 0;
sum->ift_op = 0;
sum->ift_oe = 0;
sum->ift_ob = 0;
sum->ift_co = 0;
sum->ift_dr = 0;
for (off = firstifnet, ip = iftot;
off && SLIST_NEXT(ip, chain) != NULL;
ip = SLIST_NEXT(ip, chain)) {
if (kread(off, (char *)&ifnet, sizeof ifnet)) {
off = 0;
continue;
}
ifdata_addr = (u_long)ifnet.if_data_pcpu;
if (kread(ifdata_addr, (char *)&ifdata,
sizeof(ifdata))) {
printf("ifdata 3\n");
exit(1);
}
ifnet.if_ipackets = ifdata.ifd_ipackets;
ifnet.if_ierrors = ifdata.ifd_ierrors;
ifnet.if_ibytes = ifdata.ifd_ibytes;
ifnet.if_opackets = ifdata.ifd_opackets;
ifnet.if_oerrors = ifdata.ifd_oerrors;
ifnet.if_obytes = ifdata.ifd_obytes;
ifnet.if_collisions = ifdata.ifd_collisions;
ifnet.if_oqdrops = ifdata.ifd_oqdrops;
for (cpu = 1; cpu < ncpus; ++cpu) {
if (kread(ifdata_addr + (cpu * sizeof(ifdata)),
(char *)&ifdata, sizeof(ifdata))) {
printf("ifdata 2\n");
exit(1);
}
ifnet.if_ipackets += ifdata.ifd_ipackets;
ifnet.if_ierrors += ifdata.ifd_ierrors;
ifnet.if_ibytes += ifdata.ifd_ibytes;
ifnet.if_opackets += ifdata.ifd_opackets;
ifnet.if_oerrors += ifdata.ifd_oerrors;
ifnet.if_obytes += ifdata.ifd_obytes;
ifnet.if_collisions += ifdata.ifd_collisions;
ifnet.if_oqdrops += ifdata.ifd_oqdrops;
}
if (ifnet.if_bridge) {
sum->ift_ie += ifnet.if_ierrors;
sum->ift_oe += ifnet.if_oerrors;
sum->ift_co += ifnet.if_collisions;
} else {
sum->ift_ip += ifnet.if_ipackets;
sum->ift_ie += ifnet.if_ierrors;
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_oqdrops;
}
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+1, sum->ift_ie - total->ift_ie, 1);
show_stat("lu", 10+1, sum->ift_ib - total->ift_ib, 1);
show_stat("lu", 10+1, sum->ift_op - total->ift_op, 1);
show_stat("lu", 5+1, sum->ift_oe - total->ift_oe, 1);
show_stat("lu", 10+1, sum->ift_ob - total->ift_ob, 1);
show_stat("lu", 5+1, sum->ift_co - total->ift_co, 1);
if (dflag)
show_stat("u", 5+1, sum->ift_dr - total->ift_dr, 1);
}
*total = *sum;
}
if (!first)
putchar('\n');
fflush(stdout);
oldmask = sigblock(sigmask(SIGALRM));
if (! signalled) {
sigpause(0);
}
sigsetmask(oldmask);
signalled = NO;
(void)alarm(interval1);
line++;
first = 0;
if (line == 21)
goto banner;
else
goto loop;
}
static void
catchalarm(int signo __unused)
{
signalled = YES;
}