xref: /netbsd-src/external/bsd/tcpdump/dist/print-arcnet.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
10f74e101Schristos /*
20f74e101Schristos  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
30f74e101Schristos  *	The Regents of the University of California.  All rights reserved.
40f74e101Schristos  *
50f74e101Schristos  * Redistribution and use in source and binary forms, with or without
60f74e101Schristos  * modification, are permitted provided that: (1) source code distributions
70f74e101Schristos  * retain the above copyright notice and this paragraph in its entirety, (2)
80f74e101Schristos  * distributions including binary code include the above copyright notice and
90f74e101Schristos  * this paragraph in its entirety in the documentation or other materials
100f74e101Schristos  * provided with the distribution, and (3) all advertising materials mentioning
110f74e101Schristos  * features or use of this software display the following acknowledgement:
120f74e101Schristos  * ``This product includes software developed by the University of California,
130f74e101Schristos  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
140f74e101Schristos  * the University nor the names of its contributors may be used to endorse
150f74e101Schristos  * or promote products derived from this software without specific prior
160f74e101Schristos  * written permission.
170f74e101Schristos  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
180f74e101Schristos  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
190f74e101Schristos  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
200f74e101Schristos  *
210f74e101Schristos  * From: NetBSD: print-arcnet.c,v 1.2 2000/04/24 13:02:28 itojun Exp
220f74e101Schristos  */
2311b3aaa1Schristos #include <sys/cdefs.h>
240f74e101Schristos #ifndef lint
25*26ba0b50Schristos __RCSID("$NetBSD: print-arcnet.c,v 1.10 2024/09/02 16:15:30 christos Exp $");
260f74e101Schristos #endif
270f74e101Schristos 
28dc860a36Sspz /* \summary: Attached Resource Computer NETwork (ARCNET) printer */
29dc860a36Sspz 
30c74ad251Schristos #include <config.h>
310f74e101Schristos 
32c74ad251Schristos #include "netdissect-stdinc.h"
330f74e101Schristos 
34fdccd7e4Schristos #include "netdissect.h"
350f74e101Schristos #include "extract.h"
360f74e101Schristos 
37b3a00663Schristos /*
38b3a00663Schristos  * from: NetBSD: if_arc.h,v 1.13 1999/11/19 20:41:19 thorpej Exp
39b3a00663Schristos  */
40b3a00663Schristos 
41b3a00663Schristos /*
42b3a00663Schristos  * Structure of a 2.5MB/s Arcnet header on the BSDs,
43b3a00663Schristos  * as given to interface code.
44b3a00663Schristos  */
45b3a00663Schristos struct	arc_header {
46c74ad251Schristos 	nd_uint8_t  arc_shost;
47c74ad251Schristos 	nd_uint8_t  arc_dhost;
48c74ad251Schristos 	nd_uint8_t  arc_type;
49b3a00663Schristos 	/*
50b3a00663Schristos 	 * only present for newstyle encoding with LL fragmentation.
51b3a00663Schristos 	 * Don't use sizeof(anything), use ARC_HDR{,NEW}LEN instead.
52b3a00663Schristos 	 */
53c74ad251Schristos 	nd_uint8_t  arc_flag;
54c74ad251Schristos 	nd_uint16_t arc_seqid;
55b3a00663Schristos 
56b3a00663Schristos 	/*
57b3a00663Schristos 	 * only present in exception packets (arc_flag == 0xff)
58b3a00663Schristos 	 */
59c74ad251Schristos 	nd_uint8_t  arc_type2;	/* same as arc_type */
60c74ad251Schristos 	nd_uint8_t  arc_flag2;	/* real flag value */
61c74ad251Schristos 	nd_uint16_t arc_seqid2;	/* real seqid value */
62b3a00663Schristos };
63b3a00663Schristos 
64b3a00663Schristos #define	ARC_HDRLEN		3
65b3a00663Schristos #define	ARC_HDRNEWLEN		6
66b3a00663Schristos #define	ARC_HDRNEWLEN_EXC	10
67b3a00663Schristos 
68b3a00663Schristos /* RFC 1051 */
69b3a00663Schristos #define	ARCTYPE_IP_OLD		240	/* IP protocol */
70b3a00663Schristos #define	ARCTYPE_ARP_OLD		241	/* address resolution protocol */
71b3a00663Schristos 
72b3a00663Schristos /* RFC 1201 */
73b3a00663Schristos #define	ARCTYPE_IP		212	/* IP protocol */
74b3a00663Schristos #define	ARCTYPE_ARP		213	/* address resolution protocol */
75b3a00663Schristos #define	ARCTYPE_REVARP		214	/* reverse addr resolution protocol */
76b3a00663Schristos 
77b3a00663Schristos #define	ARCTYPE_ATALK		221	/* Appletalk */
78b3a00663Schristos #define	ARCTYPE_BANIAN		247	/* Banyan Vines */
79b3a00663Schristos #define	ARCTYPE_IPX		250	/* Novell IPX */
80b3a00663Schristos 
81b3a00663Schristos #define ARCTYPE_INET6		0xc4	/* IPng */
82b3a00663Schristos #define ARCTYPE_DIAGNOSE	0x80	/* as per ANSI/ATA 878.1 */
83b3a00663Schristos 
84b3a00663Schristos /*
85b3a00663Schristos  * Structure of a 2.5MB/s Arcnet header on Linux.  Linux has
86b3a00663Schristos  * an extra "offset" field when given to interface code, and
87b3a00663Schristos  * never presents packets that look like exception frames.
88b3a00663Schristos  */
89b3a00663Schristos struct	arc_linux_header {
90c74ad251Schristos 	nd_uint8_t  arc_shost;
91c74ad251Schristos 	nd_uint8_t  arc_dhost;
92c74ad251Schristos 	nd_uint16_t arc_offset;
93c74ad251Schristos 	nd_uint8_t  arc_type;
94b3a00663Schristos 	/*
95b3a00663Schristos 	 * only present for newstyle encoding with LL fragmentation.
96b3a00663Schristos 	 * Don't use sizeof(anything), use ARC_LINUX_HDR{,NEW}LEN
97b3a00663Schristos 	 * instead.
98b3a00663Schristos 	 */
99c74ad251Schristos 	nd_uint8_t  arc_flag;
100c74ad251Schristos 	nd_uint16_t arc_seqid;
101b3a00663Schristos };
102b3a00663Schristos 
103b3a00663Schristos #define	ARC_LINUX_HDRLEN	5
104b3a00663Schristos #define	ARC_LINUX_HDRNEWLEN	8
105b3a00663Schristos 
106b3a00663Schristos static int arcnet_encap_print(netdissect_options *, u_char arctype, const u_char *p,
1070f74e101Schristos     u_int length, u_int caplen);
1080f74e101Schristos 
109870189d2Schristos static const struct tok arctypemap[] = {
1100f74e101Schristos 	{ ARCTYPE_IP_OLD,	"oldip" },
1110f74e101Schristos 	{ ARCTYPE_ARP_OLD,	"oldarp" },
1120f74e101Schristos 	{ ARCTYPE_IP,		"ip" },
1130f74e101Schristos 	{ ARCTYPE_ARP,		"arp" },
1140f74e101Schristos 	{ ARCTYPE_REVARP,	"rarp" },
1150f74e101Schristos 	{ ARCTYPE_ATALK,	"atalk" },
1160f74e101Schristos 	{ ARCTYPE_BANIAN,	"banyan" },
1170f74e101Schristos 	{ ARCTYPE_IPX,		"ipx" },
1180f74e101Schristos 	{ ARCTYPE_INET6,	"ipv6" },
1190f74e101Schristos 	{ ARCTYPE_DIAGNOSE,	"diag" },
120c74ad251Schristos 	{ 0, NULL }
1210f74e101Schristos };
1220f74e101Schristos 
123c74ad251Schristos static void
124b3a00663Schristos arcnet_print(netdissect_options *ndo, const u_char *bp, u_int length, int phds,
125c74ad251Schristos              u_int flag, u_int seqid)
1260f74e101Schristos {
1270f74e101Schristos 	const struct arc_header *ap;
1280f74e101Schristos 	const char *arctypename;
1290f74e101Schristos 
130c74ad251Schristos 	ndo->ndo_protocol = "arcnet";
1310f74e101Schristos 	ap = (const struct arc_header *)bp;
1320f74e101Schristos 
133b3a00663Schristos 	if (ndo->ndo_qflag) {
134c74ad251Schristos 		ND_PRINT("%02x %02x %u: ",
135c74ad251Schristos 			     GET_U_1(ap->arc_shost),
136c74ad251Schristos 			     GET_U_1(ap->arc_dhost),
137c74ad251Schristos 			     length);
1380f74e101Schristos 		return;
1390f74e101Schristos 	}
1400f74e101Schristos 
141c74ad251Schristos 	arctypename = tok2str(arctypemap, "%02x", GET_U_1(ap->arc_type));
1420f74e101Schristos 
1430f74e101Schristos 	if (!phds) {
144c74ad251Schristos 		ND_PRINT("%02x %02x %s %u: ",
145c74ad251Schristos 			     GET_U_1(ap->arc_shost),
146c74ad251Schristos 			     GET_U_1(ap->arc_dhost),
147c74ad251Schristos 			     arctypename,
148c74ad251Schristos 			     length);
1490f74e101Schristos 		return;
1500f74e101Schristos 	}
1510f74e101Schristos 
1520f74e101Schristos 	if (flag == 0) {
153c74ad251Schristos 		ND_PRINT("%02x %02x %s seqid %04x %u: ",
154c74ad251Schristos 			GET_U_1(ap->arc_shost),
155c74ad251Schristos 			GET_U_1(ap->arc_dhost),
156c74ad251Schristos 			arctypename, seqid,
157c74ad251Schristos 			length);
1580f74e101Schristos 		return;
1590f74e101Schristos 	}
1600f74e101Schristos 
1610f74e101Schristos 	if (flag & 1)
162c74ad251Schristos 		ND_PRINT("%02x %02x %s seqid %04x "
163c74ad251Schristos 			"(first of %u fragments) %u: ",
164c74ad251Schristos 			GET_U_1(ap->arc_shost),
165c74ad251Schristos 			GET_U_1(ap->arc_dhost),
166c74ad251Schristos 			arctypename, seqid,
167c74ad251Schristos 			(flag + 3) / 2, length);
1680f74e101Schristos 	else
169c74ad251Schristos 		ND_PRINT("%02x %02x %s seqid %04x "
170c74ad251Schristos 			"(fragment %u) %u: ",
171c74ad251Schristos 			GET_U_1(ap->arc_shost),
172c74ad251Schristos 			GET_U_1(ap->arc_dhost),
173c74ad251Schristos 			arctypename, seqid,
174c74ad251Schristos 			flag/2 + 1, length);
1750f74e101Schristos }
1760f74e101Schristos 
1770f74e101Schristos /*
1780f74e101Schristos  * This is the top level routine of the printer.  'p' points
1790f74e101Schristos  * to the ARCNET header of the packet, 'h->ts' is the timestamp,
1800f74e101Schristos  * 'h->len' is the length of the packet off the wire, and 'h->caplen'
1810f74e101Schristos  * is the number of bytes actually captured.
1820f74e101Schristos  */
183c74ad251Schristos void
184b3a00663Schristos arcnet_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p)
1850f74e101Schristos {
1860f74e101Schristos 	u_int caplen = h->caplen;
1870f74e101Schristos 	u_int length = h->len;
1880f74e101Schristos 	const struct arc_header *ap;
1890f74e101Schristos 
190c74ad251Schristos 	int phds;
191c74ad251Schristos 	u_int flag = 0, archdrlen = 0;
1920f74e101Schristos 	u_int seqid = 0;
1930f74e101Schristos 	u_char arc_type;
1940f74e101Schristos 
195c74ad251Schristos 	ndo->ndo_protocol = "arcnet";
196c74ad251Schristos 	if (caplen < ARC_HDRLEN) {
197c74ad251Schristos 		ndo->ndo_ll_hdr_len += caplen;
198c74ad251Schristos 		nd_trunc_longjmp(ndo);
1990f74e101Schristos 	}
2000f74e101Schristos 
2010f74e101Schristos 	ap = (const struct arc_header *)p;
202c74ad251Schristos 	arc_type = GET_U_1(ap->arc_type);
2030f74e101Schristos 
2040f74e101Schristos 	switch (arc_type) {
2050f74e101Schristos 	default:
2060f74e101Schristos 		phds = 1;
2070f74e101Schristos 		break;
2080f74e101Schristos 	case ARCTYPE_IP_OLD:
2090f74e101Schristos 	case ARCTYPE_ARP_OLD:
2100f74e101Schristos 	case ARCTYPE_DIAGNOSE:
2110f74e101Schristos 		phds = 0;
2120f74e101Schristos 		archdrlen = ARC_HDRLEN;
2130f74e101Schristos 		break;
2140f74e101Schristos 	}
2150f74e101Schristos 
2160f74e101Schristos 	if (phds) {
217c74ad251Schristos 		if (caplen < ARC_HDRNEWLEN) {
218b3a00663Schristos 			arcnet_print(ndo, p, length, 0, 0, 0);
219c74ad251Schristos 			ND_PRINT(" phds");
220c74ad251Schristos 			ndo->ndo_ll_hdr_len += caplen;
221c74ad251Schristos 			nd_trunc_longjmp(ndo);
2220f74e101Schristos 		}
2230f74e101Schristos 
224c74ad251Schristos 		flag = GET_U_1(ap->arc_flag);
225c74ad251Schristos 		if (flag == 0xff) {
226c74ad251Schristos 			if (caplen < ARC_HDRNEWLEN_EXC) {
227b3a00663Schristos 				arcnet_print(ndo, p, length, 0, 0, 0);
228c74ad251Schristos 				ND_PRINT(" phds extended");
229c74ad251Schristos 				ndo->ndo_ll_hdr_len += caplen;
230c74ad251Schristos 				nd_trunc_longjmp(ndo);
2310f74e101Schristos 			}
232c74ad251Schristos 			flag = GET_U_1(ap->arc_flag2);
233c74ad251Schristos 			seqid = GET_BE_U_2(ap->arc_seqid2);
2340f74e101Schristos 			archdrlen = ARC_HDRNEWLEN_EXC;
2350f74e101Schristos 		} else {
236c74ad251Schristos 			seqid = GET_BE_U_2(ap->arc_seqid);
2370f74e101Schristos 			archdrlen = ARC_HDRNEWLEN;
2380f74e101Schristos 		}
2390f74e101Schristos 	}
2400f74e101Schristos 
2410f74e101Schristos 
242b3a00663Schristos 	if (ndo->ndo_eflag)
243b3a00663Schristos 		arcnet_print(ndo, p, length, phds, flag, seqid);
2440f74e101Schristos 
2450f74e101Schristos 	/*
2460f74e101Schristos 	 * Go past the ARCNET header.
2470f74e101Schristos 	 */
2480f74e101Schristos 	length -= archdrlen;
2490f74e101Schristos 	caplen -= archdrlen;
2500f74e101Schristos 	p += archdrlen;
2510f74e101Schristos 
2520f74e101Schristos 	if (phds && flag && (flag & 1) == 0) {
2530f74e101Schristos 		/*
2540f74e101Schristos 		 * This is a middle fragment.
2550f74e101Schristos 		 */
256c74ad251Schristos 		ndo->ndo_ll_hdr_len += archdrlen;
257c74ad251Schristos 		return;
2580f74e101Schristos 	}
2590f74e101Schristos 
260b3a00663Schristos 	if (!arcnet_encap_print(ndo, arc_type, p, length, caplen))
261b3a00663Schristos 		ND_DEFAULTPRINT(p, caplen);
2620f74e101Schristos 
263c74ad251Schristos 	ndo->ndo_ll_hdr_len += archdrlen;
2640f74e101Schristos }
2650f74e101Schristos 
2660f74e101Schristos /*
2670f74e101Schristos  * This is the top level routine of the printer.  'p' points
2680f74e101Schristos  * to the ARCNET header of the packet, 'h->ts' is the timestamp,
2690f74e101Schristos  * 'h->len' is the length of the packet off the wire, and 'h->caplen'
2700f74e101Schristos  * is the number of bytes actually captured.  It is quite similar
2710f74e101Schristos  * to the non-Linux style printer except that Linux doesn't ever
2720f74e101Schristos  * supply packets that look like exception frames, it always supplies
2730f74e101Schristos  * reassembled packets rather than raw frames, and headers have an
2740f74e101Schristos  * extra "offset" field between the src/dest and packet type.
2750f74e101Schristos  */
276c74ad251Schristos void
277b3a00663Schristos arcnet_linux_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p)
2780f74e101Schristos {
2790f74e101Schristos 	u_int caplen = h->caplen;
2800f74e101Schristos 	u_int length = h->len;
2810f74e101Schristos 	const struct arc_linux_header *ap;
2820f74e101Schristos 
2830f74e101Schristos 	int archdrlen = 0;
2840f74e101Schristos 	u_char arc_type;
2850f74e101Schristos 
286c74ad251Schristos 	ndo->ndo_protocol = "arcnet_linux";
287c74ad251Schristos 	if (caplen < ARC_LINUX_HDRLEN) {
288c74ad251Schristos 		ndo->ndo_ll_hdr_len += caplen;
289c74ad251Schristos 		nd_trunc_longjmp(ndo);
2900f74e101Schristos 	}
2910f74e101Schristos 
2920f74e101Schristos 	ap = (const struct arc_linux_header *)p;
293c74ad251Schristos 	arc_type = GET_U_1(ap->arc_type);
2940f74e101Schristos 
2950f74e101Schristos 	switch (arc_type) {
2960f74e101Schristos 	default:
2970f74e101Schristos 		archdrlen = ARC_LINUX_HDRNEWLEN;
298c74ad251Schristos 		if (caplen < ARC_LINUX_HDRNEWLEN) {
299c74ad251Schristos 			ndo->ndo_ll_hdr_len += caplen;
300c74ad251Schristos 			nd_trunc_longjmp(ndo);
3010f74e101Schristos 		}
3020f74e101Schristos 		break;
3030f74e101Schristos 	case ARCTYPE_IP_OLD:
3040f74e101Schristos 	case ARCTYPE_ARP_OLD:
3050f74e101Schristos 	case ARCTYPE_DIAGNOSE:
3060f74e101Schristos 		archdrlen = ARC_LINUX_HDRLEN;
3070f74e101Schristos 		break;
3080f74e101Schristos 	}
3090f74e101Schristos 
310b3a00663Schristos 	if (ndo->ndo_eflag)
311b3a00663Schristos 		arcnet_print(ndo, p, length, 0, 0, 0);
3120f74e101Schristos 
3130f74e101Schristos 	/*
3140f74e101Schristos 	 * Go past the ARCNET header.
3150f74e101Schristos 	 */
3160f74e101Schristos 	length -= archdrlen;
3170f74e101Schristos 	caplen -= archdrlen;
3180f74e101Schristos 	p += archdrlen;
3190f74e101Schristos 
320b3a00663Schristos 	if (!arcnet_encap_print(ndo, arc_type, p, length, caplen))
321b3a00663Schristos 		ND_DEFAULTPRINT(p, caplen);
3220f74e101Schristos 
323c74ad251Schristos 	ndo->ndo_ll_hdr_len += archdrlen;
3240f74e101Schristos }
3250f74e101Schristos 
3260f74e101Schristos /*
3270f74e101Schristos  * Prints the packet encapsulated in an ARCnet data field,
3280f74e101Schristos  * given the ARCnet system code.
3290f74e101Schristos  *
3300f74e101Schristos  * Returns non-zero if it can do so, zero if the system code is unknown.
3310f74e101Schristos  */
3320f74e101Schristos 
3330f74e101Schristos 
3340f74e101Schristos static int
335b3a00663Schristos arcnet_encap_print(netdissect_options *ndo, u_char arctype, const u_char *p,
3360f74e101Schristos     u_int length, u_int caplen)
3370f74e101Schristos {
3380f74e101Schristos 	switch (arctype) {
3390f74e101Schristos 
3400f74e101Schristos 	case ARCTYPE_IP_OLD:
3410f74e101Schristos 	case ARCTYPE_IP:
342b3a00663Schristos 	        ip_print(ndo, p, length);
3430f74e101Schristos 		return (1);
3440f74e101Schristos 
3450f74e101Schristos 	case ARCTYPE_INET6:
346b3a00663Schristos 		ip6_print(ndo, p, length);
3470f74e101Schristos 		return (1);
3480f74e101Schristos 
3490f74e101Schristos 	case ARCTYPE_ARP_OLD:
3500f74e101Schristos 	case ARCTYPE_ARP:
3510f74e101Schristos 	case ARCTYPE_REVARP:
352b3a00663Schristos 		arp_print(ndo, p, length, caplen);
3530f74e101Schristos 		return (1);
3540f74e101Schristos 
3550f74e101Schristos 	case ARCTYPE_ATALK:	/* XXX was this ever used? */
356b3a00663Schristos 		if (ndo->ndo_vflag)
357c74ad251Schristos 			ND_PRINT("et1 ");
358b3a00663Schristos 		atalk_print(ndo, p, length);
3590f74e101Schristos 		return (1);
3600f74e101Schristos 
3610f74e101Schristos 	case ARCTYPE_IPX:
362b3a00663Schristos 		ipx_print(ndo, p, length);
3630f74e101Schristos 		return (1);
3640f74e101Schristos 
3650f74e101Schristos 	default:
3660f74e101Schristos 		return (0);
3670f74e101Schristos 	}
3680f74e101Schristos }
369