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$
2217680Spst */
2317680Spst
2417680Spst#ifndef lint
25127675Sbmsstatic const char rcsid[] _U_ =
26190207Srpaulo    "@(#) $Header: /tcpdump/master/tcpdump/print-fddi.c,v 1.66 2005-11-13 12:12:41 guy Exp $ (LBL)";
2717680Spst#endif
2817680Spst
2956896Sfenner#ifdef HAVE_CONFIG_H
3056896Sfenner#include "config.h"
3156896Sfenner#endif
3256896Sfenner
33127675Sbms#include <tcpdump-stdinc.h>
3417680Spst
3517680Spst#include <pcap.h>
3617680Spst#include <stdio.h>
3717680Spst#include <string.h>
3817680Spst
3917680Spst#include "interface.h"
4017680Spst#include "addrtoname.h"
4117680Spst#include "ethertype.h"
4217680Spst
4375118Sfenner#include "ether.h"
4417680Spst#include "fddi.h"
4517680Spst
4617680Spst/*
4717680Spst * Some FDDI interfaces use bit-swapped addresses.
4817680Spst */
4998527Sfenner#if defined(ultrix) || defined(__alpha) || defined(__bsdi) || defined(__NetBSD__) || defined(__linux__)
5017680Spstint	fddi_bitswap = 0;
5117680Spst#else
5217680Spstint	fddi_bitswap = 1;
5317680Spst#endif
5417680Spst
5517680Spst/*
5617680Spst * FDDI support for tcpdump, by Jeffrey Mogul [DECWRL], June 1992
5717680Spst *
5817680Spst * Based in part on code by Van Jacobson, which bears this note:
5917680Spst *
6017680Spst * NOTE:  This is a very preliminary hack for FDDI support.
6117680Spst * There are all sorts of wired in constants & nothing (yet)
6217680Spst * to print SMT packets as anything other than hex dumps.
6317680Spst * Most of the necessary changes are waiting on my redoing
6417680Spst * the "header" that a kernel fddi driver supplies to bpf:  I
6517680Spst * want it to look like one byte of 'direction' (0 or 1
6617680Spst * depending on whether the packet was inbound or outbound),
6717680Spst * two bytes of system/driver dependent data (anything an
6817680Spst * implementor thinks would be useful to filter on and/or
6917680Spst * save per-packet, then the real 21-byte FDDI header.
7017680Spst * Steve McCanne & I have also talked about adding the
7117680Spst * 'direction' byte to all bpf headers (e.g., in the two
7217680Spst * bytes of padding on an ethernet header).  It's not clear
7317680Spst * we could do this in a backwards compatible way & we hate
7417680Spst * the idea of an incompatible bpf change.  Discussions are
7517680Spst * proceeding.
7617680Spst *
7717680Spst * Also, to really support FDDI (and better support 802.2
7817680Spst * over ethernet) we really need to re-think the rather simple
7917680Spst * minded assumptions about fixed length & fixed format link
8017680Spst * level headers made in gencode.c.  One day...
8117680Spst *
8217680Spst *  - vj
8317680Spst */
8417680Spst
8517680Spststatic u_char fddi_bit_swap[] = {
8617680Spst	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
8717680Spst	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
8817680Spst	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
8917680Spst	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
9017680Spst	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
9117680Spst	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
9217680Spst	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
9317680Spst	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
9417680Spst	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
9517680Spst	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
9617680Spst	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
9717680Spst	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
9817680Spst	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
9917680Spst	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
10017680Spst	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
10117680Spst	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
10217680Spst	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
10317680Spst	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
10417680Spst	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
10517680Spst	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
10617680Spst	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
10717680Spst	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
10817680Spst	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
10917680Spst	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
11017680Spst	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
11117680Spst	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
11217680Spst	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
11317680Spst	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
11417680Spst	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
11517680Spst	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
11617680Spst	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
11717680Spst	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
11817680Spst};
11917680Spst
12017680Spst/*
12117680Spst * Print FDDI frame-control bits
12217680Spst */
12317680Spststatic inline void
12417680Spstprint_fddi_fc(u_char fc)
12517680Spst{
12617680Spst	switch (fc) {
12717680Spst
12817680Spst	case FDDIFC_VOID:                         /* Void frame */
12917680Spst		printf("void ");
13017680Spst		break;
13117680Spst
13217680Spst	case FDDIFC_NRT:                          /* Nonrestricted token */
13317680Spst		printf("nrt ");
13417680Spst		break;
13517680Spst
13617680Spst	case FDDIFC_RT:                           /* Restricted token */
13717680Spst		printf("rt ");
13817680Spst		break;
13917680Spst
14017680Spst	case FDDIFC_SMT_INFO:                     /* SMT Info */
14117680Spst		printf("info ");
14217680Spst		break;
14317680Spst
14417680Spst	case FDDIFC_SMT_NSA:                      /* SMT Next station adrs */
14517680Spst		printf("nsa ");
14617680Spst		break;
14717680Spst
14817680Spst	case FDDIFC_MAC_BEACON:                   /* MAC Beacon frame */
14917680Spst		printf("beacon ");
15017680Spst		break;
15117680Spst
15217680Spst	case FDDIFC_MAC_CLAIM:                    /* MAC Claim frame */
15317680Spst		printf("claim ");
15417680Spst		break;
15517680Spst
15617680Spst	default:
15717680Spst		switch (fc & FDDIFC_CLFF) {
15817680Spst
15917680Spst		case FDDIFC_MAC:
16017680Spst			printf("mac%1x ", fc & FDDIFC_ZZZZ);
16117680Spst			break;
16217680Spst
16317680Spst		case FDDIFC_SMT:
16417680Spst			printf("smt%1x ", fc & FDDIFC_ZZZZ);
16517680Spst			break;
16617680Spst
16717680Spst		case FDDIFC_LLC_ASYNC:
16817680Spst			printf("async%1x ", fc & FDDIFC_ZZZZ);
16917680Spst			break;
17017680Spst
17117680Spst		case FDDIFC_LLC_SYNC:
17217680Spst			printf("sync%1x ", fc & FDDIFC_ZZZZ);
17317680Spst			break;
17417680Spst
17517680Spst		case FDDIFC_IMP_ASYNC:
17617680Spst			printf("imp_async%1x ", fc & FDDIFC_ZZZZ);
17717680Spst			break;
17817680Spst
17917680Spst		case FDDIFC_IMP_SYNC:
18017680Spst			printf("imp_sync%1x ", fc & FDDIFC_ZZZZ);
18117680Spst			break;
18217680Spst
18317680Spst		default:
18417680Spst			printf("%02x ", fc);
18517680Spst			break;
18617680Spst		}
18717680Spst	}
18817680Spst}
18917680Spst
19017680Spst/* Extract src, dst addresses */
19117680Spststatic inline void
19217680Spstextract_fddi_addrs(const struct fddi_header *fddip, char *fsrc, char *fdst)
19317680Spst{
19417680Spst	register int i;
19517680Spst
19617680Spst	if (fddi_bitswap) {
19717680Spst		/*
19817680Spst		 * bit-swap the fddi addresses (isn't the IEEE standards
19917680Spst		 * process wonderful!) then convert them to names.
20017680Spst		 */
20117680Spst		for (i = 0; i < 6; ++i)
20217680Spst			fdst[i] = fddi_bit_swap[fddip->fddi_dhost[i]];
20317680Spst		for (i = 0; i < 6; ++i)
20417680Spst			fsrc[i] = fddi_bit_swap[fddip->fddi_shost[i]];
20517680Spst	}
20617680Spst	else {
20798527Sfenner		memcpy(fdst, (const char *)fddip->fddi_dhost, 6);
20898527Sfenner		memcpy(fsrc, (const char *)fddip->fddi_shost, 6);
20917680Spst	}
21017680Spst}
21117680Spst
21217680Spst/*
21317680Spst * Print the FDDI MAC header
21417680Spst */
21517680Spststatic inline void
216127675Sbmsfddi_hdr_print(register const struct fddi_header *fddip, register u_int length,
21717680Spst	   register const u_char *fsrc, register const u_char *fdst)
21817680Spst{
21998527Sfenner	const char *srcname, *dstname;
22017680Spst
22117680Spst	srcname = etheraddr_string(fsrc);
22217680Spst	dstname = etheraddr_string(fdst);
22317680Spst
22417680Spst	if (vflag)
22517680Spst		(void) printf("%02x %s %s %d: ",
22617680Spst		       fddip->fddi_fc,
22717680Spst		       srcname, dstname,
22817680Spst		       length);
22917680Spst	else if (qflag)
23017680Spst		printf("%s %s %d: ", srcname, dstname, length);
23117680Spst	else {
23217680Spst		(void) print_fddi_fc(fddip->fddi_fc);
23317680Spst		(void) printf("%s %s %d: ", srcname, dstname, length);
23417680Spst	}
23517680Spst}
23617680Spst
23717680Spststatic inline void
238127675Sbmsfddi_smt_print(const u_char *p _U_, u_int length _U_)
23917680Spst{
24017680Spst	printf("<SMT printer not yet implemented>");
24117680Spst}
24217680Spst
24317680Spstvoid
244127675Sbmsfddi_print(const u_char *p, u_int length, u_int caplen)
24517680Spst{
24698527Sfenner	const struct fddi_header *fddip = (const struct fddi_header *)p;
24717680Spst	struct ether_header ehdr;
24856896Sfenner	u_short extracted_ethertype;
24917680Spst
25017680Spst	if (caplen < FDDI_HDRLEN) {
25117680Spst		printf("[|fddi]");
252127675Sbms		return;
25317680Spst	}
254127675Sbms
25517680Spst	/*
25617680Spst	 * Get the FDDI addresses into a canonical form
25717680Spst	 */
25826183Sfenner	extract_fddi_addrs(fddip, (char *)ESRC(&ehdr), (char *)EDST(&ehdr));
25917680Spst
26017680Spst	if (eflag)
261127675Sbms		fddi_hdr_print(fddip, length, ESRC(&ehdr), EDST(&ehdr));
26217680Spst
26317680Spst	/* Skip over FDDI MAC header */
26417680Spst	length -= FDDI_HDRLEN;
26517680Spst	p += FDDI_HDRLEN;
26617680Spst	caplen -= FDDI_HDRLEN;
26717680Spst
26817680Spst	/* Frame Control field determines interpretation of packet */
26917680Spst	if ((fddip->fddi_fc & FDDIFC_CLFF) == FDDIFC_LLC_ASYNC) {
27017680Spst		/* Try to print the LLC-layer header & higher layers */
27175118Sfenner		if (llc_print(p, length, caplen, ESRC(&ehdr), EDST(&ehdr),
27275118Sfenner		    &extracted_ethertype) == 0) {
27317680Spst			/*
27417680Spst			 * Some kinds of LLC packet we cannot
27517680Spst			 * handle intelligently
27617680Spst			 */
27717680Spst			if (!eflag)
278127675Sbms				fddi_hdr_print(fddip, length + FDDI_HDRLEN,
27917680Spst				    ESRC(&ehdr), EDST(&ehdr));
28017680Spst			if (extracted_ethertype) {
28117680Spst				printf("(LLC %s) ",
28217680Spst			etherproto_string(htons(extracted_ethertype)));
28317680Spst			}
284162021Ssam			if (!suppress_default_print)
28517680Spst				default_print(p, caplen);
28617680Spst		}
28717680Spst	} else if ((fddip->fddi_fc & FDDIFC_CLFF) == FDDIFC_SMT)
28817680Spst		fddi_smt_print(p, caplen);
28917680Spst	else {
29017680Spst		/* Some kinds of FDDI packet we cannot handle intelligently */
29117680Spst		if (!eflag)
292127675Sbms			fddi_hdr_print(fddip, length + FDDI_HDRLEN, ESRC(&ehdr),
29375118Sfenner			    EDST(&ehdr));
294162021Ssam		if (!suppress_default_print)
29517680Spst			default_print(p, caplen);
29617680Spst	}
29717680Spst}
298127675Sbms
299127675Sbms/*
300127675Sbms * This is the top level routine of the printer.  'p' points
301127675Sbms * to the FDDI header of the packet, 'h->ts' is the timestamp,
302146778Ssam * 'h->len' is the length of the packet off the wire, and 'h->caplen'
303127675Sbms * is the number of bytes actually captured.
304127675Sbms */
305127675Sbmsu_int
306127675Sbmsfddi_if_print(const struct pcap_pkthdr *h, register const u_char *p)
307127675Sbms{
308127675Sbms	fddi_print(p, h->len, h->caplen);
309127675Sbms
310127675Sbms	return (FDDI_HDRLEN);
311127675Sbms}
312