/*
 * |-----------------------------------------------------------|
 * | Copyright (c) 1991, 1990 MIPS Computer Systems, Inc.      |
 * | All Rights Reserved                                       |
 * |-----------------------------------------------------------|
 * |          Restricted Rights Legend                         |
 * | Use, duplication, or disclosure by the Government is      |
 * | subject to restrictions as set forth in                   |
 * | subparagraph (c)(1)(ii) of the Rights in Technical        |
 * | Data and Computer Software Clause of DFARS 252.227-7013.  |
 * |         MIPS Computer Systems, Inc.                       |
 * |         950 DeGuigne Avenue                               |
 * |         Sunnyvale, California 94088-3650, USA             |
 * |-----------------------------------------------------------|
 */
#ident	"$Header: if.c,v 1.8.2.1 92/06/24 13:40:19 marker Exp $"

/*
 * Copyright (c) 1983, 1988 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted provided
 * that: (1) source distributions retain this entire copyright notice and
 * comment, and (2) distributions including binaries display the following
 * acknowledgement:  ``This product includes software developed by the
 * University of California, Berkeley and its contributors'' in the
 * documentation or other materials provided with the distribution and in
 * all advertising materials mentioning features or use of this software.
 * Neither the name of the University nor the names of its contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#ifndef lint
static char sccsid[] = "@(#)if.c	5.14 (Berkeley) 6/18/90";
#endif /* not lint */

#include <sys/types.h>
#include <sys/socket.h>

#include <net/if.h>
#include <net/if_dl.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netns/ns.h>
#include <netns/ns_if.h>
#include <netiso/iso.h>
#include <netiso/iso_var.h>

#include <stdio.h>
#include <signal.h>

#define	YES	1
#define	NO	0

extern	int tflag;
extern	int dflag;
extern	int nflag;
#ifdef _RISCOS
extern	int Vflag;
#endif _RISCOS
extern	char *interface;
extern	int unit;
extern	char *routename(), *netname(), *ns_phost();

/*
 * Print a description of the network interfaces.
 */
