1 /*	$OpenBSD: if.c,v 1.2 2004/11/25 23:08:13 deraadt Exp $ */
2 /*
3  * Copyright (c) 2004 Markus Friedl <markus@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 #include <sys/param.h>
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <sys/sysctl.h>
21 #include <net/if.h>
22 #include <net/if_dl.h>
23 #include <net/route.h>
24 
25 #include <stdlib.h>
26 
27 #include "systat.h"
28 #include "extern.h"
29 
30 static  enum state { BOOT, TIME, RUN } state = TIME;
31 
32 struct ifcount {
33 	u_long		ifc_ib;			/* input bytes */
34 	u_long		ifc_ip;			/* input packets */
35 	u_long		ifc_ie;			/* input errors */
36 	u_long		ifc_ob;			/* output bytes */
37 	u_long		ifc_op;			/* output packets */
38 	u_long		ifc_oe;			/* output errors */
39 	u_long		ifc_co;			/* collisions */
40 } sum;
41 
42 struct ifstat {
43 	char		ifs_name[IFNAMSIZ];	/* interface name */
44 	struct ifcount	ifs_cur;
45 	struct ifcount	ifs_old;
46 	struct ifcount	ifs_now;
47 } *ifstats;
48 
49 static	int nifs = 0;
50 
51 WINDOW *
openifstat(void)52 openifstat(void)
53 {
54 
55 	return (subwin(stdscr, LINES-5-1, 0, 5, 0));
56 }
57 
58 void
closeifstat(WINDOW * w)59 closeifstat(WINDOW *w)
60 {
61 
62 	if (w == NULL)
63 		return;
64 	wclear(w);
65 	wrefresh(w);
66 	delwin(w);
67 }
68 
69 int
initifstat(void)70 initifstat(void)
71 {
72 
73 	fetchifstat();
74 	return(1);
75 }
76 
77 #define UPDATE(x, y) do { \
78 		ifs->ifs_now.x = ifm.y; \
79 		ifs->ifs_cur.x = ifs->ifs_now.x - ifs->ifs_old.x; \
80 		sum.x += ifs->ifs_cur.x; \
81 		if (state == TIME) \
82 			ifs->ifs_old.x = ifs->ifs_now.x; \
83 	} while(0)
84 
85 
86 void
rt_getaddrinfo(struct sockaddr * sa,int addrs,struct sockaddr ** info)87 rt_getaddrinfo(struct sockaddr *sa, int addrs, struct sockaddr **info)
88 {
89 	int i;
90 
91 	for (i = 0; i < RTAX_MAX; i++) {
92 		if (addrs & (1 << i)) {
93 			info[i] = sa;
94 			sa = (struct sockaddr *) ((char *)(sa) +
95 			    roundup(sa->sa_len, sizeof(long)));
96 		} else
97 			info[i] = NULL;
98 	}
99 }
100 
101 void
fetchifstat(void)102 fetchifstat(void)
103 {
104 	struct ifstat *newstats, *ifs;
105 	struct if_msghdr ifm;
106 	struct sockaddr *info[RTAX_MAX];
107 	struct sockaddr_dl *sdl;
108 	char *buf, *next, *lim;
109 	int mib[6], i;
110 	size_t need;
111 
112 	mib[0] = CTL_NET;
113 	mib[1] = AF_ROUTE;
114 	mib[2] = 0;
115 	mib[3] = 0;
116 	mib[4] = NET_RT_IFLIST;
117 	mib[5] = 0;
118 
119 	if (sysctl(mib, 6, NULL, &need, NULL, 0) == -1)
120 		return;
121 	if ((buf = malloc(need)) == NULL)
122 		return;
123 	if (sysctl(mib, 6, buf, &need, NULL, 0) == -1) {
124 		free(buf);
125 		return;
126 	}
127 
128 	bzero(&sum, sizeof(sum));
129 
130 	lim = buf + need;
131 	for (next = buf; next < lim; next += ifm.ifm_msglen) {
132 		bcopy(next, &ifm, sizeof ifm);
133 		if (ifm.ifm_type != RTM_IFINFO ||
134 		   !(ifm.ifm_addrs & RTA_IFP))
135 			continue;
136 		if (ifm.ifm_index >= nifs) {
137 			if ((newstats = realloc(ifstats, (ifm.ifm_index + 4) *
138 			    sizeof(struct ifstat))) == NULL)
139 				continue;
140 			ifstats = newstats;
141 			for (; nifs < ifm.ifm_index + 4; nifs++)
142 				ifstats[nifs].ifs_name[0] = '\0';
143 		}
144 		ifs = &ifstats[ifm.ifm_index];
145 		if (ifs->ifs_name[0] == '\0') {
146 			bzero(&info, sizeof(info));
147 			rt_getaddrinfo(
148 			    (struct sockaddr *)((struct if_msghdr *)next + 1),
149 			    ifm.ifm_addrs, info);
150 			if ((sdl = (struct sockaddr_dl *)info[RTAX_IFP])) {
151 				if (sdl->sdl_family == AF_LINK &&
152 				    sdl->sdl_nlen > 0)
153 					strlcpy(ifs->ifs_name,
154 					    sdl->sdl_data,
155 					    sizeof(ifs->ifs_name));
156 			}
157 			if (ifs->ifs_name[0] == '\0')
158 				continue;
159 		}
160 		UPDATE(ifc_ip, ifm_data.ifi_ipackets);
161 		UPDATE(ifc_ib, ifm_data.ifi_ibytes);
162 		UPDATE(ifc_ie, ifm_data.ifi_ierrors);
163 		UPDATE(ifc_op, ifm_data.ifi_opackets);
164 		UPDATE(ifc_ob, ifm_data.ifi_obytes);
165 		UPDATE(ifc_oe, ifm_data.ifi_oerrors);
166 		UPDATE(ifc_co, ifm_data.ifi_collisions);
167 	}
168 	free(buf);
169 }
170 
171 #define INSET 0
172 
173 void
labelifstat(void)174 labelifstat(void)
175 {
176 
177 	wmove(wnd, 0, 0); wclrtobot(wnd);
178 
179 	mvwaddstr(wnd, 1, INSET, "Interfaces");
180 	mvwaddstr(wnd, 1, INSET+15, "Ibytes");
181 	mvwaddstr(wnd, 1, INSET+27, "Ipkts");
182 	mvwaddstr(wnd, 1, INSET+34, "Ierrs");
183 	mvwaddstr(wnd, 1, INSET+46, "Obytes");
184 	mvwaddstr(wnd, 1, INSET+58, "Opkts");
185 	mvwaddstr(wnd, 1, INSET+65, "Oerrs");
186 	mvwaddstr(wnd, 1, INSET+74, "Colls");
187 }
188 
189 #define FMT "%-10.10s %10lu %10lu %6lu   %10lu %10lu %6lu   %6lu "
190 
191 void
showifstat(void)192 showifstat(void)
193 {
194 	int row;
195 	struct ifstat *ifs;
196 
197 	row = 2;
198 	wmove(wnd, 0, 0); wclrtoeol(wnd);
199 	for (ifs = ifstats; ifs < ifstats + nifs; ifs++) {
200 		if (ifs->ifs_name[0] == '\0')
201 			continue;
202 		mvwprintw(wnd, row++, INSET, FMT,
203 		    ifs->ifs_name,
204 		    ifs->ifs_cur.ifc_ib,
205 		    ifs->ifs_cur.ifc_ip,
206 		    ifs->ifs_cur.ifc_ie,
207 		    ifs->ifs_cur.ifc_ob,
208 		    ifs->ifs_cur.ifc_op,
209 		    ifs->ifs_cur.ifc_oe,
210 		    ifs->ifs_cur.ifc_co);
211 	}
212 	mvwprintw(wnd, row++, INSET, FMT,
213 	    "Totals",
214 	    sum.ifc_ib,
215 	    sum.ifc_ip,
216 	    sum.ifc_ie,
217 	    sum.ifc_ob,
218 	    sum.ifc_op,
219 	    sum.ifc_oe,
220 	    sum.ifc_co);
221 }
222 
223 int
cmdifstat(char * cmd,char * args)224 cmdifstat(char *cmd, char *args)
225 {
226 	struct ifstat *ifs;
227 
228 	if (prefix(cmd, "run")) {
229 		if (state != RUN)
230 			for (ifs = ifstats; ifs < ifstats + nifs; ifs++)
231 				ifs->ifs_old = ifs->ifs_now;
232 		state = RUN;
233 		return (1);
234 	}
235 	if (prefix(cmd, "boot")) {
236 		state = BOOT;
237 		for (ifs = ifstats; ifs < ifstats + nifs; ifs++)
238 			bzero(&ifs->ifs_old, sizeof(ifs->ifs_old));
239 		return (1);
240 	}
241 	if (prefix(cmd, "time")) {
242 		state = TIME;
243 		return (1);
244 	}
245 	if (prefix(cmd, "zero")) {
246 		if (state == RUN)
247 			for (ifs = ifstats; ifs < ifstats + nifs; ifs++)
248 				ifs->ifs_old = ifs->ifs_now;
249 		return (1);
250 	}
251 	return (1);
252 }
253