xref: /freebsd/contrib/tcpdump/print-arcnet.c (revision 4f29da19bd44f0e99f021510460a81bf754c21d2)
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 #ifndef lint
24 static const char rcsid[] _U_ =
25     "@(#) $Header: /tcpdump/master/tcpdump/print-arcnet.c,v 1.20 2005/04/06 21:32:38 mcr Exp $ (LBL)";
26 #endif
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 
32 #include <tcpdump-stdinc.h>
33 
34 #include <stdio.h>
35 #include <pcap.h>
36 
37 #include "interface.h"
38 #include "arcnet.h"
39 
40 static int arcnet_encap_print(u_char arctype, const u_char *p,
41     u_int length, u_int caplen);
42 
43 struct tok arctypemap[] = {
44 	{ ARCTYPE_IP_OLD,	"oldip" },
45 	{ ARCTYPE_ARP_OLD,	"oldarp" },
46 	{ ARCTYPE_IP,		"ip" },
47 	{ ARCTYPE_ARP,		"arp" },
48 	{ ARCTYPE_REVARP,	"rarp" },
49 	{ ARCTYPE_ATALK,	"atalk" },
50 	{ ARCTYPE_BANIAN,	"banyan" },
51 	{ ARCTYPE_IPX,		"ipx" },
52 	{ ARCTYPE_INET6,	"ipv6" },
53 	{ ARCTYPE_DIAGNOSE,	"diag" },
54 	{ 0, 0 }
55 };
56 
57 static inline void
58 arcnet_print(const u_char *bp, u_int length, int phds, int flag, u_int seqid)
59 {
60 	const struct arc_header *ap;
61 	const char *arctypename;
62 
63 
64 	ap = (const struct arc_header *)bp;
65 
66 
67 	if (qflag) {
68 		(void)printf("%02x %02x %d: ",
69 			     ap->arc_shost,
70 			     ap->arc_dhost,
71 			     length);
72 		return;
73 	}
74 
75 	arctypename = tok2str(arctypemap, "%02x", ap->arc_type);
76 
77 	if (!phds) {
78 		(void)printf("%02x %02x %s %d: ",
79 			     ap->arc_shost, ap->arc_dhost, arctypename,
80 			     length);
81 			     return;
82 	}
83 
84 	if (flag == 0) {
85 		(void)printf("%02x %02x %s seqid %04x %d: ",
86 			ap->arc_shost, ap->arc_dhost, arctypename, seqid,
87 			length);
88 			return;
89 	}
90 
91 	if (flag & 1)
92 		(void)printf("%02x %02x %s seqid %04x "
93 			"(first of %d fragments) %d: ",
94 			ap->arc_shost, ap->arc_dhost, arctypename, seqid,
95 			(flag + 3) / 2, length);
96 	else
97 		(void)printf("%02x %02x %s seqid %04x "
98 			"(fragment %d) %d: ",
99 			ap->arc_shost, ap->arc_dhost, arctypename, seqid,
100 			flag/2 + 1, length);
101 }
102 
103 /*
104  * This is the top level routine of the printer.  'p' points
105  * to the ARCNET header of the packet, 'h->ts' is the timestamp,
106  * 'h->len' is the length of the packet off the wire, and 'h->caplen'
107  * is the number of bytes actually captured.
108  */
109 u_int
110 arcnet_if_print(const struct pcap_pkthdr *h, const u_char *p)
111 {
112 	u_int caplen = h->caplen;
113 	u_int length = h->len;
114 	const struct arc_header *ap;
115 
116 	int phds, flag = 0, archdrlen = 0;
117 	u_int seqid = 0;
118 	u_char arc_type;
119 
120 	if (caplen < ARC_HDRLEN) {
121 		printf("[|arcnet]");
122 		return (caplen);
123 	}
124 
125 	ap = (const struct arc_header *)p;
126 	arc_type = ap->arc_type;
127 
128 	switch (arc_type) {
129 	default:
130 		phds = 1;
131 		break;
132 	case ARCTYPE_IP_OLD:
133 	case ARCTYPE_ARP_OLD:
134 	case ARCTYPE_DIAGNOSE:
135 		phds = 0;
136 		archdrlen = ARC_HDRLEN;
137 		break;
138 	}
139 
140 	if (phds) {
141 		if (caplen < ARC_HDRNEWLEN) {
142 			arcnet_print(p, length, 0, 0, 0);
143 			printf("[|phds]");
144 			return (caplen);
145 		}
146 
147 		if (ap->arc_flag == 0xff) {
148 			if (caplen < ARC_HDRNEWLEN_EXC) {
149 				arcnet_print(p, length, 0, 0, 0);
150 				printf("[|phds extended]");
151 				return (caplen);
152 			}
153 			flag = ap->arc_flag2;
154 			seqid = ntohs(ap->arc_seqid2);
155 			archdrlen = ARC_HDRNEWLEN_EXC;
156 		} else {
157 			flag = ap->arc_flag;
158 			seqid = ntohs(ap->arc_seqid);
159 			archdrlen = ARC_HDRNEWLEN;
160 		}
161 	}
162 
163 
164 	if (eflag)
165 		arcnet_print(p, length, phds, flag, seqid);
166 
167 	/*
168 	 * Go past the ARCNET header.
169 	 */
170 	length -= archdrlen;
171 	caplen -= archdrlen;
172 	p += archdrlen;
173 
174 	if (phds && flag && (flag & 1) == 0) {
175 		/*
176 		 * This is a middle fragment.
177 		 */
178 		return (archdrlen);
179 	}
180 
181 	if (!arcnet_encap_print(arc_type, p, length, caplen))
182 		default_print(p, caplen);
183 
184 	return (archdrlen);
185 }
186 
187 /*
188  * This is the top level routine of the printer.  'p' points
189  * to the ARCNET header of the packet, 'h->ts' is the timestamp,
190  * 'h->len' is the length of the packet off the wire, and 'h->caplen'
191  * is the number of bytes actually captured.  It is quite similar
192  * to the non-Linux style printer except that Linux doesn't ever
193  * supply packets that look like exception frames, it always supplies
194  * reassembled packets rather than raw frames, and headers have an
195  * extra "offset" field between the src/dest and packet type.
196  */
197 u_int
198 arcnet_linux_if_print(const struct pcap_pkthdr *h, const u_char *p)
199 {
200 	u_int caplen = h->caplen;
201 	u_int length = h->len;
202 	const struct arc_linux_header *ap;
203 
204 	int archdrlen = 0;
205 	u_char arc_type;
206 
207 	if (caplen < ARC_LINUX_HDRLEN) {
208 		printf("[|arcnet]");
209 		return (caplen);
210 	}
211 
212 	ap = (const struct arc_linux_header *)p;
213 	arc_type = ap->arc_type;
214 
215 	switch (arc_type) {
216 	default:
217 		archdrlen = ARC_LINUX_HDRNEWLEN;
218 		if (caplen < ARC_LINUX_HDRNEWLEN) {
219 			printf("[|arcnet]");
220 			return (caplen);
221 		}
222 		break;
223 	case ARCTYPE_IP_OLD:
224 	case ARCTYPE_ARP_OLD:
225 	case ARCTYPE_DIAGNOSE:
226 		archdrlen = ARC_LINUX_HDRLEN;
227 		break;
228 	}
229 
230 	if (eflag)
231 		arcnet_print(p, length, 0, 0, 0);
232 
233 	/*
234 	 * Go past the ARCNET header.
235 	 */
236 	length -= archdrlen;
237 	caplen -= archdrlen;
238 	p += archdrlen;
239 
240 	if (!arcnet_encap_print(arc_type, p, length, caplen))
241 		default_print(p, caplen);
242 
243 	return (archdrlen);
244 }
245 
246 /*
247  * Prints the packet encapsulated in an ARCnet data field,
248  * given the ARCnet system code.
249  *
250  * Returns non-zero if it can do so, zero if the system code is unknown.
251  */
252 
253 
254 static int
255 arcnet_encap_print(u_char arctype, const u_char *p,
256     u_int length, u_int caplen)
257 {
258 	switch (arctype) {
259 
260 	case ARCTYPE_IP_OLD:
261 	case ARCTYPE_IP:
262 	        ip_print(gndo, p, length);
263 		return (1);
264 
265 #ifdef INET6
266 	case ARCTYPE_INET6:
267 		ip6_print(p, length);
268 		return (1);
269 #endif /*INET6*/
270 
271 	case ARCTYPE_ARP_OLD:
272 	case ARCTYPE_ARP:
273 	case ARCTYPE_REVARP:
274 	  arp_print(gndo, p, length, caplen);
275 		return (1);
276 
277 	case ARCTYPE_ATALK:	/* XXX was this ever used? */
278 		if (vflag)
279 			fputs("et1 ", stdout);
280 		atalk_print(p, length);
281 		return (1);
282 
283 	case ARCTYPE_IPX:
284 		ipx_print(p, length);
285 		return (1);
286 
287 	default:
288 		return (0);
289 	}
290 }
291 
292 /*
293  * Local Variables:
294  * c-style: bsd
295  * End:
296  */
297 
298