xref: /openbsd/usr.bin/systat/if.c (revision 479c151d)
1*479c151dSjsg /*	$OpenBSD: if.c,v 1.28 2024/09/20 02:00:46 jsg Exp $ */
21612fc5aSmarkus /*
31612fc5aSmarkus  * Copyright (c) 2004 Markus Friedl <markus@openbsd.org>
41612fc5aSmarkus  *
51612fc5aSmarkus  * Permission to use, copy, modify, and distribute this software for any
61612fc5aSmarkus  * purpose with or without fee is hereby granted, provided that the above
71612fc5aSmarkus  * copyright notice and this permission notice appear in all copies.
81612fc5aSmarkus  *
91612fc5aSmarkus  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
101612fc5aSmarkus  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
111612fc5aSmarkus  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
121612fc5aSmarkus  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
131612fc5aSmarkus  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
141612fc5aSmarkus  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
151612fc5aSmarkus  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
161612fc5aSmarkus  */
17bc595886Sjasper 
18b3fb853aSderaadt #include <sys/types.h>
198f6b3bafSderaadt #include <sys/signal.h>
201612fc5aSmarkus #include <sys/socket.h>
211612fc5aSmarkus #include <sys/sysctl.h>
221612fc5aSmarkus #include <net/if.h>
231612fc5aSmarkus #include <net/if_dl.h>
241612fc5aSmarkus #include <net/route.h>
257d0bcf9cSderaadt #include <sys/sockio.h>
26bc595886Sjasper #include <sys/ioctl.h>
271612fc5aSmarkus 
281612fc5aSmarkus #include <stdlib.h>
296cf6eca7Sderaadt #include <string.h>
30bc595886Sjasper #include <unistd.h>
311612fc5aSmarkus 
32b3fb853aSderaadt #define roundup(x, y)   ((((x)+((y)-1))/(y))*(y))
33b3fb853aSderaadt 
341612fc5aSmarkus #include "systat.h"
351612fc5aSmarkus 
361612fc5aSmarkus static  enum state { BOOT, TIME, RUN } state = TIME;
371612fc5aSmarkus 
381612fc5aSmarkus struct ifstat {
391612fc5aSmarkus 	char		ifs_name[IFNAMSIZ];	/* interface name */
407d0bcf9cSderaadt 	char		ifs_description[IFDESCRSIZE];
411612fc5aSmarkus 	struct ifcount	ifs_cur;
421612fc5aSmarkus 	struct ifcount	ifs_old;
431612fc5aSmarkus 	struct ifcount	ifs_now;
44d7c69161Scanacar 	char		ifs_flag;
451612fc5aSmarkus } *ifstats;
461612fc5aSmarkus 
4708e35e0cSmortimer struct ifcount sum;
4808e35e0cSmortimer 
491612fc5aSmarkus static	int nifs = 0;
5073baed14Scanacar static int num_ifs = 0;
515c280c62Smpf static int show_bits = 0;
521612fc5aSmarkus 
5373baed14Scanacar void print_if(void);
5473baed14Scanacar int read_if(void);
5573baed14Scanacar int select_if(void);
5673baed14Scanacar int if_keyboard_callback(int);
5750de0d1bSclaudio 
58f429edc3Sderaadt void fetchifstat(void);
5973baed14Scanacar static void showifstat(struct ifstat *);
6073baed14Scanacar static void showtotal(void);
614a1020e8Slum static void rt_getaddrinfo(struct sockaddr *, int, struct sockaddr **);
621612fc5aSmarkus 
63c5f96cb8Sdlg const char ifails[] = "IFAILS";
64c5f96cb8Sdlg const char ofails[] = "OFAILS";
65c5f96cb8Sdlg 
66c5f96cb8Sdlg #define IF_ERR_SUM	0
67c5f96cb8Sdlg #define IF_ERR_ERRORS	1
68c5f96cb8Sdlg #define IF_ERR_QDROPS	2
69c5f96cb8Sdlg 
70c5f96cb8Sdlg struct if_err_view {
71c5f96cb8Sdlg 	const char *iname;
72c5f96cb8Sdlg 	const char *oname;
73c5f96cb8Sdlg 	uint64_t (*icount)(const struct ifcount *);
74c5f96cb8Sdlg 	uint64_t (*ocount)(const struct ifcount *);
75c5f96cb8Sdlg };
76c5f96cb8Sdlg 
77c5f96cb8Sdlg static uint64_t if_err_ifails(const struct ifcount *);
78c5f96cb8Sdlg static uint64_t if_err_ofails(const struct ifcount *);
79c5f96cb8Sdlg static uint64_t if_err_ierrors(const struct ifcount *);
80c5f96cb8Sdlg static uint64_t if_err_oerrors(const struct ifcount *);
81c5f96cb8Sdlg static uint64_t if_err_iqdrops(const struct ifcount *);
82c5f96cb8Sdlg static uint64_t if_err_oqdrops(const struct ifcount *);
83c5f96cb8Sdlg 
84c5f96cb8Sdlg static const struct if_err_view if_err_views[] = {
85c5f96cb8Sdlg 	[IF_ERR_SUM] =    {
86c5f96cb8Sdlg 		.iname = ifails,
87c5f96cb8Sdlg 		.oname = ofails,
88c5f96cb8Sdlg 		.icount = if_err_ifails,
89c5f96cb8Sdlg 		.ocount = if_err_ofails,
90c5f96cb8Sdlg 	},
91c5f96cb8Sdlg 	[IF_ERR_ERRORS] = {
92c5f96cb8Sdlg 		.iname = "IERRS",
93c5f96cb8Sdlg 		.oname = "OERRS",
94c5f96cb8Sdlg 		.icount = if_err_ierrors,
95c5f96cb8Sdlg 		.ocount = if_err_oerrors,
96c5f96cb8Sdlg 	},
97c5f96cb8Sdlg 	[IF_ERR_QDROPS] = {
98c5f96cb8Sdlg 		.iname = "IQDROPS",
99c5f96cb8Sdlg 		.oname = "OQDROPS",
100c5f96cb8Sdlg 		.icount = if_err_iqdrops,
101c5f96cb8Sdlg 		.ocount = if_err_oqdrops,
102c5f96cb8Sdlg 	},
103c5f96cb8Sdlg };
104c5f96cb8Sdlg 
105c5f96cb8Sdlg static const struct if_err_view *if_err_view = &if_err_views[IF_ERR_SUM];
1061612fc5aSmarkus 
10773baed14Scanacar /* Define fields */
10873baed14Scanacar field_def fields_if[] = {
10973baed14Scanacar 	{"IFACE", 8, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
1107d0bcf9cSderaadt 	{"STATE", 4, 6, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
11173baed14Scanacar 	{"IPKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
11273baed14Scanacar 	{"IBYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
113c5f96cb8Sdlg 	{ifails, 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
11473baed14Scanacar 	{"OPKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
11573baed14Scanacar 	{"OBYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
116c5f96cb8Sdlg 	{ofails, 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
11773baed14Scanacar 	{"COLLS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
1187d0bcf9cSderaadt 	{"DESC", 14, 64, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
11973baed14Scanacar };
1201612fc5aSmarkus 
12173baed14Scanacar 
122596a8091Sjasper #define FLD_IF_IFACE	FIELD_ADDR(fields_if,0)
123596a8091Sjasper #define FLD_IF_STATE	FIELD_ADDR(fields_if,1)
124596a8091Sjasper #define FLD_IF_IPKTS	FIELD_ADDR(fields_if,2)
125596a8091Sjasper #define FLD_IF_IBYTES	FIELD_ADDR(fields_if,3)
126596a8091Sjasper #define FLD_IF_IERRS	FIELD_ADDR(fields_if,4)
127596a8091Sjasper #define FLD_IF_OPKTS	FIELD_ADDR(fields_if,5)
128596a8091Sjasper #define FLD_IF_OBYTES	FIELD_ADDR(fields_if,6)
129596a8091Sjasper #define FLD_IF_OERRS	FIELD_ADDR(fields_if,7)
130596a8091Sjasper #define FLD_IF_COLLS	FIELD_ADDR(fields_if,8)
131596a8091Sjasper #define FLD_IF_DESC	FIELD_ADDR(fields_if,9)
13273baed14Scanacar 
13373baed14Scanacar 
13473baed14Scanacar /* Define views */
13573baed14Scanacar field_def *view_if_0[] = {
1367d0bcf9cSderaadt 	FLD_IF_IFACE, FLD_IF_STATE, FLD_IF_DESC, FLD_IF_IPKTS,
1377d0bcf9cSderaadt 	FLD_IF_IBYTES, FLD_IF_IERRS, FLD_IF_OPKTS, FLD_IF_OBYTES,
1387d0bcf9cSderaadt 	FLD_IF_OERRS, FLD_IF_COLLS, NULL
13973baed14Scanacar };
14073baed14Scanacar 
14173baed14Scanacar /* Define view managers */
14273baed14Scanacar 
14373baed14Scanacar struct view_manager ifstat_mgr = {
14473baed14Scanacar 	"Ifstat", select_if, read_if, NULL, print_header,
14573baed14Scanacar 	print_if, if_keyboard_callback, NULL, NULL
14673baed14Scanacar };
14773baed14Scanacar 
14873baed14Scanacar field_view views_if[] = {
14973baed14Scanacar 	{view_if_0, "ifstat", '1', &ifstat_mgr},
15073baed14Scanacar 	{NULL, NULL, 0, NULL}
15173baed14Scanacar };
15273baed14Scanacar 
1531612fc5aSmarkus 
1541612fc5aSmarkus int
initifstat(void)1551612fc5aSmarkus initifstat(void)
1561612fc5aSmarkus {
15773baed14Scanacar 	field_view *v;
15873baed14Scanacar 	read_if();
15973baed14Scanacar 	for (v = views_if; v->name != NULL; v++)
16073baed14Scanacar 		add_view(v);
1611612fc5aSmarkus 
1621612fc5aSmarkus 	return(1);
1631612fc5aSmarkus }
1641612fc5aSmarkus 
1651612fc5aSmarkus #define UPDATE(x, y) do { \
1663e4efdf5Sderaadt 		ifs->ifs_now.x = ifm.y; \
1671612fc5aSmarkus 		ifs->ifs_cur.x = ifs->ifs_now.x - ifs->ifs_old.x; \
168e24b9d6eSdlg 		if (state == TIME) {\
1691612fc5aSmarkus 			ifs->ifs_old.x = ifs->ifs_now.x; \
170e24b9d6eSdlg 			ifs->ifs_cur.x /= naptime; \
171e24b9d6eSdlg 		} \
172e24b9d6eSdlg 		sum.x += ifs->ifs_cur.x; \
1731612fc5aSmarkus 	} while(0)
1741612fc5aSmarkus 
1751612fc5aSmarkus 
1761612fc5aSmarkus void
rt_getaddrinfo(struct sockaddr * sa,int addrs,struct sockaddr ** info)1771612fc5aSmarkus rt_getaddrinfo(struct sockaddr *sa, int addrs, struct sockaddr **info)
1781612fc5aSmarkus {
1791612fc5aSmarkus 	int i;
1801612fc5aSmarkus 
1811612fc5aSmarkus 	for (i = 0; i < RTAX_MAX; i++) {
1821612fc5aSmarkus 		if (addrs & (1 << i)) {
1831612fc5aSmarkus 			info[i] = sa;
1841612fc5aSmarkus 			sa = (struct sockaddr *) ((char *)(sa) +
1851612fc5aSmarkus 			    roundup(sa->sa_len, sizeof(long)));
1861612fc5aSmarkus 		} else
1871612fc5aSmarkus 			info[i] = NULL;
1881612fc5aSmarkus 	}
1891612fc5aSmarkus }
1901612fc5aSmarkus 
19173baed14Scanacar 
19273baed14Scanacar 
19373baed14Scanacar int
select_if(void)19473baed14Scanacar select_if(void)
19573baed14Scanacar {
19673baed14Scanacar 	num_disp = num_ifs + 1;
19773baed14Scanacar 	return (0);
19873baed14Scanacar }
19973baed14Scanacar 
20073baed14Scanacar int
read_if(void)20173baed14Scanacar read_if(void)
20273baed14Scanacar {
20373baed14Scanacar 	fetchifstat();
20473baed14Scanacar 	num_disp = num_ifs + 1;
20573baed14Scanacar 
20673baed14Scanacar 	return 0;
20773baed14Scanacar }
20873baed14Scanacar 
2091612fc5aSmarkus void
print_if(void)21073baed14Scanacar print_if(void)
21173baed14Scanacar {
21273baed14Scanacar 	int n, i, count = 0;
21373baed14Scanacar 
21473baed14Scanacar 	for (n = 0, i = 0; n < nifs; n++) {
21573baed14Scanacar 		if (ifstats[n].ifs_name[0] == '\0')
21673baed14Scanacar 			continue;
21773baed14Scanacar 		if (i++ < dispstart)
21873baed14Scanacar 			continue;
21973baed14Scanacar 		if (i == num_disp)
22073baed14Scanacar 			break;
22173baed14Scanacar 		showifstat(ifstats + n);
22273baed14Scanacar 		if (maxprint > 0 && ++count >= maxprint)
22373baed14Scanacar 			return;
22473baed14Scanacar 	}
22573baed14Scanacar 	showtotal();
22673baed14Scanacar }
22773baed14Scanacar 
22873baed14Scanacar 
229f429edc3Sderaadt void
fetchifstat(void)2301612fc5aSmarkus fetchifstat(void)
2311612fc5aSmarkus {
2321612fc5aSmarkus 	struct ifstat *newstats, *ifs;
2333e4efdf5Sderaadt 	struct if_msghdr ifm;
2341612fc5aSmarkus 	struct sockaddr *info[RTAX_MAX];
2351612fc5aSmarkus 	struct sockaddr_dl *sdl;
2361612fc5aSmarkus 	char *buf, *next, *lim;
237d7c69161Scanacar 	int mib[6], i;
2381612fc5aSmarkus 	size_t need;
2391612fc5aSmarkus 
2401612fc5aSmarkus 	mib[0] = CTL_NET;
241149dc9fcSguenther 	mib[1] = PF_ROUTE;
2421612fc5aSmarkus 	mib[2] = 0;
2431612fc5aSmarkus 	mib[3] = 0;
2441612fc5aSmarkus 	mib[4] = NET_RT_IFLIST;
2451612fc5aSmarkus 	mib[5] = 0;
2461612fc5aSmarkus 
2471612fc5aSmarkus 	if (sysctl(mib, 6, NULL, &need, NULL, 0) == -1)
2481612fc5aSmarkus 		return;
2491612fc5aSmarkus 	if ((buf = malloc(need)) == NULL)
2501612fc5aSmarkus 		return;
2511612fc5aSmarkus 	if (sysctl(mib, 6, buf, &need, NULL, 0) == -1) {
2521612fc5aSmarkus 		free(buf);
2531612fc5aSmarkus 		return;
2541612fc5aSmarkus 	}
2551612fc5aSmarkus 
2561612fc5aSmarkus 	bzero(&sum, sizeof(sum));
25773baed14Scanacar 	num_ifs = 0;
2581612fc5aSmarkus 
2591612fc5aSmarkus 	lim = buf + need;
2603e4efdf5Sderaadt 	for (next = buf; next < lim; next += ifm.ifm_msglen) {
2613e4efdf5Sderaadt 		bcopy(next, &ifm, sizeof ifm);
26277e759e9Sclaudio 		if (ifm.ifm_version != RTM_VERSION ||
26377e759e9Sclaudio 		    ifm.ifm_type != RTM_IFINFO ||
2643e4efdf5Sderaadt 		    !(ifm.ifm_addrs & RTA_IFP))
2651612fc5aSmarkus 			continue;
2663e4efdf5Sderaadt 		if (ifm.ifm_index >= nifs) {
2677e81aea1Sdoug 			if ((newstats = reallocarray(ifstats, ifm.ifm_index + 4,
2687e81aea1Sdoug 			    sizeof(struct ifstat))) == NULL)
2691612fc5aSmarkus 				continue;
2701612fc5aSmarkus 			ifstats = newstats;
2713e4efdf5Sderaadt 			for (; nifs < ifm.ifm_index + 4; nifs++)
27273baed14Scanacar 				bzero(&ifstats[nifs], sizeof(*ifstats));
2731612fc5aSmarkus 		}
2743e4efdf5Sderaadt 		ifs = &ifstats[ifm.ifm_index];
2751612fc5aSmarkus 		if (ifs->ifs_name[0] == '\0') {
2761612fc5aSmarkus 			bzero(&info, sizeof(info));
2773e4efdf5Sderaadt 			rt_getaddrinfo(
2783e4efdf5Sderaadt 			    (struct sockaddr *)((struct if_msghdr *)next + 1),
2793e4efdf5Sderaadt 			    ifm.ifm_addrs, info);
2807d0bcf9cSderaadt 			sdl = (struct sockaddr_dl *)info[RTAX_IFP];
2817d0bcf9cSderaadt 
2827d0bcf9cSderaadt 			if (sdl && sdl->sdl_family == AF_LINK &&
2834d152fbaSdlg 			    sdl->sdl_nlen > 0) {
2847d0bcf9cSderaadt 				struct ifreq ifrdesc;
2857d0bcf9cSderaadt 				char ifdescr[IFDESCRSIZE];
2867d0bcf9cSderaadt 				int s;
2877d0bcf9cSderaadt 
2884d152fbaSdlg 				bcopy(sdl->sdl_data, ifs->ifs_name,
2894d152fbaSdlg 				      sdl->sdl_nlen);
2904d152fbaSdlg 				ifs->ifs_name[sdl->sdl_nlen] = '\0';
2917d0bcf9cSderaadt 
2927d0bcf9cSderaadt 				/* Get the interface description */
2937d0bcf9cSderaadt 				memset(&ifrdesc, 0, sizeof(ifrdesc));
2947d0bcf9cSderaadt 				strlcpy(ifrdesc.ifr_name, ifs->ifs_name,
2957d0bcf9cSderaadt 					sizeof(ifrdesc.ifr_name));
2967d0bcf9cSderaadt 				ifrdesc.ifr_data = (caddr_t)&ifdescr;
2977d0bcf9cSderaadt 
2987d0bcf9cSderaadt 				s = socket(AF_INET, SOCK_DGRAM, 0);
2997d0bcf9cSderaadt 				if (s != -1) {
3007d0bcf9cSderaadt 					if (ioctl(s, SIOCGIFDESCR, &ifrdesc) == 0)
3017d0bcf9cSderaadt 						strlcpy(ifs->ifs_description,
3027d0bcf9cSderaadt 						    ifrdesc.ifr_data,
3037d0bcf9cSderaadt 						    sizeof(ifs->ifs_description));
3047d0bcf9cSderaadt 					close(s);
3054d152fbaSdlg 				}
3061612fc5aSmarkus 			}
3071612fc5aSmarkus 			if (ifs->ifs_name[0] == '\0')
3081612fc5aSmarkus 				continue;
3091612fc5aSmarkus 		}
31073baed14Scanacar 		num_ifs++;
3111612fc5aSmarkus 		UPDATE(ifc_ip, ifm_data.ifi_ipackets);
3121612fc5aSmarkus 		UPDATE(ifc_ib, ifm_data.ifi_ibytes);
3131612fc5aSmarkus 		UPDATE(ifc_ie, ifm_data.ifi_ierrors);
314c5f96cb8Sdlg 		UPDATE(ifc_iq, ifm_data.ifi_iqdrops);
3151612fc5aSmarkus 		UPDATE(ifc_op, ifm_data.ifi_opackets);
3161612fc5aSmarkus 		UPDATE(ifc_ob, ifm_data.ifi_obytes);
3171612fc5aSmarkus 		UPDATE(ifc_oe, ifm_data.ifi_oerrors);
318c5f96cb8Sdlg 		UPDATE(ifc_oq, ifm_data.ifi_oqdrops);
3191612fc5aSmarkus 		UPDATE(ifc_co, ifm_data.ifi_collisions);
32050de0d1bSclaudio 		ifs->ifs_cur.ifc_flags = ifm.ifm_flags;
32150de0d1bSclaudio 		ifs->ifs_cur.ifc_state = ifm.ifm_data.ifi_link_state;
322d7c69161Scanacar 		ifs->ifs_flag++;
3231612fc5aSmarkus 	}
324d7c69161Scanacar 
325d7c69161Scanacar 	/* remove unreferenced interfaces */
326d7c69161Scanacar 	for (i = 0; i < nifs; i++) {
327d7c69161Scanacar 		ifs = &ifstats[i];
328d7c69161Scanacar 		if (ifs->ifs_flag)
329d7c69161Scanacar 			ifs->ifs_flag = 0;
330d7c69161Scanacar 		else
331d7c69161Scanacar 			ifs->ifs_name[0] = '\0';
332d7c69161Scanacar 	}
333d7c69161Scanacar 
3341612fc5aSmarkus 	free(buf);
3351612fc5aSmarkus }
3361612fc5aSmarkus 
3371612fc5aSmarkus 
33873baed14Scanacar static void
showifstat(struct ifstat * ifs)33973baed14Scanacar showifstat(struct ifstat *ifs)
3401612fc5aSmarkus {
3415c280c62Smpf 	int conv = show_bits ? 8 : 1;
3425c280c62Smpf 	int div = show_bits ? 1000 : 1024;
3435c280c62Smpf 
34473baed14Scanacar 	print_fld_str(FLD_IF_IFACE, ifs->ifs_name);
3451612fc5aSmarkus 
34673baed14Scanacar 	tb_start();
34773baed14Scanacar 	tbprintf("%s", ifs->ifs_cur.ifc_flags & IFF_UP ?
34873baed14Scanacar 		 "up" : "dn");
3491612fc5aSmarkus 
35073baed14Scanacar 	switch (ifs->ifs_cur.ifc_state) {
35150de0d1bSclaudio 	case LINK_STATE_UP:
35230762738Sreyk 	case LINK_STATE_HALF_DUPLEX:
35330762738Sreyk 	case LINK_STATE_FULL_DUPLEX:
35473baed14Scanacar 		tbprintf(":U");
35573baed14Scanacar 		break;
35650de0d1bSclaudio 	case LINK_STATE_DOWN:
35773baed14Scanacar 		tbprintf (":D");
35873baed14Scanacar 		break;
35950de0d1bSclaudio 	}
3601612fc5aSmarkus 
36173baed14Scanacar 	print_fld_tb(FLD_IF_STATE);
36273baed14Scanacar 
3637d0bcf9cSderaadt 	print_fld_str(FLD_IF_DESC, ifs->ifs_description);
3647d0bcf9cSderaadt 
3655c280c62Smpf 	print_fld_sdiv(FLD_IF_IBYTES, ifs->ifs_cur.ifc_ib * conv, div);
36673baed14Scanacar 	print_fld_size(FLD_IF_IPKTS, ifs->ifs_cur.ifc_ip);
367c5f96cb8Sdlg 	print_fld_size(FLD_IF_IERRS, if_err_view->icount(&ifs->ifs_cur));
36873baed14Scanacar 
3695c280c62Smpf 	print_fld_sdiv(FLD_IF_OBYTES, ifs->ifs_cur.ifc_ob * conv, div);
37073baed14Scanacar 	print_fld_size(FLD_IF_OPKTS, ifs->ifs_cur.ifc_op);
371c5f96cb8Sdlg 	print_fld_size(FLD_IF_OERRS, if_err_view->ocount(&ifs->ifs_cur));
37273baed14Scanacar 
37373baed14Scanacar 	print_fld_size(FLD_IF_COLLS, ifs->ifs_cur.ifc_co);
37473baed14Scanacar 
37573baed14Scanacar 	end_line();
37673baed14Scanacar }
37773baed14Scanacar 
37873baed14Scanacar static void
showtotal(void)37973baed14Scanacar showtotal(void)
3801612fc5aSmarkus {
3815c280c62Smpf 	int conv = show_bits ? 8 : 1;
3825c280c62Smpf 	int div = show_bits ? 1000 : 1024;
3835c280c62Smpf 
38473baed14Scanacar 	print_fld_str(FLD_IF_IFACE, "Totals");
3851612fc5aSmarkus 
3865c280c62Smpf 	print_fld_sdiv(FLD_IF_IBYTES, sum.ifc_ib * conv, div);
38773baed14Scanacar 	print_fld_size(FLD_IF_IPKTS, sum.ifc_ip);
388c5f96cb8Sdlg 	print_fld_size(FLD_IF_IERRS, if_err_view->icount(&sum));
38973baed14Scanacar 
3905c280c62Smpf 	print_fld_sdiv(FLD_IF_OBYTES, sum.ifc_ob * conv, div);
39173baed14Scanacar 	print_fld_size(FLD_IF_OPKTS, sum.ifc_op);
392c5f96cb8Sdlg 	print_fld_size(FLD_IF_OERRS, if_err_view->ocount(&sum));
39373baed14Scanacar 
39473baed14Scanacar 	print_fld_size(FLD_IF_COLLS, sum.ifc_co);
39573baed14Scanacar 
39673baed14Scanacar 	end_line();
39773baed14Scanacar 
3981612fc5aSmarkus }
3991612fc5aSmarkus 
400c5f96cb8Sdlg static uint64_t
if_err_ifails(const struct ifcount * ifc)401c5f96cb8Sdlg if_err_ifails(const struct ifcount *ifc)
402c5f96cb8Sdlg {
403c5f96cb8Sdlg 	return (ifc->ifc_ie + ifc->ifc_iq);
404c5f96cb8Sdlg }
405c5f96cb8Sdlg 
406c5f96cb8Sdlg static uint64_t
if_err_ofails(const struct ifcount * ifc)407c5f96cb8Sdlg if_err_ofails(const struct ifcount *ifc)
408c5f96cb8Sdlg {
409c5f96cb8Sdlg 	return (ifc->ifc_oe + ifc->ifc_oq);
410c5f96cb8Sdlg }
411c5f96cb8Sdlg 
412c5f96cb8Sdlg static uint64_t
if_err_ierrors(const struct ifcount * ifc)413c5f96cb8Sdlg if_err_ierrors(const struct ifcount *ifc)
414c5f96cb8Sdlg {
415c5f96cb8Sdlg 	return (ifc->ifc_ie);
416c5f96cb8Sdlg }
417c5f96cb8Sdlg 
418c5f96cb8Sdlg static uint64_t
if_err_oerrors(const struct ifcount * ifc)419c5f96cb8Sdlg if_err_oerrors(const struct ifcount *ifc)
420c5f96cb8Sdlg {
421c5f96cb8Sdlg 	return (ifc->ifc_oe);
422c5f96cb8Sdlg }
423c5f96cb8Sdlg 
424c5f96cb8Sdlg static uint64_t
if_err_iqdrops(const struct ifcount * ifc)425c5f96cb8Sdlg if_err_iqdrops(const struct ifcount *ifc)
426c5f96cb8Sdlg {
427c5f96cb8Sdlg 	return (ifc->ifc_iq);
428c5f96cb8Sdlg }
429c5f96cb8Sdlg 
430c5f96cb8Sdlg static uint64_t
if_err_oqdrops(const struct ifcount * ifc)431c5f96cb8Sdlg if_err_oqdrops(const struct ifcount *ifc)
432c5f96cb8Sdlg {
433c5f96cb8Sdlg 	return (ifc->ifc_oq);
434c5f96cb8Sdlg }
435c5f96cb8Sdlg 
436c5f96cb8Sdlg static void
if_set_errs(unsigned int v)437c5f96cb8Sdlg if_set_errs(unsigned int v)
438c5f96cb8Sdlg {
439c5f96cb8Sdlg 	if_err_view = &if_err_views[v];
440c5f96cb8Sdlg 	FLD_IF_IERRS->title = if_err_view->iname;
441d7dbde78Sdlg 	FLD_IF_OERRS->title = if_err_view->oname;
442c5f96cb8Sdlg 	gotsig_alarm = 1;
443c5f96cb8Sdlg }
444c5f96cb8Sdlg 
4451612fc5aSmarkus int
if_keyboard_callback(int ch)44673baed14Scanacar if_keyboard_callback(int ch)
4471612fc5aSmarkus {
4481612fc5aSmarkus 	struct ifstat *ifs;
4491612fc5aSmarkus 
45073baed14Scanacar 	switch (ch) {
451c5f96cb8Sdlg 	case 'd':
452c5f96cb8Sdlg 		if_set_errs(IF_ERR_QDROPS);
453c5f96cb8Sdlg 		break;
454c5f96cb8Sdlg 	case 'e':
455c5f96cb8Sdlg 		if_set_errs(IF_ERR_ERRORS);
456c5f96cb8Sdlg 		break;
457c5f96cb8Sdlg 	case 'f':
458c5f96cb8Sdlg 		if_set_errs(IF_ERR_SUM);
459c5f96cb8Sdlg 		break;
460c5f96cb8Sdlg 
46173baed14Scanacar 	case 'r':
4621612fc5aSmarkus 		for (ifs = ifstats; ifs < ifstats + nifs; ifs++)
4631612fc5aSmarkus 			ifs->ifs_old = ifs->ifs_now;
4641612fc5aSmarkus 		state = RUN;
46573baed14Scanacar 		gotsig_alarm = 1;
46673baed14Scanacar 
46773baed14Scanacar 		break;
46873baed14Scanacar 	case 'b':
4691612fc5aSmarkus 		state = BOOT;
4701612fc5aSmarkus 		for (ifs = ifstats; ifs < ifstats + nifs; ifs++)
4711612fc5aSmarkus 			bzero(&ifs->ifs_old, sizeof(ifs->ifs_old));
47273baed14Scanacar 		gotsig_alarm = 1;
47373baed14Scanacar 		break;
4745c280c62Smpf 	case 'B':
4755c280c62Smpf 		show_bits = !show_bits;
4765c280c62Smpf 		if (show_bits) {
4775c280c62Smpf 			FLD_IF_IBYTES->title = "IBITS";
4785c280c62Smpf 			FLD_IF_OBYTES->title = "OBITS";
4795c280c62Smpf 		} else {
4805c280c62Smpf 			FLD_IF_IBYTES->title = "IBYTES";
4815c280c62Smpf 			FLD_IF_OBYTES->title = "OBYTES";
4825c280c62Smpf 		}
4835c280c62Smpf 		gotsig_alarm = 1;
4845c280c62Smpf 		break;
48573baed14Scanacar 	case 't':
4861612fc5aSmarkus 		state = TIME;
48773baed14Scanacar 		gotsig_alarm = 1;
48873baed14Scanacar 		break;
48973baed14Scanacar 	default:
49073baed14Scanacar 		return keyboard_callback(ch);
491*479c151dSjsg 	}
49273baed14Scanacar 
49373baed14Scanacar 	return 1;
4941612fc5aSmarkus }
49573baed14Scanacar 
496