Subject: misc/1053: ARCnet support additions for libpcap/tcpdump
To: None <gnats-admin@sun-lamp.cs.berkeley.edu>
From: Ignatios Souvatzis <is@beverly.rhein.de>
List: netbsd-bugs
Date: 05/16/1995 02:50:06
>Number:         1053
>Category:       misc
>Synopsis:       ARCnet support additions for libpcap/tcpdump
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    misc-bug-people (Misc Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Tue May 16 02:50:03 1995
>Originator:     Ignatios Souvatzis
>Organization:
"	private Internet site"
>Release:        1.0A
>Environment:
	
System: NetBSD beverly 1.0A NetBSD 1.0A (BEVERLY) #120: Tue May 9 13:55:13 MET DST 1995 is@beverly:/usr/src/sys/arch/amiga/compile/BEVERLY amiga


>Description:
	tcpdump/libpcap don't support DLT_ARCNET devices.
>How-To-Repeat:
	On a system with ARCnet primary interface, try
	tcpdump.
	On a system with multiple interfaces, one of which is ARCnet, try
	tcpdump -i bah0
>Fix:

I developed the following set of diffs. They are supposed to work (and tested
with) RFC1051 IP over ARCnet and should work with RFC1051 ARP over ARCnet, 
too, but won't work for RFC1201-style encapsulations (e.g., new IP/ARP/RARP
over ARCnet or IPX). These require bigger changes, at least special code, as
most of tcpdump/libpcap assumes every protocol has only one encapsulation and
all encapsulations have same length.

I might implement those later, when I need to debug the RFC1201 code for the
kernel I didn't write yet.
	- Ignatios Souvatzis

diff -u usr.sbin/tcpdump.bak/Makefile usr.sbin/tcpdump/Makefile
--- usr.sbin/tcpdump.bak/Makefile	Thu May 11 16:05:20 1995
+++ usr.sbin/tcpdump/Makefile	Fri May 12 22:49:49 1995
@@ -30,7 +30,8 @@
 DPADD+=	${LIBL} ${LIBPCAP}
 
 SRCS=	tcpdump.c addrtoname.c \
-	print-ether.c print-ip.c print-arp.c print-tcp.c print-udp.c \
+	print-arc.c print-ether.c \
+	print-ip.c print-arp.c print-tcp.c print-udp.c \
 	print-atalk.c print-domain.c print-tftp.c print-bootp.c print-nfs.c \
 	print-icmp.c print-sl.c print-ppp.c print-rip.c \
 	print-snmp.c print-ntp.c print-null.c print-egp.c print-ospf.c \
diff -u usr.sbin/tcpdump.bak/addrtoname.c usr.sbin/tcpdump/addrtoname.c
--- usr.sbin/tcpdump.bak/addrtoname.c	Thu May 11 16:05:39 1995
+++ usr.sbin/tcpdump/addrtoname.c	Sat May 13 22:57:03 1995
@@ -35,6 +35,7 @@
 #include <net/if.h>
 
 #include <netinet/in.h>
+#include <netinet/if_arc.h>
 #include <netinet/if_ether.h>
 
 #include <arpa/inet.h>
@@ -101,6 +102,15 @@
 
 struct protoidmem protoidtable[HASHNAMESIZE];
 
+struct arcnamemem {
+	u_char addr;
+	char *name;
+	struct arcnamemem *nxt;
+};
+
+struct arcnamemem arcnametable[HASHNAMESIZE];
+struct arcnamemem arcprototable[HASHNAMESIZE];
+
 /*
  * A faster replacement for inet_ntoa().
  */
@@ -246,6 +256,42 @@
 
 static char hex[] = "0123456789abcdef";
 
+char *
+arcaddr_string(ap)
+        register u_char ap;
+{
+        register struct anamemem *tp;
+        register char *cp;
+
+        cp = (char *)malloc(sizeof("00"));
+
+        cp[0] = hex[ap >> 4];
+        cp[1] = hex[ap & 0xf];
+        cp[2] = 0;
+
+        return (cp);
+}
+
+char *
+arcproto_string(port)
+        u_char port;
+{
+	register char *cp0, *cp;
+	register struct arcnamemem *tp;
+
+	for (tp = &arcprototable[port & (HASHNAMESIZE-1)];
+	    tp->nxt; tp = tp->nxt)
+		if (tp->addr == port)
+			return (tp->name);
+
+        cp0 = cp = (char *)malloc(sizeof("00"));
+
+        *cp++ = hex[port >> 4 & 0xf];
+        *cp++ = hex[port & 0xf];
+        *cp++ = '\0';
+
+        return (cp0);
+}
 
 /* Find the hash node that corresponds the ether address 'ep'. */
 