intpr(interval, ifnetaddr)
	int interval;
	off_t ifnetaddr;
{
	struct ifnet ifnet;
	union {
		struct ifaddr ifa;
		struct in_ifaddr in;
		struct ns_ifaddr ns;
		struct iso_ifaddr iso;
	} ifaddr;
#ifdef _RISCOS
	struct sockaddr ifaddr_ifa_addr;
	struct sockaddr ifaddr_ifa_dstaddr;
#endif _RISCOS
	off_t ifaddraddr;
	struct sockaddr *sa;
	char name[16];

	if (ifnetaddr == 0) {
		printf("ifnet: symbol not defined\n");
		return;
	}
	if (interval) {
		sidewaysintpr((unsigned)interval, ifnetaddr);
		return;
	}
	kvm_read(ifnetaddr, (char *)&ifnetaddr, sizeof ifnetaddr);
#ifdef _RISCOS
	printf(
	       (Vflag 
		   ? "%-5.5s %-5.5s %-11.11s %-15.15s %7.7s %5.5s %7.7s %5.5s"
		   : "%-5.5s %-5.5s %-11.11s %-15.15s %-7.7s %-5.5s %-7.7s %-5.5s"),
#else _RISCOS
	printf("%-5.5s %-5.5s %-11.11s %-15.15s %8.8s %5.5s %8.8s %5.5s",
#endif _RISCOS
		"Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs",
		"Opkts", "Oerrs");
#ifdef _RISCOS
	printf((Vflag ? " %6.6s" : " %-6.6s"), "Collis");
#else _RISCOS
	printf(" %5s", "Coll");
#endif _RISCOS
	if (tflag)
#ifdef _RISCOS
		printf((Vflag ? " %6.6s" : " %-6.6s"), "Timer");
#else _RISCOS
		printf(" %s", "Time");
#endif _RISCOS
	if (dflag)
		printf(" %s", "Drop");
	putchar('\n');
	ifaddraddr = 0;
	while (ifnetaddr || ifaddraddr) {
		struct sockaddr_in *sin;
		register char *cp;
		int n, m;
		char *index();
		struct in_addr inet_makeaddr();

		if (ifaddraddr == 0) {
			kvm_read(ifnetaddr, (char *)&ifnet, sizeof ifnet);
			kvm_read((off_t)ifnet.if_name, name, 16);
			name[15] = '\0';
			ifnetaddr = (off_t) ifnet.if_next;
			if (interface != 0 &&
			    (strcmp(name, interface) != 0 || unit != ifnet.if_unit))
				continue;
			cp = index(name, '\0');
#ifdef _RISCOS
			sprintf(cp,"%d",ifnet.if_unit);
			cp += strlen(cp);
#else _RISCOS
			*cp++ = ifnet.if_unit + '0';
#endif _RISCOS
			if ((ifnet.if_flags&IFF_UP) == 0)
				*cp++ = '*';
			*cp = '\0';
			ifaddraddr = (off_t)ifnet.if_addrlist;
		}
#ifdef _RISCOS
		if (Vflag) {
			col_printf_begin();
			col_printf(6,"%-5s ",name,0);
			col_printf(12,"%-5d ",ifnet.if_mtu,0);
		} else 
#endif _RISCOS
		{
			printf("%-5.5s %-5d ", name, ifnet.if_mtu);
		}
		if (ifaddraddr == 0) {
#ifdef _RISCOS
			if (Vflag) {
				col_printf(24,"%-11s ", "none",0);
				col_printf(40,"%-15s ", "none",0);
			} else {
				printf("%-11.11s ", "none");
				printf("%-15.15s ", "none");
			}
#else _RISCOS
			printf("%-11.11s ", "none");
			printf("%-15.15s ", "none");
#endif _RISCOS
		} else {
			kvm_read((off_t) ifaddraddr, &ifaddr, sizeof ifaddr);
#ifdef _RISCOS
			if (ifaddr.ifa.ifa_addr != 0) {
				kvm_read((off_t) ifaddr.ifa.ifa_addr,
					&ifaddr_ifa_addr,
					sizeof(ifaddr_ifa_addr));
			} else
				bzero(&ifaddr_ifa_addr,
				      sizeof(ifaddr_ifa_addr));
			ifaddr.ifa.ifa_addr = &ifaddr_ifa_addr;
			if (ifaddr.ifa.ifa_dstaddr != 0) {
				kvm_read((off_t) ifaddr.ifa.ifa_dstaddr,
					&ifaddr_ifa_dstaddr,
					sizeof(ifaddr_ifa_dstaddr));
			} else
				bzero(&ifaddr_ifa_dstaddr,
				      sizeof(ifaddr_ifa_dstaddr));
			ifaddr.ifa.ifa_dstaddr = &ifaddr_ifa_dstaddr;
			sa = &ifaddr_ifa_addr;
#else _RISCOS
#define CP(x) ((char *)(x))
			cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) +
				CP(&ifaddr); sa = (struct sockaddr *)cp;
#endif _RISCOS
			switch (sa->sa_family) {
			case AF_UNSPEC:
#ifdef _RISCOS
				if (Vflag) {
					col_printf(24,"%-11s ", "none",0);
					col_printf(40,"%-15s ", "none",0);
				} else {
					printf("%-11.11s ", "none");
					printf("%-15.15s ", "none");
				};
#else _RISCOS
				printf("%-11.11s ", "none");
				printf("%-15.15s ", "none");
#endif _RISCOS
				break;
			case AF_INET:
				sin = (struct sockaddr_in *)sa;
#ifdef notdef
				/* can't use inet_makeaddr because kernel
				 * keeps nets unshifted.
				 */
				in = inet_makeaddr(ifaddr.in.ia_subnet,
					INADDR_ANY);
#ifdef _RISCOS
				if (Vflag) {
					col_printf(24,"%-11s ", netname(in),0);
				} else {
					printf("%-11.11s ", netname(in));
				};
#else _RISCOS
				printf("%-11.11s ", netname(in));
#endif _RISCOS
#else notdef
#ifdef _RISCOS
				if (Vflag) {
					col_printf(24,"%-11s ",
						netname(htonl(ifaddr.in.ia_subnet),
							ifaddr.in.ia_subnetmask),
						   0);
				} else {
					printf("%-11.11s ",
						netname(htonl(ifaddr.in.ia_subnet),
							ifaddr.in.ia_subnetmask));
				}
#else _RISCOS
				printf("%-11.11s ",
						netname(htonl(ifaddr.in.ia_subnet),
							ifaddr.in.ia_subnetmask));
#endif _RISCOS
#endif notdef
#ifdef _RISCOS
				if (Vflag) {
					col_printf(40,"%-15s ",
						   routename(sin->sin_addr),0);
				} else {
					printf("%-15.15s ",
						   routename(sin->sin_addr));
				}
#else _RISCOS
				printf("%-15.15s ", routename(sin->sin_addr));
#endif _RISCOS
				break;
			case AF_NS:
				{
				struct sockaddr_ns *sns =
					(struct sockaddr_ns *)sa;
				u_long net;
				char netnum[8];
				char *ns_phost();
				*(union ns_net *) &net = sns->sns_addr.x_net;
				sprintf(netnum, "%lxH", ntohl(net));
				upHex(netnum);
#ifdef _RISCOS
				if (Vflag) {
					col_printf(24,"ns:%-8s ", netnum,0);
					col_printf(40,"%-15s ",ns_phost(sns),0);
				} else {
					printf("ns:%-8s ", netnum);

					printf("%-15s ",ns_phost(sns));
				}
#else _RISCOS
				printf("ns:%-8s ", netnum);
				printf("%-15s ", ns_phost(sns));
#endif _RISCOS
				}
				break;
			case AF_LINK:
				{
				struct sockaddr_dl *sdl =
					(struct sockaddr_dl *)sa;
				    cp = (char *)LLADDR(sdl);
				    n = sdl->sdl_alen;
				}
#ifdef _RISCOS
				if (Vflag) {
					col_printf(18,"<Link> ",0);
				} else {
					printf("<Link>");
				}
#else _RISCOS
				m = printf("<Link>");
#endif _RISCOS
				goto hexprint;

			default:
#ifdef _RISCOS
				if (Vflag) {
					col_printf(18,"af%2d: ",
						   sa->sa_family,0);
				} else {
					printf("af%2d: ",
						   sa->sa_family);
				}
#else _RISCOS
				m = printf("(%d)", sa->sa_family);
#endif _RISCOS
				for (cp = sa->sa_len + (char *)sa;
					--cp > sa->sa_data && (*cp == 0);) {}
				n = cp - sa->sa_data + 1;
				cp = sa->sa_data;
hexprint:
#ifdef _RISCOS
				m = 0;
				if (n <= 1)
					n--;
				else if (n <= 6) {
					while (--n) {
					    if (Vflag) {
						col_printf(-1,"%02x.", *cp++ & 0xff,0);
					    } else {
						printf("%02x.", *cp++ & 0xff);
					    }
					m += 3;
					};
				} else {
					while (--n) {
					    if (Vflag) {
						col_printf(-1,"%02x", *cp++ & 0xff,0);
					    } else {
						printf("%02x", *cp++ & 0xff);
					    }
					m += 2;
					};
				}
				if (n >= 0) {
				    if (Vflag) {
					col_printf(-1,"%02x", *cp & 0xff,0);
				    } else {
					printf("%02x", *cp & 0xff);
				    }
				    m += 2;
				}
				m = 22 - m;
				if (Vflag)
					col_printf(40," ",NULL,1);
				else {
					while (m-- > 0)
						putchar(' ');
				}
#else _RISCOS
				while (--n >= 0)
					m += printf("%x%c", *cp++ & 0xff,
						    n > 0 ? '.' : ' ');
				m = 28 - m;
				while (m-- > 0)
					putchar(' ');
#endif _RISCOS
				break;
			}
			ifaddraddr = (off_t)ifaddr.ifa.ifa_next;
		}
#ifdef _RISCOS
		if (Vflag) {
			col_printf(48,"%d ",ifnet.if_ipackets,1);
			col_printf(54,"%d ",ifnet.if_ierrors,1);
			col_printf(62,"%d ",ifnet.if_opackets,1);
			col_printf(68,"%d ",ifnet.if_oerrors,1);
			col_printf(74,"%d",ifnet.if_collisions,1);
			if (tflag) {
				col_printf(80," %d", ifnet.if_timer,1);
				if (dflag)
					col_printf(87, " %d", ifnet.if_snd.ifq_drops);
			} else if (dflag)
				col_printf(80, " %d", ifnet.if_snd.ifq_drops);
		} else {
			printf("%-7d %-5d %-7d %-5d %-6d",
			    ifnet.if_ipackets, ifnet.if_ierrors,
			    ifnet.if_opackets, ifnet.if_oerrors,
			    ifnet.if_collisions);
			if (tflag)
				printf(" %-6d", ifnet.if_timer);
		if (dflag)
			printf(" %-3d", ifnet.if_snd.ifq_drops);
		}
#else _RISCOS
		printf("%8d %5d %8d %5d %5d",
			    ifnet.if_ipackets, ifnet.if_ierrors,
			    ifnet.if_opackets, ifnet.if_oerrors,
			    ifnet.if_collisions);
		if (tflag)
			printf(" %3d", ifnet.if_timer);
		if (dflag)
			printf(" %3d", ifnet.if_snd.ifq_drops);
#endif _RISCOS
		putchar('\n');
	}
}

