Upgrade to tcpdump-4.0.0.
[dragonfly.git] / contrib / tcpdump / print-arcnet.c
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