/*
 * Copyright (c) 2001 Hellmuth Michaelis. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *---------------------------------------------------------------------------
 *
 *	nifmon - network interface handling
 *	-----------------------------------
 *
 *      last edit-date: [Sat Sep  8 15:28:18 2001]
 *
 *---------------------------------------------------------------------------*/

#include "nifmon.h"

static int ifcount = 0;
static int sockfd = -1;
static int mrow;
static struct ifconf ifc;
static char buf[2048];
static int len;
static char *ptr;
static struct ifreq *ifr, *ifr1;
static struct sockaddr_in *sin;
static char *addr, *dstaddr;
static char lastaddr[] = "";
static size_t slen;
static int row;
static struct ifmibdata ifmd;
static int name[6];
static struct hostent he;
static struct hostent *hep;

static time_t lastchange;
static time_t prevchange;
static time_t lastdiff;
static time_t prevdiff;

static u_long ibs;
static u_long obs;
static u_long ips;
static u_long ops;

static time_t m_t;
static u_long ibm;
static u_long obm;
static u_long ipm;
static u_long opm;

static time_t h_t;
static u_long ibh;
static u_long obh;
static u_long iph;
static u_long oph;

static struct timeval tvlast;

/*---------------------------------------------------------------------------*
 *	initialize interface data
 *---------------------------------------------------------------------------*/
void
init_interface(char *interface)
{
	slen = sizeof(int);

	if (sysctlbyname("net.link.generic.system.ifcount", &ifcount, &slen, 0, 0) < 0)
	{
		perror("sysctl-ifcount");
		do_exit(1);
	}

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);

	ifc.ifc_len = sizeof(buf);
	ifc.ifc_req = (struct ifreq *) buf;
	ioctl(sockfd, SIOCGIFCONF, &ifc);

	for (ptr = buf; ptr < buf + ifc.ifc_len;)
	{
		ifr = (struct ifreq *) ptr;
		len = sizeof(struct sockaddr);

		if (ifr->ifr_addr.sa_len > len)
			len = ifr->ifr_addr.sa_len;

		ptr += sizeof(ifr->ifr_name) + len;

		if (strcmp(ifr->ifr_name, interface))
			continue;

		if (ifr->ifr_addr.sa_family == AF_INET)
		{
			ifr1 = ifr;

			if (ioctl(sockfd, SIOCGIFFLAGS, ifr1) < 0)
			{
				perror("FLAGS");
				do_exit(1);
			}

			if_flags = ifr1->ifr_flags;

			for (row = 1; row <= ifcount; row++)
			{
				slen = sizeof(ifmd);

				name[0] = CTL_NET;
				name[1] = PF_LINK;
				name[2] = NETLINK_GENERIC;
				name[3] = IFMIB_IFDATA;
				name[4] = row;
				name[5] = IFDATA_GENERAL;

				sysctl(name, 6, &ifmd, &slen, (void *) 0, 0);

				if (!strcmp(ifmd.ifmd_name, ifr->ifr_name))
				{
					mrow = row;

					prevchange =
						ifmd.ifmd_data.ifi_lastchange.
						tv_sec;

					lastchange = prevchange =
						ifmd.ifmd_data.ifi_lastchange.
						tv_sec;

					gettimeofday(&tvlast, NULL);

					m_t = h_t = tvlast.tv_sec;

					ibs = ibm = ibh =
						ifmd.ifmd_data.ifi_ibytes;
					obs = obm = obh =
						ifmd.ifmd_data.ifi_obytes;

					ips = ipm = iph =
						ifmd.ifmd_data.ifi_ipackets;
					ops = opm = oph =
						ifmd.ifmd_data.ifi_opackets;

					break;
				}
			}
			break;
		}
	}
}

/*---------------------------------------------------------------------------*
 *	update interface data
 *---------------------------------------------------------------------------*/
