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