14edb46e9SPaul Traina /* 2699fc314SBill Fenner * Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997 34edb46e9SPaul Traina * The Regents of the University of California. All rights reserved. 44edb46e9SPaul Traina * 54edb46e9SPaul Traina * Redistribution and use in source and binary forms, with or without 64edb46e9SPaul Traina * modification, are permitted provided that: (1) source code distributions 74edb46e9SPaul Traina * retain the above copyright notice and this paragraph in its entirety, (2) 84edb46e9SPaul Traina * distributions including binary code include the above copyright notice and 94edb46e9SPaul Traina * this paragraph in its entirety in the documentation or other materials 104edb46e9SPaul Traina * provided with the distribution, and (3) all advertising materials mentioning 114edb46e9SPaul Traina * features or use of this software display the following acknowledgement: 124edb46e9SPaul Traina * ``This product includes software developed by the University of California, 134edb46e9SPaul Traina * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 144edb46e9SPaul Traina * the University nor the names of its contributors may be used to endorse 154edb46e9SPaul Traina * or promote products derived from this software without specific prior 164edb46e9SPaul Traina * written permission. 174edb46e9SPaul Traina * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 184edb46e9SPaul Traina * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 194edb46e9SPaul Traina * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20a88113a8SBill Fenner * 21a88113a8SBill Fenner * $FreeBSD$ 224edb46e9SPaul Traina */ 234edb46e9SPaul Traina 244edb46e9SPaul Traina #ifndef lint 252ebf6c05SBill Fenner static const char rcsid[] = 26a88113a8SBill Fenner "@(#) $Header: /tcpdump/master/tcpdump/print-fddi.c,v 1.40 1999/12/14 16:49:02 fenner Exp $ (LBL)"; 274edb46e9SPaul Traina #endif 284edb46e9SPaul Traina 29a88113a8SBill Fenner #ifdef HAVE_CONFIG_H 30a88113a8SBill Fenner #include "config.h" 31a88113a8SBill Fenner #endif 32a88113a8SBill Fenner 334edb46e9SPaul Traina #include <sys/param.h> 344edb46e9SPaul Traina #include <sys/time.h> 354edb46e9SPaul Traina #include <sys/socket.h> 364edb46e9SPaul Traina #include <sys/file.h> 374edb46e9SPaul Traina #include <sys/ioctl.h> 384edb46e9SPaul Traina 394edb46e9SPaul Traina #if __STDC__ 404edb46e9SPaul Traina struct mbuf; 414edb46e9SPaul Traina struct rtentry; 424edb46e9SPaul Traina #endif 434edb46e9SPaul Traina #include <net/if.h> 444edb46e9SPaul Traina 454edb46e9SPaul Traina #include <netinet/in.h> 46ee3e7633SGarrett Wollman #include <net/ethernet.h> 474edb46e9SPaul Traina #include <netinet/in_systm.h> 484edb46e9SPaul Traina #include <netinet/ip.h> 494edb46e9SPaul Traina 504edb46e9SPaul Traina #include <ctype.h> 514edb46e9SPaul Traina #include <netdb.h> 524edb46e9SPaul Traina #include <pcap.h> 534edb46e9SPaul Traina #include <stdio.h> 544edb46e9SPaul Traina #include <string.h> 554edb46e9SPaul Traina 564edb46e9SPaul Traina #include "interface.h" 574edb46e9SPaul Traina #include "addrtoname.h" 584edb46e9SPaul Traina #include "ethertype.h" 594edb46e9SPaul Traina 604edb46e9SPaul Traina #include "fddi.h" 614edb46e9SPaul Traina 624edb46e9SPaul Traina /* 634edb46e9SPaul Traina * Some FDDI interfaces use bit-swapped addresses. 644edb46e9SPaul Traina */ 65a88113a8SBill Fenner #if defined(ultrix) || defined(__alpha) || defined(__bsdi) || defined(__NetBSD__) 664edb46e9SPaul Traina int fddi_bitswap = 0; 674edb46e9SPaul Traina #else 684edb46e9SPaul Traina int fddi_bitswap = 1; 694edb46e9SPaul Traina #endif 704edb46e9SPaul Traina 714edb46e9SPaul Traina /* 724edb46e9SPaul Traina * FDDI support for tcpdump, by Jeffrey Mogul [DECWRL], June 1992 734edb46e9SPaul Traina * 744edb46e9SPaul Traina * Based in part on code by Van Jacobson, which bears this note: 754edb46e9SPaul Traina * 764edb46e9SPaul Traina * NOTE: This is a very preliminary hack for FDDI support. 774edb46e9SPaul Traina * There are all sorts of wired in constants & nothing (yet) 784edb46e9SPaul Traina * to print SMT packets as anything other than hex dumps. 794edb46e9SPaul Traina * Most of the necessary changes are waiting on my redoing 804edb46e9SPaul Traina * the "header" that a kernel fddi driver supplies to bpf: I 814edb46e9SPaul Traina * want it to look like one byte of 'direction' (0 or 1 824edb46e9SPaul Traina * depending on whether the packet was inbound or outbound), 834edb46e9SPaul Traina * two bytes of system/driver dependent data (anything an 844edb46e9SPaul Traina * implementor thinks would be useful to filter on and/or 854edb46e9SPaul Traina * save per-packet, then the real 21-byte FDDI header. 864edb46e9SPaul Traina * Steve McCanne & I have also talked about adding the 874edb46e9SPaul Traina * 'direction' byte to all bpf headers (e.g., in the two 884edb46e9SPaul Traina * bytes of padding on an ethernet header). It's not clear 894edb46e9SPaul Traina * we could do this in a backwards compatible way & we hate 904edb46e9SPaul Traina * the idea of an incompatible bpf change. Discussions are 914edb46e9SPaul Traina * proceeding. 924edb46e9SPaul Traina * 934edb46e9SPaul Traina * Also, to really support FDDI (and better support 802.2 944edb46e9SPaul Traina * over ethernet) we really need to re-think the rather simple 954edb46e9SPaul Traina * minded assumptions about fixed length & fixed format link 964edb46e9SPaul Traina * level headers made in gencode.c. One day... 974edb46e9SPaul Traina * 984edb46e9SPaul Traina * - vj 994edb46e9SPaul Traina */ 1004edb46e9SPaul Traina 1014edb46e9SPaul Traina #define FDDI_HDRLEN (sizeof(struct fddi_header)) 1024edb46e9SPaul Traina 1034edb46e9SPaul Traina static u_char fddi_bit_swap[] = { 1044edb46e9SPaul Traina 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 1054edb46e9SPaul Traina 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 1064edb46e9SPaul Traina 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 1074edb46e9SPaul Traina 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 1084edb46e9SPaul Traina 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 1094edb46e9SPaul Traina 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 1104edb46e9SPaul Traina 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 1114edb46e9SPaul Traina 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 1124edb46e9SPaul Traina 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 1134edb46e9SPaul Traina 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 1144edb46e9SPaul Traina 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 1154edb46e9SPaul Traina 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 1164edb46e9SPaul Traina 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 1174edb46e9SPaul Traina 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 1184edb46e9SPaul Traina 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 1194edb46e9SPaul Traina 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 1204edb46e9SPaul Traina 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 1214edb46e9SPaul Traina 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 1224edb46e9SPaul Traina 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 1234edb46e9SPaul Traina 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 1244edb46e9SPaul Traina 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 1254edb46e9SPaul Traina 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 1264edb46e9SPaul Traina 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 1274edb46e9SPaul Traina 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 1284edb46e9SPaul Traina 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 1294edb46e9SPaul Traina 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 1304edb46e9SPaul Traina 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 1314edb46e9SPaul Traina 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 1324edb46e9SPaul Traina 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 1334edb46e9SPaul Traina 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 1344edb46e9SPaul Traina 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 1354edb46e9SPaul Traina 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, 1364edb46e9SPaul Traina }; 1374edb46e9SPaul Traina 1384edb46e9SPaul Traina /* 1394edb46e9SPaul Traina * Print FDDI frame-control bits 1404edb46e9SPaul Traina */ 1414edb46e9SPaul Traina static inline void 1424edb46e9SPaul Traina print_fddi_fc(u_char fc) 1434edb46e9SPaul Traina { 1444edb46e9SPaul Traina switch (fc) { 1454edb46e9SPaul Traina 1464edb46e9SPaul Traina case FDDIFC_VOID: /* Void frame */ 1474edb46e9SPaul Traina printf("void "); 1484edb46e9SPaul Traina break; 1494edb46e9SPaul Traina 1504edb46e9SPaul Traina case FDDIFC_NRT: /* Nonrestricted token */ 1514edb46e9SPaul Traina printf("nrt "); 1524edb46e9SPaul Traina break; 1534edb46e9SPaul Traina 1544edb46e9SPaul Traina case FDDIFC_RT: /* Restricted token */ 1554edb46e9SPaul Traina printf("rt "); 1564edb46e9SPaul Traina break; 1574edb46e9SPaul Traina 1584edb46e9SPaul Traina case FDDIFC_SMT_INFO: /* SMT Info */ 1594edb46e9SPaul Traina printf("info "); 1604edb46e9SPaul Traina break; 1614edb46e9SPaul Traina 1624edb46e9SPaul Traina case FDDIFC_SMT_NSA: /* SMT Next station adrs */ 1634edb46e9SPaul Traina printf("nsa "); 1644edb46e9SPaul Traina break; 1654edb46e9SPaul Traina 1664edb46e9SPaul Traina case FDDIFC_MAC_BEACON: /* MAC Beacon frame */ 1674edb46e9SPaul Traina printf("beacon "); 1684edb46e9SPaul Traina break; 1694edb46e9SPaul Traina 1704edb46e9SPaul Traina case FDDIFC_MAC_CLAIM: /* MAC Claim frame */ 1714edb46e9SPaul Traina printf("claim "); 1724edb46e9SPaul Traina break; 1734edb46e9SPaul Traina 1744edb46e9SPaul Traina default: 1754edb46e9SPaul Traina switch (fc & FDDIFC_CLFF) { 1764edb46e9SPaul Traina 1774edb46e9SPaul Traina case FDDIFC_MAC: 1784edb46e9SPaul Traina printf("mac%1x ", fc & FDDIFC_ZZZZ); 1794edb46e9SPaul Traina break; 1804edb46e9SPaul Traina 1814edb46e9SPaul Traina case FDDIFC_SMT: 1824edb46e9SPaul Traina printf("smt%1x ", fc & FDDIFC_ZZZZ); 1834edb46e9SPaul Traina break; 1844edb46e9SPaul Traina 1854edb46e9SPaul Traina case FDDIFC_LLC_ASYNC: 1864edb46e9SPaul Traina printf("async%1x ", fc & FDDIFC_ZZZZ); 1874edb46e9SPaul Traina break; 1884edb46e9SPaul Traina 1894edb46e9SPaul Traina case FDDIFC_LLC_SYNC: 1904edb46e9SPaul Traina printf("sync%1x ", fc & FDDIFC_ZZZZ); 1914edb46e9SPaul Traina break; 1924edb46e9SPaul Traina 1934edb46e9SPaul Traina case FDDIFC_IMP_ASYNC: 1944edb46e9SPaul Traina printf("imp_async%1x ", fc & FDDIFC_ZZZZ); 1954edb46e9SPaul Traina break; 1964edb46e9SPaul Traina 1974edb46e9SPaul Traina case FDDIFC_IMP_SYNC: 1984edb46e9SPaul Traina printf("imp_sync%1x ", fc & FDDIFC_ZZZZ); 1994edb46e9SPaul Traina break; 2004edb46e9SPaul Traina 2014edb46e9SPaul Traina default: 2024edb46e9SPaul Traina printf("%02x ", fc); 2034edb46e9SPaul Traina break; 2044edb46e9SPaul Traina } 2054edb46e9SPaul Traina } 2064edb46e9SPaul Traina } 2074edb46e9SPaul Traina 2084edb46e9SPaul Traina /* Extract src, dst addresses */ 2094edb46e9SPaul Traina static inline void 2104edb46e9SPaul Traina extract_fddi_addrs(const struct fddi_header *fddip, char *fsrc, char *fdst) 2114edb46e9SPaul Traina { 2124edb46e9SPaul Traina register int i; 2134edb46e9SPaul Traina 2144edb46e9SPaul Traina if (fddi_bitswap) { 2154edb46e9SPaul Traina /* 2164edb46e9SPaul Traina * bit-swap the fddi addresses (isn't the IEEE standards 2174edb46e9SPaul Traina * process wonderful!) then convert them to names. 2184edb46e9SPaul Traina */ 2194edb46e9SPaul Traina for (i = 0; i < 6; ++i) 2204edb46e9SPaul Traina fdst[i] = fddi_bit_swap[fddip->fddi_dhost[i]]; 2214edb46e9SPaul Traina for (i = 0; i < 6; ++i) 2224edb46e9SPaul Traina fsrc[i] = fddi_bit_swap[fddip->fddi_shost[i]]; 2234edb46e9SPaul Traina } 2244edb46e9SPaul Traina else { 2254edb46e9SPaul Traina memcpy(fdst, (char *)fddip->fddi_dhost, 6); 2264edb46e9SPaul Traina memcpy(fsrc, (char *)fddip->fddi_shost, 6); 2274edb46e9SPaul Traina } 2284edb46e9SPaul Traina } 2294edb46e9SPaul Traina 2304edb46e9SPaul Traina /* 2314edb46e9SPaul Traina * Print the FDDI MAC header 2324edb46e9SPaul Traina */ 2334edb46e9SPaul Traina static inline void 2344edb46e9SPaul Traina fddi_print(register const struct fddi_header *fddip, register u_int length, 2354edb46e9SPaul Traina register const u_char *fsrc, register const u_char *fdst) 2364edb46e9SPaul Traina { 2374edb46e9SPaul Traina char *srcname, *dstname; 2384edb46e9SPaul Traina 2394edb46e9SPaul Traina srcname = etheraddr_string(fsrc); 2404edb46e9SPaul Traina dstname = etheraddr_string(fdst); 2414edb46e9SPaul Traina 2424edb46e9SPaul Traina if (vflag) 2434edb46e9SPaul Traina (void) printf("%02x %s %s %d: ", 2444edb46e9SPaul Traina fddip->fddi_fc, 2454edb46e9SPaul Traina srcname, dstname, 2464edb46e9SPaul Traina length); 2474edb46e9SPaul Traina else if (qflag) 2484edb46e9SPaul Traina printf("%s %s %d: ", srcname, dstname, length); 2494edb46e9SPaul Traina else { 2504edb46e9SPaul Traina (void) print_fddi_fc(fddip->fddi_fc); 2514edb46e9SPaul Traina (void) printf("%s %s %d: ", srcname, dstname, length); 2524edb46e9SPaul Traina } 2534edb46e9SPaul Traina } 2544edb46e9SPaul Traina 2554edb46e9SPaul Traina static inline void 2564edb46e9SPaul Traina fddi_smt_print(const u_char *p, u_int length) 2574edb46e9SPaul Traina { 2584edb46e9SPaul Traina printf("<SMT printer not yet implemented>"); 2594edb46e9SPaul Traina } 2604edb46e9SPaul Traina 2614edb46e9SPaul Traina /* 2624edb46e9SPaul Traina * This is the top level routine of the printer. 'sp' is the points 2634edb46e9SPaul Traina * to the FDDI header of the packet, 'tvp' is the timestamp, 2644edb46e9SPaul Traina * 'length' is the length of the packet off the wire, and 'caplen' 2654edb46e9SPaul Traina * is the number of bytes actually captured. 2664edb46e9SPaul Traina */ 2674edb46e9SPaul Traina void 2684edb46e9SPaul Traina fddi_if_print(u_char *pcap, const struct pcap_pkthdr *h, 2694edb46e9SPaul Traina register const u_char *p) 2704edb46e9SPaul Traina { 2714edb46e9SPaul Traina u_int caplen = h->caplen; 2724edb46e9SPaul Traina u_int length = h->len; 2734edb46e9SPaul Traina const struct fddi_header *fddip = (struct fddi_header *)p; 2744edb46e9SPaul Traina struct ether_header ehdr; 275a88113a8SBill Fenner u_short extracted_ethertype; 2764edb46e9SPaul Traina 2774edb46e9SPaul Traina ts_print(&h->ts); 2784edb46e9SPaul Traina 2794edb46e9SPaul Traina if (caplen < FDDI_HDRLEN) { 2804edb46e9SPaul Traina printf("[|fddi]"); 2814edb46e9SPaul Traina goto out; 2824edb46e9SPaul Traina } 2834edb46e9SPaul Traina /* 2844edb46e9SPaul Traina * Get the FDDI addresses into a canonical form 2854edb46e9SPaul Traina */ 2864edb46e9SPaul Traina extract_fddi_addrs(fddip, (char *)ESRC(&ehdr), (char *)EDST(&ehdr)); 2874edb46e9SPaul Traina /* 2884edb46e9SPaul Traina * Some printers want to get back at the link level addresses, 2894edb46e9SPaul Traina * and/or check that they're not walking off the end of the packet. 2904edb46e9SPaul Traina * Rather than pass them all the way down, we set these globals. 2914edb46e9SPaul Traina */ 2924edb46e9SPaul Traina snapend = p + caplen; 2934edb46e9SPaul Traina /* 2944edb46e9SPaul Traina * Actually, the only printer that uses packetp is print-bootp.c, 2954edb46e9SPaul Traina * and it assumes that packetp points to an Ethernet header. The 2964edb46e9SPaul Traina * right thing to do is to fix print-bootp.c to know which link 2974edb46e9SPaul Traina * type is in use when it excavates. XXX 2984edb46e9SPaul Traina */ 2994edb46e9SPaul Traina packetp = (u_char *)&ehdr; 3004edb46e9SPaul Traina 3014edb46e9SPaul Traina if (eflag) 3024edb46e9SPaul Traina fddi_print(fddip, length, ESRC(&ehdr), EDST(&ehdr)); 3034edb46e9SPaul Traina 3044edb46e9SPaul Traina /* Skip over FDDI MAC header */ 3054edb46e9SPaul Traina length -= FDDI_HDRLEN; 3064edb46e9SPaul Traina p += FDDI_HDRLEN; 3074edb46e9SPaul Traina caplen -= FDDI_HDRLEN; 3084edb46e9SPaul Traina 3094edb46e9SPaul Traina /* Frame Control field determines interpretation of packet */ 3104edb46e9SPaul Traina extracted_ethertype = 0; 3114edb46e9SPaul Traina if ((fddip->fddi_fc & FDDIFC_CLFF) == FDDIFC_LLC_ASYNC) { 3124edb46e9SPaul Traina /* Try to print the LLC-layer header & higher layers */ 3134edb46e9SPaul Traina if (llc_print(p, length, caplen, ESRC(&ehdr), EDST(&ehdr)) 3144edb46e9SPaul Traina == 0) { 3154edb46e9SPaul Traina /* 3164edb46e9SPaul Traina * Some kinds of LLC packet we cannot 3174edb46e9SPaul Traina * handle intelligently 3184edb46e9SPaul Traina */ 3194edb46e9SPaul Traina if (!eflag) 3204edb46e9SPaul Traina fddi_print(fddip, length, 3214edb46e9SPaul Traina ESRC(&ehdr), EDST(&ehdr)); 3224edb46e9SPaul Traina if (extracted_ethertype) { 3234edb46e9SPaul Traina printf("(LLC %s) ", 3244edb46e9SPaul Traina etherproto_string(htons(extracted_ethertype))); 3254edb46e9SPaul Traina } 3264edb46e9SPaul Traina if (!xflag && !qflag) 3274edb46e9SPaul Traina default_print(p, caplen); 3284edb46e9SPaul Traina } 3294edb46e9SPaul Traina } else if ((fddip->fddi_fc & FDDIFC_CLFF) == FDDIFC_SMT) 3304edb46e9SPaul Traina fddi_smt_print(p, caplen); 3314edb46e9SPaul Traina else { 3324edb46e9SPaul Traina /* Some kinds of FDDI packet we cannot handle intelligently */ 3334edb46e9SPaul Traina if (!eflag) 3344edb46e9SPaul Traina fddi_print(fddip, length, ESRC(&ehdr), EDST(&ehdr)); 3354edb46e9SPaul Traina if (!xflag && !qflag) 3364edb46e9SPaul Traina default_print(p, caplen); 3374edb46e9SPaul Traina } 3384edb46e9SPaul Traina if (xflag) 3394edb46e9SPaul Traina default_print(p, caplen); 3404edb46e9SPaul Traina out: 3414edb46e9SPaul Traina putchar('\n'); 3424edb46e9SPaul Traina } 343