117680Spst/*
239300Sfenner * Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997
317680Spst *	The Regents of the University of California.  All rights reserved.
417680Spst *
517680Spst * Redistribution and use in source and binary forms, with or without
617680Spst * modification, are permitted provided that: (1) source code distributions
717680Spst * retain the above copyright notice and this paragraph in its entirety, (2)
817680Spst * distributions including binary code include the above copyright notice and
917680Spst * this paragraph in its entirety in the documentation or other materials
1017680Spst * provided with the distribution, and (3) all advertising materials mentioning
1117680Spst * features or use of this software display the following acknowledgement:
1217680Spst * ``This product includes software developed by the University of California,
1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1417680Spst * the University nor the names of its contributors may be used to endorse
1517680Spst * or promote products derived from this software without specific prior
1617680Spst * written permission.
1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2056896Sfenner *
2156896Sfenner * $FreeBSD: releng/11.0/contrib/tcpdump/print-fddi.c 276788 2015-01-07 19:55:18Z delphij $
2217680Spst */
2317680Spst
24276788Sdelphij#define NETDISSECT_REWORKED
2556896Sfenner#ifdef HAVE_CONFIG_H
2656896Sfenner#include "config.h"
2756896Sfenner#endif
2856896Sfenner
29127675Sbms#include <tcpdump-stdinc.h>
3017680Spst
3117680Spst#include <string.h>
3217680Spst
3317680Spst#include "interface.h"
3417680Spst#include "addrtoname.h"
3575118Sfenner#include "ether.h"
3617680Spst
3717680Spst/*
38276788Sdelphij * Based on Ultrix if_fddi.h
39276788Sdelphij */
40276788Sdelphij
41276788Sdelphijstruct fddi_header {
42276788Sdelphij	u_char  fddi_fc;		/* frame control */
43276788Sdelphij	u_char  fddi_dhost[6];
44276788Sdelphij	u_char  fddi_shost[6];
45276788Sdelphij};
46276788Sdelphij
47276788Sdelphij/*
48276788Sdelphij * Length of an FDDI header; note that some compilers may pad
49276788Sdelphij * "struct fddi_header" to a multiple of 4 bytes, for example, so
50276788Sdelphij * "sizeof (struct fddi_header)" may not give the right
51276788Sdelphij * answer.
52276788Sdelphij */
53276788Sdelphij#define FDDI_HDRLEN 13
54276788Sdelphij
55276788Sdelphij/* Useful values for fddi_fc (frame control) field */
56276788Sdelphij
57276788Sdelphij/*
58276788Sdelphij * FDDI Frame Control bits
59276788Sdelphij */
60276788Sdelphij#define	FDDIFC_C		0x80		/* Class bit */
61276788Sdelphij#define	FDDIFC_L		0x40		/* Address length bit */
62276788Sdelphij#define	FDDIFC_F		0x30		/* Frame format bits */
63276788Sdelphij#define	FDDIFC_Z		0x0f		/* Control bits */
64276788Sdelphij
65276788Sdelphij/*
66276788Sdelphij * FDDI Frame Control values. (48-bit addressing only).
67276788Sdelphij */
68276788Sdelphij#define	FDDIFC_VOID		0x40		/* Void frame */
69276788Sdelphij#define	FDDIFC_NRT		0x80		/* Nonrestricted token */
70276788Sdelphij#define	FDDIFC_RT		0xc0		/* Restricted token */
71276788Sdelphij#define	FDDIFC_SMT_INFO		0x41		/* SMT Info */
72276788Sdelphij#define	FDDIFC_SMT_NSA		0x4F		/* SMT Next station adrs */
73276788Sdelphij#define	FDDIFC_MAC_BEACON	0xc2		/* MAC Beacon frame */
74276788Sdelphij#define	FDDIFC_MAC_CLAIM	0xc3		/* MAC Claim frame */
75276788Sdelphij#define	FDDIFC_LLC_ASYNC	0x50		/* Async. LLC frame */
76276788Sdelphij#define	FDDIFC_LLC_SYNC		0xd0		/* Sync. LLC frame */
77276788Sdelphij#define	FDDIFC_IMP_ASYNC	0x60		/* Implementor Async. */
78276788Sdelphij#define	FDDIFC_IMP_SYNC		0xe0		/* Implementor Synch. */
79276788Sdelphij#define FDDIFC_SMT		0x40		/* SMT frame */
80276788Sdelphij#define FDDIFC_MAC		0xc0		/* MAC frame */
81276788Sdelphij
82276788Sdelphij#define	FDDIFC_CLFF		0xF0		/* Class/Length/Format bits */
83276788Sdelphij#define	FDDIFC_ZZZZ		0x0F		/* Control bits */
84276788Sdelphij
85276788Sdelphij/*
8617680Spst * Some FDDI interfaces use bit-swapped addresses.
8717680Spst */
8898527Sfenner#if defined(ultrix) || defined(__alpha) || defined(__bsdi) || defined(__NetBSD__) || defined(__linux__)
8917680Spstint	fddi_bitswap = 0;
9017680Spst#else
9117680Spstint	fddi_bitswap = 1;
9217680Spst#endif
9317680Spst
9417680Spst/*
9517680Spst * FDDI support for tcpdump, by Jeffrey Mogul [DECWRL], June 1992
9617680Spst *
9717680Spst * Based in part on code by Van Jacobson, which bears this note:
9817680Spst *
9917680Spst * NOTE:  This is a very preliminary hack for FDDI support.
10017680Spst * There are all sorts of wired in constants & nothing (yet)
10117680Spst * to print SMT packets as anything other than hex dumps.
10217680Spst * Most of the necessary changes are waiting on my redoing
10317680Spst * the "header" that a kernel fddi driver supplies to bpf:  I
10417680Spst * want it to look like one byte of 'direction' (0 or 1
10517680Spst * depending on whether the packet was inbound or outbound),
10617680Spst * two bytes of system/driver dependent data (anything an
10717680Spst * implementor thinks would be useful to filter on and/or
10817680Spst * save per-packet, then the real 21-byte FDDI header.
10917680Spst * Steve McCanne & I have also talked about adding the
11017680Spst * 'direction' byte to all bpf headers (e.g., in the two
11117680Spst * bytes of padding on an ethernet header).  It's not clear
11217680Spst * we could do this in a backwards compatible way & we hate
11317680Spst * the idea of an incompatible bpf change.  Discussions are
11417680Spst * proceeding.
11517680Spst *
11617680Spst * Also, to really support FDDI (and better support 802.2
11717680Spst * over ethernet) we really need to re-think the rather simple
11817680Spst * minded assumptions about fixed length & fixed format link
11917680Spst * level headers made in gencode.c.  One day...
12017680Spst *
12117680Spst *  - vj
12217680Spst */
12317680Spst
124276788Sdelphijstatic const u_char fddi_bit_swap[] = {
12517680Spst	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
12617680Spst	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
12717680Spst	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
12817680Spst	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
12917680Spst	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
13017680Spst	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
13117680Spst	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
13217680Spst	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
13317680Spst	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
13417680Spst	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
13517680Spst	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
13617680Spst	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
13717680Spst	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
13817680Spst	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
13917680Spst	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
14017680Spst	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
14117680Spst	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
14217680Spst	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
14317680Spst	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
14417680Spst	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
14517680Spst	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
14617680Spst	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
14717680Spst	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
14817680Spst	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
14917680Spst	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
15017680Spst	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
15117680Spst	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
15217680Spst	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
15317680Spst	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
15417680Spst	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
15517680Spst	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
15617680Spst	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
15717680Spst};
15817680Spst
15917680Spst/*
16017680Spst * Print FDDI frame-control bits
16117680Spst */
16217680Spststatic inline void
163276788Sdelphijprint_fddi_fc(netdissect_options *ndo, u_char fc)
16417680Spst{
16517680Spst	switch (fc) {
16617680Spst
16717680Spst	case FDDIFC_VOID:                         /* Void frame */
168276788Sdelphij		ND_PRINT((ndo, "void "));
16917680Spst		break;
17017680Spst
17117680Spst	case FDDIFC_NRT:                          /* Nonrestricted token */
172276788Sdelphij		ND_PRINT((ndo, "nrt "));
17317680Spst		break;
17417680Spst
17517680Spst	case FDDIFC_RT:                           /* Restricted token */
176276788Sdelphij		ND_PRINT((ndo, "rt "));
17717680Spst		break;
17817680Spst
17917680Spst	case FDDIFC_SMT_INFO:                     /* SMT Info */
180276788Sdelphij		ND_PRINT((ndo, "info "));
18117680Spst		break;
18217680Spst
18317680Spst	case FDDIFC_SMT_NSA:                      /* SMT Next station adrs */
184276788Sdelphij		ND_PRINT((ndo, "nsa "));
18517680Spst		break;
18617680Spst
18717680Spst	case FDDIFC_MAC_BEACON:                   /* MAC Beacon frame */
188276788Sdelphij		ND_PRINT((ndo, "beacon "));
18917680Spst		break;
19017680Spst
19117680Spst	case FDDIFC_MAC_CLAIM:                    /* MAC Claim frame */
192276788Sdelphij		ND_PRINT((ndo, "claim "));
19317680Spst		break;
19417680Spst
19517680Spst	default:
19617680Spst		switch (fc & FDDIFC_CLFF) {
19717680Spst
19817680Spst		case FDDIFC_MAC:
199276788Sdelphij			ND_PRINT((ndo, "mac%1x ", fc & FDDIFC_ZZZZ));
20017680Spst			break;
20117680Spst
20217680Spst		case FDDIFC_SMT:
203276788Sdelphij			ND_PRINT((ndo, "smt%1x ", fc & FDDIFC_ZZZZ));
20417680Spst			break;
20517680Spst
20617680Spst		case FDDIFC_LLC_ASYNC:
207276788Sdelphij			ND_PRINT((ndo, "async%1x ", fc & FDDIFC_ZZZZ));
20817680Spst			break;
20917680Spst
21017680Spst		case FDDIFC_LLC_SYNC:
211276788Sdelphij			ND_PRINT((ndo, "sync%1x ", fc & FDDIFC_ZZZZ));
21217680Spst			break;
21317680Spst
21417680Spst		case FDDIFC_IMP_ASYNC:
215276788Sdelphij			ND_PRINT((ndo, "imp_async%1x ", fc & FDDIFC_ZZZZ));
21617680Spst			break;
21717680Spst
21817680Spst		case FDDIFC_IMP_SYNC:
219276788Sdelphij			ND_PRINT((ndo, "imp_sync%1x ", fc & FDDIFC_ZZZZ));
22017680Spst			break;
22117680Spst
22217680Spst		default:
223276788Sdelphij			ND_PRINT((ndo, "%02x ", fc));
22417680Spst			break;
22517680Spst		}
22617680Spst	}
22717680Spst}
22817680Spst
22917680Spst/* Extract src, dst addresses */
23017680Spststatic inline void
23117680Spstextract_fddi_addrs(const struct fddi_header *fddip, char *fsrc, char *fdst)
23217680Spst{
23317680Spst	register int i;
23417680Spst
23517680Spst	if (fddi_bitswap) {
23617680Spst		/*
23717680Spst		 * bit-swap the fddi addresses (isn't the IEEE standards
23817680Spst		 * process wonderful!) then convert them to names.
23917680Spst		 */
24017680Spst		for (i = 0; i < 6; ++i)
24117680Spst			fdst[i] = fddi_bit_swap[fddip->fddi_dhost[i]];
24217680Spst		for (i = 0; i < 6; ++i)
24317680Spst			fsrc[i] = fddi_bit_swap[fddip->fddi_shost[i]];
24417680Spst	}
24517680Spst	else {
24698527Sfenner		memcpy(fdst, (const char *)fddip->fddi_dhost, 6);
24798527Sfenner		memcpy(fsrc, (const char *)fddip->fddi_shost, 6);
24817680Spst	}
24917680Spst}
25017680Spst
25117680Spst/*
25217680Spst * Print the FDDI MAC header
25317680Spst */
25417680Spststatic inline void
255276788Sdelphijfddi_hdr_print(netdissect_options *ndo,
256276788Sdelphij               register const struct fddi_header *fddip, register u_int length,
257276788Sdelphij               register const u_char *fsrc, register const u_char *fdst)
25817680Spst{
25998527Sfenner	const char *srcname, *dstname;
26017680Spst
261276788Sdelphij	srcname = etheraddr_string(ndo, fsrc);
262276788Sdelphij	dstname = etheraddr_string(ndo, fdst);
26317680Spst
264276788Sdelphij	if (ndo->ndo_vflag)
265276788Sdelphij		ND_PRINT((ndo, "%02x %s %s %d: ",
26617680Spst		       fddip->fddi_fc,
26717680Spst		       srcname, dstname,
268276788Sdelphij		       length));
269276788Sdelphij	else if (ndo->ndo_qflag)
270276788Sdelphij		ND_PRINT((ndo, "%s %s %d: ", srcname, dstname, length));
27117680Spst	else {
272276788Sdelphij		print_fddi_fc(ndo, fddip->fddi_fc);
273276788Sdelphij		ND_PRINT((ndo, "%s %s %d: ", srcname, dstname, length));
27417680Spst	}
27517680Spst}
27617680Spst
27717680Spststatic inline void
278276788Sdelphijfddi_smt_print(netdissect_options *ndo, const u_char *p _U_, u_int length _U_)
27917680Spst{
280276788Sdelphij	ND_PRINT((ndo, "<SMT printer not yet implemented>"));
28117680Spst}
28217680Spst
28317680Spstvoid
284276788Sdelphijfddi_print(netdissect_options *ndo, const u_char *p, u_int length, u_int caplen)
28517680Spst{
28698527Sfenner	const struct fddi_header *fddip = (const struct fddi_header *)p;
28717680Spst	struct ether_header ehdr;
28856896Sfenner	u_short extracted_ethertype;
28917680Spst
29017680Spst	if (caplen < FDDI_HDRLEN) {
291276788Sdelphij		ND_PRINT((ndo, "[|fddi]"));
292127675Sbms		return;
29317680Spst	}
294127675Sbms
29517680Spst	/*
29617680Spst	 * Get the FDDI addresses into a canonical form
29717680Spst	 */
29826183Sfenner	extract_fddi_addrs(fddip, (char *)ESRC(&ehdr), (char *)EDST(&ehdr));
29917680Spst
300276788Sdelphij	if (ndo->ndo_eflag)
301276788Sdelphij		fddi_hdr_print(ndo, fddip, length, ESRC(&ehdr), EDST(&ehdr));
30217680Spst
30317680Spst	/* Skip over FDDI MAC header */
30417680Spst	length -= FDDI_HDRLEN;
30517680Spst	p += FDDI_HDRLEN;
30617680Spst	caplen -= FDDI_HDRLEN;
30717680Spst
30817680Spst	/* Frame Control field determines interpretation of packet */
30917680Spst	if ((fddip->fddi_fc & FDDIFC_CLFF) == FDDIFC_LLC_ASYNC) {
31017680Spst		/* Try to print the LLC-layer header & higher layers */
311276788Sdelphij		if (llc_print(ndo, p, length, caplen, ESRC(&ehdr), EDST(&ehdr),
31275118Sfenner		    &extracted_ethertype) == 0) {
31317680Spst			/*
31417680Spst			 * Some kinds of LLC packet we cannot
31517680Spst			 * handle intelligently
31617680Spst			 */
317276788Sdelphij			if (!ndo->ndo_eflag)
318276788Sdelphij				fddi_hdr_print(ndo, fddip, length + FDDI_HDRLEN,
31917680Spst				    ESRC(&ehdr), EDST(&ehdr));
32017680Spst			if (extracted_ethertype) {
321276788Sdelphij				ND_PRINT((ndo, "(LLC %s) ",
322276788Sdelphij			etherproto_string(htons(extracted_ethertype))));
32317680Spst			}
324276788Sdelphij			if (!ndo->ndo_suppress_default_print)
325276788Sdelphij				ND_DEFAULTPRINT(p, caplen);
32617680Spst		}
32717680Spst	} else if ((fddip->fddi_fc & FDDIFC_CLFF) == FDDIFC_SMT)
328276788Sdelphij		fddi_smt_print(ndo, p, caplen);
32917680Spst	else {
33017680Spst		/* Some kinds of FDDI packet we cannot handle intelligently */
331276788Sdelphij		if (!ndo->ndo_eflag)
332276788Sdelphij			fddi_hdr_print(ndo, fddip, length + FDDI_HDRLEN, ESRC(&ehdr),
33375118Sfenner			    EDST(&ehdr));
334276788Sdelphij		if (!ndo->ndo_suppress_default_print)
335276788Sdelphij			ND_DEFAULTPRINT(p, caplen);
33617680Spst	}
33717680Spst}
338127675Sbms
339127675Sbms/*
340127675Sbms * This is the top level routine of the printer.  'p' points
341127675Sbms * to the FDDI header of the packet, 'h->ts' is the timestamp,
342146778Ssam * 'h->len' is the length of the packet off the wire, and 'h->caplen'
343127675Sbms * is the number of bytes actually captured.
344127675Sbms */
345127675Sbmsu_int
346276788Sdelphijfddi_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, register const u_char *p)
347127675Sbms{
348276788Sdelphij	fddi_print(ndo, p, h->len, h->caplen);
349127675Sbms
350127675Sbms	return (FDDI_HDRLEN);
351127675Sbms}
352