#ifdef _RISCOS
static int col_printf_pos = 0;

col_printf_begin()
{
	col_printf_pos = 0;
}


col_printf(des_pos,fmt,arg,right_justify)
	int	des_pos;
	char	*fmt;
	int	arg;
	int	right_justify;
{
	char	buf[100];
	int	buf_len;
	int	new_pos;
	char	*ep;

	sprintf(buf,fmt,arg);
	buf_len = strlen(buf);
	new_pos = col_printf_pos + buf_len;
	if (des_pos >= 0 &&
	    des_pos < new_pos &&
	    buf_len > 1 &&
	    buf[buf_len - 1] == ' ') {
		ep = buf + strlen(buf) - 1;
		while (ep > buf &&
			ep[-1] == ' ' &&
			des_pos < new_pos) {
			*ep = 0;
			ep--;
			buf_len--;
			new_pos--;
		};
	};
	if (right_justify) {
		while (new_pos < des_pos) {
			fputs(" ",stdout);
			col_printf_pos++;
			new_pos++;
		}
	}
	col_printf_pos = new_pos;
	fputs(buf,stdout);
}

#endif _RISCOS

#ifndef MAXIF
#ifdef _RISCOS
#define MAXIF	20
#else _RISCOS
#define	MAXIF	10
#endif _RISCOS
#endif MAXIF
struct	iftot {
	char	ift_name[16];		/* interface name */
	int	ift_ip;			/* input packets */
	int	ift_ie;			/* input errors */
	int	ift_op;			/* output packets */
	int	ift_oe;			/* output errors */
	int	ift_co;			/* collisions */
	int	ift_dr;			/* drops */
} iftot[MAXIF];

