xref: /netbsd-src/external/bsd/tcpdump/dist/print-llc.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
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