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