netstat.c revision 8874
11590Srgrimes/*-
21590Srgrimes * Copyright (c) 1980, 1992, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 3. All advertising materials mentioning features or use of this software
141590Srgrimes *    must display the following acknowledgement:
151590Srgrimes *	This product includes software developed by the University of
161590Srgrimes *	California, Berkeley and its contributors.
171590Srgrimes * 4. Neither the name of the University nor the names of its contributors
181590Srgrimes *    may be used to endorse or promote products derived from this software
191590Srgrimes *    without specific prior written permission.
201590Srgrimes *
211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311590Srgrimes * SUCH DAMAGE.
321590Srgrimes */
331590Srgrimes
341590Srgrimes#ifndef lint
351590Srgrimesstatic char sccsid[] = "@(#)netstat.c	8.1 (Berkeley) 6/6/93";
361590Srgrimes#endif /* not lint */
371590Srgrimes
381590Srgrimes/*
391590Srgrimes * netstat
401590Srgrimes */
411590Srgrimes#include <sys/param.h>
421590Srgrimes#include <sys/socket.h>
431590Srgrimes#include <sys/socketvar.h>
441590Srgrimes#include <sys/mbuf.h>
451590Srgrimes#include <sys/protosw.h>
467715Sdg#include <sys/queue.h>
471590Srgrimes
481590Srgrimes#include <netinet/in.h>
491590Srgrimes#include <net/route.h>
501590Srgrimes#include <netinet/in_systm.h>
511590Srgrimes#include <netinet/ip.h>
521590Srgrimes#include <netinet/in_pcb.h>
531590Srgrimes#include <netinet/ip_icmp.h>
541590Srgrimes#include <netinet/icmp_var.h>
551590Srgrimes#include <netinet/ip_var.h>
561590Srgrimes#include <netinet/tcp.h>
571590Srgrimes#include <netinet/tcpip.h>
581590Srgrimes#include <netinet/tcp_seq.h>
591590Srgrimes#define TCPSTATES
601590Srgrimes#include <netinet/tcp_fsm.h>
611590Srgrimes#include <netinet/tcp_timer.h>
621590Srgrimes#include <netinet/tcp_var.h>
631590Srgrimes#include <netinet/tcp_debug.h>
641590Srgrimes#include <netinet/udp.h>
651590Srgrimes#include <netinet/udp_var.h>
661590Srgrimes
671590Srgrimes#include <netdb.h>
681590Srgrimes#include <stdlib.h>
691590Srgrimes#include <string.h>
701590Srgrimes#include <nlist.h>
711590Srgrimes#include <paths.h>
721590Srgrimes#include "systat.h"
731590Srgrimes#include "extern.h"
741590Srgrimes
751590Srgrimesstatic void enter __P((struct inpcb *, struct socket *, int, char *));
761590Srgrimesstatic char *inetname __P((struct in_addr));
771590Srgrimesstatic void inetprint __P((struct in_addr *, int, char *));
781590Srgrimes
791590Srgrimes#define	streq(a,b)	(strcmp(a,b)==0)
801590Srgrimes#define	YMAX(w)		((w)->maxy-1)
811590Srgrimes
821590SrgrimesWINDOW *
831590Srgrimesopennetstat()
841590Srgrimes{
851590Srgrimes	sethostent(1);
861590Srgrimes	setnetent(1);
871590Srgrimes	return (subwin(stdscr, LINES-5-1, 0, 5, 0));
881590Srgrimes}
891590Srgrimes
901590Srgrimesstruct netinfo {
911590Srgrimes	struct	netinfo *ni_forw, *ni_prev;
921590Srgrimes	short	ni_line;		/* line on screen */
931590Srgrimes	short	ni_seen;		/* 0 when not present in list */
941590Srgrimes	short	ni_flags;
951590Srgrimes#define	NIF_LACHG	0x1		/* local address changed */
961590Srgrimes#define	NIF_FACHG	0x2		/* foreign address changed */
971590Srgrimes	short	ni_state;		/* tcp state */
981590Srgrimes	char	*ni_proto;		/* protocol */
991590Srgrimes	struct	in_addr ni_laddr;	/* local address */
1001590Srgrimes	long	ni_lport;		/* local port */
1011590Srgrimes	struct	in_addr	ni_faddr;	/* foreign address */
1021590Srgrimes	long	ni_fport;		/* foreign port */
1031590Srgrimes	long	ni_rcvcc;		/* rcv buffer character count */
1041590Srgrimes	long	ni_sndcc;		/* snd buffer character count */
1051590Srgrimes};
1061590Srgrimes
1071590Srgrimesstatic struct {
1081590Srgrimes	struct	netinfo *ni_forw, *ni_prev;
1091590Srgrimes} netcb;
1101590Srgrimes
1111590Srgrimesstatic	int aflag = 0;
1121590Srgrimesstatic	int nflag = 0;
1131590Srgrimesstatic	int lastrow = 1;
1141590Srgrimesstatic	void enter(), inetprint();
1151590Srgrimesstatic	char *inetname();
1161590Srgrimes
1171590Srgrimesvoid
1181590Srgrimesclosenetstat(w)
1191590Srgrimes        WINDOW *w;
1201590Srgrimes{
1211590Srgrimes	register struct netinfo *p;
1221590Srgrimes
1231590Srgrimes	endhostent();
1241590Srgrimes	endnetent();
1251590Srgrimes	p = (struct netinfo *)netcb.ni_forw;
1261590Srgrimes	while (p != (struct netinfo *)&netcb) {
1271590Srgrimes		if (p->ni_line != -1)
1281590Srgrimes			lastrow--;
1291590Srgrimes		p->ni_line = -1;
1301590Srgrimes		p = p->ni_forw;
1311590Srgrimes	}
1321590Srgrimes        if (w != NULL) {
1331590Srgrimes		wclear(w);
1341590Srgrimes		wrefresh(w);
1351590Srgrimes		delwin(w);
1361590Srgrimes	}
1371590Srgrimes}
1381590Srgrimes
1391590Srgrimesstatic struct nlist namelist[] = {
1401590Srgrimes#define	X_TCB	0
1411590Srgrimes	{ "_tcb" },
1421590Srgrimes#define	X_UDB	1
1431590Srgrimes	{ "_udb" },
1441590Srgrimes	{ "" },
1451590Srgrimes};
1461590Srgrimes
1471590Srgrimesint
1481590Srgrimesinitnetstat()
1491590Srgrimes{
1501590Srgrimes	if (kvm_nlist(kd, namelist)) {
1511590Srgrimes		nlisterr(namelist);
1521590Srgrimes		return(0);
1531590Srgrimes	}
1541590Srgrimes	if (namelist[X_TCB].n_value == 0) {
1551590Srgrimes		error("No symbols in namelist");
1561590Srgrimes		return(0);
1571590Srgrimes	}
1581590Srgrimes	netcb.ni_forw = netcb.ni_prev = (struct netinfo *)&netcb;
1591590Srgrimes	protos = TCP|UDP;
1601590Srgrimes	return(1);
1611590Srgrimes}
1621590Srgrimes
1631590Srgrimesvoid
1641590Srgrimesfetchnetstat()
1651590Srgrimes{
1661590Srgrimes	register struct inpcb *prev, *next;
1671590Srgrimes	register struct netinfo *p;
1687715Sdg	struct inpcbhead head;
1691590Srgrimes	struct inpcb inpcb;
1701590Srgrimes	struct socket sockb;
1711590Srgrimes	struct tcpcb tcpcb;
1721590Srgrimes	void *off;
1731590Srgrimes	int istcp;
1741590Srgrimes
1751590Srgrimes	if (namelist[X_TCB].n_value == 0)
1761590Srgrimes		return;
1771590Srgrimes	for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw)
1781590Srgrimes		p->ni_seen = 0;
1791590Srgrimes	if (protos&TCP) {
1808874Srgrimes		off = NPTR(X_TCB);
1811590Srgrimes		istcp = 1;
1821590Srgrimes	}
1831590Srgrimes	else if (protos&UDP) {
1848874Srgrimes		off = NPTR(X_UDB);
1851590Srgrimes		istcp = 0;
1861590Srgrimes	}
1871590Srgrimes	else {
1881590Srgrimes		error("No protocols to display");
1891590Srgrimes		return;
1901590Srgrimes	}
1911590Srgrimesagain:
1927715Sdg	KREAD(off, &head, sizeof (struct inpcbhead));
1937715Sdg	for (next = head.lh_first; next != NULL; next = inpcb.inp_list.le_next) {
1941590Srgrimes		KREAD(next, &inpcb, sizeof (inpcb));
1951590Srgrimes		if (!aflag && inet_lnaof(inpcb.inp_laddr) == INADDR_ANY)
1961590Srgrimes			continue;
1971590Srgrimes		if (nhosts && !checkhost(&inpcb))
1981590Srgrimes			continue;
1991590Srgrimes		if (nports && !checkport(&inpcb))
2001590Srgrimes			continue;
2011590Srgrimes		KREAD(inpcb.inp_socket, &sockb, sizeof (sockb));
2021590Srgrimes		if (istcp) {
2031590Srgrimes			KREAD(inpcb.inp_ppcb, &tcpcb, sizeof (tcpcb));
2041590Srgrimes			enter(&inpcb, &sockb, tcpcb.t_state, "tcp");
2051590Srgrimes		} else
2061590Srgrimes			enter(&inpcb, &sockb, 0, "udp");
2071590Srgrimes	}
2081590Srgrimes	if (istcp && (protos&UDP)) {
2091590Srgrimes		istcp = 0;
2101590Srgrimes		off = NPTR(X_UDB);
2111590Srgrimes		goto again;
2121590Srgrimes	}
2131590Srgrimes}
2141590Srgrimes
2151590Srgrimesstatic void
2161590Srgrimesenter(inp, so, state, proto)
2171590Srgrimes	register struct inpcb *inp;
2181590Srgrimes	register struct socket *so;
2191590Srgrimes	int state;
2201590Srgrimes	char *proto;
2211590Srgrimes{
2221590Srgrimes	register struct netinfo *p;
2231590Srgrimes
2241590Srgrimes	/*
2251590Srgrimes	 * Only take exact matches, any sockets with
2261590Srgrimes	 * previously unbound addresses will be deleted
2271590Srgrimes	 * below in the display routine because they
2281590Srgrimes	 * will appear as ``not seen'' in the kernel
2291590Srgrimes	 * data structures.
2301590Srgrimes	 */
2311590Srgrimes	for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw) {
2321590Srgrimes		if (!streq(proto, p->ni_proto))
2331590Srgrimes			continue;
2341590Srgrimes		if (p->ni_lport != inp->inp_lport ||
2351590Srgrimes		    p->ni_laddr.s_addr != inp->inp_laddr.s_addr)
2361590Srgrimes			continue;
2371590Srgrimes		if (p->ni_faddr.s_addr == inp->inp_faddr.s_addr &&
2381590Srgrimes		    p->ni_fport == inp->inp_fport)
2391590Srgrimes			break;
2401590Srgrimes	}
2411590Srgrimes	if (p == (struct netinfo *)&netcb) {
2421590Srgrimes		if ((p = malloc(sizeof(*p))) == NULL) {
2431590Srgrimes			error("Out of memory");
2441590Srgrimes			return;
2451590Srgrimes		}
2461590Srgrimes		p->ni_prev = (struct netinfo *)&netcb;
2471590Srgrimes		p->ni_forw = netcb.ni_forw;
2481590Srgrimes		netcb.ni_forw->ni_prev = p;
2491590Srgrimes		netcb.ni_forw = p;
2501590Srgrimes		p->ni_line = -1;
2511590Srgrimes		p->ni_laddr = inp->inp_laddr;
2521590Srgrimes		p->ni_lport = inp->inp_lport;
2531590Srgrimes		p->ni_faddr = inp->inp_faddr;
2541590Srgrimes		p->ni_fport = inp->inp_fport;
2551590Srgrimes		p->ni_proto = proto;
2561590Srgrimes		p->ni_flags = NIF_LACHG|NIF_FACHG;
2571590Srgrimes	}
2581590Srgrimes	p->ni_rcvcc = so->so_rcv.sb_cc;
2591590Srgrimes	p->ni_sndcc = so->so_snd.sb_cc;
2601590Srgrimes	p->ni_state = state;
2611590Srgrimes	p->ni_seen = 1;
2621590Srgrimes}
2631590Srgrimes
2641590Srgrimes/* column locations */
2651590Srgrimes#define	LADDR	0
2661590Srgrimes#define	FADDR	LADDR+23
2671590Srgrimes#define	PROTO	FADDR+23
2681590Srgrimes#define	RCVCC	PROTO+6
2691590Srgrimes#define	SNDCC	RCVCC+7
2701590Srgrimes#define	STATE	SNDCC+7
2711590Srgrimes
2721590Srgrimes
2731590Srgrimesvoid
2741590Srgrimeslabelnetstat()
2751590Srgrimes{
2761590Srgrimes	if (namelist[X_TCB].n_type == 0)
2771590Srgrimes		return;
2781590Srgrimes	wmove(wnd, 0, 0); wclrtobot(wnd);
2791590Srgrimes	mvwaddstr(wnd, 0, LADDR, "Local Address");
2801590Srgrimes	mvwaddstr(wnd, 0, FADDR, "Foreign Address");
2811590Srgrimes	mvwaddstr(wnd, 0, PROTO, "Proto");
2821590Srgrimes	mvwaddstr(wnd, 0, RCVCC, "Recv-Q");
2831590Srgrimes	mvwaddstr(wnd, 0, SNDCC, "Send-Q");
2848874Srgrimes	mvwaddstr(wnd, 0, STATE, "(state)");
2851590Srgrimes}
2861590Srgrimes
2871590Srgrimesvoid
2881590Srgrimesshownetstat()
2891590Srgrimes{
2901590Srgrimes	register struct netinfo *p, *q;
2911590Srgrimes
2921590Srgrimes	/*
2931590Srgrimes	 * First, delete any connections that have gone
2941590Srgrimes	 * away and adjust the position of connections
2951590Srgrimes	 * below to reflect the deleted line.
2961590Srgrimes	 */
2971590Srgrimes	p = netcb.ni_forw;
2981590Srgrimes	while (p != (struct netinfo *)&netcb) {
2991590Srgrimes		if (p->ni_line == -1 || p->ni_seen) {
3001590Srgrimes			p = p->ni_forw;
3011590Srgrimes			continue;
3021590Srgrimes		}
3031590Srgrimes		wmove(wnd, p->ni_line, 0); wdeleteln(wnd);
3041590Srgrimes		q = netcb.ni_forw;
3051590Srgrimes		for (; q != (struct netinfo *)&netcb; q = q->ni_forw)
3061590Srgrimes			if (q != p && q->ni_line > p->ni_line) {
3071590Srgrimes				q->ni_line--;
3081590Srgrimes				/* this shouldn't be necessary */
3091590Srgrimes				q->ni_flags |= NIF_LACHG|NIF_FACHG;
3101590Srgrimes			}
3111590Srgrimes		lastrow--;
3121590Srgrimes		q = p->ni_forw;
3131590Srgrimes		p->ni_prev->ni_forw = p->ni_forw;
3141590Srgrimes		p->ni_forw->ni_prev = p->ni_prev;
3151590Srgrimes		free(p);
3161590Srgrimes		p = q;
3171590Srgrimes	}
3181590Srgrimes	/*
3191590Srgrimes	 * Update existing connections and add new ones.
3201590Srgrimes	 */
3211590Srgrimes	for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw) {
3221590Srgrimes		if (p->ni_line == -1) {
3231590Srgrimes			/*
3241590Srgrimes			 * Add a new entry if possible.
3251590Srgrimes			 */
3261590Srgrimes			if (lastrow > YMAX(wnd))
3271590Srgrimes				continue;
3281590Srgrimes			p->ni_line = lastrow++;
3291590Srgrimes			p->ni_flags |= NIF_LACHG|NIF_FACHG;
3301590Srgrimes		}
3311590Srgrimes		if (p->ni_flags & NIF_LACHG) {
3321590Srgrimes			wmove(wnd, p->ni_line, LADDR);
3331590Srgrimes			inetprint(&p->ni_laddr, p->ni_lport, p->ni_proto);
3341590Srgrimes			p->ni_flags &= ~NIF_LACHG;
3351590Srgrimes		}
3361590Srgrimes		if (p->ni_flags & NIF_FACHG) {
3371590Srgrimes			wmove(wnd, p->ni_line, FADDR);
3381590Srgrimes			inetprint(&p->ni_faddr, p->ni_fport, p->ni_proto);
3391590Srgrimes			p->ni_flags &= ~NIF_FACHG;
3401590Srgrimes		}
3411590Srgrimes		mvwaddstr(wnd, p->ni_line, PROTO, p->ni_proto);
3421590Srgrimes		mvwprintw(wnd, p->ni_line, RCVCC, "%6d", p->ni_rcvcc);
3431590Srgrimes		mvwprintw(wnd, p->ni_line, SNDCC, "%6d", p->ni_sndcc);
3441590Srgrimes		if (streq(p->ni_proto, "tcp"))
3451590Srgrimes			if (p->ni_state < 0 || p->ni_state >= TCP_NSTATES)
3461590Srgrimes				mvwprintw(wnd, p->ni_line, STATE, "%d",
3471590Srgrimes				    p->ni_state);
3481590Srgrimes			else
3491590Srgrimes				mvwaddstr(wnd, p->ni_line, STATE,
3501590Srgrimes				    tcpstates[p->ni_state]);
3511590Srgrimes		wclrtoeol(wnd);
3521590Srgrimes	}
3531590Srgrimes	if (lastrow < YMAX(wnd)) {
3541590Srgrimes		wmove(wnd, lastrow, 0); wclrtobot(wnd);
3551590Srgrimes		wmove(wnd, YMAX(wnd), 0); wdeleteln(wnd);	/* XXX */
3561590Srgrimes	}
3571590Srgrimes}
3581590Srgrimes
3591590Srgrimes/*
3601590Srgrimes * Pretty print an Internet address (net address + port).
3611590Srgrimes * If the nflag was specified, use numbers instead of names.
3621590Srgrimes */
3631590Srgrimesstatic void
3641590Srgrimesinetprint(in, port, proto)
3651590Srgrimes	register struct in_addr *in;
3661590Srgrimes	int port;
3671590Srgrimes	char *proto;
3681590Srgrimes{
3691590Srgrimes	struct servent *sp = 0;
3701590Srgrimes	char line[80], *cp, *index();
3711590Srgrimes
3721590Srgrimes	sprintf(line, "%.*s.", 16, inetname(*in));
3731590Srgrimes	cp = index(line, '\0');
3741590Srgrimes	if (!nflag && port)
3751590Srgrimes		sp = getservbyport(port, proto);
3761590Srgrimes	if (sp || port == 0)
3771590Srgrimes		sprintf(cp, "%.8s", sp ? sp->s_name : "*");
3781590Srgrimes	else
3791590Srgrimes		sprintf(cp, "%d", ntohs((u_short)port));
3801590Srgrimes	/* pad to full column to clear any garbage */
3811590Srgrimes	cp = index(line, '\0');
3821590Srgrimes	while (cp - line < 22)
3831590Srgrimes		*cp++ = ' ';
3841590Srgrimes	*cp = '\0';
3851590Srgrimes	waddstr(wnd, line);
3861590Srgrimes}
3871590Srgrimes
3881590Srgrimes/*
3891590Srgrimes * Construct an Internet address representation.
3908874Srgrimes * If the nflag has been supplied, give
3911590Srgrimes * numeric value, otherwise try for symbolic name.
3921590Srgrimes */
3931590Srgrimesstatic char *
3941590Srgrimesinetname(in)
3951590Srgrimes	struct in_addr in;
3961590Srgrimes{
3971590Srgrimes	char *cp = 0;
3981590Srgrimes	static char line[50];
3991590Srgrimes	struct hostent *hp;
4001590Srgrimes	struct netent *np;
4011590Srgrimes
4021590Srgrimes	if (!nflag && in.s_addr != INADDR_ANY) {
4031590Srgrimes		int net = inet_netof(in);
4041590Srgrimes		int lna = inet_lnaof(in);
4051590Srgrimes
4061590Srgrimes		if (lna == INADDR_ANY) {
4071590Srgrimes			np = getnetbyaddr(net, AF_INET);
4081590Srgrimes			if (np)
4091590Srgrimes				cp = np->n_name;
4101590Srgrimes		}
4111590Srgrimes		if (cp == 0) {
4121590Srgrimes			hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
4131590Srgrimes			if (hp)
4141590Srgrimes				cp = hp->h_name;
4151590Srgrimes		}
4161590Srgrimes	}
4171590Srgrimes	if (in.s_addr == INADDR_ANY)
4181590Srgrimes		strcpy(line, "*");
4191590Srgrimes	else if (cp)
4201590Srgrimes		strcpy(line, cp);
4211590Srgrimes	else {
4221590Srgrimes		in.s_addr = ntohl(in.s_addr);
4231590Srgrimes#define C(x)	((x) & 0xff)
4241590Srgrimes		sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
4251590Srgrimes			C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
4261590Srgrimes	}
4271590Srgrimes	return (line);
4281590Srgrimes}
4291590Srgrimes
4301590Srgrimesint
4311590Srgrimescmdnetstat(cmd, args)
4321590Srgrimes	char *cmd, *args;
4331590Srgrimes{
4341590Srgrimes	register struct netinfo *p;
4351590Srgrimes
4361590Srgrimes	if (prefix(cmd, "all")) {
4371590Srgrimes		aflag = !aflag;
4381590Srgrimes		goto fixup;
4391590Srgrimes	}
4401590Srgrimes	if  (prefix(cmd, "numbers") || prefix(cmd, "names")) {
4411590Srgrimes		int new;
4421590Srgrimes
4431590Srgrimes		new = prefix(cmd, "numbers");
4441590Srgrimes		if (new == nflag)
4451590Srgrimes			return (1);
4461590Srgrimes		p = netcb.ni_forw;
4471590Srgrimes		for (; p != (struct netinfo *)&netcb; p = p->ni_forw) {
4481590Srgrimes			if (p->ni_line == -1)
4491590Srgrimes				continue;
4501590Srgrimes			p->ni_flags |= NIF_LACHG|NIF_FACHG;
4511590Srgrimes		}
4521590Srgrimes		nflag = new;
4531590Srgrimes		goto redisplay;
4541590Srgrimes	}
4551590Srgrimes	if (!netcmd(cmd, args))
4561590Srgrimes		return (0);
4571590Srgrimesfixup:
4581590Srgrimes	fetchnetstat();
4591590Srgrimesredisplay:
4601590Srgrimes	shownetstat();
4611590Srgrimes	refresh();
4621590Srgrimes	return (1);
4631590Srgrimes}
464