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. 2017680Spst */ 2117680Spst 22313537Sglebius/* \summary: Fiber Distributed Data Interface (FDDI) printer */ 23313537Sglebius 2456896Sfenner#ifdef HAVE_CONFIG_H 2556896Sfenner#include "config.h" 2656896Sfenner#endif 2756896Sfenner 28313537Sglebius#include <netdissect-stdinc.h> 2917680Spst 3017680Spst#include <string.h> 3117680Spst 32313537Sglebius#include "netdissect.h" 3317680Spst#include "addrtoname.h" 3475118Sfenner#include "ether.h" 3517680Spst 3617680Spst/* 37276788Sdelphij * Based on Ultrix if_fddi.h 38276788Sdelphij */ 39276788Sdelphij 40276788Sdelphijstruct fddi_header { 41276788Sdelphij u_char fddi_fc; /* frame control */ 42276788Sdelphij u_char fddi_dhost[6]; 43276788Sdelphij u_char fddi_shost[6]; 44276788Sdelphij}; 45276788Sdelphij 46276788Sdelphij/* 47276788Sdelphij * Length of an FDDI header; note that some compilers may pad 48276788Sdelphij * "struct fddi_header" to a multiple of 4 bytes, for example, so 49276788Sdelphij * "sizeof (struct fddi_header)" may not give the right 50276788Sdelphij * answer. 51276788Sdelphij */ 52276788Sdelphij#define FDDI_HDRLEN 13 53276788Sdelphij 54276788Sdelphij/* Useful values for fddi_fc (frame control) field */ 55276788Sdelphij 56276788Sdelphij/* 57276788Sdelphij * FDDI Frame Control bits 58276788Sdelphij */ 59276788Sdelphij#define FDDIFC_C 0x80 /* Class bit */ 60276788Sdelphij#define FDDIFC_L 0x40 /* Address length bit */ 61276788Sdelphij#define FDDIFC_F 0x30 /* Frame format bits */ 62276788Sdelphij#define FDDIFC_Z 0x0f /* Control bits */ 63276788Sdelphij 64276788Sdelphij/* 65276788Sdelphij * FDDI Frame Control values. (48-bit addressing only). 66276788Sdelphij */ 67276788Sdelphij#define FDDIFC_VOID 0x40 /* Void frame */ 68276788Sdelphij#define FDDIFC_NRT 0x80 /* Nonrestricted token */ 69276788Sdelphij#define FDDIFC_RT 0xc0 /* Restricted token */ 70276788Sdelphij#define FDDIFC_SMT_INFO 0x41 /* SMT Info */ 71276788Sdelphij#define FDDIFC_SMT_NSA 0x4F /* SMT Next station adrs */ 72276788Sdelphij#define FDDIFC_MAC_BEACON 0xc2 /* MAC Beacon frame */ 73276788Sdelphij#define FDDIFC_MAC_CLAIM 0xc3 /* MAC Claim frame */ 74276788Sdelphij#define FDDIFC_LLC_ASYNC 0x50 /* Async. LLC frame */ 75276788Sdelphij#define FDDIFC_LLC_SYNC 0xd0 /* Sync. LLC frame */ 76276788Sdelphij#define FDDIFC_IMP_ASYNC 0x60 /* Implementor Async. */ 77276788Sdelphij#define FDDIFC_IMP_SYNC 0xe0 /* Implementor Synch. */ 78276788Sdelphij#define FDDIFC_SMT 0x40 /* SMT frame */ 79276788Sdelphij#define FDDIFC_MAC 0xc0 /* MAC frame */ 80276788Sdelphij 81276788Sdelphij#define FDDIFC_CLFF 0xF0 /* Class/Length/Format bits */ 82276788Sdelphij#define FDDIFC_ZZZZ 0x0F /* Control bits */ 83276788Sdelphij 84276788Sdelphij/* 8517680Spst * Some FDDI interfaces use bit-swapped addresses. 8617680Spst */ 8798527Sfenner#if defined(ultrix) || defined(__alpha) || defined(__bsdi) || defined(__NetBSD__) || defined(__linux__) 88313537Sglebiusstatic int fddi_bitswap = 0; 8917680Spst#else 90313537Sglebiusstatic int fddi_bitswap = 1; 9117680Spst#endif 9217680Spst 9317680Spst/* 9417680Spst * FDDI support for tcpdump, by Jeffrey Mogul [DECWRL], June 1992 9517680Spst * 9617680Spst * Based in part on code by Van Jacobson, which bears this note: 9717680Spst * 9817680Spst * NOTE: This is a very preliminary hack for FDDI support. 9917680Spst * There are all sorts of wired in constants & nothing (yet) 10017680Spst * to print SMT packets as anything other than hex dumps. 10117680Spst * Most of the necessary changes are waiting on my redoing 10217680Spst * the "header" that a kernel fddi driver supplies to bpf: I 10317680Spst * want it to look like one byte of 'direction' (0 or 1 10417680Spst * depending on whether the packet was inbound or outbound), 10517680Spst * two bytes of system/driver dependent data (anything an 10617680Spst * implementor thinks would be useful to filter on and/or 10717680Spst * save per-packet, then the real 21-byte FDDI header. 10817680Spst * Steve McCanne & I have also talked about adding the 10917680Spst * 'direction' byte to all bpf headers (e.g., in the two 11017680Spst * bytes of padding on an ethernet header). It's not clear 11117680Spst * we could do this in a backwards compatible way & we hate 11217680Spst * the idea of an incompatible bpf change. Discussions are 11317680Spst * proceeding. 11417680Spst * 11517680Spst * Also, to really support FDDI (and better support 802.2 11617680Spst * over ethernet) we really need to re-think the rather simple 11717680Spst * minded assumptions about fixed length & fixed format link 11817680Spst * level headers made in gencode.c. One day... 11917680Spst * 12017680Spst * - vj 12117680Spst */ 12217680Spst 123276788Sdelphijstatic const u_char fddi_bit_swap[] = { 12417680Spst 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 12517680Spst 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 12617680Spst 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 12717680Spst 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 12817680Spst 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 12917680Spst 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 13017680Spst 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 13117680Spst 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 13217680Spst 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 13317680Spst 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 13417680Spst 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 13517680Spst 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 13617680Spst 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 13717680Spst 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 13817680Spst 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 13917680Spst 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 14017680Spst 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 14117680Spst 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 14217680Spst 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 14317680Spst 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 14417680Spst 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 14517680Spst 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 14617680Spst 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 14717680Spst 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 14817680Spst 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 14917680Spst 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 15017680Spst 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 15117680Spst 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 15217680Spst 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 15317680Spst 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 15417680Spst 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 15517680Spst 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, 15617680Spst}; 15717680Spst 15817680Spst/* 15917680Spst * Print FDDI frame-control bits 16017680Spst */ 16117680Spststatic inline void 162276788Sdelphijprint_fddi_fc(netdissect_options *ndo, u_char fc) 16317680Spst{ 16417680Spst switch (fc) { 16517680Spst 16617680Spst case FDDIFC_VOID: /* Void frame */ 167276788Sdelphij ND_PRINT((ndo, "void ")); 16817680Spst break; 16917680Spst 17017680Spst case FDDIFC_NRT: /* Nonrestricted token */ 171276788Sdelphij ND_PRINT((ndo, "nrt ")); 17217680Spst break; 17317680Spst 17417680Spst case FDDIFC_RT: /* Restricted token */ 175276788Sdelphij ND_PRINT((ndo, "rt ")); 17617680Spst break; 17717680Spst 17817680Spst case FDDIFC_SMT_INFO: /* SMT Info */ 179276788Sdelphij ND_PRINT((ndo, "info ")); 18017680Spst break; 18117680Spst 18217680Spst case FDDIFC_SMT_NSA: /* SMT Next station adrs */ 183276788Sdelphij ND_PRINT((ndo, "nsa ")); 18417680Spst break; 18517680Spst 18617680Spst case FDDIFC_MAC_BEACON: /* MAC Beacon frame */ 187276788Sdelphij ND_PRINT((ndo, "beacon ")); 18817680Spst break; 18917680Spst 19017680Spst case FDDIFC_MAC_CLAIM: /* MAC Claim frame */ 191276788Sdelphij ND_PRINT((ndo, "claim ")); 19217680Spst break; 19317680Spst 19417680Spst default: 19517680Spst switch (fc & FDDIFC_CLFF) { 19617680Spst 19717680Spst case FDDIFC_MAC: 198276788Sdelphij ND_PRINT((ndo, "mac%1x ", fc & FDDIFC_ZZZZ)); 19917680Spst break; 20017680Spst 20117680Spst case FDDIFC_SMT: 202276788Sdelphij ND_PRINT((ndo, "smt%1x ", fc & FDDIFC_ZZZZ)); 20317680Spst break; 20417680Spst 20517680Spst case FDDIFC_LLC_ASYNC: 206276788Sdelphij ND_PRINT((ndo, "async%1x ", fc & FDDIFC_ZZZZ)); 20717680Spst break; 20817680Spst 20917680Spst case FDDIFC_LLC_SYNC: 210276788Sdelphij ND_PRINT((ndo, "sync%1x ", fc & FDDIFC_ZZZZ)); 21117680Spst break; 21217680Spst 21317680Spst case FDDIFC_IMP_ASYNC: 214276788Sdelphij ND_PRINT((ndo, "imp_async%1x ", fc & FDDIFC_ZZZZ)); 21517680Spst break; 21617680Spst 21717680Spst case FDDIFC_IMP_SYNC: 218276788Sdelphij ND_PRINT((ndo, "imp_sync%1x ", fc & FDDIFC_ZZZZ)); 21917680Spst break; 22017680Spst 22117680Spst default: 222276788Sdelphij ND_PRINT((ndo, "%02x ", fc)); 22317680Spst break; 22417680Spst } 22517680Spst } 22617680Spst} 22717680Spst 22817680Spst/* Extract src, dst addresses */ 22917680Spststatic inline void 23017680Spstextract_fddi_addrs(const struct fddi_header *fddip, char *fsrc, char *fdst) 23117680Spst{ 23217680Spst register int i; 23317680Spst 23417680Spst if (fddi_bitswap) { 23517680Spst /* 23617680Spst * bit-swap the fddi addresses (isn't the IEEE standards 23717680Spst * process wonderful!) then convert them to names. 23817680Spst */ 23917680Spst for (i = 0; i < 6; ++i) 24017680Spst fdst[i] = fddi_bit_swap[fddip->fddi_dhost[i]]; 24117680Spst for (i = 0; i < 6; ++i) 24217680Spst fsrc[i] = fddi_bit_swap[fddip->fddi_shost[i]]; 24317680Spst } 24417680Spst else { 24598527Sfenner memcpy(fdst, (const char *)fddip->fddi_dhost, 6); 24698527Sfenner memcpy(fsrc, (const char *)fddip->fddi_shost, 6); 24717680Spst } 24817680Spst} 24917680Spst 25017680Spst/* 25117680Spst * Print the FDDI MAC header 25217680Spst */ 25317680Spststatic inline void 254276788Sdelphijfddi_hdr_print(netdissect_options *ndo, 255276788Sdelphij register const struct fddi_header *fddip, register u_int length, 256276788Sdelphij register const u_char *fsrc, register const u_char *fdst) 25717680Spst{ 25898527Sfenner const char *srcname, *dstname; 25917680Spst 260276788Sdelphij srcname = etheraddr_string(ndo, fsrc); 261276788Sdelphij dstname = etheraddr_string(ndo, fdst); 26217680Spst 263313537Sglebius if (!ndo->ndo_qflag) 264276788Sdelphij print_fddi_fc(ndo, fddip->fddi_fc); 265313537Sglebius ND_PRINT((ndo, "%s > %s, length %u: ", 266313537Sglebius srcname, dstname, 267313537Sglebius length)); 26817680Spst} 26917680Spst 27017680Spststatic inline void 271276788Sdelphijfddi_smt_print(netdissect_options *ndo, const u_char *p _U_, u_int length _U_) 27217680Spst{ 273276788Sdelphij ND_PRINT((ndo, "<SMT printer not yet implemented>")); 27417680Spst} 27517680Spst 276313537Sglebiusu_int 277276788Sdelphijfddi_print(netdissect_options *ndo, const u_char *p, u_int length, u_int caplen) 27817680Spst{ 27998527Sfenner const struct fddi_header *fddip = (const struct fddi_header *)p; 28017680Spst struct ether_header ehdr; 281313537Sglebius struct lladdr_info src, dst; 282313537Sglebius int llc_hdrlen; 28317680Spst 28417680Spst if (caplen < FDDI_HDRLEN) { 285276788Sdelphij ND_PRINT((ndo, "[|fddi]")); 286313537Sglebius return (caplen); 28717680Spst } 288127675Sbms 28917680Spst /* 29017680Spst * Get the FDDI addresses into a canonical form 29117680Spst */ 29226183Sfenner extract_fddi_addrs(fddip, (char *)ESRC(&ehdr), (char *)EDST(&ehdr)); 29317680Spst 294276788Sdelphij if (ndo->ndo_eflag) 295276788Sdelphij fddi_hdr_print(ndo, fddip, length, ESRC(&ehdr), EDST(&ehdr)); 29617680Spst 297313537Sglebius src.addr = ESRC(&ehdr); 298313537Sglebius src.addr_string = etheraddr_string; 299313537Sglebius dst.addr = EDST(&ehdr); 300313537Sglebius dst.addr_string = etheraddr_string; 301313537Sglebius 30217680Spst /* Skip over FDDI MAC header */ 30317680Spst length -= FDDI_HDRLEN; 30417680Spst p += FDDI_HDRLEN; 30517680Spst caplen -= FDDI_HDRLEN; 30617680Spst 30717680Spst /* Frame Control field determines interpretation of packet */ 30817680Spst if ((fddip->fddi_fc & FDDIFC_CLFF) == FDDIFC_LLC_ASYNC) { 30917680Spst /* Try to print the LLC-layer header & higher layers */ 310313537Sglebius llc_hdrlen = llc_print(ndo, p, length, caplen, &src, &dst); 311313537Sglebius if (llc_hdrlen < 0) { 31217680Spst /* 31317680Spst * Some kinds of LLC packet we cannot 31417680Spst * handle intelligently 31517680Spst */ 316276788Sdelphij if (!ndo->ndo_suppress_default_print) 317276788Sdelphij ND_DEFAULTPRINT(p, caplen); 318313537Sglebius llc_hdrlen = -llc_hdrlen; 31917680Spst } 320313537Sglebius } else if ((fddip->fddi_fc & FDDIFC_CLFF) == FDDIFC_SMT) { 321276788Sdelphij fddi_smt_print(ndo, p, caplen); 322313537Sglebius llc_hdrlen = 0; 323313537Sglebius } else { 32417680Spst /* Some kinds of FDDI packet we cannot handle intelligently */ 325276788Sdelphij if (!ndo->ndo_eflag) 326276788Sdelphij fddi_hdr_print(ndo, fddip, length + FDDI_HDRLEN, ESRC(&ehdr), 32775118Sfenner EDST(&ehdr)); 328276788Sdelphij if (!ndo->ndo_suppress_default_print) 329276788Sdelphij ND_DEFAULTPRINT(p, caplen); 330313537Sglebius llc_hdrlen = 0; 33117680Spst } 332313537Sglebius return (FDDI_HDRLEN + llc_hdrlen); 33317680Spst} 334127675Sbms 335127675Sbms/* 336127675Sbms * This is the top level routine of the printer. 'p' points 337127675Sbms * to the FDDI header of the packet, 'h->ts' is the timestamp, 338146778Ssam * 'h->len' is the length of the packet off the wire, and 'h->caplen' 339127675Sbms * is the number of bytes actually captured. 340127675Sbms */ 341127675Sbmsu_int 342276788Sdelphijfddi_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, register const u_char *p) 343127675Sbms{ 344313537Sglebius return (fddi_print(ndo, p, h->len, h->caplen)); 345127675Sbms} 346