10f74e101Schristos /* 20f74e101Schristos * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 30f74e101Schristos * The Regents of the University of California. All rights reserved. 40f74e101Schristos * 50f74e101Schristos * Redistribution and use in source and binary forms, with or without 60f74e101Schristos * modification, are permitted provided that: (1) source code distributions 70f74e101Schristos * retain the above copyright notice and this paragraph in its entirety, (2) 80f74e101Schristos * distributions including binary code include the above copyright notice and 90f74e101Schristos * this paragraph in its entirety in the documentation or other materials 100f74e101Schristos * provided with the distribution, and (3) all advertising materials mentioning 110f74e101Schristos * features or use of this software display the following acknowledgement: 120f74e101Schristos * ``This product includes software developed by the University of California, 130f74e101Schristos * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 140f74e101Schristos * the University nor the names of its contributors may be used to endorse 150f74e101Schristos * or promote products derived from this software without specific prior 160f74e101Schristos * written permission. 170f74e101Schristos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 180f74e101Schristos * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 190f74e101Schristos * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 200f74e101Schristos */ 21b3a00663Schristos 2211b3aaa1Schristos #include <sys/cdefs.h> 230f74e101Schristos #ifndef lint 24*26ba0b50Schristos __RCSID("$NetBSD: print-ether.c,v 1.11 2024/09/02 16:15:31 christos Exp $"); 250f74e101Schristos #endif 260f74e101Schristos 27dc860a36Sspz /* \summary: Ethernet printer */ 28dc860a36Sspz 29c74ad251Schristos #include <config.h> 300f74e101Schristos 31c74ad251Schristos #include "netdissect-stdinc.h" 320f74e101Schristos 33c74ad251Schristos #define ND_LONGJMP_FROM_TCHECK 34fdccd7e4Schristos #include "netdissect.h" 350f74e101Schristos #include "extract.h" 360f74e101Schristos #include "addrtoname.h" 370f74e101Schristos #include "ethertype.h" 38c74ad251Schristos 39c74ad251Schristos /* 40c74ad251Schristos * Structure of an Ethernet header. 41c74ad251Schristos */ 42c74ad251Schristos struct ether_header { 43c74ad251Schristos nd_mac_addr ether_dhost; 44c74ad251Schristos nd_mac_addr ether_shost; 45c74ad251Schristos nd_uint16_t ether_length_type; 46c74ad251Schristos }; 47c74ad251Schristos 48c74ad251Schristos /* 49c74ad251Schristos * Length of an Ethernet header; note that some compilers may pad 50c74ad251Schristos * "struct ether_header" to a multiple of 4 bytes, for example, so 51c74ad251Schristos * "sizeof (struct ether_header)" may not give the right answer. 52c74ad251Schristos */ 53c74ad251Schristos #define ETHER_HDRLEN 14 540f74e101Schristos 550f74e101Schristos const struct tok ethertype_values[] = { 560f74e101Schristos { ETHERTYPE_IP, "IPv4" }, 570f74e101Schristos { ETHERTYPE_MPLS, "MPLS unicast" }, 580f74e101Schristos { ETHERTYPE_MPLS_MULTI, "MPLS multicast" }, 590f74e101Schristos { ETHERTYPE_IPV6, "IPv6" }, 600f74e101Schristos { ETHERTYPE_8021Q, "802.1Q" }, 610e9868baSchristos { ETHERTYPE_8021Q9100, "802.1Q-9100" }, 620e9868baSchristos { ETHERTYPE_8021QinQ, "802.1Q-QinQ" }, 630e9868baSchristos { ETHERTYPE_8021Q9200, "802.1Q-9200" }, 64c74ad251Schristos { ETHERTYPE_MACSEC, "802.1AE MACsec" }, 650f74e101Schristos { ETHERTYPE_VMAN, "VMAN" }, 660f74e101Schristos { ETHERTYPE_PUP, "PUP" }, 670f74e101Schristos { ETHERTYPE_ARP, "ARP"}, 680f74e101Schristos { ETHERTYPE_REVARP, "Reverse ARP"}, 690f74e101Schristos { ETHERTYPE_NS, "NS" }, 700f74e101Schristos { ETHERTYPE_SPRITE, "Sprite" }, 710f74e101Schristos { ETHERTYPE_TRAIL, "Trail" }, 720f74e101Schristos { ETHERTYPE_MOPDL, "MOP DL" }, 730f74e101Schristos { ETHERTYPE_MOPRC, "MOP RC" }, 740f74e101Schristos { ETHERTYPE_DN, "DN" }, 750f74e101Schristos { ETHERTYPE_LAT, "LAT" }, 760f74e101Schristos { ETHERTYPE_SCA, "SCA" }, 770f74e101Schristos { ETHERTYPE_TEB, "TEB" }, 780f74e101Schristos { ETHERTYPE_LANBRIDGE, "Lanbridge" }, 790f74e101Schristos { ETHERTYPE_DECDNS, "DEC DNS" }, 800f74e101Schristos { ETHERTYPE_DECDTS, "DEC DTS" }, 810f74e101Schristos { ETHERTYPE_VEXP, "VEXP" }, 820f74e101Schristos { ETHERTYPE_VPROD, "VPROD" }, 830f74e101Schristos { ETHERTYPE_ATALK, "Appletalk" }, 840f74e101Schristos { ETHERTYPE_AARP, "Appletalk ARP" }, 850f74e101Schristos { ETHERTYPE_IPX, "IPX" }, 860f74e101Schristos { ETHERTYPE_PPP, "PPP" }, 870f74e101Schristos { ETHERTYPE_MPCP, "MPCP" }, 880f74e101Schristos { ETHERTYPE_SLOW, "Slow Protocols" }, 890f74e101Schristos { ETHERTYPE_PPPOED, "PPPoE D" }, 900f74e101Schristos { ETHERTYPE_PPPOES, "PPPoE S" }, 910f74e101Schristos { ETHERTYPE_EAPOL, "EAPOL" }, 92c74ad251Schristos { ETHERTYPE_REALTEK, "Realtek protocols" }, 93870189d2Schristos { ETHERTYPE_MS_NLB_HB, "MS NLB heartbeat" }, 940f74e101Schristos { ETHERTYPE_JUMBO, "Jumbo" }, 95c74ad251Schristos { ETHERTYPE_NSH, "NSH" }, 960f74e101Schristos { ETHERTYPE_LOOPBACK, "Loopback" }, 970f74e101Schristos { ETHERTYPE_ISO, "OSI" }, 980f74e101Schristos { ETHERTYPE_GRE_ISO, "GRE-OSI" }, 990f74e101Schristos { ETHERTYPE_CFM_OLD, "CFM (old)" }, 1000f74e101Schristos { ETHERTYPE_CFM, "CFM" }, 101b3a00663Schristos { ETHERTYPE_IEEE1905_1, "IEEE1905.1" }, 1020f74e101Schristos { ETHERTYPE_LLDP, "LLDP" }, 1030e9868baSchristos { ETHERTYPE_TIPC, "TIPC"}, 104870189d2Schristos { ETHERTYPE_GEONET_OLD, "GeoNet (old)"}, 105870189d2Schristos { ETHERTYPE_GEONET, "GeoNet"}, 106870189d2Schristos { ETHERTYPE_CALM_FAST, "CALM FAST"}, 107b3a00663Schristos { ETHERTYPE_AOE, "AoE" }, 108c74ad251Schristos { ETHERTYPE_PTP, "PTP" }, 109c74ad251Schristos { ETHERTYPE_ARISTA, "Arista Vendor Specific Protocol" }, 1100f74e101Schristos { 0, NULL} 1110f74e101Schristos }; 1120f74e101Schristos 113c74ad251Schristos static void 114c74ad251Schristos ether_addresses_print(netdissect_options *ndo, const u_char *src, 115c74ad251Schristos const u_char *dst) 1160f74e101Schristos { 117c74ad251Schristos ND_PRINT("%s > %s, ", 118c74ad251Schristos GET_ETHERADDR_STRING(src), GET_ETHERADDR_STRING(dst)); 1190f74e101Schristos } 1200f74e101Schristos 121c74ad251Schristos static void 122c74ad251Schristos ether_type_print(netdissect_options *ndo, uint16_t type) 123c74ad251Schristos { 124c74ad251Schristos if (!ndo->ndo_qflag) 125c74ad251Schristos ND_PRINT("ethertype %s (0x%04x)", 126c74ad251Schristos tok2str(ethertype_values, "Unknown", type), type); 127c74ad251Schristos else 128c74ad251Schristos ND_PRINT("%s", 129c74ad251Schristos tok2str(ethertype_values, "Unknown Ethertype (0x%04x)", type)); 1300f74e101Schristos } 1310f74e101Schristos 1320f74e101Schristos /* 133c74ad251Schristos * Common code for printing Ethernet frames. 134dc860a36Sspz * 135c74ad251Schristos * It can handle Ethernet headers with extra tag information inserted 136c74ad251Schristos * after the destination and source addresses, as is inserted by some 137c74ad251Schristos * switch chips, and extra encapsulation header information before 138c74ad251Schristos * printing Ethernet header information (such as a LANE ID for ATM LANE). 1390f74e101Schristos */ 140c74ad251Schristos static u_int 141c74ad251Schristos ether_common_print(netdissect_options *ndo, const u_char *p, u_int length, 142c74ad251Schristos u_int caplen, 143c74ad251Schristos void (*print_switch_tag)(netdissect_options *ndo, const u_char *), 144c74ad251Schristos u_int switch_tag_len, 145c74ad251Schristos void (*print_encap_header)(netdissect_options *ndo, const u_char *), 146c74ad251Schristos const u_char *encap_header_arg) 1470f74e101Schristos { 148c74ad251Schristos const struct ether_header *ehp; 1490f74e101Schristos u_int orig_length; 150fdccd7e4Schristos u_int hdrlen; 151c74ad251Schristos u_short length_type; 152c74ad251Schristos int printed_length; 153fdccd7e4Schristos int llc_hdrlen; 154dc860a36Sspz struct lladdr_info src, dst; 1550f74e101Schristos 156c74ad251Schristos if (length < caplen) { 157c74ad251Schristos ND_PRINT("[length %u < caplen %u]", length, caplen); 158c74ad251Schristos nd_print_invalid(ndo); 159c74ad251Schristos return length; 160fdccd7e4Schristos } 161c74ad251Schristos if (caplen < ETHER_HDRLEN + switch_tag_len) { 162c74ad251Schristos nd_print_trunc(ndo); 163c74ad251Schristos return caplen; 164c74ad251Schristos } 165c74ad251Schristos 166c74ad251Schristos if (print_encap_header != NULL) 167c74ad251Schristos (*print_encap_header)(ndo, encap_header_arg); 168c74ad251Schristos 169c74ad251Schristos orig_length = length; 170c74ad251Schristos 171c74ad251Schristos /* 172c74ad251Schristos * Get the source and destination addresses, skip past them, 173c74ad251Schristos * and print them if we're printing the link-layer header. 174c74ad251Schristos */ 175c74ad251Schristos ehp = (const struct ether_header *)p; 176c74ad251Schristos src.addr = ehp->ether_shost; 177c74ad251Schristos src.addr_string = etheraddr_string; 178c74ad251Schristos dst.addr = ehp->ether_dhost; 179c74ad251Schristos dst.addr_string = etheraddr_string; 180c74ad251Schristos 181c74ad251Schristos length -= 2*MAC_ADDR_LEN; 182c74ad251Schristos caplen -= 2*MAC_ADDR_LEN; 183c74ad251Schristos p += 2*MAC_ADDR_LEN; 184c74ad251Schristos hdrlen = 2*MAC_ADDR_LEN; 185c74ad251Schristos 186c74ad251Schristos if (ndo->ndo_eflag) 187c74ad251Schristos ether_addresses_print(ndo, src.addr, dst.addr); 188c74ad251Schristos 189c74ad251Schristos /* 190c74ad251Schristos * Print the switch tag, if we have one, and skip past it. 191c74ad251Schristos */ 192c74ad251Schristos if (print_switch_tag != NULL) 193c74ad251Schristos (*print_switch_tag)(ndo, p); 194c74ad251Schristos 195c74ad251Schristos length -= switch_tag_len; 196c74ad251Schristos caplen -= switch_tag_len; 197c74ad251Schristos p += switch_tag_len; 198c74ad251Schristos hdrlen += switch_tag_len; 199c74ad251Schristos 200c74ad251Schristos /* 201c74ad251Schristos * Get the length/type field, skip past it, and print it 202c74ad251Schristos * if we're printing the link-layer header. 203c74ad251Schristos */ 204c74ad251Schristos recurse: 205c74ad251Schristos length_type = GET_BE_U_2(p); 206c74ad251Schristos 207c74ad251Schristos length -= 2; 208c74ad251Schristos caplen -= 2; 209c74ad251Schristos p += 2; 210c74ad251Schristos hdrlen += 2; 211c74ad251Schristos 212c74ad251Schristos /* 213c74ad251Schristos * Process 802.1AE MACsec headers. 214c74ad251Schristos */ 215c74ad251Schristos printed_length = 0; 216c74ad251Schristos if (length_type == ETHERTYPE_MACSEC) { 217c74ad251Schristos /* 218c74ad251Schristos * MACsec, aka IEEE 802.1AE-2006 219c74ad251Schristos * Print the header, and try to print the payload if it's not encrypted 220c74ad251Schristos */ 221c74ad251Schristos if (ndo->ndo_eflag) { 222c74ad251Schristos ether_type_print(ndo, length_type); 223c74ad251Schristos ND_PRINT(", length %u: ", orig_length); 224c74ad251Schristos printed_length = 1; 225c74ad251Schristos } 226c74ad251Schristos 227c74ad251Schristos int ret = macsec_print(ndo, &p, &length, &caplen, &hdrlen, 228c74ad251Schristos &src, &dst); 229c74ad251Schristos 230c74ad251Schristos if (ret == 0) { 231c74ad251Schristos /* Payload is encrypted; print it as raw data. */ 232c74ad251Schristos if (!ndo->ndo_suppress_default_print) 233c74ad251Schristos ND_DEFAULTPRINT(p, caplen); 234c74ad251Schristos return hdrlen; 235c74ad251Schristos } else if (ret > 0) { 236c74ad251Schristos /* Problem printing the header; just quit. */ 237c74ad251Schristos return ret; 238c74ad251Schristos } else { 239c74ad251Schristos /* 240c74ad251Schristos * Keep processing type/length fields. 241c74ad251Schristos */ 242c74ad251Schristos length_type = GET_BE_U_2(p); 243c74ad251Schristos 244*26ba0b50Schristos ND_ICHECK_U(caplen, <, 2); 245c74ad251Schristos length -= 2; 246c74ad251Schristos caplen -= 2; 247c74ad251Schristos p += 2; 248c74ad251Schristos hdrlen += 2; 249c74ad251Schristos } 250c74ad251Schristos } 251c74ad251Schristos 252c74ad251Schristos /* 253c74ad251Schristos * Process VLAN tag types. 254c74ad251Schristos */ 255c74ad251Schristos while (length_type == ETHERTYPE_8021Q || 256c74ad251Schristos length_type == ETHERTYPE_8021Q9100 || 257c74ad251Schristos length_type == ETHERTYPE_8021Q9200 || 258c74ad251Schristos length_type == ETHERTYPE_8021QinQ) { 259c74ad251Schristos /* 260c74ad251Schristos * It has a VLAN tag. 261c74ad251Schristos * Print VLAN information, and then go back and process 262c74ad251Schristos * the enclosed type field. 263c74ad251Schristos */ 264c74ad251Schristos if (caplen < 4) { 265c74ad251Schristos ndo->ndo_protocol = "vlan"; 266c74ad251Schristos nd_print_trunc(ndo); 267c74ad251Schristos return hdrlen + caplen; 268c74ad251Schristos } 269c74ad251Schristos if (length < 4) { 270c74ad251Schristos ndo->ndo_protocol = "vlan"; 271c74ad251Schristos nd_print_trunc(ndo); 272c74ad251Schristos return hdrlen + length; 273c74ad251Schristos } 274c74ad251Schristos if (ndo->ndo_eflag) { 275c74ad251Schristos uint16_t tag = GET_BE_U_2(p); 276c74ad251Schristos 277c74ad251Schristos ether_type_print(ndo, length_type); 278c74ad251Schristos if (!printed_length) { 279c74ad251Schristos ND_PRINT(", length %u: ", orig_length); 280c74ad251Schristos printed_length = 1; 281c74ad251Schristos } else 282c74ad251Schristos ND_PRINT(", "); 283c74ad251Schristos ND_PRINT("%s, ", ieee8021q_tci_string(tag)); 284c74ad251Schristos } 285c74ad251Schristos 286c74ad251Schristos length_type = GET_BE_U_2(p + 2); 287c74ad251Schristos p += 4; 288c74ad251Schristos length -= 4; 289c74ad251Schristos caplen -= 4; 290c74ad251Schristos hdrlen += 4; 291c74ad251Schristos } 292c74ad251Schristos 293c74ad251Schristos /* 294c74ad251Schristos * We now have the final length/type field. 295c74ad251Schristos */ 296c74ad251Schristos if (length_type <= MAX_ETHERNET_LENGTH_VAL) { 297c74ad251Schristos /* 298c74ad251Schristos * It's a length field, containing the length of the 299c74ad251Schristos * remaining payload; use it as such, as long as 300c74ad251Schristos * it's not too large (bigger than the actual payload). 301c74ad251Schristos */ 302c74ad251Schristos if (length_type < length) { 303c74ad251Schristos length = length_type; 304c74ad251Schristos if (caplen > length) 305c74ad251Schristos caplen = length; 306c74ad251Schristos } 307c74ad251Schristos 308c74ad251Schristos /* 309c74ad251Schristos * Cut off the snapshot length to the end of the 310c74ad251Schristos * payload. 311c74ad251Schristos */ 312c74ad251Schristos if (!nd_push_snaplen(ndo, p, length)) { 313c74ad251Schristos (*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC, 314c74ad251Schristos "%s: can't push snaplen on buffer stack", __func__); 3150f74e101Schristos } 3160f74e101Schristos 3170e9868baSchristos if (ndo->ndo_eflag) { 318c74ad251Schristos ND_PRINT("802.3"); 319c74ad251Schristos if (!printed_length) 320c74ad251Schristos ND_PRINT(", length %u: ", length); 3210f74e101Schristos } 3220f74e101Schristos 3230f74e101Schristos /* 324c74ad251Schristos * An LLC header follows the length. Print that and 325c74ad251Schristos * higher layers. 3260f74e101Schristos */ 327dc860a36Sspz llc_hdrlen = llc_print(ndo, p, length, caplen, &src, &dst); 328fdccd7e4Schristos if (llc_hdrlen < 0) { 329fdccd7e4Schristos /* packet type not known, print raw packet */ 3300e9868baSchristos if (!ndo->ndo_suppress_default_print) 331b3a00663Schristos ND_DEFAULTPRINT(p, caplen); 332fdccd7e4Schristos llc_hdrlen = -llc_hdrlen; 3330f74e101Schristos } 334fdccd7e4Schristos hdrlen += llc_hdrlen; 335c74ad251Schristos nd_pop_packet_info(ndo); 336fdccd7e4Schristos } else if (length_type == ETHERTYPE_JUMBO) { 3370f74e101Schristos /* 338c74ad251Schristos * It's a type field, with the type for Alteon jumbo frames. 3390f74e101Schristos * See 3400f74e101Schristos * 341c74ad251Schristos * https://tools.ietf.org/html/draft-ietf-isis-ext-eth-01 3420f74e101Schristos * 3430f74e101Schristos * which indicates that, following the type field, 3440f74e101Schristos * there's an LLC header and payload. 3450f74e101Schristos */ 3460f74e101Schristos /* Try to print the LLC-layer header & higher layers */ 347dc860a36Sspz llc_hdrlen = llc_print(ndo, p, length, caplen, &src, &dst); 348fdccd7e4Schristos if (llc_hdrlen < 0) { 349fdccd7e4Schristos /* packet type not known, print raw packet */ 3500e9868baSchristos if (!ndo->ndo_suppress_default_print) 351b3a00663Schristos ND_DEFAULTPRINT(p, caplen); 352fdccd7e4Schristos llc_hdrlen = -llc_hdrlen; 3530f74e101Schristos } 354fdccd7e4Schristos hdrlen += llc_hdrlen; 355c74ad251Schristos } else if (length_type == ETHERTYPE_ARISTA) { 356c74ad251Schristos if (caplen < 2) { 357c74ad251Schristos ND_PRINT("[|arista]"); 358c74ad251Schristos return hdrlen + caplen; 359c74ad251Schristos } 360c74ad251Schristos if (length < 2) { 361c74ad251Schristos ND_PRINT("[|arista]"); 362c74ad251Schristos return hdrlen + length; 363c74ad251Schristos } 364c74ad251Schristos ether_type_print(ndo, length_type); 365c74ad251Schristos ND_PRINT(", length %u: ", orig_length); 366c74ad251Schristos int bytesConsumed = arista_ethertype_print(ndo, p, length); 367c74ad251Schristos if (bytesConsumed > 0) { 368c74ad251Schristos p += bytesConsumed; 369c74ad251Schristos length -= bytesConsumed; 370c74ad251Schristos caplen -= bytesConsumed; 371c74ad251Schristos hdrlen += bytesConsumed; 372c74ad251Schristos goto recurse; 3730f74e101Schristos } else { 374c74ad251Schristos /* subtype/version not known, print raw packet */ 375c74ad251Schristos if (!ndo->ndo_eflag && length_type > MAX_ETHERNET_LENGTH_VAL) { 376c74ad251Schristos ether_addresses_print(ndo, src.addr, dst.addr); 377c74ad251Schristos ether_type_print(ndo, length_type); 378c74ad251Schristos ND_PRINT(", length %u: ", orig_length); 379c74ad251Schristos } 380c74ad251Schristos if (!ndo->ndo_suppress_default_print) 381c74ad251Schristos ND_DEFAULTPRINT(p, caplen); 382c74ad251Schristos } 383c74ad251Schristos } else { 384c74ad251Schristos /* 385c74ad251Schristos * It's a type field with some other value. 386c74ad251Schristos */ 387c74ad251Schristos if (ndo->ndo_eflag) { 388c74ad251Schristos ether_type_print(ndo, length_type); 389c74ad251Schristos if (!printed_length) 390c74ad251Schristos ND_PRINT(", length %u: ", orig_length); 391c74ad251Schristos else 392c74ad251Schristos ND_PRINT(", "); 393c74ad251Schristos } 394dc860a36Sspz if (ethertype_print(ndo, length_type, p, length, caplen, &src, &dst) == 0) { 395fdccd7e4Schristos /* type not known, print raw packet */ 3960e9868baSchristos if (!ndo->ndo_eflag) { 397c74ad251Schristos /* 398c74ad251Schristos * We didn't print the full link-layer 399c74ad251Schristos * header, as -e wasn't specified, so 400c74ad251Schristos * print only the source and destination 401c74ad251Schristos * MAC addresses and the final Ethernet 402c74ad251Schristos * type. 403c74ad251Schristos */ 404c74ad251Schristos ether_addresses_print(ndo, src.addr, dst.addr); 405c74ad251Schristos ether_type_print(ndo, length_type); 406c74ad251Schristos ND_PRINT(", length %u: ", orig_length); 4070f74e101Schristos } 4080f74e101Schristos 4090e9868baSchristos if (!ndo->ndo_suppress_default_print) 410b3a00663Schristos ND_DEFAULTPRINT(p, caplen); 4110f74e101Schristos } 4120f74e101Schristos } 413c74ad251Schristos invalid: 414c74ad251Schristos return hdrlen; 415c74ad251Schristos } 416c74ad251Schristos 417c74ad251Schristos /* 418*26ba0b50Schristos * Print an Ethernet frame while specifying a non-standard Ethernet header 419c74ad251Schristos * length. 420c74ad251Schristos * This might be encapsulated within another frame; we might be passed 421c74ad251Schristos * a pointer to a function that can print header information for that 422c74ad251Schristos * frame's protocol, and an argument to pass to that function. 423c74ad251Schristos * 424c74ad251Schristos * FIXME: caplen can and should be derived from ndo->ndo_snapend and p. 425c74ad251Schristos */ 426c74ad251Schristos u_int 427c74ad251Schristos ether_switch_tag_print(netdissect_options *ndo, const u_char *p, u_int length, 428c74ad251Schristos u_int caplen, 429c74ad251Schristos void (*print_switch_tag)(netdissect_options *, const u_char *), 430c74ad251Schristos u_int switch_tag_len) 431c74ad251Schristos { 432c74ad251Schristos return ether_common_print(ndo, p, length, caplen, print_switch_tag, 433c74ad251Schristos switch_tag_len, NULL, NULL); 434c74ad251Schristos } 435c74ad251Schristos 436c74ad251Schristos /* 437c74ad251Schristos * Print an Ethernet frame. 438c74ad251Schristos * This might be encapsulated within another frame; we might be passed 439c74ad251Schristos * a pointer to a function that can print header information for that 440c74ad251Schristos * frame's protocol, and an argument to pass to that function. 441c74ad251Schristos * 442c74ad251Schristos * FIXME: caplen can and should be derived from ndo->ndo_snapend and p. 443c74ad251Schristos */ 444c74ad251Schristos u_int 445c74ad251Schristos ether_print(netdissect_options *ndo, 446c74ad251Schristos const u_char *p, u_int length, u_int caplen, 447c74ad251Schristos void (*print_encap_header)(netdissect_options *ndo, const u_char *), 448c74ad251Schristos const u_char *encap_header_arg) 449c74ad251Schristos { 450c74ad251Schristos ndo->ndo_protocol = "ether"; 451c74ad251Schristos return ether_common_print(ndo, p, length, caplen, NULL, 0, 452c74ad251Schristos print_encap_header, encap_header_arg); 4530f74e101Schristos } 4540f74e101Schristos 4550f74e101Schristos /* 4560f74e101Schristos * This is the top level routine of the printer. 'p' points 457fdccd7e4Schristos * to the ether header of the packet, 'h->len' is the length 458fdccd7e4Schristos * of the packet off the wire, and 'h->caplen' is the number 459fdccd7e4Schristos * of bytes actually captured. 4600f74e101Schristos */ 461c74ad251Schristos void 4620e9868baSchristos ether_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, 4630e9868baSchristos const u_char *p) 4640f74e101Schristos { 465c74ad251Schristos ndo->ndo_protocol = "ether"; 466c74ad251Schristos ndo->ndo_ll_hdr_len += 467c74ad251Schristos ether_print(ndo, p, h->len, h->caplen, NULL, NULL); 4680f74e101Schristos } 4690f74e101Schristos 4700f74e101Schristos /* 4710e9868baSchristos * This is the top level routine of the printer. 'p' points 472fdccd7e4Schristos * to the ether header of the packet, 'h->len' is the length 473fdccd7e4Schristos * of the packet off the wire, and 'h->caplen' is the number 474fdccd7e4Schristos * of bytes actually captured. 4750e9868baSchristos * 4760e9868baSchristos * This is for DLT_NETANALYZER, which has a 4-byte pseudo-header 4770e9868baSchristos * before the Ethernet header. 4780e9868baSchristos */ 479c74ad251Schristos void 4800e9868baSchristos netanalyzer_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, 4810e9868baSchristos const u_char *p) 4820e9868baSchristos { 4830e9868baSchristos /* 4840e9868baSchristos * Fail if we don't have enough data for the Hilscher pseudo-header. 4850e9868baSchristos */ 486c74ad251Schristos ndo->ndo_protocol = "netanalyzer"; 487c74ad251Schristos ND_TCHECK_LEN(p, 4); 4880e9868baSchristos 4890e9868baSchristos /* Skip the pseudo-header. */ 490c74ad251Schristos ndo->ndo_ll_hdr_len += 4; 491c74ad251Schristos ndo->ndo_ll_hdr_len += 492c74ad251Schristos ether_print(ndo, p + 4, h->len - 4, h->caplen - 4, NULL, NULL); 4930e9868baSchristos } 4940e9868baSchristos 4950e9868baSchristos /* 4960e9868baSchristos * This is the top level routine of the printer. 'p' points 497fdccd7e4Schristos * to the ether header of the packet, 'h->len' is the length 498fdccd7e4Schristos * of the packet off the wire, and 'h->caplen' is the number 499fdccd7e4Schristos * of bytes actually captured. 5000e9868baSchristos * 5010e9868baSchristos * This is for DLT_NETANALYZER_TRANSPARENT, which has a 4-byte 5020e9868baSchristos * pseudo-header, a 7-byte Ethernet preamble, and a 1-byte Ethernet SOF 5030e9868baSchristos * before the Ethernet header. 5040e9868baSchristos */ 505c74ad251Schristos void 5060e9868baSchristos netanalyzer_transparent_if_print(netdissect_options *ndo, 5070e9868baSchristos const struct pcap_pkthdr *h, 5080e9868baSchristos const u_char *p) 5090e9868baSchristos { 5100e9868baSchristos /* 5110e9868baSchristos * Fail if we don't have enough data for the Hilscher pseudo-header, 5120e9868baSchristos * preamble, and SOF. 5130e9868baSchristos */ 514c74ad251Schristos ndo->ndo_protocol = "netanalyzer_transparent"; 515c74ad251Schristos ND_TCHECK_LEN(p, 12); 5160e9868baSchristos 5170e9868baSchristos /* Skip the pseudo-header, preamble, and SOF. */ 518c74ad251Schristos ndo->ndo_ll_hdr_len += 12; 519c74ad251Schristos ndo->ndo_ll_hdr_len += 520c74ad251Schristos ether_print(ndo, p + 12, h->len - 12, h->caplen - 12, NULL, NULL); 5210e9868baSchristos } 5220e9868baSchristos 5230e9868baSchristos /* 5240f74e101Schristos * Prints the packet payload, given an Ethernet type code for the payload's 5250f74e101Schristos * protocol. 5260f74e101Schristos * 5270f74e101Schristos * Returns non-zero if it can do so, zero if the ethertype is unknown. 5280f74e101Schristos */ 5290f74e101Schristos 5300f74e101Schristos int 5310e9868baSchristos ethertype_print(netdissect_options *ndo, 5320e9868baSchristos u_short ether_type, const u_char *p, 533dc860a36Sspz u_int length, u_int caplen, 534dc860a36Sspz const struct lladdr_info *src, const struct lladdr_info *dst) 5350f74e101Schristos { 5360f74e101Schristos switch (ether_type) { 5370f74e101Schristos 5380f74e101Schristos case ETHERTYPE_IP: 5390e9868baSchristos ip_print(ndo, p, length); 5400f74e101Schristos return (1); 5410f74e101Schristos 5420f74e101Schristos case ETHERTYPE_IPV6: 5430e9868baSchristos ip6_print(ndo, p, length); 5440f74e101Schristos return (1); 5450f74e101Schristos 5460f74e101Schristos case ETHERTYPE_ARP: 5470f74e101Schristos case ETHERTYPE_REVARP: 5480e9868baSchristos arp_print(ndo, p, length, caplen); 5490f74e101Schristos return (1); 5500f74e101Schristos 5510f74e101Schristos case ETHERTYPE_DN: 552b3a00663Schristos decnet_print(ndo, p, length, caplen); 5530f74e101Schristos return (1); 5540f74e101Schristos 5550f74e101Schristos case ETHERTYPE_ATALK: 5560e9868baSchristos if (ndo->ndo_vflag) 557c74ad251Schristos ND_PRINT("et1 "); 558b3a00663Schristos atalk_print(ndo, p, length); 5590f74e101Schristos return (1); 5600f74e101Schristos 5610f74e101Schristos case ETHERTYPE_AARP: 562b3a00663Schristos aarp_print(ndo, p, length); 5630f74e101Schristos return (1); 5640f74e101Schristos 5650f74e101Schristos case ETHERTYPE_IPX: 566c74ad251Schristos ND_PRINT("(NOV-ETHII) "); 567b3a00663Schristos ipx_print(ndo, p, length); 5680f74e101Schristos return (1); 5690f74e101Schristos 5700f74e101Schristos case ETHERTYPE_ISO: 571dc860a36Sspz if (length == 0 || caplen == 0) { 572c74ad251Schristos ndo->ndo_protocol = "isoclns"; 573c74ad251Schristos nd_print_trunc(ndo); 574dc860a36Sspz return (1); 575dc860a36Sspz } 576c74ad251Schristos /* At least one byte is required */ 577c74ad251Schristos /* FIXME: Reference for this byte? */ 578c74ad251Schristos ND_TCHECK_LEN(p, 1); 57972c96ff3Schristos isoclns_print(ndo, p + 1, length - 1); 5800f74e101Schristos return(1); 5810f74e101Schristos 5820f74e101Schristos case ETHERTYPE_PPPOED: 5830f74e101Schristos case ETHERTYPE_PPPOES: 5840f74e101Schristos case ETHERTYPE_PPPOED2: 5850f74e101Schristos case ETHERTYPE_PPPOES2: 586b3a00663Schristos pppoe_print(ndo, p, length); 5870f74e101Schristos return (1); 5880f74e101Schristos 5890f74e101Schristos case ETHERTYPE_EAPOL: 590c74ad251Schristos eapol_print(ndo, p); 5910f74e101Schristos return (1); 5920f74e101Schristos 593c74ad251Schristos case ETHERTYPE_REALTEK: 594c74ad251Schristos rtl_print(ndo, p, length, src, dst); 5950f74e101Schristos return (1); 5960f74e101Schristos 5970f74e101Schristos case ETHERTYPE_PPP: 5980f74e101Schristos if (length) { 599c74ad251Schristos ND_PRINT(": "); 600b3a00663Schristos ppp_print(ndo, p, length); 6010f74e101Schristos } 6020f74e101Schristos return (1); 6030f74e101Schristos 6040f74e101Schristos case ETHERTYPE_MPCP: 605b3a00663Schristos mpcp_print(ndo, p, length); 6060f74e101Schristos return (1); 6070f74e101Schristos 6080f74e101Schristos case ETHERTYPE_SLOW: 609b3a00663Schristos slow_print(ndo, p, length); 6100f74e101Schristos return (1); 6110f74e101Schristos 6120f74e101Schristos case ETHERTYPE_CFM: 6130f74e101Schristos case ETHERTYPE_CFM_OLD: 614b3a00663Schristos cfm_print(ndo, p, length); 6150f74e101Schristos return (1); 6160f74e101Schristos 6170f74e101Schristos case ETHERTYPE_LLDP: 618b3a00663Schristos lldp_print(ndo, p, length); 6190f74e101Schristos return (1); 6200f74e101Schristos 621c74ad251Schristos case ETHERTYPE_NSH: 622c74ad251Schristos nsh_print(ndo, p, length); 623c74ad251Schristos return (1); 624c74ad251Schristos 6250f74e101Schristos case ETHERTYPE_LOOPBACK: 626b3a00663Schristos loopback_print(ndo, p, length); 6270f74e101Schristos return (1); 6280f74e101Schristos 6290f74e101Schristos case ETHERTYPE_MPLS: 6300f74e101Schristos case ETHERTYPE_MPLS_MULTI: 631b3a00663Schristos mpls_print(ndo, p, length); 6320e9868baSchristos return (1); 6330e9868baSchristos 6340e9868baSchristos case ETHERTYPE_TIPC: 6350e9868baSchristos tipc_print(ndo, p, length, caplen); 6360f74e101Schristos return (1); 6370f74e101Schristos 638870189d2Schristos case ETHERTYPE_MS_NLB_HB: 639870189d2Schristos msnlb_print(ndo, p); 640870189d2Schristos return (1); 641870189d2Schristos 642870189d2Schristos case ETHERTYPE_GEONET_OLD: 643870189d2Schristos case ETHERTYPE_GEONET: 644dc860a36Sspz geonet_print(ndo, p, length, src); 645870189d2Schristos return (1); 646870189d2Schristos 647870189d2Schristos case ETHERTYPE_CALM_FAST: 648dc860a36Sspz calm_fast_print(ndo, p, length, src); 649870189d2Schristos return (1); 650870189d2Schristos 651b3a00663Schristos case ETHERTYPE_AOE: 652b3a00663Schristos aoe_print(ndo, p, length); 653b3a00663Schristos return (1); 654b3a00663Schristos 655c74ad251Schristos case ETHERTYPE_PTP: 656c74ad251Schristos ptp_print(ndo, p, length); 657fdccd7e4Schristos return (1); 658fdccd7e4Schristos 6590f74e101Schristos case ETHERTYPE_LAT: 6600f74e101Schristos case ETHERTYPE_SCA: 6610f74e101Schristos case ETHERTYPE_MOPRC: 6620f74e101Schristos case ETHERTYPE_MOPDL: 663b3a00663Schristos case ETHERTYPE_IEEE1905_1: 6640f74e101Schristos /* default_print for now */ 6650f74e101Schristos default: 6660f74e101Schristos return (0); 6670f74e101Schristos } 6680f74e101Schristos } 669