print-fddi.c revision 146778
1327952Sdim/*
2286425Sdim * Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997
3353358Sdim *	The Regents of the University of California.  All rights reserved.
4353358Sdim *
5353358Sdim * Redistribution and use in source and binary forms, with or without
6286425Sdim * modification, are permitted provided that: (1) source code distributions
7286425Sdim * retain the above copyright notice and this paragraph in its entirety, (2)
8286425Sdim * distributions including binary code include the above copyright notice and
9314564Sdim * this paragraph in its entirety in the documentation or other materials
10314564Sdim * provided with the distribution, and (3) all advertising materials mentioning
11314564Sdim * features or use of this software display the following acknowledgement:
12314564Sdim * ``This product includes software developed by the University of California,
13314564Sdim * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14286425Sdim * the University nor the names of its contributors may be used to endorse
15286425Sdim * or promote products derived from this software without specific prior
16327952Sdim * written permission.
17286425Sdim * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18321369Sdim * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19314564Sdim * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20314564Sdim *
21314564Sdim * $FreeBSD: head/contrib/tcpdump/print-fddi.c 146778 2005-05-29 19:09:28Z sam $
22314564Sdim */
23286425Sdim
24286425Sdim#ifndef lint
25286425Sdimstatic const char rcsid[] _U_ =
26314564Sdim    "@(#) $Header: /tcpdump/master/tcpdump/print-fddi.c,v 1.64 2004/03/17 23:24:37 guy Exp $ (LBL)";
27286425Sdim#endif
28314564Sdim
29286425Sdim#ifdef HAVE_CONFIG_H
30327952Sdim#include "config.h"
31314564Sdim#endif
32360784Sdim
33309124Sdim#include <tcpdump-stdinc.h>
34286425Sdim
35286425Sdim#include <pcap.h>
36314564Sdim#include <stdio.h>
37321369Sdim#include <string.h>
38314564Sdim
39314564Sdim#include "interface.h"
40314564Sdim#include "addrtoname.h"
41314564Sdim#include "ethertype.h"
42314564Sdim
43314564Sdim#include "ether.h"
44286425Sdim#include "fddi.h"
45286425Sdim
46321369Sdim/*
47321369Sdim * Some FDDI interfaces use bit-swapped addresses.
48286425Sdim */
49286425Sdim#if defined(ultrix) || defined(__alpha) || defined(__bsdi) || defined(__NetBSD__) || defined(__linux__)
50286425Sdimint	fddi_bitswap = 0;
51286425Sdim#else
52286425Sdimint	fddi_bitswap = 1;
53286425Sdim#endif
54286425Sdim
55286425Sdim/*
56286425Sdim * FDDI support for tcpdump, by Jeffrey Mogul [DECWRL], June 1992
57286425Sdim *
58341825Sdim * Based in part on code by Van Jacobson, which bears this note:
59341825Sdim *
60341825Sdim * NOTE:  This is a very preliminary hack for FDDI support.
61341825Sdim * There are all sorts of wired in constants & nothing (yet)
62341825Sdim * to print SMT packets as anything other than hex dumps.
63341825Sdim * Most of the necessary changes are waiting on my redoing
64286425Sdim * the "header" that a kernel fddi driver supplies to bpf:  I
65286425Sdim * want it to look like one byte of 'direction' (0 or 1
66286425Sdim * depending on whether the packet was inbound or outbound),
67286425Sdim * two bytes of system/driver dependent data (anything an
68286425Sdim * implementor thinks would be useful to filter on and/or
69286425Sdim * save per-packet, then the real 21-byte FDDI header.
70286425Sdim * Steve McCanne & I have also talked about adding the
71286425Sdim * 'direction' byte to all bpf headers (e.g., in the two
72286425Sdim * bytes of padding on an ethernet header).  It's not clear
73286425Sdim * we could do this in a backwards compatible way & we hate
74286425Sdim * the idea of an incompatible bpf change.  Discussions are
75286425Sdim * proceeding.
76286425Sdim *
77286425Sdim * Also, to really support FDDI (and better support 802.2
78286425Sdim * over ethernet) we really need to re-think the rather simple
79314564Sdim * minded assumptions about fixed length & fixed format link
80314564Sdim * level headers made in gencode.c.  One day...
81314564Sdim *
82286425Sdim *  - vj
83314564Sdim */
84286425Sdim
85314564Sdimstatic u_char fddi_bit_swap[] = {
86286425Sdim	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
87286425Sdim	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
88286425Sdim	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
89314564Sdim	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
90286425Sdim	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
91286425Sdim	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
92286425Sdim	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
93296417Sdim	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
94286425Sdim	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
95341825Sdim	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
96360784Sdim	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
97360784Sdim	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
98360784Sdim	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
99360784Sdim	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
100286425Sdim	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
101286425Sdim	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
102286425Sdim	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
103286425Sdim	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
104286425Sdim	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
105286425Sdim	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
106286425Sdim	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
107286425Sdim	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
108286425Sdim	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
109286425Sdim	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
110286425Sdim	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
111286425Sdim	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
112286425Sdim	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
113286425Sdim	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
114286425Sdim	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
115286425Sdim	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
116286425Sdim	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
117286425Sdim	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
118286425Sdim};
119286425Sdim
120286425Sdim/*
121286425Sdim * Print FDDI frame-control bits
122286425Sdim */
123286425Sdimstatic inline void
124286425Sdimprint_fddi_fc(u_char fc)
125286425Sdim{
126286425Sdim	switch (fc) {
127286425Sdim
128286425Sdim	case FDDIFC_VOID:                         /* Void frame */
129286425Sdim		printf("void ");
130286425Sdim		break;
131286425Sdim
132286425Sdim	case FDDIFC_NRT:                          /* Nonrestricted token */
133286425Sdim		printf("nrt ");
134286425Sdim		break;
135286425Sdim
136286425Sdim	case FDDIFC_RT:                           /* Restricted token */
137286425Sdim		printf("rt ");
138286425Sdim		break;
139286425Sdim
140286425Sdim	case FDDIFC_SMT_INFO:                     /* SMT Info */
141286425Sdim		printf("info ");
142286425Sdim		break;
143286425Sdim
144286425Sdim	case FDDIFC_SMT_NSA:                      /* SMT Next station adrs */
145286425Sdim		printf("nsa ");
146286425Sdim		break;
147286425Sdim
148286425Sdim	case FDDIFC_MAC_BEACON:                   /* MAC Beacon frame */
149286425Sdim		printf("beacon ");
150286425Sdim		break;
151286425Sdim
152286425Sdim	case FDDIFC_MAC_CLAIM:                    /* MAC Claim frame */
153286425Sdim		printf("claim ");
154286425Sdim		break;
155286425Sdim
156286425Sdim	default:
157286425Sdim		switch (fc & FDDIFC_CLFF) {
158286425Sdim
159286425Sdim		case FDDIFC_MAC:
160286425Sdim			printf("mac%1x ", fc & FDDIFC_ZZZZ);
161286425Sdim			break;
162286425Sdim
163286425Sdim		case FDDIFC_SMT:
164286425Sdim			printf("smt%1x ", fc & FDDIFC_ZZZZ);
165286425Sdim			break;
166286425Sdim
167286425Sdim		case FDDIFC_LLC_ASYNC:
168286425Sdim			printf("async%1x ", fc & FDDIFC_ZZZZ);
169314564Sdim			break;
170286425Sdim
171360784Sdim		case FDDIFC_LLC_SYNC:
172286425Sdim			printf("sync%1x ", fc & FDDIFC_ZZZZ);
173314564Sdim			break;
174286425Sdim
175360784Sdim		case FDDIFC_IMP_ASYNC:
176286425Sdim			printf("imp_async%1x ", fc & FDDIFC_ZZZZ);
177286425Sdim			break;
178286425Sdim
179286425Sdim		case FDDIFC_IMP_SYNC:
180286425Sdim			printf("imp_sync%1x ", fc & FDDIFC_ZZZZ);
181286425Sdim			break;
182314564Sdim
183286425Sdim		default:
184286425Sdim			printf("%02x ", fc);
185314564Sdim			break;
186286425Sdim		}
187286425Sdim	}
188286425Sdim}
189286425Sdim
190286425Sdim/* Extract src, dst addresses */
191286425Sdimstatic inline void
192286425Sdimextract_fddi_addrs(const struct fddi_header *fddip, char *fsrc, char *fdst)
193286425Sdim{
194327952Sdim	register int i;
195286425Sdim
196286425Sdim	if (fddi_bitswap) {
197286425Sdim		/*
198286425Sdim		 * bit-swap the fddi addresses (isn't the IEEE standards
199286425Sdim		 * process wonderful!) then convert them to names.
200286425Sdim		 */
201286425Sdim		for (i = 0; i < 6; ++i)
202314564Sdim			fdst[i] = fddi_bit_swap[fddip->fddi_dhost[i]];
203314564Sdim		for (i = 0; i < 6; ++i)
204286425Sdim			fsrc[i] = fddi_bit_swap[fddip->fddi_shost[i]];
205327952Sdim	}
206286425Sdim	else {
207286425Sdim		memcpy(fdst, (const char *)fddip->fddi_dhost, 6);
208286425Sdim		memcpy(fsrc, (const char *)fddip->fddi_shost, 6);
209286425Sdim	}
210286425Sdim}
211286425Sdim
212286425Sdim/*
213286425Sdim * Print the FDDI MAC header
214314564Sdim */
215314564Sdimstatic inline void
216286425Sdimfddi_hdr_print(register const struct fddi_header *fddip, register u_int length,
217286425Sdim	   register const u_char *fsrc, register const u_char *fdst)
218286425Sdim{
219286425Sdim	const char *srcname, *dstname;
220286425Sdim
221314564Sdim	srcname = etheraddr_string(fsrc);
222286425Sdim	dstname = etheraddr_string(fdst);
223286425Sdim
224286425Sdim	if (vflag)
225286425Sdim		(void) printf("%02x %s %s %d: ",
226286425Sdim		       fddip->fddi_fc,
227286425Sdim		       srcname, dstname,
228286425Sdim		       length);
229286425Sdim	else if (qflag)
230286425Sdim		printf("%s %s %d: ", srcname, dstname, length);
231286425Sdim	else {
232286425Sdim		(void) print_fddi_fc(fddip->fddi_fc);
233286425Sdim		(void) printf("%s %s %d: ", srcname, dstname, length);
234286425Sdim	}
235286425Sdim}
236286425Sdim
237314564Sdimstatic inline void
238286425Sdimfddi_smt_print(const u_char *p _U_, u_int length _U_)
239286425Sdim{
240314564Sdim	printf("<SMT printer not yet implemented>");
241286425Sdim}
242286425Sdim
243286425Sdimvoid
244314564Sdimfddi_print(const u_char *p, u_int length, u_int caplen)
245286425Sdim{
246286425Sdim	const struct fddi_header *fddip = (const struct fddi_header *)p;
247286425Sdim	struct ether_header ehdr;
248286425Sdim	u_short extracted_ethertype;
249286425Sdim
250286425Sdim	if (caplen < FDDI_HDRLEN) {
251286425Sdim		printf("[|fddi]");
252286425Sdim		return;
253286425Sdim	}
254286425Sdim
255286425Sdim	/*
256286425Sdim	 * Get the FDDI addresses into a canonical form
257286425Sdim	 */
258286425Sdim	extract_fddi_addrs(fddip, (char *)ESRC(&ehdr), (char *)EDST(&ehdr));
259286425Sdim
260286425Sdim	if (eflag)
261286425Sdim		fddi_hdr_print(fddip, length, ESRC(&ehdr), EDST(&ehdr));
262286425Sdim
263286425Sdim	/* Skip over FDDI MAC header */
264286425Sdim	length -= FDDI_HDRLEN;
265286425Sdim	p += FDDI_HDRLEN;
266314564Sdim	caplen -= FDDI_HDRLEN;
267286425Sdim
268286425Sdim	/* Frame Control field determines interpretation of packet */
269286425Sdim	extracted_ethertype = 0;
270286425Sdim	if ((fddip->fddi_fc & FDDIFC_CLFF) == FDDIFC_LLC_ASYNC) {
271286425Sdim		/* Try to print the LLC-layer header & higher layers */
272286425Sdim		if (llc_print(p, length, caplen, ESRC(&ehdr), EDST(&ehdr),
273314564Sdim		    &extracted_ethertype) == 0) {
274286425Sdim			/*
275360784Sdim			 * Some kinds of LLC packet we cannot
276286425Sdim			 * handle intelligently
277286425Sdim			 */
278314564Sdim			if (!eflag)
279286425Sdim				fddi_hdr_print(fddip, length + FDDI_HDRLEN,
280314564Sdim				    ESRC(&ehdr), EDST(&ehdr));
281286425Sdim			if (extracted_ethertype) {
282286425Sdim				printf("(LLC %s) ",
283286425Sdim			etherproto_string(htons(extracted_ethertype)));
284286425Sdim			}
285286425Sdim			if (!xflag && !qflag)
286286425Sdim				default_print(p, caplen);
287286425Sdim		}
288327952Sdim	} else if ((fddip->fddi_fc & FDDIFC_CLFF) == FDDIFC_SMT)
289327952Sdim		fddi_smt_print(p, caplen);
290286425Sdim	else {
291286425Sdim		/* Some kinds of FDDI packet we cannot handle intelligently */
292286425Sdim		if (!eflag)
293286425Sdim			fddi_hdr_print(fddip, length + FDDI_HDRLEN, ESRC(&ehdr),
294286425Sdim			    EDST(&ehdr));
295286425Sdim		if (!xflag && !qflag)
296286425Sdim			default_print(p, caplen);
297286425Sdim	}
298314564Sdim}
299286425Sdim
300314564Sdim/*
301286425Sdim * This is the top level routine of the printer.  'p' points
302286425Sdim * to the FDDI header of the packet, 'h->ts' is the timestamp,
303286425Sdim * 'h->len' is the length of the packet off the wire, and 'h->caplen'
304286425Sdim * is the number of bytes actually captured.
305286425Sdim */
306286425Sdimu_int
307286425Sdimfddi_if_print(const struct pcap_pkthdr *h, register const u_char *p)
308286425Sdim{
309286425Sdim	fddi_print(p, h->len, h->caplen);
310286425Sdim
311286425Sdim	return (FDDI_HDRLEN);
312286425Sdim}
313286425Sdim