@@ -539,6 +585,38 @@
 	endservent();
 }
 
+struct arcproto {
+	char *s;
+	u_short p;
+} arcproto_db[] = {
+	{"oldip",	240},
+	{"oldarp",	241},
+	{"ip",		212},
+	{"arp",		213},
+	{"rarp",	214},
+	{"atalk",	221},
+	{"banian",	247},
+	{"ipx",		250},
+	{NULL,		0}
+};
+
+static void
+init_arcprotoarray(void)
+{
+	register int i;
+	register struct arcnamemem *table;
+
+	for (i=0; arcproto_db[i].s; ++i) {
+		int j = arcproto_db[i].p & (HASHNAMESIZE-1);
+		table = &arcprototable[j];
+		while (table->name)
+			table = table->nxt;
+		table->name = arcproto_db[i].s;
+		table->addr = arcproto_db[i].p;
+		table->nxt = (struct arcnamemem *)calloc(1, sizeof(*table));
+	}
+}
+
 /*XXX from libbpfc.a */
 extern struct eproto {
 	char *s;
@@ -696,6 +774,7 @@
 		 */
 		return;
 
+	init_arcprotoarray();
 	init_etherarray();
 	init_servarray();
 	init_eprotoarray();
diff -u usr.sbin/tcpdump.bak/interface.h usr.sbin/tcpdump/interface.h
--- usr.sbin/tcpdump.bak/interface.h	Thu May 11 16:06:49 1995
+++ usr.sbin/tcpdump/interface.h	Fri May 12 22:58:26 1995
@@ -101,6 +101,8 @@
 
 extern void ether_if_print(u_char *, const struct pcap_pkthdr *,
 			   const u_char *);
+extern void arc_if_print(u_char *, const struct pcap_pkthdr *,
+			   const u_char *);
 extern void fddi_if_print(u_char *, const struct pcap_pkthdr *, const u_char*);
 extern void null_if_print(u_char *, const struct pcap_pkthdr *, const u_char*);
 extern void ppp_if_print(u_char *, const struct pcap_pkthdr *, const u_char *);
@@ -119,6 +121,7 @@
 extern void bootp_print(const u_char *, int, u_short, u_short);
 extern void decnet_print(const u_char *, int, int);
 extern void egp_print(const u_char *, int, const u_char *);
+extern int arc_encap_print(u_short, const u_char *, int, int);
 extern int ether_encap_print(u_short, const u_char *, int, int);
 extern void ipx_print(const u_char *, int length);
 extern void isoclns_print(const u_char *, int, int,
diff -u usr.sbin/tcpdump.bak/os.h usr.sbin/tcpdump/os.h
--- usr.sbin/tcpdump.bak/os.h	Thu May 11 16:07:27 1995
+++ usr.sbin/tcpdump/os.h	Fri May 12 23:02:11 1995
@@ -34,6 +34,9 @@
 #define THA(ap) ((ap)->arp_tha)
 #define TPA(ap) ((ap)->arp_tpa)
 
+#define ADST(ap) ((ap)->arc_dhost)
+#define ASRC(ap) ((ap)->arc_shost)
+
 #define EDST(ep) ((ep)->ether_dhost)
 #define ESRC(ep) ((ep)->ether_shost)
 
diff -u usr.sbin/tcpdump.bak/tcpdump.c usr.sbin/tcpdump/tcpdump.c
--- usr.sbin/tcpdump.bak/tcpdump.c	Thu May 11 16:10:32 1995
+++ usr.sbin/tcpdump/tcpdump.c	Fri May 12 11:09:09 1995
@@ -84,6 +84,7 @@
 
 static struct printer printers[] = {
 	{ ether_if_print,	DLT_EN10MB },
+	{ arc_if_print,		DLT_ARCNET },
 	{ sl_if_print,		DLT_SLIP },
 	{ ppp_if_print,		DLT_PPP },
 	{ fddi_if_print,	DLT_FDDI },


diff -u lib/libpcap.old/gencode.c lib/libpcap/gencode.c
--- lib/libpcap.old/gencode.c	Thu May 11 16:32:19 1995
+++ lib/libpcap/gencode.c	Sun May 14 00:19:59 1995
@@ -34,6 +34,7 @@
 
 #include <netinet/in.h>
 #include <netinet/if_ether.h>
+#include <netinet/if_arc.h>
 
 #include <memory.h>
 #include <pcap.h>
@@ -444,6 +445,7 @@
  * is set to -1 for no encapsulation, in which case, IP is assumed.
  */
 static u_int off_linktype;
+static u_int size_linktype;
 static u_int off_nl;
 static int linktype;
 #ifdef FDDI
@@ -456,8 +458,15 @@
 {
 	linktype = type;
 
+	size_linktype = 2;	/* for most sane protocols, but... */
 	switch (type) {
 
+	case DLT_ARCNET:
+		off_linktype = 2;
+		size_linktype = 1;
+		off_nl = 3;
+		return;
+
 	case DLT_EN10MB:
 		off_linktype = 12;
 		off_nl = 14;
@@ -545,8 +554,22 @@
 		if (proto == ETHERTYPE_IP)
 			proto = 0x0021;		/* XXX - need ppp.h defs */
 		break;
+
+	case DLT_ARCNET:
+		switch(proto) {			/*
+						 * XXX - needs more work;
+						 * especially for RFC1201
+						 */
+		case ETHERTYPE_IP:
+			proto = ARCTYPE_IP_OLD;
+			break;
+		case ETHERTYPE_ARP:
+			proto = ARCTYPE_IP_OLD;
+			break;
+		}
+		break;
 	}
-	return gen_cmp(off_linktype, BPF_H, (long)proto);
+	return gen_cmp(off_linktype, size_linktype, (long)proto);
 }
 
 static struct block *
@@ -592,6 +615,39 @@
 }
 
 static struct block *
+gen_ahostop(aaddr, dir)
+	u_char *aaddr;
+	int dir;
+{
+	struct block *b0, *b1;
+
+	switch (dir) {
+
+	case Q_SRC:
+		return gen_bcmp(0, 1, aaddr);
+
+	case Q_DST:
+		return gen_bcmp(1, 1, aaddr);
+
+	case Q_AND:
+		b0 = gen_ahostop(aaddr, Q_SRC);
+		b1 = gen_ahostop(aaddr, Q_DST);
+		gen_and(b0, b1);
+		return b1;
+
+	case Q_DEFAULT:
+	case Q_OR:
+		b0 = gen_ahostop(aaddr, Q_SRC);
+		b1 = gen_ahostop(aaddr, Q_DST);
+		gen_or(b0, b1);
+		return b1;
+	}
+	abort();
+	/* NOTREACHED */
+}
+
+
+static struct block *
 gen_ehostop(eaddr, dir)
 	u_char *eaddr;
 	int dir;
@@ -821,12 +877,17 @@
 	case Q_RARP:
 		if (linktype == DLT_EN10MB)
 			b0 = gen_ehostop(eaddr, Q_OR);
+
+		else if (linktype == DLT_ARCNET)
+			b0 = gen_ahostop(eaddr, Q_OR);
 #ifdef FDDI
 		else if (linktype == DLT_FDDI)
 			b0 = gen_fhostop(eaddr, Q_OR);
 #endif
+
 		else
-			bpf_error("'gateway' supported only on ethernet or FDDI");
+			bpf_error("'gateway' supported only on ethernet, \
+arcnet or FDDI");
 
 		b1 = gen_host(**alist++, 0xffffffffL, proto, Q_OR);
 		while (*alist) {
@@ -1149,6 +1210,14 @@
 	case Q_HOST:
 		if (proto == Q_LINK) {
 			switch (linktype) {
+#if 0	/* no /etc/arcs yet */
+			case DLT_ARCNET:
+				eaddr = pcap_arc_hostton(name);
+				if (eaddr == NULL)
+					bpf_error("unknown arc host '%s'",
+					    name);
+				return gen_ahostop(eaddr, dir);
+#endif
 			case DLT_EN10MB:
 				eaddr = pcap_ether_hostton(name);
 				if (eaddr == NULL)
@@ -1163,7 +1232,7 @@
 				return gen_fhostop(eaddr, dir);
 #endif
 			default:
-				bpf_error("only ethernet/FDDI supports link-level host name");
+				bpf_error("only ether-,arcnet and FDDI support link-level host name");
 				break;
 			}
 		} else if (proto == Q_DECNET) {
@@ -1292,6 +1361,8 @@
 	struct qual q;
 {
 	if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) {
+		if (linktype == DLT_ARCNET)
+			return gen_ahostop(eaddr, (int)q.dir);
 		if (linktype == DLT_EN10MB)
 			return gen_ehostop(eaddr, (int)q.dir);
 #ifdef FDDI
@@ -1667,11 +1738,15 @@
 	u_long hostmask;
 	struct block *b0, *b1, *b2;
 	static u_char ebroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+	static u_char abroadcast[] = { 0x0 };
 
 	switch (proto) {
 
 	case Q_DEFAULT:
 	case Q_LINK:
+		if (linktype == DLT_ARCNET)
+			return gen_ahostop(abroadcast, Q_DST);
+
 		if (linktype == DLT_EN10MB)
 			return gen_ehostop(ebroadcast, Q_DST);
 #ifdef FDDI
diff -u lib/libpcap.old/grammar.y lib/libpcap/grammar.y
--- lib/libpcap.old/grammar.y	Thu May 11 16:33:24 1995
+++ lib/libpcap/grammar.y	Sat May 13 23:54:57 1995
@@ -98,11 +98,12 @@
 %token  NUM INBOUND OUTBOUND
 %token  LINK
 %token	GEQ LEQ NEQ
-%token	ID EID HID
+%token	ID AID EID HID
 %token	LSH RSH
 %token  LEN
 
 %type	<s> ID
+%type	<e> AID
 %type	<e> EID
 %type	<h> HID
 %type	<i> NUM
@@ -157,6 +158,7 @@
 				  }
 				}
 	| EID			{ $$.b = gen_ecode($1, $$.q = $<blk>0.q); }
+	| AID			{ $$.b = gen_ecode($1, $$.q = $<blk>0.q); }
 	| not id		{ gen_not($2.b); $$ = $2; }
 	;
 not:	  '!'			{ $$ = $<blk>0; }
diff -u lib/libpcap.old/nametoaddr.c lib/libpcap/nametoaddr.c
--- lib/libpcap.old/nametoaddr.c	Thu May 11 16:33:35 1995
+++ lib/libpcap/nametoaddr.c	Sun May 14 00:16:22 1995
@@ -263,6 +263,26 @@
 	return(addr);
 }
 
+u_char *
+pcap_arc_aton(const char *s)
+{
+	register u_char *ep;
+	register u_int d;
+
+	ep = (u_char *)malloc(1);
+
+	if (*s)
+		++s;
+
+	d = xdtoi(*s++);
+	if (isxdigit(*s)) {
+		d <<= 4;
+		d |= xdtoi(*s);
+	}
+	*ep = d;
+	return (ep);
+}
+
 /*
  * Convert 's' which has the form "xx:xx:xx:xx:xx:xx" into a new
  * ethernet address.  Assumes 's' is well formed.
diff -u lib/libpcap.old/pcap-namedb.h lib/libpcap/pcap-namedb.h
--- lib/libpcap.old/pcap-namedb.h	Thu May 11 16:34:52 1995
+++ lib/libpcap/pcap-namedb.h	Sun May 14 00:17:52 1995
@@ -56,6 +56,8 @@
 u_char *pcap_ether_hostton(const char*);
 u_char *pcap_ether_aton(const char *);
 
+u_char *pcap_arc_aton(const char *);
+
 u_long	**pcap_nametoaddr(const char *);
 u_long	pcap_nametonetaddr(const char *);
 
diff -u lib/libpcap.old/scanner.l lib/libpcap/scanner.l
--- lib/libpcap.old/scanner.l	Thu May 11 16:36:06 1995
+++ lib/libpcap/scanner.l	Sat May 13 23:52:28 1995
@@ -81,6 +81,7 @@
 src		return SRC;
 
 link|ether|ppp|slip  return LINK;
+arc		return LINK;
 fddi		return LINK;
 arp		return ARP;
 rarp		return RARP;
@@ -129,6 +130,8 @@
 }
 {B}:{B}:{B}:{B}:{B}:{B} { yylval.e = pcap_ether_aton((char *)yytext);
 			  return EID; }
+:{B}			{ yylval.e = pcap_arc_aton((char *)yytext);
+			  return AID; }
 {B}:+({B}:+)+		{ bpf_error("bogus ethernet address %s", yytext); }
 [A-Za-z][-_.A-Za-z0-9]*	{ yylval.s = sdup((char *)yytext); return ID; }
 "\\"[^ !()\n\t]+	{ yylval.s = sdup((char *)yytext + 1); return ID; }
>Audit-Trail:
>Unformatted:


Ignatios Souvatzis