198524Sfenner/*
298524Sfenner * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
398524Sfenner *	The Regents of the University of California.  All rights reserved.
498524Sfenner *
598524Sfenner * Redistribution and use in source and binary forms, with or without
698524Sfenner * modification, are permitted provided that: (1) source code distributions
798524Sfenner * retain the above copyright notice and this paragraph in its entirety, (2)
898524Sfenner * distributions including binary code include the above copyright notice and
998524Sfenner * this paragraph in its entirety in the documentation or other materials
1098524Sfenner * provided with the distribution, and (3) all advertising materials mentioning
1198524Sfenner * features or use of this software display the following acknowledgement:
1298524Sfenner * ``This product includes software developed by the University of California,
1398524Sfenner * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1498524Sfenner * the University nor the names of its contributors may be used to endorse
1598524Sfenner * or promote products derived from this software without specific prior
1698524Sfenner * written permission.
1798524Sfenner * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1898524Sfenner * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1998524Sfenner * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20127668Sbms *
2198524Sfenner * From: NetBSD: print-arcnet.c,v 1.2 2000/04/24 13:02:28 itojun Exp
2298524Sfenner */
2398524Sfenner
24276788Sdelphij#define NETDISSECT_REWORKED
2598524Sfenner#ifdef HAVE_CONFIG_H
2698524Sfenner#include "config.h"
2798524Sfenner#endif
2898524Sfenner
29127668Sbms#include <tcpdump-stdinc.h>
3098524Sfenner
3198524Sfenner#include "interface.h"
32214478Srpaulo#include "extract.h"
3398524Sfenner
34276788Sdelphij/*
35276788Sdelphij * from: NetBSD: if_arc.h,v 1.13 1999/11/19 20:41:19 thorpej Exp
36276788Sdelphij */
37276788Sdelphij
38276788Sdelphij/*
39276788Sdelphij * Structure of a 2.5MB/s Arcnet header on the BSDs,
40276788Sdelphij * as given to interface code.
41276788Sdelphij */
42276788Sdelphijstruct	arc_header {
43276788Sdelphij	uint8_t  arc_shost;
44276788Sdelphij	uint8_t  arc_dhost;
45276788Sdelphij	uint8_t  arc_type;
46276788Sdelphij	/*
47276788Sdelphij	 * only present for newstyle encoding with LL fragmentation.
48276788Sdelphij	 * Don't use sizeof(anything), use ARC_HDR{,NEW}LEN instead.
49276788Sdelphij	 */
50276788Sdelphij	uint8_t  arc_flag;
51276788Sdelphij	uint16_t arc_seqid;
52276788Sdelphij
53276788Sdelphij	/*
54276788Sdelphij	 * only present in exception packets (arc_flag == 0xff)
55276788Sdelphij	 */
56276788Sdelphij	uint8_t  arc_type2;	/* same as arc_type */
57276788Sdelphij	uint8_t  arc_flag2;	/* real flag value */
58276788Sdelphij	uint16_t arc_seqid2;	/* real seqid value */
59276788Sdelphij};
60276788Sdelphij
61276788Sdelphij#define	ARC_HDRLEN		3
62276788Sdelphij#define	ARC_HDRNEWLEN		6
63276788Sdelphij#define	ARC_HDRNEWLEN_EXC	10
64276788Sdelphij
65276788Sdelphij/* RFC 1051 */
66276788Sdelphij#define	ARCTYPE_IP_OLD		240	/* IP protocol */
67276788Sdelphij#define	ARCTYPE_ARP_OLD		241	/* address resolution protocol */
68276788Sdelphij
69276788Sdelphij/* RFC 1201 */
70276788Sdelphij#define	ARCTYPE_IP		212	/* IP protocol */
71276788Sdelphij#define	ARCTYPE_ARP		213	/* address resolution protocol */
72276788Sdelphij#define	ARCTYPE_REVARP		214	/* reverse addr resolution protocol */
73276788Sdelphij
74276788Sdelphij#define	ARCTYPE_ATALK		221	/* Appletalk */
75276788Sdelphij#define	ARCTYPE_BANIAN		247	/* Banyan Vines */
76276788Sdelphij#define	ARCTYPE_IPX		250	/* Novell IPX */
77276788Sdelphij
78276788Sdelphij#define ARCTYPE_INET6		0xc4	/* IPng */
79276788Sdelphij#define ARCTYPE_DIAGNOSE	0x80	/* as per ANSI/ATA 878.1 */
80276788Sdelphij
81276788Sdelphij/*
82276788Sdelphij * Structure of a 2.5MB/s Arcnet header on Linux.  Linux has
83276788Sdelphij * an extra "offset" field when given to interface code, and
84276788Sdelphij * never presents packets that look like exception frames.
85276788Sdelphij */
86276788Sdelphijstruct	arc_linux_header {
87276788Sdelphij	uint8_t  arc_shost;
88276788Sdelphij	uint8_t  arc_dhost;
89276788Sdelphij	uint16_t arc_offset;
90276788Sdelphij	uint8_t  arc_type;
91276788Sdelphij	/*
92276788Sdelphij	 * only present for newstyle encoding with LL fragmentation.
93276788Sdelphij	 * Don't use sizeof(anything), use ARC_LINUX_HDR{,NEW}LEN
94276788Sdelphij	 * instead.
95276788Sdelphij	 */
96276788Sdelphij	uint8_t  arc_flag;
97276788Sdelphij	uint16_t arc_seqid;
98276788Sdelphij};
99276788Sdelphij
100276788Sdelphij#define	ARC_LINUX_HDRLEN	5
101276788Sdelphij#define	ARC_LINUX_HDRNEWLEN	8
102276788Sdelphij
103276788Sdelphijstatic int arcnet_encap_print(netdissect_options *, u_char arctype, const u_char *p,
10498524Sfenner    u_int length, u_int caplen);
10598524Sfenner
106276788Sdelphijstatic const struct tok arctypemap[] = {
10798524Sfenner	{ ARCTYPE_IP_OLD,	"oldip" },
10898524Sfenner	{ ARCTYPE_ARP_OLD,	"oldarp" },
10998524Sfenner	{ ARCTYPE_IP,		"ip" },
11098524Sfenner	{ ARCTYPE_ARP,		"arp" },
11198524Sfenner	{ ARCTYPE_REVARP,	"rarp" },
11298524Sfenner	{ ARCTYPE_ATALK,	"atalk" },
11398524Sfenner	{ ARCTYPE_BANIAN,	"banyan" },
11498524Sfenner	{ ARCTYPE_IPX,		"ipx" },
11598524Sfenner	{ ARCTYPE_INET6,	"ipv6" },
11698524Sfenner	{ ARCTYPE_DIAGNOSE,	"diag" },
11798524Sfenner	{ 0, 0 }
11898524Sfenner};
11998524Sfenner
12098524Sfennerstatic inline void
121276788Sdelphijarcnet_print(netdissect_options *ndo, const u_char *bp, u_int length, int phds,
122276788Sdelphij             int flag, u_int seqid)
12398524Sfenner{
12498524Sfenner	const struct arc_header *ap;
12598524Sfenner	const char *arctypename;
12698524Sfenner
12798524Sfenner
12898524Sfenner	ap = (const struct arc_header *)bp;
12998524Sfenner
13098524Sfenner
131276788Sdelphij	if (ndo->ndo_qflag) {
132276788Sdelphij		ND_PRINT((ndo, "%02x %02x %d: ",
13398524Sfenner			     ap->arc_shost,
13498524Sfenner			     ap->arc_dhost,
135276788Sdelphij			     length));
13698524Sfenner		return;
13798524Sfenner	}
13898524Sfenner
13998524Sfenner	arctypename = tok2str(arctypemap, "%02x", ap->arc_type);
14098524Sfenner
14198524Sfenner	if (!phds) {
142276788Sdelphij		ND_PRINT((ndo, "%02x %02x %s %d: ",
14398524Sfenner			     ap->arc_shost, ap->arc_dhost, arctypename,
144276788Sdelphij			     length));
14598524Sfenner			     return;
14698524Sfenner	}
14798524Sfenner
14898524Sfenner	if (flag == 0) {
149276788Sdelphij		ND_PRINT((ndo, "%02x %02x %s seqid %04x %d: ",
15098524Sfenner			ap->arc_shost, ap->arc_dhost, arctypename, seqid,
151276788Sdelphij			length));
15298524Sfenner			return;
15398524Sfenner	}
15498524Sfenner
15598524Sfenner	if (flag & 1)
156276788Sdelphij		ND_PRINT((ndo, "%02x %02x %s seqid %04x "
15798524Sfenner			"(first of %d fragments) %d: ",
15898524Sfenner			ap->arc_shost, ap->arc_dhost, arctypename, seqid,
159276788Sdelphij			(flag + 3) / 2, length));
16098524Sfenner	else
161276788Sdelphij		ND_PRINT((ndo, "%02x %02x %s seqid %04x "
16298524Sfenner			"(fragment %d) %d: ",
16398524Sfenner			ap->arc_shost, ap->arc_dhost, arctypename, seqid,
164276788Sdelphij			flag/2 + 1, length));
16598524Sfenner}
16698524Sfenner
16798524Sfenner/*
168127668Sbms * This is the top level routine of the printer.  'p' points
169127668Sbms * to the ARCNET header of the packet, 'h->ts' is the timestamp,
170146773Ssam * 'h->len' is the length of the packet off the wire, and 'h->caplen'
17198524Sfenner * is the number of bytes actually captured.
17298524Sfenner */
173127668Sbmsu_int
174276788Sdelphijarcnet_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p)
17598524Sfenner{
17698524Sfenner	u_int caplen = h->caplen;
17798524Sfenner	u_int length = h->len;
17898524Sfenner	const struct arc_header *ap;
17998524Sfenner
18098524Sfenner	int phds, flag = 0, archdrlen = 0;
18198524Sfenner	u_int seqid = 0;
18298524Sfenner	u_char arc_type;
18398524Sfenner
184285275Spkelsey	if (caplen < ARC_HDRLEN || length < ARC_HDRLEN) {
185276788Sdelphij		ND_PRINT((ndo, "[|arcnet]"));
186127668Sbms		return (caplen);
18798524Sfenner	}
18898524Sfenner
18998524Sfenner	ap = (const struct arc_header *)p;
19098524Sfenner	arc_type = ap->arc_type;
19198524Sfenner
19298524Sfenner	switch (arc_type) {
19398524Sfenner	default:
19498524Sfenner		phds = 1;
19598524Sfenner		break;
19698524Sfenner	case ARCTYPE_IP_OLD:
19798524Sfenner	case ARCTYPE_ARP_OLD:
19898524Sfenner	case ARCTYPE_DIAGNOSE:
19998524Sfenner		phds = 0;
20098524Sfenner		archdrlen = ARC_HDRLEN;
20198524Sfenner		break;
20298524Sfenner	}
20398524Sfenner
20498524Sfenner	if (phds) {
205285275Spkelsey		if (caplen < ARC_HDRNEWLEN || length < ARC_HDRNEWLEN) {
206276788Sdelphij			arcnet_print(ndo, p, length, 0, 0, 0);
207276788Sdelphij			ND_PRINT((ndo, "[|phds]"));
208127668Sbms			return (caplen);
20998524Sfenner		}
21098524Sfenner
21198524Sfenner		if (ap->arc_flag == 0xff) {
212285275Spkelsey			if (caplen < ARC_HDRNEWLEN_EXC || length < ARC_HDRNEWLEN_EXC) {
213276788Sdelphij				arcnet_print(ndo, p, length, 0, 0, 0);
214276788Sdelphij				ND_PRINT((ndo, "[|phds extended]"));
215127668Sbms				return (caplen);
21698524Sfenner			}
21798524Sfenner			flag = ap->arc_flag2;
218214478Srpaulo			seqid = EXTRACT_16BITS(&ap->arc_seqid2);
21998524Sfenner			archdrlen = ARC_HDRNEWLEN_EXC;
22098524Sfenner		} else {
22198524Sfenner			flag = ap->arc_flag;
222214478Srpaulo			seqid = EXTRACT_16BITS(&ap->arc_seqid);
22398524Sfenner			archdrlen = ARC_HDRNEWLEN;
22498524Sfenner		}
22598524Sfenner	}
22698524Sfenner
22798524Sfenner
228276788Sdelphij	if (ndo->ndo_eflag)
229276788Sdelphij		arcnet_print(ndo, p, length, phds, flag, seqid);
23098524Sfenner
23198524Sfenner	/*
232127668Sbms	 * Go past the ARCNET header.
23398524Sfenner	 */
23498524Sfenner	length -= archdrlen;
23598524Sfenner	caplen -= archdrlen;
23698524Sfenner	p += archdrlen;
23798524Sfenner
238127668Sbms	if (phds && flag && (flag & 1) == 0) {
239127668Sbms		/*
240127668Sbms		 * This is a middle fragment.
241127668Sbms		 */
242127668Sbms		return (archdrlen);
243127668Sbms	}
24498524Sfenner
245276788Sdelphij	if (!arcnet_encap_print(ndo, arc_type, p, length, caplen))
246276788Sdelphij		ND_DEFAULTPRINT(p, caplen);
247127668Sbms
248127668Sbms	return (archdrlen);
249127668Sbms}
250127668Sbms
251127668Sbms/*
252127668Sbms * This is the top level routine of the printer.  'p' points
253127668Sbms * to the ARCNET header of the packet, 'h->ts' is the timestamp,
254146773Ssam * 'h->len' is the length of the packet off the wire, and 'h->caplen'
255127668Sbms * is the number of bytes actually captured.  It is quite similar
256127668Sbms * to the non-Linux style printer except that Linux doesn't ever
257127668Sbms * supply packets that look like exception frames, it always supplies
258127668Sbms * reassembled packets rather than raw frames, and headers have an
259127668Sbms * extra "offset" field between the src/dest and packet type.
260127668Sbms */
261127668Sbmsu_int
262276788Sdelphijarcnet_linux_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p)
263127668Sbms{
264127668Sbms	u_int caplen = h->caplen;
265127668Sbms	u_int length = h->len;
266127668Sbms	const struct arc_linux_header *ap;
267127668Sbms
268127668Sbms	int archdrlen = 0;
269127668Sbms	u_char arc_type;
270127668Sbms
271285275Spkelsey	if (caplen < ARC_LINUX_HDRLEN || length < ARC_LINUX_HDRLEN) {
272276788Sdelphij		ND_PRINT((ndo, "[|arcnet]"));
273127668Sbms		return (caplen);
27498524Sfenner	}
27598524Sfenner
276127668Sbms	ap = (const struct arc_linux_header *)p;
277127668Sbms	arc_type = ap->arc_type;
278127668Sbms
279127668Sbms	switch (arc_type) {
280127668Sbms	default:
281127668Sbms		archdrlen = ARC_LINUX_HDRNEWLEN;
282285275Spkelsey		if (caplen < ARC_LINUX_HDRNEWLEN || length < ARC_LINUX_HDRNEWLEN) {
283276788Sdelphij			ND_PRINT((ndo, "[|arcnet]"));
284127668Sbms			return (caplen);
285127668Sbms		}
286127668Sbms		break;
287127668Sbms	case ARCTYPE_IP_OLD:
288127668Sbms	case ARCTYPE_ARP_OLD:
289127668Sbms	case ARCTYPE_DIAGNOSE:
290127668Sbms		archdrlen = ARC_LINUX_HDRLEN;
291127668Sbms		break;
292127668Sbms	}
293127668Sbms
294276788Sdelphij	if (ndo->ndo_eflag)
295276788Sdelphij		arcnet_print(ndo, p, length, 0, 0, 0);
296127668Sbms
297127668Sbms	/*
298127668Sbms	 * Go past the ARCNET header.
299127668Sbms	 */
300127668Sbms	length -= archdrlen;
301127668Sbms	caplen -= archdrlen;
302127668Sbms	p += archdrlen;
303127668Sbms
304276788Sdelphij	if (!arcnet_encap_print(ndo, arc_type, p, length, caplen))
305276788Sdelphij		ND_DEFAULTPRINT(p, caplen);
30698524Sfenner
307127668Sbms	return (archdrlen);
30898524Sfenner}
30998524Sfenner
31098524Sfenner/*
31198524Sfenner * Prints the packet encapsulated in an ARCnet data field,
31298524Sfenner * given the ARCnet system code.
31398524Sfenner *
31498524Sfenner * Returns non-zero if it can do so, zero if the system code is unknown.
31598524Sfenner */
31698524Sfenner
31798524Sfenner
318127668Sbmsstatic int
319276788Sdelphijarcnet_encap_print(netdissect_options *ndo, u_char arctype, const u_char *p,
32098524Sfenner    u_int length, u_int caplen)
32198524Sfenner{
32298524Sfenner	switch (arctype) {
32398524Sfenner
32498524Sfenner	case ARCTYPE_IP_OLD:
32598524Sfenner	case ARCTYPE_IP:
326276788Sdelphij	        ip_print(ndo, p, length);
32798524Sfenner		return (1);
32898524Sfenner
32998524Sfenner	case ARCTYPE_INET6:
330276788Sdelphij		ip6_print(ndo, p, length);
33198524Sfenner		return (1);
33298524Sfenner
33398524Sfenner	case ARCTYPE_ARP_OLD:
33498524Sfenner	case ARCTYPE_ARP:
33598524Sfenner	case ARCTYPE_REVARP:
336276788Sdelphij		arp_print(ndo, p, length, caplen);
33798524Sfenner		return (1);
33898524Sfenner
33998524Sfenner	case ARCTYPE_ATALK:	/* XXX was this ever used? */
340276788Sdelphij		if (ndo->ndo_vflag)
341276788Sdelphij			ND_PRINT((ndo, "et1 "));
342276788Sdelphij		atalk_print(ndo, p, length);
34398524Sfenner		return (1);
34498524Sfenner
345127668Sbms	case ARCTYPE_IPX:
346276788Sdelphij		ipx_print(ndo, p, length);
347127668Sbms		return (1);
348127668Sbms
34998524Sfenner	default:
35098524Sfenner		return (0);
35198524Sfenner	}
35298524Sfenner}
353146773Ssam
354146773Ssam/*
355146773Ssam * Local Variables:
356146773Ssam * c-style: bsd
357146773Ssam * End:
358146773Ssam */
359146773Ssam
360