10f74e101Schristos /* 20f74e101Schristos * Copyright (c) 1992, 1993, 1994, 1995, 1996, 1997 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 * 210f74e101Schristos * Code by Matt Thomas, Digital Equipment Corporation 220f74e101Schristos * with an awful lot of hacking by Jeffrey Mogul, DECWRL 230f74e101Schristos */ 240f74e101Schristos 2511b3aaa1Schristos #include <sys/cdefs.h> 260f74e101Schristos #ifndef lint 27*26ba0b50Schristos __RCSID("$NetBSD: print-llc.c,v 1.11 2024/09/02 16:15:31 christos Exp $"); 280f74e101Schristos #endif 290f74e101Schristos 30dc860a36Sspz /* \summary: IEEE 802.2 LLC printer */ 31dc860a36Sspz 32c74ad251Schristos #include <config.h> 330f74e101Schristos 34c74ad251Schristos #include "netdissect-stdinc.h" 350f74e101Schristos 36fdccd7e4Schristos #include "netdissect.h" 370f74e101Schristos #include "addrtoname.h" 38fdccd7e4Schristos #include "extract.h" 390f74e101Schristos 400f74e101Schristos #include "llc.h" 410f74e101Schristos #include "ethertype.h" 420f74e101Schristos #include "oui.h" 430f74e101Schristos 44870189d2Schristos static const struct tok llc_values[] = { 450f74e101Schristos { LLCSAP_NULL, "Null" }, 460f74e101Schristos { LLCSAP_GLOBAL, "Global" }, 470f74e101Schristos { LLCSAP_8021B_I, "802.1B I" }, 480f74e101Schristos { LLCSAP_8021B_G, "802.1B G" }, 490f74e101Schristos { LLCSAP_IP, "IP" }, 500f74e101Schristos { LLCSAP_SNA, "SNA" }, 510f74e101Schristos { LLCSAP_PROWAYNM, "ProWay NM" }, 520f74e101Schristos { LLCSAP_8021D, "STP" }, 530f74e101Schristos { LLCSAP_RS511, "RS511" }, 540f74e101Schristos { LLCSAP_ISO8208, "ISO8208" }, 550f74e101Schristos { LLCSAP_PROWAY, "ProWay" }, 560f74e101Schristos { LLCSAP_SNAP, "SNAP" }, 570f74e101Schristos { LLCSAP_IPX, "IPX" }, 580f74e101Schristos { LLCSAP_NETBEUI, "NetBeui" }, 590f74e101Schristos { LLCSAP_ISONS, "OSI" }, 600f74e101Schristos { 0, NULL }, 610f74e101Schristos }; 620f74e101Schristos 63870189d2Schristos static const struct tok llc_cmd_values[] = { 640f74e101Schristos { LLC_UI, "ui" }, 650f74e101Schristos { LLC_TEST, "test" }, 660f74e101Schristos { LLC_XID, "xid" }, 670f74e101Schristos { LLC_UA, "ua" }, 680f74e101Schristos { LLC_DISC, "disc" }, 690f74e101Schristos { LLC_DM, "dm" }, 700f74e101Schristos { LLC_SABME, "sabme" }, 710f74e101Schristos { LLC_FRMR, "frmr" }, 720f74e101Schristos { 0, NULL } 730f74e101Schristos }; 740f74e101Schristos 750f74e101Schristos static const struct tok llc_flag_values[] = { 760f74e101Schristos { 0, "Command" }, 770f74e101Schristos { LLC_GSAP, "Response" }, 780f74e101Schristos { LLC_U_POLL, "Poll" }, 790f74e101Schristos { LLC_GSAP|LLC_U_POLL, "Final" }, 800f74e101Schristos { LLC_IS_POLL, "Poll" }, 810f74e101Schristos { LLC_GSAP|LLC_IS_POLL, "Final" }, 820f74e101Schristos { 0, NULL } 830f74e101Schristos }; 840f74e101Schristos 850f74e101Schristos 860f74e101Schristos static const struct tok llc_ig_flag_values[] = { 870f74e101Schristos { 0, "Individual" }, 880f74e101Schristos { LLC_IG, "Group" }, 890f74e101Schristos { 0, NULL } 900f74e101Schristos }; 910f74e101Schristos 920f74e101Schristos 930f74e101Schristos static const struct tok llc_supervisory_values[] = { 940f74e101Schristos { 0, "Receiver Ready" }, 950f74e101Schristos { 1, "Receiver not Ready" }, 960f74e101Schristos { 2, "Reject" }, 970f74e101Schristos { 0, NULL } 980f74e101Schristos }; 990f74e101Schristos 1000f74e101Schristos 1010f74e101Schristos static const struct tok cisco_values[] = { 1020f74e101Schristos { PID_CISCO_CDP, "CDP" }, 1030f74e101Schristos { PID_CISCO_VTP, "VTP" }, 1040f74e101Schristos { PID_CISCO_DTP, "DTP" }, 1050f74e101Schristos { PID_CISCO_UDLD, "UDLD" }, 1060f74e101Schristos { PID_CISCO_PVST, "PVST" }, 107870189d2Schristos { PID_CISCO_VLANBRIDGE, "VLAN Bridge" }, 1080f74e101Schristos { 0, NULL } 1090f74e101Schristos }; 1100f74e101Schristos 1110f74e101Schristos static const struct tok bridged_values[] = { 1120f74e101Schristos { PID_RFC2684_ETH_FCS, "Ethernet + FCS" }, 1130f74e101Schristos { PID_RFC2684_ETH_NOFCS, "Ethernet w/o FCS" }, 1140f74e101Schristos { PID_RFC2684_802_4_FCS, "802.4 + FCS" }, 1150f74e101Schristos { PID_RFC2684_802_4_NOFCS, "802.4 w/o FCS" }, 1160f74e101Schristos { PID_RFC2684_802_5_FCS, "Token Ring + FCS" }, 1170f74e101Schristos { PID_RFC2684_802_5_NOFCS, "Token Ring w/o FCS" }, 1180f74e101Schristos { PID_RFC2684_FDDI_FCS, "FDDI + FCS" }, 1190f74e101Schristos { PID_RFC2684_FDDI_NOFCS, "FDDI w/o FCS" }, 1200f74e101Schristos { PID_RFC2684_802_6_FCS, "802.6 + FCS" }, 1210f74e101Schristos { PID_RFC2684_802_6_NOFCS, "802.6 w/o FCS" }, 1220f74e101Schristos { PID_RFC2684_BPDU, "BPDU" }, 1230f74e101Schristos { 0, NULL }, 1240f74e101Schristos }; 1250f74e101Schristos 1260f74e101Schristos static const struct tok null_values[] = { 1270f74e101Schristos { 0, NULL } 1280f74e101Schristos }; 1290f74e101Schristos 1300f74e101Schristos struct oui_tok { 131b3a00663Schristos uint32_t oui; 1320f74e101Schristos const struct tok *tok; 1330f74e101Schristos }; 1340f74e101Schristos 1350f74e101Schristos static const struct oui_tok oui_to_tok[] = { 1360f74e101Schristos { OUI_ENCAP_ETHER, ethertype_values }, 1370f74e101Schristos { OUI_CISCO_90, ethertype_values }, /* uses some Ethertype values */ 1380f74e101Schristos { OUI_APPLETALK, ethertype_values }, /* uses some Ethertype values */ 1390f74e101Schristos { OUI_CISCO, cisco_values }, 1400f74e101Schristos { OUI_RFC2684, bridged_values }, /* bridged, RFC 2427 FR or RFC 2864 ATM */ 1410f74e101Schristos { 0, NULL } 1420f74e101Schristos }; 1430f74e101Schristos 1440f74e101Schristos /* 145fdccd7e4Schristos * If we printed information about the payload, returns the length of the LLC 146fdccd7e4Schristos * header, plus the length of any SNAP header following it. 147fdccd7e4Schristos * 148fdccd7e4Schristos * Otherwise (for example, if the packet has unknown SAPs or has a SNAP 149fdccd7e4Schristos * header with an unknown OUI/PID combination), returns the *negative* 150fdccd7e4Schristos * of that value. 1510f74e101Schristos */ 1520f74e101Schristos int 153b3a00663Schristos llc_print(netdissect_options *ndo, const u_char *p, u_int length, u_int caplen, 154dc860a36Sspz const struct lladdr_info *src, const struct lladdr_info *dst) 1550f74e101Schristos { 156b3a00663Schristos uint8_t dsap_field, dsap, ssap_field, ssap; 157b3a00663Schristos uint16_t control; 158fdccd7e4Schristos int hdrlen; 1590f74e101Schristos int is_u; 1600f74e101Schristos 161c74ad251Schristos ndo->ndo_protocol = "llc"; 162fdccd7e4Schristos if (caplen < 3) { 163c74ad251Schristos nd_print_trunc(ndo); 164fdccd7e4Schristos ND_DEFAULTPRINT((const u_char *)p, caplen); 165fdccd7e4Schristos return (caplen); 166fdccd7e4Schristos } 167fdccd7e4Schristos if (length < 3) { 168c74ad251Schristos nd_print_trunc(ndo); 169fdccd7e4Schristos ND_DEFAULTPRINT((const u_char *)p, caplen); 170fdccd7e4Schristos return (length); 1710f74e101Schristos } 1720f74e101Schristos 173c74ad251Schristos dsap_field = GET_U_1(p); 174c74ad251Schristos ssap_field = GET_U_1(p + 1); 1750f74e101Schristos 1760f74e101Schristos /* 1770f74e101Schristos * OK, what type of LLC frame is this? The length 1780f74e101Schristos * of the control field depends on that - I frames 1790f74e101Schristos * have a two-byte control field, and U frames have 1800f74e101Schristos * a one-byte control field. 1810f74e101Schristos */ 182c74ad251Schristos control = GET_U_1(p + 2); 1830f74e101Schristos if ((control & LLC_U_FMT) == LLC_U_FMT) { 1840f74e101Schristos /* 1850f74e101Schristos * U frame. 1860f74e101Schristos */ 1870f74e101Schristos is_u = 1; 188fdccd7e4Schristos hdrlen = 3; /* DSAP, SSAP, 1-byte control field */ 1890f74e101Schristos } else { 1900f74e101Schristos /* 1910f74e101Schristos * The control field in I and S frames is 1920f74e101Schristos * 2 bytes... 1930f74e101Schristos */ 194fdccd7e4Schristos if (caplen < 4) { 195c74ad251Schristos nd_print_trunc(ndo); 196fdccd7e4Schristos ND_DEFAULTPRINT((const u_char *)p, caplen); 197fdccd7e4Schristos return (caplen); 198fdccd7e4Schristos } 199fdccd7e4Schristos if (length < 4) { 200c74ad251Schristos nd_print_trunc(ndo); 201fdccd7e4Schristos ND_DEFAULTPRINT((const u_char *)p, caplen); 202fdccd7e4Schristos return (length); 2030f74e101Schristos } 2040f74e101Schristos 2050f74e101Schristos /* 2060f74e101Schristos * ...and is little-endian. 2070f74e101Schristos */ 208c74ad251Schristos control = GET_LE_U_2(p + 2); 2090f74e101Schristos is_u = 0; 210fdccd7e4Schristos hdrlen = 4; /* DSAP, SSAP, 2-byte control field */ 2110f74e101Schristos } 2120f74e101Schristos 2130f74e101Schristos if (ssap_field == LLCSAP_GLOBAL && dsap_field == LLCSAP_GLOBAL) { 2140f74e101Schristos /* 2150f74e101Schristos * This is an Ethernet_802.3 IPX frame; it has an 2160f74e101Schristos * 802.3 header (i.e., an Ethernet header where the 217c74ad251Schristos * type/length field is <= MAX_ETHERNET_LENGTH_VAL, 218c74ad251Schristos * i.e. it's a length field, not a type field), but 219c74ad251Schristos * has no 802.2 header - the IPX packet starts right 220c74ad251Schristos * after the Ethernet header, with a signature of two 221c74ad251Schristos * bytes of 0xFF (which is LLCSAP_GLOBAL). 2220f74e101Schristos * 2230f74e101Schristos * (It might also have been an Ethernet_802.3 IPX at 2240f74e101Schristos * one time, but got bridged onto another network, 2250f74e101Schristos * such as an 802.11 network; this has appeared in at 2260f74e101Schristos * least one capture file.) 2270f74e101Schristos */ 2280f74e101Schristos 229b3a00663Schristos if (ndo->ndo_eflag) 230c74ad251Schristos ND_PRINT("IPX 802.3: "); 2310f74e101Schristos 232b3a00663Schristos ipx_print(ndo, p, length); 233fdccd7e4Schristos return (0); /* no LLC header */ 2340f74e101Schristos } 2350f74e101Schristos 2360f74e101Schristos dsap = dsap_field & ~LLC_IG; 2370f74e101Schristos ssap = ssap_field & ~LLC_GSAP; 2380f74e101Schristos 239b3a00663Schristos if (ndo->ndo_eflag) { 240c74ad251Schristos ND_PRINT("LLC, dsap %s (0x%02x) %s, ssap %s (0x%02x) %s", 2410f74e101Schristos tok2str(llc_values, "Unknown", dsap), 2420f74e101Schristos dsap, 2430f74e101Schristos tok2str(llc_ig_flag_values, "Unknown", dsap_field & LLC_IG), 2440f74e101Schristos tok2str(llc_values, "Unknown", ssap), 2450f74e101Schristos ssap, 246c74ad251Schristos tok2str(llc_flag_values, "Unknown", ssap_field & LLC_GSAP)); 2470f74e101Schristos 2480f74e101Schristos if (is_u) { 249c74ad251Schristos ND_PRINT(", ctrl 0x%02x: ", control); 2500f74e101Schristos } else { 251c74ad251Schristos ND_PRINT(", ctrl 0x%04x: ", control); 2520f74e101Schristos } 2530f74e101Schristos } 2540f74e101Schristos 255fdccd7e4Schristos /* 256fdccd7e4Schristos * Skip LLC header. 257fdccd7e4Schristos */ 258fdccd7e4Schristos p += hdrlen; 259fdccd7e4Schristos length -= hdrlen; 260fdccd7e4Schristos caplen -= hdrlen; 261fdccd7e4Schristos 262fdccd7e4Schristos if (ssap == LLCSAP_SNAP && dsap == LLCSAP_SNAP 263fdccd7e4Schristos && control == LLC_UI) { 264fdccd7e4Schristos /* 265fdccd7e4Schristos * XXX - what *is* the right bridge pad value here? 266fdccd7e4Schristos * Does anybody ever bridge one form of LAN traffic 267fdccd7e4Schristos * over a networking type that uses 802.2 LLC? 268fdccd7e4Schristos */ 269dc860a36Sspz if (!snap_print(ndo, p, length, caplen, src, dst, 2)) { 270fdccd7e4Schristos /* 271fdccd7e4Schristos * Unknown packet type; tell our caller, by 272fdccd7e4Schristos * returning a negative value, so they 273fdccd7e4Schristos * can print the raw packet. 274fdccd7e4Schristos */ 275fdccd7e4Schristos return (-(hdrlen + 5)); /* include LLC and SNAP header */ 276fdccd7e4Schristos } else 277fdccd7e4Schristos return (hdrlen + 5); /* include LLC and SNAP header */ 278fdccd7e4Schristos } 279fdccd7e4Schristos 2800f74e101Schristos if (ssap == LLCSAP_8021D && dsap == LLCSAP_8021D && 2810f74e101Schristos control == LLC_UI) { 282fdccd7e4Schristos stp_print(ndo, p, length); 283fdccd7e4Schristos return (hdrlen); 2840f74e101Schristos } 2850f74e101Schristos 2860f74e101Schristos if (ssap == LLCSAP_IP && dsap == LLCSAP_IP && 2870f74e101Schristos control == LLC_UI) { 288fdccd7e4Schristos /* 289fdccd7e4Schristos * This is an RFC 948-style IP packet, with 290fdccd7e4Schristos * an 802.3 header and an 802.2 LLC header 291fdccd7e4Schristos * with the source and destination SAPs being 292fdccd7e4Schristos * the IP SAP. 293fdccd7e4Schristos */ 294fdccd7e4Schristos ip_print(ndo, p, length); 295fdccd7e4Schristos return (hdrlen); 2960f74e101Schristos } 2970f74e101Schristos 2980f74e101Schristos if (ssap == LLCSAP_IPX && dsap == LLCSAP_IPX && 2990f74e101Schristos control == LLC_UI) { 3000f74e101Schristos /* 3010f74e101Schristos * This is an Ethernet_802.2 IPX frame, with an 802.3 3020f74e101Schristos * header and an 802.2 LLC header with the source and 3030f74e101Schristos * destination SAPs being the IPX SAP. 3040f74e101Schristos */ 305b3a00663Schristos if (ndo->ndo_eflag) 306c74ad251Schristos ND_PRINT("IPX 802.2: "); 3070f74e101Schristos 308fdccd7e4Schristos ipx_print(ndo, p, length); 309fdccd7e4Schristos return (hdrlen); 3100f74e101Schristos } 3110f74e101Schristos 312fdccd7e4Schristos #ifdef ENABLE_SMB 3130f74e101Schristos if (ssap == LLCSAP_NETBEUI && dsap == LLCSAP_NETBEUI 3140f74e101Schristos && (!(control & LLC_S_FMT) || control == LLC_U_FMT)) { 3150f74e101Schristos /* 3160f74e101Schristos * we don't actually have a full netbeui parser yet, but the 3170f74e101Schristos * smb parser can handle many smb-in-netbeui packets, which 3180f74e101Schristos * is very useful, so we call that 3190f74e101Schristos * 3200f74e101Schristos * We don't call it for S frames, however, just I frames 3210f74e101Schristos * (which are frames that don't have the low-order bit, 3220f74e101Schristos * LLC_S_FMT, set in the first byte of the control field) 3230f74e101Schristos * and UI frames (whose control field is just 3, LLC_U_FMT). 3240f74e101Schristos */ 325b3a00663Schristos netbeui_print(ndo, control, p, length); 326fdccd7e4Schristos return (hdrlen); 3270f74e101Schristos } 3280f74e101Schristos #endif 3290f74e101Schristos if (ssap == LLCSAP_ISONS && dsap == LLCSAP_ISONS 3300f74e101Schristos && control == LLC_UI) { 33172c96ff3Schristos isoclns_print(ndo, p, length); 332fdccd7e4Schristos return (hdrlen); 3330f74e101Schristos } 3340f74e101Schristos 335b3a00663Schristos if (!ndo->ndo_eflag) { 3360f74e101Schristos if (ssap == dsap) { 337dc860a36Sspz if (src == NULL || dst == NULL) 338c74ad251Schristos ND_PRINT("%s ", tok2str(llc_values, "Unknown DSAP 0x%02x", dsap)); 3390f74e101Schristos else 340c74ad251Schristos ND_PRINT("%s > %s %s ", 341dc860a36Sspz (src->addr_string)(ndo, src->addr), 342dc860a36Sspz (dst->addr_string)(ndo, dst->addr), 343c74ad251Schristos tok2str(llc_values, "Unknown DSAP 0x%02x", dsap)); 3440f74e101Schristos } else { 345dc860a36Sspz if (src == NULL || dst == NULL) 346c74ad251Schristos ND_PRINT("%s > %s ", 3470f74e101Schristos tok2str(llc_values, "Unknown SSAP 0x%02x", ssap), 348c74ad251Schristos tok2str(llc_values, "Unknown DSAP 0x%02x", dsap)); 3490f74e101Schristos else 350c74ad251Schristos ND_PRINT("%s %s > %s %s ", 351dc860a36Sspz (src->addr_string)(ndo, src->addr), 3520f74e101Schristos tok2str(llc_values, "Unknown SSAP 0x%02x", ssap), 353dc860a36Sspz (dst->addr_string)(ndo, dst->addr), 354c74ad251Schristos tok2str(llc_values, "Unknown DSAP 0x%02x", dsap)); 3550f74e101Schristos } 3560f74e101Schristos } 3570f74e101Schristos 3580f74e101Schristos if (is_u) { 359c74ad251Schristos ND_PRINT("Unnumbered, %s, Flags [%s], length %u", 3600f74e101Schristos tok2str(llc_cmd_values, "%02x", LLC_U_CMD(control)), 3610f74e101Schristos tok2str(llc_flag_values,"?",(ssap_field & LLC_GSAP) | (control & LLC_U_POLL)), 362c74ad251Schristos length + hdrlen); 3630f74e101Schristos 3640f74e101Schristos if ((control & ~LLC_U_POLL) == LLC_XID) { 365dc860a36Sspz if (length == 0) { 366dc860a36Sspz /* 367dc860a36Sspz * XID with no payload. 368dc860a36Sspz * This could, for example, be an SNA 369dc860a36Sspz * "short form" XID. 370dc860a36Sspz */ 371dc860a36Sspz return (hdrlen); 372dc860a36Sspz } 373dc860a36Sspz if (caplen < 1) { 374c74ad251Schristos nd_print_trunc(ndo); 375dc860a36Sspz if (caplen > 0) 376dc860a36Sspz ND_DEFAULTPRINT((const u_char *)p, caplen); 377dc860a36Sspz return (hdrlen); 378dc860a36Sspz } 379c74ad251Schristos if (GET_U_1(p) == LLC_XID_FI) { 380dc860a36Sspz if (caplen < 3 || length < 3) { 381c74ad251Schristos nd_print_trunc(ndo); 382dc860a36Sspz if (caplen > 0) 383dc860a36Sspz ND_DEFAULTPRINT((const u_char *)p, caplen); 384dc860a36Sspz } else 385c74ad251Schristos ND_PRINT(": %02x %02x", 386c74ad251Schristos GET_U_1(p + 1), 387c74ad251Schristos GET_U_1(p + 2)); 388fdccd7e4Schristos return (hdrlen); 3890f74e101Schristos } 3900f74e101Schristos } 3910f74e101Schristos } else { 3920f74e101Schristos if ((control & LLC_S_FMT) == LLC_S_FMT) { 393c74ad251Schristos ND_PRINT("Supervisory, %s, rcv seq %u, Flags [%s], length %u", 3940f74e101Schristos tok2str(llc_supervisory_values,"?",LLC_S_CMD(control)), 3950f74e101Schristos LLC_IS_NR(control), 3960f74e101Schristos tok2str(llc_flag_values,"?",(ssap_field & LLC_GSAP) | (control & LLC_IS_POLL)), 397c74ad251Schristos length + hdrlen); 398fdccd7e4Schristos return (hdrlen); /* no payload to print */ 3990f74e101Schristos } else { 400c74ad251Schristos ND_PRINT("Information, send seq %u, rcv seq %u, Flags [%s], length %u", 4010f74e101Schristos LLC_I_NS(control), 4020f74e101Schristos LLC_IS_NR(control), 4030f74e101Schristos tok2str(llc_flag_values,"?",(ssap_field & LLC_GSAP) | (control & LLC_IS_POLL)), 404c74ad251Schristos length + hdrlen); 4050f74e101Schristos } 4060f74e101Schristos } 407fdccd7e4Schristos return (-hdrlen); 408fdccd7e4Schristos } 409fdccd7e4Schristos 410fdccd7e4Schristos static const struct tok * 411fdccd7e4Schristos oui_to_struct_tok(uint32_t orgcode) 412fdccd7e4Schristos { 413fdccd7e4Schristos const struct tok *tok = null_values; 414fdccd7e4Schristos const struct oui_tok *otp; 415fdccd7e4Schristos 416fdccd7e4Schristos for (otp = &oui_to_tok[0]; otp->tok != NULL; otp++) { 417fdccd7e4Schristos if (otp->oui == orgcode) { 418fdccd7e4Schristos tok = otp->tok; 419fdccd7e4Schristos break; 420fdccd7e4Schristos } 421fdccd7e4Schristos } 422fdccd7e4Schristos return (tok); 4230f74e101Schristos } 4240f74e101Schristos 4250f74e101Schristos int 426fdccd7e4Schristos snap_print(netdissect_options *ndo, const u_char *p, u_int length, u_int caplen, 427dc860a36Sspz const struct lladdr_info *src, const struct lladdr_info *dst, 428dc860a36Sspz u_int bridge_pad) 4290f74e101Schristos { 430b3a00663Schristos uint32_t orgcode; 431c74ad251Schristos u_short et; 432c74ad251Schristos int ret; 4330f74e101Schristos 434c74ad251Schristos ndo->ndo_protocol = "snap"; 435c74ad251Schristos ND_TCHECK_5(p); 436ba2ff121Schristos if (caplen < 5 || length < 5) 437ba2ff121Schristos goto trunc; 438c74ad251Schristos orgcode = GET_BE_U_3(p); 439c74ad251Schristos et = GET_BE_U_2(p + 3); 4400f74e101Schristos 441b3a00663Schristos if (ndo->ndo_eflag) { 442fdccd7e4Schristos /* 443fdccd7e4Schristos * Somebody's already printed the MAC addresses, if there 444fdccd7e4Schristos * are any, so just print the SNAP header, not the MAC 445fdccd7e4Schristos * addresses. 446fdccd7e4Schristos */ 447c74ad251Schristos ND_PRINT("oui %s (0x%06x), %s %s (0x%04x), length %u: ", 4480f74e101Schristos tok2str(oui_values, "Unknown", orgcode), 4490f74e101Schristos orgcode, 4500f74e101Schristos (orgcode == 0x000000 ? "ethertype" : "pid"), 451fdccd7e4Schristos tok2str(oui_to_struct_tok(orgcode), "Unknown", et), 452c74ad251Schristos et, length - 5); 4530f74e101Schristos } 4540f74e101Schristos p += 5; 4550f74e101Schristos length -= 5; 4560f74e101Schristos caplen -= 5; 4570f74e101Schristos 4580f74e101Schristos switch (orgcode) { 4590f74e101Schristos case OUI_ENCAP_ETHER: 4600f74e101Schristos case OUI_CISCO_90: 4610f74e101Schristos /* 4620f74e101Schristos * This is an encapsulated Ethernet packet, 4630f74e101Schristos * or a packet bridged by some piece of 4640f74e101Schristos * Cisco hardware; the protocol ID is 4650f74e101Schristos * an Ethernet protocol type. 4660f74e101Schristos */ 467dc860a36Sspz ret = ethertype_print(ndo, et, p, length, caplen, src, dst); 4680f74e101Schristos if (ret) 4690f74e101Schristos return (ret); 4700f74e101Schristos break; 4710f74e101Schristos 4720f74e101Schristos case OUI_APPLETALK: 4730f74e101Schristos if (et == ETHERTYPE_ATALK) { 4740f74e101Schristos /* 4750f74e101Schristos * No, I have no idea why Apple used one 4760f74e101Schristos * of their own OUIs, rather than 4770f74e101Schristos * 0x000000, and an Ethernet packet 4780f74e101Schristos * type, for Appletalk data packets, 4790f74e101Schristos * but used 0x000000 and an Ethernet 4800f74e101Schristos * packet type for AARP packets. 4810f74e101Schristos */ 482dc860a36Sspz ret = ethertype_print(ndo, et, p, length, caplen, src, dst); 4830f74e101Schristos if (ret) 4840f74e101Schristos return (ret); 4850f74e101Schristos } 4860f74e101Schristos break; 4870f74e101Schristos 4880f74e101Schristos case OUI_CISCO: 4890f74e101Schristos switch (et) { 4900f74e101Schristos case PID_CISCO_CDP: 491c74ad251Schristos cdp_print(ndo, p, length); 4920f74e101Schristos return (1); 4930f74e101Schristos case PID_CISCO_DTP: 494b3a00663Schristos dtp_print(ndo, p, length); 4950f74e101Schristos return (1); 4960f74e101Schristos case PID_CISCO_UDLD: 497b3a00663Schristos udld_print(ndo, p, length); 4980f74e101Schristos return (1); 4990f74e101Schristos case PID_CISCO_VTP: 500b3a00663Schristos vtp_print(ndo, p, length); 5010f74e101Schristos return (1); 5020f74e101Schristos case PID_CISCO_PVST: 503870189d2Schristos case PID_CISCO_VLANBRIDGE: 504b3a00663Schristos stp_print(ndo, p, length); 5050f74e101Schristos return (1); 5060f74e101Schristos default: 5070f74e101Schristos break; 5080f74e101Schristos } 509b3a00663Schristos break; 5100f74e101Schristos 5110f74e101Schristos case OUI_RFC2684: 5120f74e101Schristos switch (et) { 5130f74e101Schristos 5140f74e101Schristos case PID_RFC2684_ETH_FCS: 5150f74e101Schristos case PID_RFC2684_ETH_NOFCS: 5160f74e101Schristos /* 5170f74e101Schristos * XXX - remove the last two bytes for 5180f74e101Schristos * PID_RFC2684_ETH_FCS? 5190f74e101Schristos */ 5200f74e101Schristos /* 5210f74e101Schristos * Skip the padding. 5220f74e101Schristos */ 523c74ad251Schristos ND_TCHECK_LEN(p, bridge_pad); 5240f74e101Schristos caplen -= bridge_pad; 5250f74e101Schristos length -= bridge_pad; 5260f74e101Schristos p += bridge_pad; 5270f74e101Schristos 5280f74e101Schristos /* 5290f74e101Schristos * What remains is an Ethernet packet. 5300f74e101Schristos */ 531b3a00663Schristos ether_print(ndo, p, length, caplen, NULL, NULL); 5320f74e101Schristos return (1); 5330f74e101Schristos 5340f74e101Schristos case PID_RFC2684_802_5_FCS: 5350f74e101Schristos case PID_RFC2684_802_5_NOFCS: 5360f74e101Schristos /* 5370f74e101Schristos * XXX - remove the last two bytes for 5380f74e101Schristos * PID_RFC2684_ETH_FCS? 5390f74e101Schristos */ 5400f74e101Schristos /* 5410f74e101Schristos * Skip the padding, but not the Access 5420f74e101Schristos * Control field. 5430f74e101Schristos */ 544c74ad251Schristos ND_TCHECK_LEN(p, bridge_pad); 5450f74e101Schristos caplen -= bridge_pad; 5460f74e101Schristos length -= bridge_pad; 5470f74e101Schristos p += bridge_pad; 5480f74e101Schristos 5490f74e101Schristos /* 5500f74e101Schristos * What remains is an 802.5 Token Ring 5510f74e101Schristos * packet. 5520f74e101Schristos */ 553b3a00663Schristos token_print(ndo, p, length, caplen); 5540f74e101Schristos return (1); 5550f74e101Schristos 5560f74e101Schristos case PID_RFC2684_FDDI_FCS: 5570f74e101Schristos case PID_RFC2684_FDDI_NOFCS: 5580f74e101Schristos /* 5590f74e101Schristos * XXX - remove the last two bytes for 5600f74e101Schristos * PID_RFC2684_ETH_FCS? 5610f74e101Schristos */ 5620f74e101Schristos /* 5630f74e101Schristos * Skip the padding. 5640f74e101Schristos */ 565c74ad251Schristos ND_TCHECK_LEN(p, bridge_pad + 1); 5660f74e101Schristos caplen -= bridge_pad + 1; 5670f74e101Schristos length -= bridge_pad + 1; 5680f74e101Schristos p += bridge_pad + 1; 5690f74e101Schristos 5700f74e101Schristos /* 5710f74e101Schristos * What remains is an FDDI packet. 5720f74e101Schristos */ 573b3a00663Schristos fddi_print(ndo, p, length, caplen); 5740f74e101Schristos return (1); 5750f74e101Schristos 5760f74e101Schristos case PID_RFC2684_BPDU: 577b3a00663Schristos stp_print(ndo, p, length); 5780f74e101Schristos return (1); 5790f74e101Schristos } 5800f74e101Schristos } 581fdccd7e4Schristos if (!ndo->ndo_eflag) { 582fdccd7e4Schristos /* 583dc860a36Sspz * Nobody printed the link-layer addresses, so print them, if 584fdccd7e4Schristos * we have any. 585fdccd7e4Schristos */ 586dc860a36Sspz if (src != NULL && dst != NULL) { 587c74ad251Schristos ND_PRINT("%s > %s ", 588dc860a36Sspz (src->addr_string)(ndo, src->addr), 589c74ad251Schristos (dst->addr_string)(ndo, dst->addr)); 590fdccd7e4Schristos } 591fdccd7e4Schristos /* 592fdccd7e4Schristos * Print the SNAP header, but if the OUI is 000000, don't 593fdccd7e4Schristos * bother printing it, and report the PID as being an 594fdccd7e4Schristos * ethertype. 595fdccd7e4Schristos */ 596fdccd7e4Schristos if (orgcode == 0x000000) { 597c74ad251Schristos ND_PRINT("SNAP, ethertype %s (0x%04x), length %u: ", 598fdccd7e4Schristos tok2str(ethertype_values, "Unknown", et), 599c74ad251Schristos et, length); 600fdccd7e4Schristos } else { 601c74ad251Schristos ND_PRINT("SNAP, oui %s (0x%06x), pid %s (0x%04x), length %u: ", 602fdccd7e4Schristos tok2str(oui_values, "Unknown", orgcode), 603fdccd7e4Schristos orgcode, 604fdccd7e4Schristos tok2str(oui_to_struct_tok(orgcode), "Unknown", et), 605c74ad251Schristos et, length); 606fdccd7e4Schristos } 607fdccd7e4Schristos } 6080f74e101Schristos return (0); 6090f74e101Schristos 6100f74e101Schristos trunc: 611c74ad251Schristos nd_print_trunc(ndo); 6120f74e101Schristos return (1); 6130f74e101Schristos } 614