#!/usr/bin/perl
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
# John Chambers' SNMP script.  This can be put into your web server's cgi-bin #
# directory, and will return as much of the data for SNMP MIB-I and MIB-II as #
# it can find on your system.  This script is useful for two things:          #
#                                                                             #
# 1. Do you need to test your SNMP agent, and verify that it is returning the #
# correct data? This script returns the data in a form that a perl script can #
# easily parse, making it easy to verify the results of snmpget, snmpnext  or #
# snmpwalk.                                                                   #
#                                                                             #
# 2. Do you want to avoid the long development time that SNMP always entails? #
# You can take part in the effort to wipe out SNMP  in  our  lifetime.   This #
# script  lets  you  dispense with SNMP on any machine that has a web server. #
# (And who doesn't have one nowadays?) Adding new variables  here  is  a  lot #
# easier than futzing with ASN.1 MIB files.                                   #
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
# After dropping this script into your server's directory, you can invoke  it #
# from  a  web browser by appending variables to the script's name, separated #
# by a slashes, commas, or the ?___+___+___ notation:                         #
#                                                                             #
# Return the entire interfaces group:                                         #
#   http://foo.bar.com/cgi-bin/snmp/interfaces                                #
#   http://foo.bar.com/cgi-bin/snmp?interfaces                                #
#                                                                             #
# Return the system and tcp group:                                            #
#   http://foo.bar.com/cgi-bin/snmp/system,tcp                                #
#   http://foo.bar.com/cgi-bin/snmp?system+tcp                                #
#                                                                             #
# Return sysName.0, sysDescr.0, ifNumber.0 and the ifTable group:             #
#   http://foo.bar.com/cgi-bin/snmp/sysName/sysDescr/ifNumber/ifTable         #
#   http://foo.bar.com/cgi-bin/snmp/sysName?sysDescr+ifNumber+ifTable         #
#   http://foo.bar.com/cgi-bin/snmp/sysName,sysDescr,ifNumber,ifTable         #
#                                                                             #
# Note the various syntaxes that may be used to  pass  in  the  list  of  MIB #
# groups  or  variables.   The  HTTP  protocol  has several different ways of #
# passing parameters to a CGI script such as this one.  I've  tried  to  make #
# sure  that  all  the syntaxes work, and that you may use commas with any of #
# them in the usual manner.                                                   #
#                                                                             #
# Author: John Chambers <jc@trillian.mit.edu> <jc@minya.bcs.org>                 #
# Tested-On: Linux 1.2.13                                                     #
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #

require "oidorder.pm";

print "Content-type: text/html\n";
print "\n";
print "<html>\n";
print "<title>SNMP Report</title>\n";
print "<body>\n";

$| = 1;
$D = $ENV{'D_snmp'} || $ENV{'V_snmp'} || 1;
$ipadp  = '\d+\.\d+\.\d+\.\d+';
$ipptp = "$ipadp:\\d+";
$ethadp = '..:..:..:..:..:..';
$ifpat0 = "(\\w+)\\s+(\\d+)\\s+(\\d+)\\s+$ipadp\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)";
$ifpat1 = '(\w+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\w+)$';

&getname(0);
print "<H1>SNMP Report from $sysName:</H1>\n";

$; = '","';

