vendor/TCPDUMP: Import tcpdump 4.9.3
[dragonfly.git] / contrib / tcpdump / print-fddi.c
1 /*
2  * Copyright (c) 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
22 /* \summary: Fiber Distributed Data Interface (FDDI) printer */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <netdissect-stdinc.h>
29
30 #include <string.h>
31
32 #include "netdissect.h"
33 #include "addrtoname.h"
34 #include "ether.h"
35
36 /*
37  * Based on Ultrix if_fddi.h
38  */
39
40 struct fddi_header {
41         u_char  fddi_fc;                /* frame control */
42         u_char  fddi_dhost[6];
43         u_char  fddi_shost[6];
44 };
45
46 /*
47  * Length of an FDDI header; note that some compilers may pad
48  * "struct fddi_header" to a multiple of 4 bytes, for example, so
49  * "sizeof (struct fddi_header)" may not give the right
50  * answer.
51  */
52 #define FDDI_HDRLEN 13
53
54 /* Useful values for fddi_fc (frame control) field */
55
56 /*
57  * FDDI Frame Control bits
58  */
59 #define FDDIFC_C                0x80            /* Class bit */
60 #define FDDIFC_L                0x40            /* Address length bit */
61 #define FDDIFC_F                0x30            /* Frame format bits */
62 #define FDDIFC_Z                0x0f            /* Control bits */
63
64 /*
65  * FDDI Frame Control values. (48-bit addressing only).
66  */
67 #define FDDIFC_VOID             0x40            /* Void frame */
68 #define FDDIFC_NRT              0x80            /* Nonrestricted token */
69 #define FDDIFC_RT               0xc0            /* Restricted token */
70 #define FDDIFC_SMT_INFO         0x41            /* SMT Info */
71 #define FDDIFC_SMT_NSA          0x4F            /* SMT Next station adrs */
72 #define FDDIFC_MAC_BEACON       0xc2            /* MAC Beacon frame */
73 #define FDDIFC_MAC_CLAIM        0xc3            /* MAC Claim frame */
74 #define FDDIFC_LLC_ASYNC        0x50            /* Async. LLC frame */
75 #define FDDIFC_LLC_SYNC         0xd0            /* Sync. LLC frame */
76 #define FDDIFC_IMP_ASYNC        0x60            /* Implementor Async. */
77 #define FDDIFC_IMP_SYNC         0xe0            /* Implementor Synch. */
78 #define FDDIFC_SMT              0x40            /* SMT frame */
79 #define FDDIFC_MAC              0xc0            /* MAC frame */
80
81 #define FDDIFC_CLFF             0xF0            /* Class/Length/Format bits */
82 #define FDDIFC_ZZZZ             0x0F            /* Control bits */
83
84 /*
85  * Some FDDI interfaces use bit-swapped addresses.
86  */
87 #if defined(ultrix) || defined(__alpha) || defined(__bsdi) || defined(__NetBSD__) || defined(__linux__)
88 static int fddi_bitswap = 0;
89 #else
90 static int fddi_bitswap = 1;
91 #endif
92
93 /*
94  * FDDI support for tcpdump, by Jeffrey Mogul [DECWRL], June 1992
95  *
96  * Based in part on code by Van Jacobson, which bears this note:
97  *
98  * NOTE:  This is a very preliminary hack for FDDI support.
99  * There are all sorts of wired in constants & nothing (yet)
100  * to print SMT packets as anything other than hex dumps.
101  * Most of the necessary changes are waiting on my redoing
102  * the "header" that a kernel fddi driver supplies to bpf:  I
103  * want it to look like one byte of 'direction' (0 or 1
104  * depending on whether the packet was inbound or outbound),
105  * two bytes of system/driver dependent data (anything an
106  * implementor thinks would be useful to filter on and/or
107  * save per-packet, then the real 21-byte FDDI header.
108  * Steve McCanne & I have also talked about adding the
109  * 'direction' byte to all bpf headers (e.g., in the two
110  * bytes of padding on an ethernet header).  It's not clear
111  * we could do this in a backwards compatible way & we hate
112  * the idea of an incompatible bpf change.  Discussions are
113  * proceeding.
114  *
115  * Also, to really support FDDI (and better support 802.2
116  * over ethernet) we really need to re-think the rather simple
117  * minded assumptions about fixed length & fixed format link
118  * level headers made in gencode.c.  One day...
119  *
120  *  - vj
121  */
122
123 static const u_char fddi_bit_swap[] = {
124         0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
125         0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
126         0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
127         0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
128         0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
129         0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
130         0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
131         0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
132         0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
133         0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
134         0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
135         0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
136         0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
137         0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
138         0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
139         0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
140         0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
141         0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
142         0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
143         0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
144         0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
145         0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
146         0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
147         0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
148         0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
149         0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
150         0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
151         0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
152         0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
153         0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
154         0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
155         0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
156 };
157
158 /*
159  * Print FDDI frame-control bits
160  */
161 static inline void
162 print_fddi_fc(netdissect_options *ndo, u_char fc)
163 {
164         switch (fc) {
165
166         case FDDIFC_VOID:                         /* Void frame */
167                 ND_PRINT((ndo, "void "));
168                 break;
169
170         case FDDIFC_NRT:                          /* Nonrestricted token */
171                 ND_PRINT((ndo, "nrt "));
172                 break;
173
174         case FDDIFC_RT:                           /* Restricted token */
175                 ND_PRINT((ndo, "rt "));
176                 break;
177
178         case FDDIFC_SMT_INFO:                     /* SMT Info */
179                 ND_PRINT((ndo, "info "));
180                 break;
181
182         case FDDIFC_SMT_NSA:                      /* SMT Next station adrs */
183                 ND_PRINT((ndo, "nsa "));
184                 break;
185
186         case FDDIFC_MAC_BEACON:                   /* MAC Beacon frame */
187                 ND_PRINT((ndo, "beacon "));
188                 break;
189
190         case FDDIFC_MAC_CLAIM:                    /* MAC Claim frame */
191                 ND_PRINT((ndo, "claim "));
192                 break;
193
194         default:
195                 switch (fc & FDDIFC_CLFF) {
196
197                 case FDDIFC_MAC:
198                         ND_PRINT((ndo, "mac%1x ", fc & FDDIFC_ZZZZ));
199                         break;
200
201                 case FDDIFC_SMT:
202                         ND_PRINT((ndo, "smt%1x ", fc & FDDIFC_ZZZZ));
203                         break;
204
205                 case FDDIFC_LLC_ASYNC:
206                         ND_PRINT((ndo, "async%1x ", fc & FDDIFC_ZZZZ));
207                         break;
208
209                 case FDDIFC_LLC_SYNC:
210                         ND_PRINT((ndo, "sync%1x ", fc & FDDIFC_ZZZZ));
211                         break;
212
213                 case FDDIFC_IMP_ASYNC:
214                         ND_PRINT((ndo, "imp_async%1x ", fc & FDDIFC_ZZZZ));
215                         break;
216
217                 case FDDIFC_IMP_SYNC:
218                         ND_PRINT((ndo, "imp_sync%1x ", fc & FDDIFC_ZZZZ));
219                         break;
220
221                 default:
222                         ND_PRINT((ndo, "%02x ", fc));
223                         break;
224                 }
225         }
226 }
227
228 /* Extract src, dst addresses */
229 static inline void
230 extract_fddi_addrs(const struct fddi_header *fddip, char *fsrc, char *fdst)
231 {
232         register int i;
233
234         if (fddi_bitswap) {
235                 /*
236                  * bit-swap the fddi addresses (isn't the IEEE standards
237                  * process wonderful!) then convert them to names.
238                  */
239                 for (i = 0; i < 6; ++i)
240                         fdst[i] = fddi_bit_swap[fddip->fddi_dhost[i]];
241                 for (i = 0; i < 6; ++i)
242                         fsrc[i] = fddi_bit_swap[fddip->fddi_shost[i]];
243         }
244         else {
245                 memcpy(fdst, (const char *)fddip->fddi_dhost, 6);
246                 memcpy(fsrc, (const char *)fddip->fddi_shost, 6);
247         }
248 }
249
250 /*
251  * Print the FDDI MAC header
252  */
253 static inline void
254 fddi_hdr_print(netdissect_options *ndo,
255                register const struct fddi_header *fddip, register u_int length,
256                register const u_char *fsrc, register const u_char *fdst)
257 {
258         const char *srcname, *dstname;
259
260         srcname = etheraddr_string(ndo, fsrc);
261         dstname = etheraddr_string(ndo, fdst);
262
263         if (!ndo->ndo_qflag)
264                 print_fddi_fc(ndo, fddip->fddi_fc);
265         ND_PRINT((ndo, "%s > %s, length %u: ",
266                srcname, dstname,
267                length));
268 }
269
270 static inline void
271 fddi_smt_print(netdissect_options *ndo, const u_char *p _U_, u_int length _U_)
272 {
273         ND_PRINT((ndo, "<SMT printer not yet implemented>"));
274 }
275
276 u_int
277 fddi_print(netdissect_options *ndo, const u_char *p, u_int length, u_int caplen)
278 {
279         const struct fddi_header *fddip = (const struct fddi_header *)p;
280         struct ether_header ehdr;
281         struct lladdr_info src, dst;
282         int llc_hdrlen;
283
284         if (caplen < FDDI_HDRLEN) {
285                 ND_PRINT((ndo, "[|fddi]"));
286                 return (caplen);
287         }
288
289         /*
290          * Get the FDDI addresses into a canonical form
291          */
292         extract_fddi_addrs(fddip, (char *)ESRC(&ehdr), (char *)EDST(&ehdr));
293
294         if (ndo->ndo_eflag)
295                 fddi_hdr_print(ndo, fddip, length, ESRC(&ehdr), EDST(&ehdr));
296
297         src.addr = ESRC(&ehdr);
298         src.addr_string = etheraddr_string;
299         dst.addr = EDST(&ehdr);
300         dst.addr_string = etheraddr_string;
301
302         /* Skip over FDDI MAC header */
303         length -= FDDI_HDRLEN;
304         p += FDDI_HDRLEN;
305         caplen -= FDDI_HDRLEN;
306
307         /* Frame Control field determines interpretation of packet */
308         if ((fddip->fddi_fc & FDDIFC_CLFF) == FDDIFC_LLC_ASYNC) {
309                 /* Try to print the LLC-layer header & higher layers */
310                 llc_hdrlen = llc_print(ndo, p, length, caplen, &src, &dst);
311                 if (llc_hdrlen < 0) {
312                         /*
313                          * Some kinds of LLC packet we cannot
314                          * handle intelligently
315                          */
316                         if (!ndo->ndo_suppress_default_print)
317                                 ND_DEFAULTPRINT(p, caplen);
318                         llc_hdrlen = -llc_hdrlen;
319                 }
320         } else if ((fddip->fddi_fc & FDDIFC_CLFF) == FDDIFC_SMT) {
321                 fddi_smt_print(ndo, p, caplen);
322                 llc_hdrlen = 0;
323         } else {
324                 /* Some kinds of FDDI packet we cannot handle intelligently */
325                 if (!ndo->ndo_eflag)
326                         fddi_hdr_print(ndo, fddip, length + FDDI_HDRLEN, ESRC(&ehdr),
327                             EDST(&ehdr));
328                 if (!ndo->ndo_suppress_default_print)
329                         ND_DEFAULTPRINT(p, caplen);
330                 llc_hdrlen = 0;
331         }
332         return (FDDI_HDRLEN + llc_hdrlen);
333 }
334
335 /*
336  * This is the top level routine of the printer.  'p' points
337  * to the FDDI header of the packet, 'h->ts' is the timestamp,
338  * 'h->len' is the length of the packet off the wire, and 'h->caplen'
339  * is the number of bytes actually captured.
340  */
341 u_int
342 fddi_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, register const u_char *p)
343 {
344         return (fddi_print(ndo, p, h->len, h->caplen));
345 }