void
update_interface(char *interface)
{
	struct timeval tv;

	gettimeofday(&tv, NULL);

	if (tv.tv_sec == tvlast.tv_sec)
		return;

	if (tv.tv_sec == (tvlast.tv_sec + 1))
	{
		if (tv.tv_usec < tvlast.tv_usec)
			return;
	}

	tvlast = tv;

	ifc.ifc_len = sizeof(buf);
	ifc.ifc_req = (struct ifreq *) buf;
	ioctl(sockfd, SIOCGIFCONF, &ifc);

	for (ptr = buf; ptr < buf + ifc.ifc_len;)
	{
		ifr = (struct ifreq *) ptr;
		len = sizeof(struct sockaddr);

		if (ifr->ifr_addr.sa_len > len)
			len = ifr->ifr_addr.sa_len;

		ptr += sizeof(ifr->ifr_name) + len;

		if (strcmp(ifr->ifr_name, interface))
			continue;

		if (ifr->ifr_addr.sa_family == AF_INET)
		{
			ifr1 = ifr;

			if (ioctl(sockfd, SIOCGIFFLAGS, ifr1) < 0)
			{
				perror("FLAGS");
				do_exit(1);
			}

			sin = (struct sockaddr_in *) &ifr1->ifr_addr;
			addr = inet_ntoa(sin->sin_addr);

			if(strcmp(addr, lastaddr))
			{
				strcpy(lastaddr, addr);

				hep = &he;
	
				hep = gethostbyaddr((char *) &sin->sin_addr,
					      sizeof(sin->sin_addr), AF_INET);
	
				if (hep)
					hostname = hep->h_name;
				else
					hostname = "unknown hostname";
			}	
			mvwprintw(upper_w, V_IP, H_LOCIP, "%-15s", addr);
			mvwprintw(upper_w, V_IP, H_LOCHN, "%-36s", hostname);

			if (ifr1->ifr_flags & IFF_LOOPBACK)
			{
			}
			else if (ifr1->ifr_flags & IFF_POINTOPOINT)
			{
				if (ioctl(sockfd, SIOCGIFDSTADDR, ifr1) < 0)
				{
					perror("DST");
					do_exit(1);
				}

				sin =
					(struct sockaddr_in *) &ifr1->
					ifr_dstaddr;
				dstaddr = inet_ntoa(sin->sin_addr);
				mvwprintw(upper_w, V_IP, H_REMIP, "%-15s",
					  dstaddr);
			}
			else
			{
				if (ioctl(sockfd, SIOCGIFBRDADDR, ifr1) < 0)
				{
					perror("BRD");
					do_exit(1);
				}

				sin = (struct sockaddr_in *) &ifr1->ifr_broadaddr;
				dstaddr = inet_ntoa(sin->sin_addr);
				mvwprintw(upper_w, V_IP, H_REMIP, "%-15s",
					  dstaddr);
			}

			slen = sizeof(ifmd);

			name[0] = CTL_NET;
			name[1] = PF_LINK;
			name[2] = NETLINK_GENERIC;
			name[3] = IFMIB_IFDATA;
			name[4] = mrow;
			name[5] = IFDATA_GENERAL;

			sysctl(name, 6, &ifmd, &slen, (void *) 0, 0);

			if (ifmd.ifmd_data.ifi_ibytes > 1024000000)
				sprintf(buf, "%lu (%dG)",
					ifmd.ifmd_data.ifi_ibytes,
					(int)ifmd.ifmd_data.ifi_ibytes / 1024000000);
			else if (ifmd.ifmd_data.ifi_ibytes > 1024000)
				sprintf(buf, "%lu (%dM)",
					ifmd.ifmd_data.ifi_ibytes,
					(int)ifmd.ifmd_data.ifi_ibytes / 1024000);
			else if (ifmd.ifmd_data.ifi_ibytes > 1024)
				sprintf(buf, "%lu (%dk)",
					ifmd.ifmd_data.ifi_ibytes,
					(int)ifmd.ifmd_data.ifi_ibytes / 1024);
			else
				sprintf(buf, "%lu",
					ifmd.ifmd_data.ifi_ibytes);

			mvwprintw(upper_w, V_BIO, H_BIN, "%-24s", buf);

			if (ifmd.ifmd_data.ifi_obytes > 1024000000)
				sprintf(buf, "%lu (%dG)",
					ifmd.ifmd_data.ifi_obytes,
					(int)ifmd.ifmd_data.ifi_obytes / 1024000000);
			else if (ifmd.ifmd_data.ifi_obytes > 1024000)
				sprintf(buf, "%lu (%dM)",
					ifmd.ifmd_data.ifi_obytes,
					(int)ifmd.ifmd_data.ifi_obytes / 1024000);
			else if (ifmd.ifmd_data.ifi_obytes > 1024)
				sprintf(buf, "%lu (%dk)",
					ifmd.ifmd_data.ifi_obytes,
					(int)ifmd.ifmd_data.ifi_obytes / 1024);
			else
				sprintf(buf, "%lu",
					ifmd.ifmd_data.ifi_obytes);

			mvwprintw(upper_w, V_BIO, H_BOUT, "%-24s", buf);

			mvwprintw(upper_w, V_PIO, H_PIN,  "%lu",
				  ifmd.ifmd_data.ifi_ipackets);
			mvwprintw(upper_w, V_PIO, H_POUT, "%lu",
				  ifmd.ifmd_data.ifi_opackets);

			if (ifmd.ifmd_data.ifi_lastchange.tv_sec)
			{
				time_t diff;
				time_t d, h, m, r;

				diff = (time_t) difftime(tv.tv_sec,
							  ifmd.ifmd_data.
							  ifi_lastchange.
							  tv_sec);

				d = diff / (24 * 60 * 60);
				r = diff % (24 * 60 * 60);

				h = r / (60 * 60);
				r = r % (60 * 60);

				m = r / 60;

				sprintf(buf, "%24.24s (%d:%d:%d)",
					ctime(&ifmd.ifmd_data. ifi_lastchange.tv_sec),
					(int)d, (int)h, (int)m);

				mvwprintw(upper_w, V_LADCD, H_LADMCHG, "%-35s", buf);

				if (ifmd.ifmd_data.ifi_lastchange.tv_sec !=
				    lastchange)
				{
					prevdiff = lastdiff;
					prevchange = lastchange;
					lastchange =
						ifmd.ifmd_data.ifi_lastchange.
						tv_sec;

					d = prevdiff / (24 * 60 * 60);
					r = prevdiff % (24 * 60 * 60);

					h = r / (60 * 60);
					r = r % (60 * 60);

					m = r / 60;

					sprintf(buf, "%24.24s (%d:%d:%d)",
						ctime(&prevchange),
						(int)d, (int)h, (int)m);

					mvwprintw(upper_w, V_LADCD, H_PADMCHG, "%-35s", buf);
				}
				lastdiff = diff;
			}
			else
			{
				mvwprintw(upper_w, V_LADCD, H_LADMCHG,
					  "last administrative change time unsupported by driver");
			}
			mvwprintw(upper_w, V_IBYTE, H_SEC, "%-9lu",
				  ifmd.ifmd_data.ifi_ibytes - ibs);
			ibs = ifmd.ifmd_data.ifi_ibytes;

			mvwprintw(upper_w, V_OBYTE, H_SEC, "%-9lu",
				  ifmd.ifmd_data.ifi_obytes - obs);
			obs = ifmd.ifmd_data.ifi_obytes;

			mvwprintw(upper_w, V_IPACK, H_SEC, "%-9lu",
				  ifmd.ifmd_data.ifi_ipackets - ips);
			ips = ifmd.ifmd_data.ifi_ipackets;

			mvwprintw(upper_w, V_OPACK, H_SEC, "%-9lu",
				  ifmd.ifmd_data.ifi_opackets - ops);
			ops = ifmd.ifmd_data.ifi_opackets;

			if (tv.tv_sec > (m_t + 60))
			{
				m_t = tv.tv_sec;
				mvwprintw(upper_w, V_IBYTE, H_MIN, "%-16lu",
					  ifmd.ifmd_data.ifi_ibytes - ibm);
				ibm = ifmd.ifmd_data.ifi_ibytes;

				mvwprintw(upper_w, V_OBYTE, H_MIN, "%-16lu",
					  ifmd.ifmd_data.ifi_obytes - obm);
				obm = ifmd.ifmd_data.ifi_obytes;

				mvwprintw(upper_w, V_IPACK, H_MIN, "%-16lu",
					  ifmd.ifmd_data.ifi_ipackets - ipm);
				ipm = ifmd.ifmd_data.ifi_ipackets;

				mvwprintw(upper_w, V_OPACK, H_MIN, "%-16lu",
					  ifmd.ifmd_data.ifi_opackets - opm);
				opm = ifmd.ifmd_data.ifi_opackets;
			}

			if (tv.tv_sec > (h_t + (60 * 60)))
			{
				h_t = tv.tv_sec;

				mvwprintw(upper_w, V_IBYTE, H_HR, "%-16lu",
					  ifmd.ifmd_data.ifi_ibytes - ibh);
				ibh = ifmd.ifmd_data.ifi_ibytes;

				mvwprintw(upper_w, V_OBYTE, H_HR, "%-16lu",
					  ifmd.ifmd_data.ifi_obytes - obh);
				obh = ifmd.ifmd_data.ifi_obytes;

				mvwprintw(upper_w, V_IPACK, H_HR, "%-16lu",
					  ifmd.ifmd_data.ifi_ipackets - iph);
				iph = ifmd.ifmd_data.ifi_ipackets;

				mvwprintw(upper_w, V_OPACK, H_HR, "%-16lu",
					  ifmd.ifmd_data.ifi_opackets - oph);
				oph = ifmd.ifmd_data.ifi_opackets;
			}
			wrefresh(upper_w);
			break;
		}
	}
}

/* EOF */


syntax highlighted by Code2HTML, v. 0.9.1