vendor/TCPDUMP: Import libpcap 4.99.1
[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 "extract.h"
34 #include "addrtoname.h"
35
36 /*
37  * Based on Ultrix if_fddi.h
38  */
39
40 struct fddi_header {
41         nd_uint8_t  fddi_fc;            /* frame control */
42         nd_mac_addr fddi_dhost;
43         nd_mac_addr fddi_shost;
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 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("void ");
168                 break;
169
170         case FDDIFC_NRT:                          /* Nonrestricted token */
171                 ND_PRINT("nrt ");
172                 break;
173
174         case FDDIFC_RT:                           /* Restricted token */
175                 ND_PRINT("rt ");
176                 break;
177
178         case FDDIFC_SMT_INFO:                     /* SMT Info */
179                 ND_PRINT("info ");
180                 break;
181
182         case FDDIFC_SMT_NSA:                      /* SMT Next station adrs */
183                 ND_PRINT("nsa ");
184                 break;
185
186         case FDDIFC_MAC_BEACON:                   /* MAC Beacon frame */
187                 ND_PRINT("beacon ");
188                 break;
189
190         case FDDIFC_MAC_CLAIM:                    /* MAC Claim frame */
191                 ND_PRINT("claim ");
192                 break;
193
194         default:
195                 switch (fc & FDDIFC_CLFF) {
196
197                 case FDDIFC_MAC:
198                         ND_PRINT("mac%1x ", fc & FDDIFC_ZZZZ);
199                         break;
200
201                 case FDDIFC_SMT:
202                         ND_PRINT("smt%1x ", fc & FDDIFC_ZZZZ);
203                         break;
204
205                 case FDDIFC_LLC_ASYNC:
206                         ND_PRINT("async%1x ", fc & FDDIFC_ZZZZ);
207                         break;
208
209                 case FDDIFC_LLC_SYNC:
210                         ND_PRINT("sync%1x ", fc & FDDIFC_ZZZZ);
211                         break;
212
213                 case FDDIFC_IMP_ASYNC:
214                         ND_PRINT("imp_async%1x ", fc & FDDIFC_ZZZZ);
215                         break;
216
217                 case FDDIFC_IMP_SYNC:
218                         ND_PRINT("imp_sync%1x ", fc & FDDIFC_ZZZZ);
219                         break;
220
221                 default:
222                         ND_PRINT("%02x ", fc);
223                         break;
224                 }
225         }
226 }
227
228 /* Extract src, dst addresses */
229 static void
230 extract_fddi_addrs(const struct fddi_header *fddip, char *fsrc, char *fdst)
231 {
232         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 void
254 fddi_hdr_print(netdissect_options *ndo,
255                const struct fddi_header *fddip, u_int length,
256                const u_char *fsrc, 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, GET_U_1(fddip->fddi_fc));
265         ND_PRINT("%s > %s, length %u: ",
266                srcname, dstname,
267                length);
268 }
269
270 static void
271 fddi_smt_print(netdissect_options *ndo, const u_char *p _U_, u_int length _U_)
272 {
273         ND_PRINT("<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         uint8_t fc;
281         nd_mac_addr srcmac, dstmac;
282         struct lladdr_info src, dst;
283         int llc_hdrlen;
284
285         ndo->ndo_protocol = "fddi";
286         if (caplen < FDDI_HDRLEN) {
287                 nd_print_trunc(ndo);
288                 return (caplen);
289         }
290
291         fc = GET_U_1(fddip->fddi_fc);
292
293         /*
294          * Get the FDDI addresses into a canonical form
295          */
296         extract_fddi_addrs(fddip, (char *)srcmac, (char *)dstmac);
297
298         if (ndo->ndo_eflag)
299                 fddi_hdr_print(ndo, fddip, length, srcmac, dstmac);
300
301         src.addr = srcmac;
302         src.addr_string = etheraddr_string;
303         dst.addr = dstmac;
304         dst.addr_string = etheraddr_string;
305
306         /* Skip over FDDI MAC header */
307         length -= FDDI_HDRLEN;
308         p += FDDI_HDRLEN;
309         caplen -= FDDI_HDRLEN;
310
311         /* Frame Control field determines interpretation of packet */
312         if ((fc & FDDIFC_CLFF) == FDDIFC_LLC_ASYNC) {
313                 /* Try to print the LLC-layer header & higher layers */
314                 llc_hdrlen = llc_print(ndo, p, length, caplen, &src, &dst);
315                 if (llc_hdrlen < 0) {
316                         /*
317                          * Some kinds of LLC packet we cannot
318                          * handle intelligently
319                          */
320                         if (!ndo->ndo_suppress_default_print)
321                                 ND_DEFAULTPRINT(p, caplen);
322                         llc_hdrlen = -llc_hdrlen;
323                 }
324         } else if ((fc & FDDIFC_CLFF) == FDDIFC_SMT) {
325                 fddi_smt_print(ndo, p, caplen);
326                 llc_hdrlen = 0;
327         } else {
328                 /* Some kinds of FDDI packet we cannot handle intelligently */
329                 if (!ndo->ndo_eflag)
330                         fddi_hdr_print(ndo, fddip, length + FDDI_HDRLEN, srcmac,
331                             dstmac);
332                 if (!ndo->ndo_suppress_default_print)
333                         ND_DEFAULTPRINT(p, caplen);
334                 llc_hdrlen = 0;
335         }
336         return (FDDI_HDRLEN + llc_hdrlen);
337 }
338
339 /*
340  * This is the top level routine of the printer.  'p' points
341  * to the FDDI header of the packet, 'h->ts' is the timestamp,
342  * 'h->len' is the length of the packet off the wire, and 'h->caplen'
343  * is the number of bytes actually captured.
344  */
345 void
346 fddi_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p)
347 {
348         ndo->ndo_protocol = "fddi";
349         ndo->ndo_ll_hdr_len += fddi_print(ndo, p, h->len, h->caplen);
350 }