u_char	signalled;			/* set if alarm goes off "early" */

/*
 * Print a running summary of interface statistics.
 * Repeat display every interval seconds, showing statistics
 * collected over that interval.  Assumes that interval is non-zero.
 * First line printed at top of screen is always cumulative.
 */
sidewaysintpr(interval, off)
	unsigned interval;
	off_t off;
{
	struct ifnet ifnet;
	off_t firstifnet;
	register struct iftot *ip, *total;
	register int line;
	struct iftot *lastif, *sum, *interesting;
	int oldmask;
	int catchalarm();

	kvm_read(off, (char *)&firstifnet, sizeof (off_t));
	lastif = iftot;
	sum = iftot + MAXIF - 1;
	total = sum - 1;
	interesting = iftot;
	for (off = firstifnet, ip = iftot; off;) {
		char *cp;

		kvm_read(off, (char *)&ifnet, sizeof ifnet);
		ip->ift_name[0] = '(';
		kvm_read((off_t)ifnet.if_name, ip->ift_name + 1, 15);
		if (interface && strcmp(ip->ift_name + 1, interface) == 0 &&
		    unit == ifnet.if_unit)
			interesting = ip;
		ip->ift_name[15] = '\0';
		cp = index(ip->ift_name, '\0');
		sprintf(cp, "%d)", ifnet.if_unit);
		ip++;
		if (ip >= iftot + MAXIF - 2)
			break;
		off = (off_t) ifnet.if_next;
	}
	lastif = ip;

	(void)signal(SIGALRM, catchalarm);
	signalled = NO;
	(void)alarm(interval);
banner:
	printf("    input   %-6.6s    output       ", interesting->ift_name);
	if (lastif - iftot > 0) {
		if (dflag)
			printf("      ");
		printf("     input   (Total)    output");
	}
	for (ip = iftot; ip < iftot + MAXIF; ip++) {
		ip->ift_ip = 0;
		ip->ift_ie = 0;
		ip->ift_op = 0;
		ip->ift_oe = 0;
		ip->ift_co = 0;
		ip->ift_dr = 0;
	}
	putchar('\n');
	printf("%8.8s %5.5s %8.8s %5.5s %5.5s ",
		"packets", "errs", "packets", "errs", "colls");
	if (dflag)
		printf("%5.5s ", "drops");
	if (lastif - iftot > 0)
		printf(" %8.8s %5.5s %8.8s %5.5s %5.5s",
			"packets", "errs", "packets", "errs", "colls");
	if (dflag)
		printf(" %5.5s", "drops");
	putchar('\n');
	fflush(stdout);
	line = 0;
loop:
	sum->ift_ip = 0;
	sum->ift_ie = 0;
	sum->ift_op = 0;
	sum->ift_oe = 0;
	sum->ift_co = 0;
	sum->ift_dr = 0;
	for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) {
		kvm_read(off, (char *)&ifnet, sizeof ifnet);
		if (ip == interesting) {
			printf("%8d %5d %8d %5d %5d",
				ifnet.if_ipackets - ip->ift_ip,
				ifnet.if_ierrors - ip->ift_ie,
				ifnet.if_opackets - ip->ift_op,
				ifnet.if_oerrors - ip->ift_oe,
				ifnet.if_collisions - ip->ift_co);
			if (dflag)
				printf(" %5d",
				    ifnet.if_snd.ifq_drops - ip->ift_dr);
		}
		ip->ift_ip = ifnet.if_ipackets;
		ip->ift_ie = ifnet.if_ierrors;
		ip->ift_op = ifnet.if_opackets;
		ip->ift_oe = ifnet.if_oerrors;
		ip->ift_co = ifnet.if_collisions;
		ip->ift_dr = ifnet.if_snd.ifq_drops;
		sum->ift_ip += ip->ift_ip;
		sum->ift_ie += ip->ift_ie;
		sum->ift_op += ip->ift_op;
		sum->ift_oe += ip->ift_oe;
		sum->ift_co += ip->ift_co;
		sum->ift_dr += ip->ift_dr;
		off = (off_t) ifnet.if_next;
	}
	if (lastif - iftot > 0) {
		printf("  %8d %5d %8d %5d %5d",
			sum->ift_ip - total->ift_ip,
			sum->ift_ie - total->ift_ie,
			sum->ift_op - total->ift_op,
			sum->ift_oe - total->ift_oe,
			sum->ift_co - total->ift_co);
		if (dflag)
			printf(" %5d", sum->ift_dr - total->ift_dr);
	}
	*total = *sum;
	putchar('\n');
	fflush(stdout);
	line++;
	oldmask = sigblock(sigmask(SIGALRM));
	if (! signalled) {
		sigpause(0);
	}
	sigsetmask(oldmask);
	signalled = NO;
	(void)alarm(interval);
	if (line == 21)
		goto banner;
	goto loop;
	/*NOTREACHED*/
}

/*
 * Called if an interval expires before sidewaysintpr has completed a loop.
 * Sets a flag to not wait for the alarm.
 */
catchalarm()
{
	signalled = YES;
}