if ($D>1) {
	print "<br>argc is $#ARGV, argv is \"@ARGV\"\n";
	print "<br>\$0 is \"$0\"\n";
	print "<hr>\n";
}
if ($D > -1) {
	$ENV{'AUTH_TYPE'}         = '' if !$ENV{'AUTH_TYPE'};
	$ENV{'CONTENT_LENGTH'}    = '' if !$ENV{'CONTENT_LENGTH'};
	$ENV{'CONTENT_TYPE'}      = '' if !$ENV{'CONTENT_TYPE'};
	$ENV{'GATEWAY_INTERFACE'} = '' if !$ENV{'GATEWAY_INTERFACE'};
	$ENV{'HTTP_ACCEPT'}       = '' if !$ENV{'HTTP_ACCEPT'};
	$ENV{'PATH_INFO'}         = '' if !$ENV{'PATH_INFO'};
	$ENV{'PATH_TRANSLATED'}   = '' if !$ENV{'PATH_TRANSLATED'};
	$ENV{'QUERY_STRING'}      = '' if !$ENV{'QUERY_STRING'};
	$ENV{'REMOTE_ADDR'}       = '' if !$ENV{'REMOTE_ADDR'};
	$ENV{'REMOTE_HOST'}       = '' if !$ENV{'REMOTE_HOST'};
	$ENV{'REMOTE_USER'}       = '' if !$ENV{'REMOTE_USER'};
	$ENV{'REQUEST_METHOD'}    = '' if !$ENV{'REQUEST_METHOD'};
	$ENV{'SCRIPT_NAME'}       = '' if !$ENV{'SCRIPT_NAME'};
	$ENV{'SERVER_NAME'}       = '' if !$ENV{'SERVER_NAME'};
	$ENV{'SERVER_PORT'}       = '' if !$ENV{'SERVER_PORT'};
	$ENV{'SERVER_PROTOCOL'}   = '' if !$ENV{'SERVER_PROTOCOL'};
	$ENV{'SERVER_SOFTWARE'}   = '' if !$ENV{'SERVER_SOFTWARE'};
}
if ($D>1) {
	print "<dl compact>\n";
	for $v (sort keys %ENV) {
		print "<dt>$v<dd>\"$ENV{$v}\"\n";
	}
}
# We recognize these MIB symbols (groups and variables).  The value is
# a 1-char type indicator:  'v' for variables, 'g' for groups, and 't'
# for tables.
%mib = (
	'snmp', 'g',
	'system', 'g',
	'interfaces', 'g',
	'at', 'g',
	'ip', 'g',
	'icmp', 'g',
	'tcp', 'g',
	'udp', 'g',
	'egp', 'g',
	'sysDescr', 'v',
	'sysObjectID', 'v',
	'sysUpTime', 'v',
	'sysContact', 'v',
	'sysName', 'v',
	'sysLocation', 'v',
	'sysServices', 'v',
	'ifNumber', 'v',
	'ifTable','t',
	'ifEntry', 'e',
	'ifIndex', 'v',
	'ifDescr', 'v',
	'ifType', 'v',
	'ifMtu', 'v',
	'ifSpeed', 'v',
	'ifPhysAddress', 'v',
	'ifAdminStat', 'v',
	'ifOperStat', 'v',
	'ifLastChange', 'v',
	'ifInOctets', 'v',
	'ifInUcastPkts', 'v',
	'ifInNUcastPkts', 'v',
	'ifInDiscards', 'v',
	'ifInErrors', 'v',
	'ifInUnknownProtos', 'v',
	'ifOutOctets', 'v',
	'ifOutUcastPkts', 'v',
	'ifOutNUcastPkts', 'v',
	'ifOutDiscards', 'v',
	'ifOutErrors', 'v',
	'ifOutQLen', 'v',
	'atTable','t',
	'atEntry', 'e',
	'atIfIndex', 'v',
	'atPhysAddress', 'v',
	'atNetAddress', 'v',
	'ipForwarding', 'v',
	'ipDefaultTTL', 'v',
	'ipInReceives', 'v',
	'ipInHdrErrors', 'v',
	'ipInAddrErrors', 'v',
	'ipForwDatagrams', 'v',
	'ipInUnknownProtos', 'v',
	'ipInDiscards', 'v',
	'ipInDelivers', 'v',
	'ipOutRequests', 'v',
	'ipOutDiscards', 'v',
	'ipOutNoRoutes', 'v',
	'ipReasmTimeout', 'v',
	'ipReasmRecords', 'v',
	'ipReasmOKs', 'v',
	'ipReasmFails', 'v',
	'ipFragOKs', 'v',
	'ipFragFails', 'v',
	'ipFragCreates', 'v',
	'ipAddrTable','t',
	'ipAddrEntry', 'e',
	'ipAdEntAddr', 'v',
	'ipAdEntIfIndex', 'v',
	'ipAdEntNetMask', 'v',
	'ipAdEntBcastAddr', 'v',
	'ipRoutingTable','t',
	'ipRouteEntry', 'e',
	'ipRouteDest', 'v',
	'ipRouteIfIndex', 'v',
	'ipRouteMetric1', 'v',
	'ipRouteMetric2', 'v',
	'ipRouteMetric3', 'v',
	'ipRouteMetric4', 'v',
	'ipRouteNextHop', 'v',
	'ipRouteType', 'v',
	'ipRouteProto', 'v',
	'ipRouteAge', 'v',
	'icmpInMsgs', 'v',
	'icmpInErrors', 'v',
	'icmpInDestUnreachs', 'v',
	'icmpInTimeExcds', 'v',
	'icmpInParmProbs', 'v',
	'icmpInSrcQuenchs', 'v',
	'icmpInRedirects', 'v',
	'icmpInEchos', 'v',
	'icmpInEchoReps', 'v',
	'icmpInTimestamps', 'v',
	'icmpInTimestampReps', 'v',
	'icmpInAddrMasks', 'v',
	'icmpInAddrMaskReps', 'v',
	'icmpOutMsgs', 'v',
	'icmpOutErrors', 'v',
	'icmpOutDestUnreachs', 'v',
	'icmpOutTimeExcds', 'v',
	'icmpOutParmProbs', 'v',
	'icmpOutSrcQuenchs', 'v',
	'icmpOutRedirects', 'v',
	'icmpOutEchos', 'v',
	'icmpOutEchoReps', 'v',
	'icmpOutTimestamps', 'v',
	'icmpOutTimestampReps', 'v',
	'icmpOutAddrMasks', 'v',
	'icmpOutAddrMaskReps', 'v',
	'tcpRtoAlgorithm', 'v',
	'tcpRtoMin', 'v',
	'tcpRtoMax', 'v',
	'tcpMaxConn', 'v',
	'tcpActiveOpens', 'v',
	'tcpPassiveOpens', 'v',
	'tcpAttemptFails', 'v',
	'tcpEstabResets', 'v',
	'tcpCurrEstab', 'v',
	'tcpInSegs', 'v',
	'tcpOutSegs', 'v',
	'tcpRetransSegs', 'v',
	'tcpConnTable','t',
	'tcpConnEntry', 'e',
	'tcpConnState', 'v',
	'tcpConnLocalAddress', 'v',
	'tcpConnLocalPort', 'v',
	'tcpConnRemAddress', 'v',
	'tcpConnRemPort', 'v',
	'udpInDatagrams', 'v',
	'udpNoPorts', 'v',
	'udpInErrors', 'v',
	'udpOutDatagrams', 'v',
	'egpInMsgs', 'v',
	'egpInErrors', 'v',
	'egpOutMsgs', 'v',
	'egpOutErrors', 'v',
	'egpNeighTable','t',
	'egpNeighEntry', 'e',
	'egpNeighState', 'v',
	'egpNeighAddr', 'v',
); 
$, = '.';
print "<br>#	PATH_INFO=\"$ENV{'PATH_INFO'}\"\n" if $D>1;
($vars = $ENV{'PATH_INFO'}) =~ s"/","g;
print "<br>#	vars=\"$vars\"\n" if $D>1;
for $arg (@ARGV) {
	$vars .= ',' . $arg;
	print "<br>#	vars=\"$vars\"\n" if $D>1;
}
@vars = split(/[\s,\/]+/,$vars);
print "<br>#	vars=(@vars)\n" if $D>1;
print "<dl compact>\n";
@vars = ('system') if !@vars;
for $var (@vars) {
	print "<br>#	var=\"$var\"\n" if $D>1;
	$var =~ s/^\.+//;
	if (@flds  = split(/\./,$var)) {
		print "<br>#	flds=(@flds)\n" if $D>1;
		if ($#flds < 1) {
			$flds[1] = 0;
			print "<br>#	flds=(@flds)\n" if $D>1;
		}
		&get(@flds);
	}
}
print "</dl>\n";
print "</body>\n";
print "</html>\n";

