xref: /netbsd-src/external/bsd/tcpdump/dist/print-arcnet.c (revision 3117ece4fc4a4ca4489ba793710b60b0d26bab6c)
1 /*
2  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that: (1) source code distributions
7  * retain the above copyright notice and this paragraph in its entirety, (2)
8  * distributions including binary code include the above copyright notice and
9  * this paragraph in its entirety in the documentation or other materials
10  * provided with the distribution, and (3) all advertising materials mentioning
11  * features or use of this software display the following acknowledgement:
12  * ``This product includes software developed by the University of California,
13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14  * the University nor the names of its contributors may be used to endorse
15  * or promote products derived from this software without specific prior
16  * written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  *
21  * From: NetBSD: print-arcnet.c,v 1.2 2000/04/24 13:02:28 itojun Exp
22  */
23 #include <sys/cdefs.h>
24 #ifndef lint
25 __RCSID("$NetBSD: print-arcnet.c,v 1.10 2024/09/02 16:15:30 christos Exp $");
26 #endif
27 
28 /* \summary: Attached Resource Computer NETwork (ARCNET) printer */
29 
30 #include <config.h>
31 
32 #include "netdissect-stdinc.h"
33 
34 #include "netdissect.h"
35 #include "extract.h"
36 
37 /*
38  * from: NetBSD: if_arc.h,v 1.13 1999/11/19 20:41:19 thorpej Exp
39  */
40 
41 /*
42  * Structure of a 2.5MB/s Arcnet header on the BSDs,
43  * as given to interface code.
44  */
45 struct	arc_header {
46 	nd_uint8_t  arc_shost;
47 	nd_uint8_t  arc_dhost;
48 	nd_uint8_t  arc_type;
49 	/*
50 	 * only present for newstyle encoding with LL fragmentation.
51 	 * Don't use sizeof(anything), use ARC_HDR{,NEW}LEN instead.
52 	 */
53 	nd_uint8_t  arc_flag;
54 	nd_uint16_t arc_seqid;
55 
56 	/*
57 	 * only present in exception packets (arc_flag == 0xff)
58 	 */
59 	nd_uint8_t  arc_type2;	/* same as arc_type */
60 	nd_uint8_t  arc_flag2;	/* real flag value */
61 	nd_uint16_t arc_seqid2;	/* real seqid value */
62 };
63 
64 #define	ARC_HDRLEN		3
65 #define	ARC_HDRNEWLEN		6
66 #define	ARC_HDRNEWLEN_EXC	10
67 
68 /* RFC 1051 */
69 #define	ARCTYPE_IP_OLD		240	/* IP protocol */
70 #define	ARCTYPE_ARP_OLD		241	/* address resolution protocol */
71 
72 /* RFC 1201 */
73 #define	ARCTYPE_IP		212	/* IP protocol */
74 #define	ARCTYPE_ARP		213	/* address resolution protocol */
75 #define	ARCTYPE_REVARP		214	/* reverse addr resolution protocol */
76 
77 #define	ARCTYPE_ATALK		221	/* Appletalk */
78 #define	ARCTYPE_BANIAN		247	/* Banyan Vines */
79 #define	ARCTYPE_IPX		250	/* Novell IPX */
80 
81 #define ARCTYPE_INET6		0xc4	/* IPng */
82 #define ARCTYPE_DIAGNOSE	0x80	/* as per ANSI/ATA 878.1 */
83 
84 /*
85  * Structure of a 2.5MB/s Arcnet header on Linux.  Linux has
86  * an extra "offset" field when given to interface code, and
87  * never presents packets that look like exception frames.
88  */
89 struct	arc_linux_header {
90 	nd_uint8_t  arc_shost;
91 	nd_uint8_t  arc_dhost;
92 	nd_uint16_t arc_offset;
93 	nd_uint8_t  arc_type;
94 	/*
95 	 * only present for newstyle encoding with LL fragmentation.
96 	 * Don't use sizeof(anything), use ARC_LINUX_HDR{,NEW}LEN
97 	 * instead.
98 	 */
99 	nd_uint8_t  arc_flag;
100 	nd_uint16_t arc_seqid;
101 };
102 
103 #define	ARC_LINUX_HDRLEN	5
104 #define	ARC_LINUX_HDRNEWLEN	8
105 
106 static int arcnet_encap_print(netdissect_options *, u_char arctype, const u_char *p,
107     u_int length, u_int caplen);
108 
109 static const struct tok arctypemap[] = {
110 	{ ARCTYPE_IP_OLD,	"oldip" },
111 	{ ARCTYPE_ARP_OLD,	"oldarp" },
112 	{ ARCTYPE_IP,		"ip" },
113 	{ ARCTYPE_ARP,		"arp" },
114 	{ ARCTYPE_REVARP,	"rarp" },
115 	{ ARCTYPE_ATALK,	"atalk" },
116 	{ ARCTYPE_BANIAN,	"banyan" },
117 	{ ARCTYPE_IPX,		"ipx" },
118 	{ ARCTYPE_INET6,	"ipv6" },
119 	{ ARCTYPE_DIAGNOSE,	"diag" },
120 	{ 0, NULL }
121 };
122 
123 static void
124 arcnet_print(netdissect_options *ndo, const u_char *bp, u_int length, int phds,
125              u_int flag, u_int seqid)
126 {
127 	const struct arc_header *ap;
128 	const char *arctypename;
129 
130 	ndo->ndo_protocol = "arcnet";
131 	ap = (const struct arc_header *)bp;
132 
133 	if (ndo->ndo_qflag) {
134 		ND_PRINT("%02x %02x %u: ",
135 			     GET_U_1(ap->arc_shost),
136 			     GET_U_1(ap->arc_dhost),
137 			     length);
138 		return;
139 	}
140 
141 	arctypename = tok2str(arctypemap, "%02x", GET_U_1(ap->arc_type));
142 
143 	if (!phds) {
144 		ND_PRINT("%02x %02x %s %u: ",
145 			     GET_U_1(ap->arc_shost),
146 			     GET_U_1(ap->arc_dhost),
147 			     arctypename,
148 			     length);
149 		return;
150 	}
151 
152 	if (flag == 0) {
153 		ND_PRINT("%02x %02x %s seqid %04x %u: ",
154 			GET_U_1(ap->arc_shost),
155 			GET_U_1(ap->arc_dhost),
156 			arctypename, seqid,
157 			length);
158 		return;
159 	}
160 
161 	if (flag & 1)
162 		ND_PRINT("%02x %02x %s seqid %04x "
163 			"(first of %u fragments) %u: ",
164 			GET_U_1(ap->arc_shost),
165 			GET_U_1(ap->arc_dhost),
166 			arctypename, seqid,
167 			(flag + 3) / 2, length);
168 	else
169 		ND_PRINT("%02x %02x %s seqid %04x "
170 			"(fragment %u) %u: ",
171 			GET_U_1(ap->arc_shost),
172 			GET_U_1(ap->arc_dhost),
173 			arctypename, seqid,
174 			flag/2 + 1, length);
175 }
176 
177 /*
178  * This is the top level routine of the printer.  'p' points
179  * to the ARCNET header of the packet, 'h->ts' is the timestamp,
180  * 'h->len' is the length of the packet off the wire, and 'h->caplen'
181  * is the number of bytes actually captured.
182  */
183 void
184 arcnet_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p)
185 {
186 	u_int caplen = h->caplen;
187 	u_int length = h->len;
188 	const struct arc_header *ap;
189 
190 	int phds;
191 	u_int flag = 0, archdrlen = 0;
192 	u_int seqid = 0;
193 	u_char arc_type;
194 
195 	ndo->ndo_protocol = "arcnet";
196 	if (caplen < ARC_HDRLEN) {
197 		ndo->ndo_ll_hdr_len += caplen;
198 		nd_trunc_longjmp(ndo);
199 	}
200 
201 	ap = (const struct arc_header *)p;
202 	arc_type = GET_U_1(ap->arc_type);
203 
204 	switch (arc_type) {
205 	default:
206 		phds = 1;
207 		break;
208 	case ARCTYPE_IP_OLD:
209 	case ARCTYPE_ARP_OLD:
210 	case ARCTYPE_DIAGNOSE:
211 		phds = 0;
212 		archdrlen = ARC_HDRLEN;
213 		break;
214 	}
215 
216 	if (phds) {
217 		if (caplen < ARC_HDRNEWLEN) {
218 			arcnet_print(ndo, p, length, 0, 0, 0);
219 			ND_PRINT(" phds");
220 			ndo->ndo_ll_hdr_len += caplen;
221 			nd_trunc_longjmp(ndo);
222 		}
223 
224 		flag = GET_U_1(ap->arc_flag);
225 		if (flag == 0xff) {
226 			if (caplen < ARC_HDRNEWLEN_EXC) {
227 				arcnet_print(ndo, p, length, 0, 0, 0);
228 				ND_PRINT(" phds extended");
229 				ndo->ndo_ll_hdr_len += caplen;
230 				nd_trunc_longjmp(ndo);
231 			}
232 			flag = GET_U_1(ap->arc_flag2);
233 			seqid = GET_BE_U_2(ap->arc_seqid2);
234 			archdrlen = ARC_HDRNEWLEN_EXC;
235 		} else {
236 			seqid = GET_BE_U_2(ap->arc_seqid);
237 			archdrlen = ARC_HDRNEWLEN;
238 		}
239 	}
240 
241 
242 	if (ndo->ndo_eflag)
243 		arcnet_print(ndo, p, length, phds, flag, seqid);
244 
245 	/*
246 	 * Go past the ARCNET header.
247 	 */
248 	length -= archdrlen;
249 	caplen -= archdrlen;
250 	p += archdrlen;
251 
252 	if (phds && flag && (flag & 1) == 0) {
253 		/*
254 		 * This is a middle fragment.
255 		 */
256 		ndo->ndo_ll_hdr_len += archdrlen;
257 		return;
258 	}
259 
260 	if (!arcnet_encap_print(ndo, arc_type, p, length, caplen))
261 		ND_DEFAULTPRINT(p, caplen);
262 
263 	ndo->ndo_ll_hdr_len += archdrlen;
264 }
265 
266 /*
267  * This is the top level routine of the printer.  'p' points
268  * to the ARCNET header of the packet, 'h->ts' is the timestamp,
269  * 'h->len' is the length of the packet off the wire, and 'h->caplen'
270  * is the number of bytes actually captured.  It is quite similar
271  * to the non-Linux style printer except that Linux doesn't ever
272  * supply packets that look like exception frames, it always supplies
273  * reassembled packets rather than raw frames, and headers have an
274  * extra "offset" field between the src/dest and packet type.
275  */
276 void
277 arcnet_linux_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p)
278 {
279 	u_int caplen = h->caplen;
280 	u_int length = h->len;
281 	const struct arc_linux_header *ap;
282 
283 	int archdrlen = 0;
284 	u_char arc_type;
285 
286 	ndo->ndo_protocol = "arcnet_linux";
287 	if (caplen < ARC_LINUX_HDRLEN) {
288 		ndo->ndo_ll_hdr_len += caplen;
289 		nd_trunc_longjmp(ndo);
290 	}
291 
292 	ap = (const struct arc_linux_header *)p;
293 	arc_type = GET_U_1(ap->arc_type);
294 
295 	switch (arc_type) {
296 	default:
297 		archdrlen = ARC_LINUX_HDRNEWLEN;
298 		if (caplen < ARC_LINUX_HDRNEWLEN) {
299 			ndo->ndo_ll_hdr_len += caplen;
300 			nd_trunc_longjmp(ndo);
301 		}
302 		break;
303 	case ARCTYPE_IP_OLD:
304 	case ARCTYPE_ARP_OLD:
305 	case ARCTYPE_DIAGNOSE:
306 		archdrlen = ARC_LINUX_HDRLEN;
307 		break;
308 	}
309 
310 	if (ndo->ndo_eflag)
311 		arcnet_print(ndo, p, length, 0, 0, 0);
312 
313 	/*
314 	 * Go past the ARCNET header.
315 	 */
316 	length -= archdrlen;
317 	caplen -= archdrlen;
318 	p += archdrlen;
319 
320 	if (!arcnet_encap_print(ndo, arc_type, p, length, caplen))
321 		ND_DEFAULTPRINT(p, caplen);
322 
323 	ndo->ndo_ll_hdr_len += archdrlen;
324 }
325 
326 /*
327  * Prints the packet encapsulated in an ARCnet data field,
328  * given the ARCnet system code.
329  *
330  * Returns non-zero if it can do so, zero if the system code is unknown.
331  */
332 
333 
334 static int
335 arcnet_encap_print(netdissect_options *ndo, u_char arctype, const u_char *p,
336     u_int length, u_int caplen)
337 {
338 	switch (arctype) {
339 
340 	case ARCTYPE_IP_OLD:
341 	case ARCTYPE_IP:
342 	        ip_print(ndo, p, length);
343 		return (1);
344 
345 	case ARCTYPE_INET6:
346 		ip6_print(ndo, p, length);
347 		return (1);
348 
349 	case ARCTYPE_ARP_OLD:
350 	case ARCTYPE_ARP:
351 	case ARCTYPE_REVARP:
352 		arp_print(ndo, p, length, caplen);
353 		return (1);
354 
355 	case ARCTYPE_ATALK:	/* XXX was this ever used? */
356 		if (ndo->ndo_vflag)
357 			ND_PRINT("et1 ");
358 		atalk_print(ndo, p, length);
359 		return (1);
360 
361 	case ARCTYPE_IPX:
362 		ipx_print(ndo, p, length);
363 		return (1);
364 
365 	default:
366 		return (0);
367 	}
368 }
369