exit 0;

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
sub get {
	local($v) = shift;
	local($c,$t,$x);
	print "<br>#get	v=\"$v\" instance=(@_)\n" if $D>1;
	if ($t = $mib{$v}) {
		if ($t eq 'g' || $t eq 't' || $t eq 'e') {
			$c = "&$v()";
			print "<br>#get	Group c=\"$c\"\n" if $D>1;
			$x = eval($c);
			print "<br>$v.@_\t$x\n" if $D>1;
		} elsif ($t eq 'v') {
			$c = "&$v(@_)";
			print "<br>#get	Variable c=\"$c\"\n" if $D>1;
			$x = eval($c);
			print "<br>#get	x=$x\n" if $D>1;
		} else {
			print "<br>#get	t=$t unknown for v=\"$v\"\n" if $D>1;
		}
	}
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
# Figure out this system's primary name, and leave it in $sysName.
sub getname {
	if ($sysName = `hostname`) {
		print "<br>#sysName hostname gave $sysName" if $D>1;
	} elsif ($sysName = `uname -n`) {
		print "<br>#sysName uname -n gave $sysName" if $D>1;
	} else {
		$sysName = 'localhost';
	}
	$sysName =~ s/\s+$//;
	$sysName;
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
# This routine HTMLizes strings for transmission to a client.  We should try
# to find a general-purpose, "correct" routine for this.
sub html {
	local($x) = @_;
	(local($y) = $x)  =~ s/\s+$//;
	$y =~ s/</\&lt;/g;
	$y =~ s/>/\&gt;/g;
	$y;
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
sub snmp {
	&system();
	&interfaces();
	&at();
	&ip();
	&icmp();
	&tcp();
	&udp();
	&egp();
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
sub system { # group.
	print "<dt>system:<dd>\n";
	print "<dl compact>\n";
	&sysDescr(0);
	&sysObjectID(0);
	&sysUpTime(0);
	&sysContact(0);
	&sysName(0);
	&sysLocation(0);
	&sysServices(0);
	print "</dl><!-- system -->\n";
}

sub sysDescr {
	print "<br>#sysDescr args=(@_)\n" if $D>1;
	local($d);
	if ($d = `uname -a`) {
		print "<br>#sysDescr uname -a gave $d" if $D>1;
	} elsif ($d = `hostname`) {
		print "<br>#sysDescr hostname gave $d" if $D>1;
	} else {
		$d = 'localhost';
	}
	$d =~ s/\s+$//;
	print "<dt>sysDescr<dd>$d\n";
}

sub sysObjectID {
	print "<dt>sysObjectID<dd>snmp.html\n";
}

sub sysUpTime {
	local($t,$x);
	print "<br>#sysName args=(@_)\n" if $D>1;
	if ($t = `uptime`) {
		print "<br>#sysUpTime uptime gave $t" if $D>1;
		if (($d,$h,$m) = ($t =~ /(\d+) days,*\s*(\d+):(\d+)/)) {
			$x = (((($d * 24) + $h) * 60) + $m) * 60 * 100;
		}
	}
	print "<dt>sysUpTime<dd>$x (${d}d${h}h${m}m)\n";
}

sub sysContact {
	local($x) = `cat sysContact`;
	$x = &html($x);
	print "<dt>sysContact<dd>$x\n";
}

sub sysLocation {
	local($x) = `cat sysLocation`;
	$x = &html($x);
	print "<dt>sysLocation<dd>$x\n";
}

sub sysName {
	print "<br>#sysName args=(@_)\n" if $D>1;
	$sysName = &getname() if !$sysName;
	print "<dt>sysName<dd>$sysName\n";
}

sub sysServices {
	print "<dt>sysServices<dd>128\n";
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
sub interfaces { # group.
	print "<dt>interfaces:<dd>\n";
	print "<dl compact>\n";
	&ifNumber();
	&ifTable();
	print "</dl><!-- interfaces -->\n";
}

sub ifNumber {
	local($n) = `netstat -in | wc`;
	$ifNumber = $n -= 2;
	print "<dt>ifNumber.0<dd>$n\n";
}

sub iftbl {
	local($ifnt,$i);
	local(@iftb) = `netstat -in`;
	local($Iface,$MTU,$Met,$RX_OK,$RX_ERR,$RX_DRP,$RX_OVR,$TX_OK,$TX_ERR,$TX_DRP,$TX_OVR,$Flags);
	print "<br>#iftbl ...\n" if $D>1;
	for $ifnt (@iftb) {
		if ($ifnt =~ /^Kernel/) {
		} elsif ($ifnt =~ /^Iface\s+MTU/) {	# Linux netstat.
		} elsif (($Iface,$MTU,$Network,$Address,$Ipkts,$Ierrs,$Opkts,$Oerrs,$Collis)
				= ($ifnt =~ $ifpat0)) {	# BSD-style netstat data line..
			++$i;
			print "<br>#iftbl i=$i.\n" if $D>1;
			$ipAdEntIfIndex{$i} = $atIfIndex{$i} = $ifIndex{$i} = $ifIndex{$Iface} = $i;
			$ifDescr{$i} = $Iface;
			$ifMtu{$i} = $MTU;
			$ifInPkts{$i} = $Ipkts;
			$ifOutPkts{$i} = $Opkts;
			$ifInErrors{$i} = $Ierrs;
			$ifOutErrors{$i} = $Oerrs;
		} elsif (($Iface,$MTU,$Met,$RX_OK,$RX_ERR,$RX_DRP,$RX_OVR,$TX_OK,$TX_ERR,$TX_DRP,$TX_OVR,$Flags)
				= ($ifnt =~ $ifpat1)) {	# Linux netstat data line..
			++$i;
			print "<br>#iftbl i=$i.\n" if $D>1;
			$ipAdEntIfIndex{$i} = $atIfIndex{$i} = $ifIndex{$i} = $ifIndex{$Iface} = $i;
			$ifDescr{$i} = $Iface;
			$ifMtu{$i} = $MTU;
			$ifInPkts{$i} = $RX_OK;
			$ifOutPkts{$i} = $TX_OK;
			$ifInErrors{$i} = $RX_ERR;
			$ifOutErrors{$i} = $TX_ERR;
			$ifInDiscards{$i} = $RX_Drp;
			$ifOutDiscards{$i} = $TX_Drp;
		}
		&ifconfig($i,$ifDescr{$i}) if ($ifDescr{$i});
	}
}

sub ifconfig {
	local($i,$iface) = @_;
	local(@ifcfg) = `ifconfig $iface`;
	print "<br>#ifconfig($i,$iface) ...\n" if $D>1;
	for $line (@ifcfg) {
		if ($line =~ /\bUP\b/i) {
			$ifOperStat{$i} = 1;
			print "<br>#ifconfig Up.\n" if $D>1;
		} elsif ($line =~ /\bDOWN\b/i) {
			$ifOperStat{$i} = 2;
			print "<br>#ifconfig Down.\n" if $D>1;
		}
		if ($line =~ /\bEthernet\b/i) {
			$ifType{$i} = 6;
			print "<br>#ifconfig Ethernet.\n" if $D>1;
		} elsif ($line =~ /\bLoopback\b/i) {
			$ifType{$i} = 1;
			print "<br>#ifconfig Loopback.\n" if $D>1;
		}
		if ($line =~ /\bHWaddr $ethadp\b/i) {
			$atPhysAddress{$i} = $ifPhysAddress{$i} = $1;
		}
		if ($line =~ /\bMask:\s*($ipadp)\b/i) {
			$ipAdEntNetMask{$i} = $1;
		}
		if ($line =~ /\binet addr:\s*($ipadp)\b/i) {
			$ipAdEntAddr{$i} = $atNetAddress{$i} = $1;
		}
		if ($line =~ /\bBcast:\s*($ipadp)\b/i) {
			($x = $1) =~ s/.*\.//;
			if ($x =~ /\.0$/) {
				$ipAdEntBcastAddr{$i} = 0;
			} else {
				$ipAdEntBcastAddr{$i} = 1;
			}
		}
		if ($line =~ /\bLink encap:(\d+)Mbps\b/i) {
			$ifSpeed{$i} = $1 * 1000000;
		}
	}
}

sub ifTable { # table.
	local($i);
	print "<dt>ifTable:<dd>\n";
	print "<dl compact>\n";
	&ifNumber() if !$ifNumber;
	for ($i=1; $i <= $ifNumber; $i++) {
		print "<br>#ifTable	i=$i.\n" if $D>1;
		&ifEntry($i);
	}
	print "</dl><!-- ifTable -->\n";
}

sub ifEntry { # entry.
	local($i) = @_;
	print "<dt>ifEntry $i:<dd>\n";
	print "<dl compact>\n";
	&ifIndex($i);
	&ifDescr($i);
	&ifType($i);
	&ifMtu($i);
	&ifSpeed($i);
	&ifPhysAddress($i);
	&ifAdminStat($i);
	&ifOperStat($i);
	&ifLastChange($i);
	&ifInOctets($i);
	&ifInUcastPkts($i);
	&ifInNUcastPkts($i);
	&ifInDiscards($i);
	&ifInErrors($i);
	&ifInUnknownProtos($i);
	&ifOutOctets($i);
	&ifOutUcastPkts($i);
	&ifOutNUcastPkts($i);
	&ifOutDiscards($i);
	&ifOutErrors($i);
	&ifOutQLen($i);
	print "</dl><!-- ifEntry $i -->\n";
}

sub ifIndex {
	local($i) = $_[0] || 1;
	print "<br>#ifIndex i=$i.\n" if $D>1;
	&iftbl() if (!@ifIndex);
	print "<dt>ifIndex.$i<dd>$ifIndex{$i}\n";
}

sub ifDescr {
	local($i) = $_[0] || 1;
	print "<br>#ifDescr i=$i.\n" if $D>1;
	&iftbl() if (!@ifDescr);
	print "<dt>ifDescr.$i<dd>$ifDescr{$i}\n";
}

sub ifType {
	local($i) = $_[0] || 1;
	print "<br>#ifType i=$i.\n" if $D>1;
	&iftbl() if (!@ifType);
	print "<dt>ifType.$i<dd>$ifType{$i}\n";
}

sub ifMtu {
	local($i) = $_[0] || 1;
	&iftbl() if (!@ifDescr);
	print "<dt>ifMtu.$i<dd>$ifMtu{$i}\n" if defined($ifMtu{$i});
}

sub ifSpeed {
	local($i) = $_[0] || 1;
	&iftbl() if (!@ifDescr);
	print "<dt>ifSpeed.$i<dd>$ifSpeed{$i}\n" if defined($ifSpeed{$i});
}

sub ifPhysAddress {
	local($i) = $_[0] || 1;
	&iftbl() if (!@ifDescr);
	print "<dt>ifPhysAddress.$i<dd>$ifPhysAddress{$i}\n" if defined($ifPhysAddress{$i});
}

sub ifAdminStat {
	local($i) = $_[0] || 1;
	&iftbl() if (!@ifDescr);
	print "<dt>ifAdminStat.$i<dd>$ifAdminStat{$i}\n" if defined($ifAdminStat{$i});
}

sub ifOperStat {
	local($i) = $_[0] || 1;
	&iftbl() if (!@ifDescr);
	print "<dt>ifOperStat.$i<dd>$ifOperStat{$i}\n" if defined($ifOperStat{$i});
}

sub ifLastChange {
	local($i) = $_[0] || 1;
	&iftbl() if (!@ifDescr);
	print "<dt>ifLastChange.$i<dd>$ifLastChange{$i}\n" if defined($ifLastChange{$i});
}

sub ifInOctets {
	local($i) = $_[0] || 1;
	&iftbl() if (!@ifDescr);
	print "<dt>ifInOctets.$i<dd>$ifInOctets{$i}\n" if defined($ifInOctets{$i});
}

sub ifInUcastPkts {
	local($i) = $_[0] || 1;
	&iftbl() if (!@ifDescr);
	print "<dt>ifInUcastPkts.$i<dd>$ifInUcastPkts{$i}\n" if defined($ifInUcastPkts{$i});
}

sub ifInNUcastPkts {
	local($i) = $_[0] || 1;
	&iftbl() if (!@ifDescr);
	print "<dt>ifInNUcastPkts.$i<dd>$ifInNUcastPkts{$i}\n" if defined($ifInNUcastPkts{$i});
}

sub ifInDiscards {
	local($i) = $_[0] || 1;
	&iftbl() if (!@ifDescr);
	print "<dt>ifInDiscards.$i<dd>$ifInDiscards{$i}\n" if defined($ifInDiscards{$i});
}

sub ifInErrors {
	local($i) = $_[0] || 1;
	&iftbl() if (!@ifDescr);
	print "<dt>ifInErrors.$i<dd>$ifInErrors{$i}\n" if defined($ifInErrors{$i});
}

sub ifInUnknownProtos {
	local($i) = $_[0] || 1;
	&iftbl() if (!@ifDescr);
	print "<dt>ifInUnknownProtos.$i<dd>$ifInUnknownProtos{$i}\n" if defined($ifInUnknownProtos{$i});
}

sub ifOutOctets {
	local($i) = $_[0] || 1;
	&iftbl() if (!@ifDescr);
	print "<dt>ifOutOctets.$i<dd>$ifOutOctets{$i}\n" if defined($ifOutOctets{$i});
}

sub ifOutUcastPkts {
	local($i) = $_[0] || 1;
	&iftbl() if (!@ifDescr);
	print "<dt>ifOutUcastPkts.$i<dd>$ifOutUcastPkts{$i}\n" if defined($ifOutUcastPkts{$i});
}

sub ifOutNUcastPkts {
	local($i) = $_[0] || 1;
	&iftbl() if (!@ifDescr);
	print "<dt>ifOutNUcastPkts.$i<dd>$ifOutNUcastPkts{$i}\n" if defined($ifOutNUcastPkts{$i});
}

sub ifOutDiscards {
	local($i) = $_[0] || 1;
	&iftbl() if (!@ifDescr);
	print "<dt>ifOutDiscards.$i<dd>$ifOutDiscards{$i}\n" if defined($ifOutDiscards{$i});
}

sub ifOutErrors {
	local($i) = $_[0] || 1;
	&iftbl() if (!@ifDescr);
	print "<dt>ifOutErrors.$i<dd>$ifOutErrors{$i}\n" if defined($ifOutErrors{$i});
}

sub ifOutQLen {
	local($i) = $_[0] || 1;
	&iftbl() if (!@ifDescr);
	print "<dt>ifOutQLen.$i<dd>$ifOutQLen{$i}\n" if defined($ifOutQLen{$i});
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
sub at { # group.
	print "<dt>at:<dd>\n";
	print "<dl compact>\n";
	&atTable();
	print "</dl><!-- at -->\n";
}

sub atTable { # table.
	local($i);
	print "<dt>atTable:<dd>\n";
	print "<dl compact>\n";
	&ifNumber() if !$ifNumber;
	for ($i=1; $i <= $ifNumber; $i++) {
		print "<br>#atTable	i=$i.\n" if $D>1;
		&atEntry($i);
	}
	print "</dl><!-- atTable -->\n";
}

sub atEntry { # entry.
	local($i) = @_;
	print "<dt>atEntry $i:<dd>\n";
	print "<dl compact>\n";
	&atIfIndex($i);
	&atPhysAddress($i);
	&atNetAddress($i);
	print "</dl><!-- atEntry $i -->\n";
}

sub atIfIndex {
	local($i) = $_[0] || 1;
	&attbl() if !$atNumber;
	print "<dt>atIfIndex.$i<dd>$atIfIndex{$i}\n" if defined($atIfIndex{$i});
}

sub atPhysAddress {
	local($i) = $_[0] || 1;
	&attbl() if !$atNumber;
	print "<dt>atPhysAddress.$i<dd>$atPhysAddress{$i}\n" if defined($atPhysAddress{$i});
}

sub atNetAddress {
	local($i) = $_[0] || 1;
	&attbl() if !$atNumber;
	print "<dt>atNetAddress.$i<dd>$atNetAddress{$i}\n" if defined($atNetAddress{$i});
}

sub attbl {
	local($ifnt,$i);
	local(@attb) = `arp -a`;
	local($Addr,$HWtp,$HWaddr,$Flags,$Mask);
	print "<br>#attbl ...\n" if $D>1;
	for $ifnt (@attb) {
		if (($Addr,$HWtp,$HWaddr,$Flags,$Mask)
				=~ "^($ipadp)\s+(.*)\s+($ethadp)\s+(\s+)\s+(.*)") {
		}
	}
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
sub ip { # group.
	print "<dt>ip:<dd>\n";
	print "<dl compact>\n";
	&ipForwarding();
	&ipDefaultTTL();
	&ipInReceives();
	&ipInHdrErrors();
	&ipInAddrErrors();
	&ipForwDatagrams();
	&ipInUnknownProtos();
	&ipInDiscards();
	&ipInDelivers();
	&ipOutRequests();
	&ipOutDiscards();
	&ipOutNoRoutes();
	&ipReasmTimeout();
	&ipReasmRecords();
	&ipReasmOKs();
	&ipReasmFails();
	&ipFragOKs();
	&ipFragFails();
	&ipFragCreates();
	&ipAddrTable();
	&ipRoutingTable();
	print "</dl><!-- ip -->\n";
}

sub ipForwarding {print "<dt># ipForwarding not implemented yet.\n" } 
sub ipDefaultTTL {print "<dt># ipDefaultTTL not implemented yet.\n" } 
sub ipInReceives {print "<dt># ipInReceives not implemented yet.\n" } 
sub ipInHdrErrors {print "<dt># ipInHdrErrors not implemented yet.\n" } 
sub ipInAddrErrors {print "<dt># ipInAddrErrors not implemented yet.\n" } 
sub ipForwDatagrams {print "<dt># ipForwDatagrams not implemented yet.\n" } 
sub ipInUnknownProtos {print "<dt># ipInUnknownProtos not implemented yet.\n" } 
sub ipInDiscards {print "<dt># ipInDiscards not implemented yet.\n" } 
sub ipInDelivers {print "<dt># ipInDelivers not implemented yet.\n" } 
sub ipOutRequests {print "<dt># ipOutRequests not implemented yet.\n" } 
sub ipOutDiscards {print "<dt># ipOutDiscards not implemented yet.\n" } 
sub ipOutNoRoutes {print "<dt># ipOutNoRoutes not implemented yet.\n" } 
sub ipReasmTimeout {print "<dt># ipReasmTimeout not implemented yet.\n" } 
sub ipReasmRecords {print "<dt># ipReasmRecords not implemented yet.\n" } 
sub ipReasmOKs {print "<dt># ipReasmOKs not implemented yet.\n" } 
sub ipReasmFails {print "<dt># ipReasmFails not implemented yet.\n" } 
sub ipFragOKs {print "<dt># ipFragOKs not implemented yet.\n" } 
sub ipFragFails {print "<dt># ipFragFails not implemented yet.\n" } 
sub ipFragCreates {print "<dt># ipFragCreates not implemented yet.\n" }

sub ipAddrTable {print "<dt># ipAddrTable not implemented yet.\n" }

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
sub ipAddr { # group.
	print "<dt>ipAddr:<dd>\n";
	print "<dl compact>\n";
	&ipAddrTable();
	print "</dl><!-- ipAddr -->\n";
}

sub ipAddrEntry {print "<dt># ipAddrEntry not implemented yet.\n" } 
sub ipAdEntAddr {print "<dt># ipAdEntAddr not implemented yet.\n" } 
sub ipAdEntIfIndex {print "<dt># ipAdEntIfIndex not implemented yet.\n" } 
sub ipAdEntNetMask {print "<dt># ipAdEntNetMask not implemented yet.\n" } 
sub ipAdEntBcastAddr {print "<dt># ipAdEntBcastAddr not implemented yet.\n" }

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
sub rttbl {
	local(@rttb) = `netstat -rn`;
	local($Dest,$Addr,$Mask,$Flags,$M1,$Ref,$Use,$Iface);	# linux.
	local($i);
	print "<br>#rttbl ...\n" if $D>1;
	&iftbl() if (!@ifIndex);	# We'll need this to decode Iface.
#	rtnt Dest Addr Mask Flags M1 Ref Use Iface
#	ipRouteDest ipRouteIfIndex ipRouteMetric1 ipRouteNextHop
	for $rtnt (@rttb) {
		if (($Dest,$Addr,$Mask,$Flags,$M1,$Ref,$Use,$Iface)
				= ($rtnt =~ /^($ipadp)\s+($ipadp)\s+($ipadp)\s+(\w+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\w+)\s*$/)) {
			++$i;
			$ipRouteDest{$Dest}    = $Addr;
			$ipRouteIfIndex{$Dest} = $ifIndex{$Iface};
			$ipRouteMetric1{$Dest} = $M1;
#			$ipRouteMetric2{$Dest} = 0;
#			$ipRouteMetric3{$Dest} = 0;
#			$ipRouteMetric4{$Dest} = 0;
			$ipRouteNextHop{$Dest} = $Dest;
#			$ipRouteType{$Dest}    = '?';
#			$ipRouteProto{$Dest}   = '?';
#			$ipRouteAge{$Dest}     = '?';
		}
	}
	$ipRouteNumber = $i;
}

sub ipRoutingTable { # group.
	print "<dt>ipRoutingTable:<dd>\n";
	print "<dl compact>\n";
	&rttbl() if !$ipRouteNumber;
	print "<dt>#ipRoutingTable $ipRouteNumber entries:<dd>\n" if $D>1;
	for $a (sort oidorder keys(%ipRouteDest)) {
		&ipRouteEntry($a);
	}
	print "</dl><!-- ipRoutingTable -->\n";
}

sub ipRouteEntry { # entry.
	local($i) = @_;
	print "<dt>ipRouteEntry $i:<dd>\n";
	print "<dl compact>\n";
	&ipRouteDest($i);
	&ipRouteIfIndex($i);
	&ipRouteMetric1($i);
	&ipRouteMetric2($i);
	&ipRouteMetric3($i);
	&ipRouteMetric4($i);
	&ipRouteNextHop($i);
	&ipRouteType($i);
	&ipRouteProto($i);
	&ipRouteAge($i);
	print "</dl><!-- ipRouteEntry $i -->\n";
}

sub ipRouteDest {
	local($i) = @_;
	print "<br>#ipRouteDest i=$i.\n" if $dbg;
	&rttbl() if !$ipRouteNumber;
	print "<dt>ipRouteDest.$i<dd>$ipRouteDest{$i}\n" if defined($ipRouteDest{$i});;
}

sub ipRouteIfIndex {
	local($i) = @_;
	print "<br>#ipRouteIfIndex i=$i.\n" if $dbg;
	&rttbl() if !$ipRouteNumber;
	print "<dt>ipRouteIfIndex.$i<dd>$ipRouteIfIndex{$i}\n" if defined($ipRouteIfIndex{$i});;
}

sub ipRouteMetric1 {
	local($i) = @_;
	print "<br>#ipRouteMetric1 i=$i.\n" if $dbg;
	&rttbl() if !$ipRouteNumber;
	print "<dt>ipRouteMetric1.$i<dd>$ipRouteMetric1{$i}\n" if defined($ipRouteMetric1{$i});;
}

sub ipRouteMetric2 {
	local($i) = @_;
	print "<br>#ipRouteMetric2 i=$i.\n" if $dbg;
	&rttbl() if !$ipRouteNumber;
	print "<dt>ipRouteMetric2.$i<dd>$ipRouteMetric2{$i}\n" if defined($ipRouteMetric2{$i});;
}

sub ipRouteMetric3 {
	local($i) = @_;
	print "<br>#ipRouteMetric3 i=$i.\n" if $dbg;
	&rttbl() if !$ipRouteNumber;
	print "<dt>ipRouteMetric3.$i<dd>$ipRouteMetric3{$i}\n" if defined($ipRouteMetric3{$i});;
}

sub ipRouteMetric4 {
	local($i) = @_;
	print "<br>#ipRouteMetric4 i=$i.\n" if $dbg;
	&rttbl() if !$ipRouteNumber;
	print "<dt>ipRouteMetric4.$i<dd>$ipRouteMetric4{$i}\n" if defined($ipRouteMetric4{$i});;
}

sub ipRouteNextHop {
	local($i) = @_;
	print "<br>#ipRouteNextHop i=$i.\n" if $dbg;
	&rttbl() if !$ipRouteNumber;
	print "<dt>ipRouteNextHop.$i<dd>$ipRouteNextHop{$i}\n" if defined($ipRouteNextHop{$i});;
}

sub ipRouteType {
	local($i) = @_;
	print "<br>#ipRouteType i=$i.\n" if $dbg;
	&rttbl() if !$ipRouteNumber;
	print "<dt>ipRouteType.$i<dd>$ipRouteType{$i}\n" if defined($ipRouteType{$i});;
}

sub ipRouteProto {
	local($i) = @_;
	print "<br>#ipRouteProto i=$i.\n" if $dbg;
	&rttbl() if !$ipRouteNumber;
	print "<dt>ipRouteProto.$i<dd>$ipRouteProto{$i}\n" if defined($ipRouteProto{$i});;
}

sub ipRouteAge {
	local($i) = @_;
	print "<br>#ipRouteAge i=$i.\n" if $dbg;
	&rttbl() if !$ipRouteNumber;
	print "<dt>ipRouteAge.$i<dd>$ipRouteAge{$i}\n" if defined($ipRouteAge{$i});;
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
sub icmp { # group.
	print "<dt>icmp:<dd>\n";
	print "<dl compact>\n";
	&icmpOutAddrMaskReps();
	&icmpOutAddrMasks();
	&icmpOutTimestampReps();
	&icmpOutTimestamps();
	&icmpOutEchoReps();
	&icmpOutEchos();
	&icmpOutRedirects();
	&icmpOutSrcQuenchs();
	&icmpOutParmProbs();
	&icmpOutTimeExcds();
	&icmpOutDestUnreachs();
	&icmpOutErrors();
	&icmpOutMsgs();
	&icmpInAddrMaskReps();
	&icmpInAddrMasks();
	&icmpInTimestampReps();
	&icmpInTimestamps();
	&icmpInEchoReps();
	&icmpInEchos();
	&icmpInRedirects();
	&icmpInSrcQuenchs();
	&icmpInParmProbs();
	&icmpInTimeExcds();
	&icmpInDestUnreachs();
	&icmpInErrors();
	&icmpInMsgs();
	print "</dl><!-- icmp -->\n";
}

sub icmpInMsgs {print "<dt># icmpInMsgs not implemented yet.\n" } 
sub icmpInErrors {print "<dt># icmpInErrors not implemented yet.\n" } 
sub icmpInDestUnreachs {print "<dt># icmpInDestUnreachs not implemented yet.\n" } 
sub icmpInTimeExcds {print "<dt># icmpInTimeExcds not implemented yet.\n" } 
sub icmpInParmProbs {print "<dt># icmpInParmProbs not implemented yet.\n" } 
sub icmpInSrcQuenchs {print "<dt># icmpInSrcQuenchs not implemented yet.\n" } 
sub icmpInRedirects {print "<dt># icmpInRedirects not implemented yet.\n" } 
sub icmpInEchos {print "<dt># icmpInEchos not implemented yet.\n" } 
sub icmpInEchoReps {print "<dt># icmpInEchoReps not implemented yet.\n" } 
sub icmpInTimestamps {print "<dt># icmpInTimestamps not implemented yet.\n" } 
sub icmpInTimestampReps {print "<dt># icmpInTimestampReps not implemented yet.\n" } 
sub icmpInAddrMasks {print "<dt># icmpInAddrMasks not implemented yet.\n" } 
sub icmpInAddrMaskReps {print "<dt># icmpInAddrMaskReps not implemented yet.\n" } 
sub icmpOutMsgs {print "<dt># icmpOutMsgs not implemented yet.\n" } 
sub icmpOutErrors {print "<dt># icmpOutErrors not implemented yet.\n" } 
sub icmpOutDestUnreachs {print "<dt># icmpOutDestUnreachs not implemented yet.\n" } 
sub icmpOutTimeExcds {print "<dt># icmpOutTimeExcds not implemented yet.\n" } 
sub icmpOutParmProbs {print "<dt># icmpOutParmProbs not implemented yet.\n" } 
sub icmpOutSrcQuenchs {print "<dt># icmpOutSrcQuenchs not implemented yet.\n" } 
sub icmpOutRedirects {print "<dt># icmpOutRedirects not implemented yet.\n" } 
sub icmpOutEchos {print "<dt># icmpOutEchos not implemented yet.\n" } 
sub icmpOutEchoReps {print "<dt># icmpOutEchoReps not implemented yet.\n" } 
sub icmpOutTimestamps {print "<dt># icmpOutTimestamps not implemented yet.\n" } 
sub icmpOutTimestampReps {print "<dt># icmpOutTimestampReps not implemented yet.\n" } 
sub icmpOutAddrMasks {print "<dt># icmpOutAddrMasks not implemented yet.\n" } 
sub icmpOutAddrMaskReps {print "<dt># icmpOutAddrMaskReps not implemented yet.\n" }

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
sub tcp { # group.
	print "<dt>tcp:<dd>\n";
	print "<dl compact>\n";
	&tcpRtoAlgorithm();
	&tcpRtoMin();
	&tcpRtoMax();
	&tcpMaxConn();
	&tcpActiveOpens();
	&tcpPassiveOpens();
	&tcpAttemptFails();
	&tcpEstabResets();
	&tcpCurrEstab();
	&tcpInSegs();
	&tcpOutSegs();
	&tcpRetransSegs();
	&tcpConnTable();
	print "</dl><!-- tcp -->\n";
}

sub tcpRtoAlgorithm {print "<dt># tcpRtoAlgorithm not implemented yet.\n" } 
sub tcpRtoMin {print "<dt># tcpRtoMin not implemented yet.\n" } 
sub tcpRtoMax {print "<dt># tcpRtoMax not implemented yet.\n" } 
sub tcpMaxConn {print "<dt># tcpMaxConn not implemented yet.\n" } 
sub tcpPassiveOpens {print "<dt># tcpPassiveOpens not implemented yet.\n" } 
sub tcpAttemptFails {print "<dt># tcpAttemptFails not implemented yet.\n" } 
sub tcpEstabResets {print "<dt># tcpEstabResets not implemented yet.\n" } 
sub tcpInSegs {print "<dt># tcpInSegs not implemented yet.\n" } 
sub tcpOutSegs {print "<dt># tcpOutSegs not implemented yet.\n" }
sub tcpRetransSegs {print "<dt># tcpRetransSegs not implemented yet.\n" }

sub tcptbl {
	local($tcpnt,$i,$n);
	local(@tcptb) = `netstat -an`;
	local($Proto,$RecvQ,$SendQ,$LAddr,$LPort,$FAddr,$FPort,$State,$User);
	print "<br>#tcptbl ...\n" if $D>1;
	$tcpActiveOpens = $tcpCurrEstab = 0;
	$plinux="^tcp\\s+(-*\\d+)\\s+(-*\\d+)\\s+($ipadp):(\\d+)\\s+($ipadp):(\\d+)\\s+(\\w+)\\s+(\\w+)";
	$pultrix = "^tcp\\s+(-*\\d+)\\s+(-*\\d+)\\s+($ipadp)\\.(\\d+)\\s+($ipadp)\\.(\\d+)\\s+(\\w+)";
#	tcpnt Proto RecvQ SendQ LAddr LPort FAddr FPort State User
	for $tcpnt (@tcptb) {
		$tcpnt =~ s/ \*\./ 0.0.0.0./g;
		$tcpnt =~ s/\.\* /.0 /g;
		if (
			(($RecvQ,$SendQ,$LAddr,$LPort,$FAddr,$FPort,$State,$User) = ($tcpnt =~ m/$plinux/))
		||	(($RecvQ,$SendQ,$LAddr,$LPort,$FAddr,$FPort,$State      ) = ($tcpnt =~ m/$pultrix/))
		) {
			print "<br>#tcptbl	Got tcp line.\n" if $D>1;
			$i = "$LAddr.$LPort.$FAddr.$FPort";
			++$n;
			$tcpConnTable{$i} = 1;	# List of keys.
			$tcpConnLocalAddress{$i} = $LAddr;
			$tcpConnRemAddress{$i} = $FAddr;
			$tcpConnLocalPort{$i} = $LPort;
			$tcpConnRemPort{$i} = $FPort;
			if ($State eq LISTEN) {
				$tcpConnState{$i} = 2;
				++$tcpActiveOpens;
				print "<br>#	tcpActiveOpens=$tcpActiveOpens\n" if $D>1;
			} elsif ($State eq CLOSE_WAIT) {
				$tcpConnState{$i} = 10;
			} elsif ($State eq ESTABLISHED) {
				$tcpConnState{$i} = 5;
				++$tcpActiveOpens;
				++$tcpCurrEstab;
				print "<br>#	tcpCurrEstab=$tcpCurrEstab\n" if $D>1;
			} else {
				$tcpConnState{$i} = 0;
			}
		}
	}
	$tcpConnNumber = $n;
}

sub tcpinfo {
	&tcptbl();
}

sub tcpConnTable { # table.
	local($i);
	print "<dt>tcpConnTable:<dd>\n";
	print "<dl compact>\n";
	&tcpinfo() if !defined($tcpConnNumber);
	for $i (sort oidorder keys(%tcpConnTable)) {
		print "<br>#tcpConnTable	i=$i.\n" if $D>1;
		&tcpConnEntry($i);
	}
	print "</dl><!-- tcpConnTable -->\n";
}

sub tcpConnEntry { # entry.
	local($i) = @_;
	print "<dt>tcpConnEntry $i:<dd>\n";
	print "<dl compact>\n";
	&tcpConnState($i);
	&tcpConnLocalAddress($i);
	&tcpConnLocalPort($i);
	&tcpConnRemAddress($i);
	&tcpConnRemPort($i);
	print "</dl><!-- tcpConnEntry $i -->\n";
}

sub tcpActiveOpens {
	print "<br>#tcpActiveOpens ...\n" if $D>1;
	&tcptbl() if !defined($tcpConnNumber);
	print "<dt>tcpActiveOpens<dd>$tcpActiveOpens\n" if defined($tcpActiveOpens);
}

sub tcpCurrEstab {
	print "<br>#tcpCurrEstab ...\n" if $D>1;
	&tcptbl() if !defined($tcpConnNumber);
	print "<dt>tcpCurrEstab<dd>$tcpCurrEstab\n" if defined($tcpCurrEstab);
}

sub tcpConnState {
	local($i) = $_[0] || 1;
	print "<br>#tcpConnState i=$i.\n" if $D>1;
	&tcptbl() if (!@tcpConnState);
	print "<dt>tcpConnState.$i<dd>$tcpConnState{$i}\n";
}

sub tcpConnLocalAddress {
	local($i) = $_[0] || 1;
	print "<br>#tcpConnLocalAddress i=$i.\n" if $D>1;
	&tcptbl() if (!@tcpConnLocalAddress);
	print "<dt>tcpConnLocalAddress.$i<dd>$tcpConnLocalAddress{$i}\n";
}

sub tcpConnLocalPort {
	local($i) = $_[0] || 1;
	print "<br>#tcpConnLocalPort i=$i.\n" if $D>1;
	&tcptbl() if (!@tcpConnLocalPort);
	print "<dt>tcpConnLocalPort.$i<dd>$tcpConnLocalPort{$i}\n";
}

sub tcpConnRemAddress {
	local($i) = $_[0] || 1;
	print "<br>#tcpConnRemAddress i=$i.\n" if $D>1;
	&tcptbl() if (!@tcpConnRemAddress);
	print "<dt>tcpConnRemAddress.$i<dd>$tcpConnRemAddress{$i}\n";
}

sub tcpConnRemPort {
	local($i) = $_[0] || 1;
	print "<br>#tcpConnRemPort i=$i.\n" if $D>1;
	&tcptbl() if (!@tcpConnRemPort);
	print "<dt>tcpConnRemPort.$i<dd>$tcpConnRemPort{$i}\n";
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
sub udp { # group.
	print "<dt>udp:<dd>\n";
	print "<dl compact>\n";
	&udpInDatagrams();
	&udpNoPorts();
	&udpInErrors();
	&udpOutDatagrams();
	print "</dl><!-- udp -->\n";
}

sub udpInDatagrams {print "<dt># udpInDatagrams not implemented yet.\n" } 
sub udpNoPorts {print "<dt># udpNoPorts not implemented yet.\n" } 
sub udpInErrors {print "<dt># udpInErrors not implemented yet.\n" } 
sub udpOutDatagrams {print "<dt># udpOutDatagrams not implemented yet.\n" }

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
sub egp { # group.
	print "<dt>egp:<dd>\n";
	print "<dl compact>\n";
	&egpTable();
	print "</dl><!-- egp -->\n";
}

sub egpTable { # group.
	print "<dt>egpTable:<dd>\n";
	print "<dl compact>\n";
	&rttbl() if !$egpNumber;
	print "<dt>#egpTable $egpNumber entries:<dd>\n" if $D>1;
	for $a (sort oidorder keys(%egpDest)) {
		&egpEntry($a);
	}
	print "</dl><!-- egpTable -->\n";
}

sub egpEntry { # entry.
	local($i) = @_;
	print "<dt>egpEntry $i:<dd>\n";
	print "<dl compact>\n";
	&egpInMsgs($i);
	&egpInErrors($i);
	&egpOutMsgs($i);
	&egpOutErrors($i);
	&egpNeighTable($i);
	&egpNeighEntry($i);
	&egpNeighState($i);
	&egpNeighAddr($i);
	print "</dl><!-- egpEntry $i -->\n";
}

sub egpInMsgs {print "<dt># egpInMsgs not implemented yet.\n" } 
sub egpInErrors {print "<dt># egpInErrors not implemented yet.\n" } 
sub egpOutMsgs {print "<dt># egpOutMsgs not implemented yet.\n" } 
sub egpOutErrors {print "<dt># egpOutErrors not implemented yet.\n" } 
sub egpNeighTable {print "<dt># egpNeighTable not implemented yet.\n" } 
sub egpNeighEntry {print "<dt># egpNeighEntry not implemented yet.\n" } 
sub egpNeighState {print "<dt># egpNeighState not implemented yet.\n" } 
sub egpNeighAddr {print "<dt># egpNeighAddr not implemented yet.\n" } 

sub xxx {
	local($i) = $_[0] || 1;
	print "<br>#xxx i=$i.\n" if $dbg;
	&rttbl() if !$ipRouteNumber;
	print "<dt>xxx.$i<dd>$xxx{$i}\n" if defined($xxx{$i});;
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
# Missing so far:
# egpInMsgs { } 
# egpNeighState { } 
# egpNeighTable { } 
# egpOutMsgs { } 
# icmpInAddrMaskReps { } 
# icmpInDestUnreachs { } 
# icmpInEchoReps { } 
# icmpInMsgs { } 
# icmpInParmProbs { } 
# icmpInRedirects { } 
# icmpInTimestampReps { } 
# icmpOutAddrMasks { } 
# icmpOutEchos { } 
# icmpOutErrors { } 
# icmpOutSrcQuenchs { } 
# icmpOutTimeExcds { } 
# icmpOutTimestamps { } 
# ipAdEntBcastAddr { }
# ipAdEntIfIndex { } 
# ipAddrEntry { } 
# ipForwarding { } 
# ipFragCreates { }
# ipFragOKs { } 
# ipInAddrErrors { } 
# ipInDelivers { } 
# ipInReceives { } 
# ipInUnknownProtos { } 
# ipOutDiscards { } 
# ipReasmOKs { } 
# ipReasmTimeout { } 
# tcpAttemptFails { } 
# tcpOutSegs { }
# tcpRtoAlgorithm { } 
# tcpRtoMax { } 
# udpNoPorts { } 
# udpOutDatagrams { }
