xref: /netbsd-src/external/bsd/tcpdump/dist/print-sll.c (revision 181254a7b1bdde6873432bffef2d2decc4b5c22f)
1 /*
2  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that: (1) source code distributions
7  * retain the above copyright notice and this paragraph in its entirety, (2)
8  * distributions including binary code include the above copyright notice and
9  * this paragraph in its entirety in the documentation or other materials
10  * provided with the distribution, and (3) all advertising materials mentioning
11  * features or use of this software display the following acknowledgement:
12  * ``This product includes software developed by the University of California,
13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14  * the University nor the names of its contributors may be used to endorse
15  * or promote products derived from this software without specific prior
16  * written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  */
21 
22 #include <sys/cdefs.h>
23 #ifndef lint
24 __RCSID("$NetBSD: print-sll.c,v 1.9 2019/10/01 16:06:16 christos Exp $");
25 #endif
26 
27 /* \summary: Linux cooked sockets capture printer */
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include <netdissect-stdinc.h>
34 
35 #include "netdissect.h"
36 #include "addrtoname.h"
37 #include "ethertype.h"
38 #include "extract.h"
39 
40 #include "ether.h"
41 
42 /*
43  * For captures on Linux cooked sockets, we construct a fake header
44  * that includes:
45  *
46  *	a 2-byte "packet type" which is one of:
47  *
48  *		LINUX_SLL_HOST		packet was sent to us
49  *		LINUX_SLL_BROADCAST	packet was broadcast
50  *		LINUX_SLL_MULTICAST	packet was multicast
51  *		LINUX_SLL_OTHERHOST	packet was sent to somebody else
52  *		LINUX_SLL_OUTGOING	packet was sent *by* us;
53  *
54  *	a 2-byte Ethernet protocol field;
55  *
56  *	a 2-byte link-layer type;
57  *
58  *	a 2-byte link-layer address length;
59  *
60  *	an 8-byte source link-layer address, whose actual length is
61  *	specified by the previous value.
62  *
63  * All fields except for the link-layer address are in network byte order.
64  *
65  * DO NOT change the layout of this structure, or change any of the
66  * LINUX_SLL_ values below.  If you must change the link-layer header
67  * for a "cooked" Linux capture, introduce a new DLT_ type (ask
68  * "tcpdump-workers@lists.tcpdump.org" for one, so that you don't give it
69  * a value that collides with a value already being used), and use the
70  * new header in captures of that type, so that programs that can
71  * handle DLT_LINUX_SLL captures will continue to handle them correctly
72  * without any change, and so that capture files with different headers
73  * can be told apart and programs that read them can dissect the
74  * packets in them.
75  *
76  * This structure, and the #defines below, must be the same in the
77  * libpcap and tcpdump versions of "sll.h".
78  */
79 
80 /*
81  * A DLT_LINUX_SLL fake link-layer header.
82  */
83 #define SLL_HDR_LEN	16		/* total header length */
84 #define SLL_ADDRLEN	8		/* length of address field */
85 
86 struct sll_header {
87 	uint16_t	sll_pkttype;	/* packet type */
88 	uint16_t	sll_hatype;	/* link-layer address type */
89 	uint16_t	sll_halen;	/* link-layer address length */
90 	uint8_t		sll_addr[SLL_ADDRLEN];	/* link-layer address */
91 	uint16_t	sll_protocol;	/* protocol */
92 };
93 
94 /*
95  * The LINUX_SLL_ values for "sll_pkttype"; these correspond to the
96  * PACKET_ values on Linux, but are defined here so that they're
97  * available even on systems other than Linux, and so that they
98  * don't change even if the PACKET_ values change.
99  */
100 #define LINUX_SLL_HOST		0
101 #define LINUX_SLL_BROADCAST	1
102 #define LINUX_SLL_MULTICAST	2
103 #define LINUX_SLL_OTHERHOST	3
104 #define LINUX_SLL_OUTGOING	4
105 
106 /*
107  * The LINUX_SLL_ values for "sll_protocol"; these correspond to the
108  * ETH_P_ values on Linux, but are defined here so that they're
109  * available even on systems other than Linux.  We assume, for now,
110  * that the ETH_P_ values won't change in Linux; if they do, then:
111  *
112  *	if we don't translate them in "pcap-linux.c", capture files
113  *	won't necessarily be readable if captured on a system that
114  *	defines ETH_P_ values that don't match these values;
115  *
116  *	if we do translate them in "pcap-linux.c", that makes life
117  *	unpleasant for the BPF code generator, as the values you test
118  *	for in the kernel aren't the values that you test for when
119  *	reading a capture file, so the fixup code run on BPF programs
120  *	handed to the kernel ends up having to do more work.
121  *
122  * Add other values here as necessary, for handling packet types that
123  * might show up on non-Ethernet, non-802.x networks.  (Not all the ones
124  * in the Linux "if_ether.h" will, I suspect, actually show up in
125  * captures.)
126  */
127 #define LINUX_SLL_P_802_3	0x0001	/* Novell 802.3 frames without 802.2 LLC header */
128 #define LINUX_SLL_P_802_2	0x0004	/* 802.2 frames (not D/I/X Ethernet) */
129 
130 static const struct tok sll_pkttype_values[] = {
131     { LINUX_SLL_HOST, "In" },
132     { LINUX_SLL_BROADCAST, "B" },
133     { LINUX_SLL_MULTICAST, "M" },
134     { LINUX_SLL_OTHERHOST, "P" },
135     { LINUX_SLL_OUTGOING, "Out" },
136     { 0, NULL}
137 };
138 
139 static inline void
140 sll_print(netdissect_options *ndo, register const struct sll_header *sllp, u_int length)
141 {
142 	u_short ether_type;
143 
144         ND_PRINT((ndo, "%3s ",tok2str(sll_pkttype_values,"?",EXTRACT_16BITS(&sllp->sll_pkttype))));
145 
146 	/*
147 	 * XXX - check the link-layer address type value?
148 	 * For now, we just assume 6 means Ethernet.
149 	 * XXX - print others as strings of hex?
150 	 */
151 	if (EXTRACT_16BITS(&sllp->sll_halen) == 6)
152 		ND_PRINT((ndo, "%s ", etheraddr_string(ndo, sllp->sll_addr)));
153 
154 	if (!ndo->ndo_qflag) {
155 		ether_type = EXTRACT_16BITS(&sllp->sll_protocol);
156 
157 		if (ether_type <= ETHERMTU) {
158 			/*
159 			 * Not an Ethernet type; what type is it?
160 			 */
161 			switch (ether_type) {
162 
163 			case LINUX_SLL_P_802_3:
164 				/*
165 				 * Ethernet_802.3 IPX frame.
166 				 */
167 				ND_PRINT((ndo, "802.3"));
168 				break;
169 
170 			case LINUX_SLL_P_802_2:
171 				/*
172 				 * 802.2.
173 				 */
174 				ND_PRINT((ndo, "802.2"));
175 				break;
176 
177 			default:
178 				/*
179 				 * What is it?
180 				 */
181 				ND_PRINT((ndo, "ethertype Unknown (0x%04x)",
182 				    ether_type));
183 				break;
184 			}
185 		} else {
186 			ND_PRINT((ndo, "ethertype %s (0x%04x)",
187 			    tok2str(ethertype_values, "Unknown", ether_type),
188 			    ether_type));
189 		}
190 		ND_PRINT((ndo, ", length %u: ", length));
191 	}
192 }
193 
194 /*
195  * This is the top level routine of the printer.  'p' points to the
196  * Linux "cooked capture" header of the packet, 'h->ts' is the timestamp,
197  * 'h->len' is the length of the packet off the wire, and 'h->caplen'
198  * is the number of bytes actually captured.
199  */
200 u_int
201 sll_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p)
202 {
203 	u_int caplen = h->caplen;
204 	u_int length = h->len;
205 	register const struct sll_header *sllp;
206 	u_short hatype;
207 	u_short ether_type;
208 	int llc_hdrlen;
209 	u_int hdrlen;
210 
211 	if (caplen < SLL_HDR_LEN) {
212 		/*
213 		 * XXX - this "can't happen" because "pcap-linux.c" always
214 		 * adds this many bytes of header to every packet in a
215 		 * cooked socket capture.
216 		 */
217 		ND_PRINT((ndo, "[|sll]"));
218 		return (caplen);
219 	}
220 
221 	sllp = (const struct sll_header *)p;
222 
223 	if (ndo->ndo_eflag)
224 		sll_print(ndo, sllp, length);
225 
226 	/*
227 	 * Go past the cooked-mode header.
228 	 */
229 	length -= SLL_HDR_LEN;
230 	caplen -= SLL_HDR_LEN;
231 	p += SLL_HDR_LEN;
232 	hdrlen = SLL_HDR_LEN;
233 
234 	hatype = EXTRACT_16BITS(&sllp->sll_hatype);
235 	switch (hatype) {
236 
237 	case 803:
238 		/*
239 		 * This is an packet with a radiotap header;
240 		 * just dissect the payload as such.
241 		 */
242 		return (SLL_HDR_LEN + ieee802_11_radio_print(ndo, p, length, caplen));
243 	}
244 	ether_type = EXTRACT_16BITS(&sllp->sll_protocol);
245 
246 recurse:
247 	/*
248 	 * Is it (gag) an 802.3 encapsulation, or some non-Ethernet
249 	 * packet type?
250 	 */
251 	if (ether_type <= ETHERMTU) {
252 		/*
253 		 * Yes - what type is it?
254 		 */
255 		switch (ether_type) {
256 
257 		case LINUX_SLL_P_802_3:
258 			/*
259 			 * Ethernet_802.3 IPX frame.
260 			 */
261 			ipx_print(ndo, p, length);
262 			break;
263 
264 		case LINUX_SLL_P_802_2:
265 			/*
266 			 * 802.2.
267 			 * Try to print the LLC-layer header & higher layers.
268 			 */
269 			llc_hdrlen = llc_print(ndo, p, length, caplen, NULL, NULL);
270 			if (llc_hdrlen < 0)
271 				goto unknown;	/* unknown LLC type */
272 			hdrlen += llc_hdrlen;
273 			break;
274 
275 		default:
276 			/*FALLTHROUGH*/
277 
278 		unknown:
279 			/* packet type not known, print raw packet */
280 			if (!ndo->ndo_suppress_default_print)
281 				ND_DEFAULTPRINT(p, caplen);
282 			break;
283 		}
284 	} else if (ether_type == ETHERTYPE_8021Q) {
285 		/*
286 		 * Print VLAN information, and then go back and process
287 		 * the enclosed type field.
288 		 */
289 		if (caplen < 4) {
290 			ND_PRINT((ndo, "[|vlan]"));
291 			return (hdrlen + caplen);
292 		}
293 		if (length < 4) {
294 			ND_PRINT((ndo, "[|vlan]"));
295 			return (hdrlen + length);
296 		}
297 	        if (ndo->ndo_eflag) {
298 	        	uint16_t tag = EXTRACT_16BITS(p);
299 
300 			ND_PRINT((ndo, "%s, ", ieee8021q_tci_string(tag)));
301 		}
302 
303 		ether_type = EXTRACT_16BITS(p + 2);
304 		if (ether_type <= ETHERMTU)
305 			ether_type = LINUX_SLL_P_802_2;
306 		if (!ndo->ndo_qflag) {
307 			ND_PRINT((ndo, "ethertype %s, ",
308 			    tok2str(ethertype_values, "Unknown", ether_type)));
309 		}
310 		p += 4;
311 		length -= 4;
312 		caplen -= 4;
313 		hdrlen += 4;
314 		goto recurse;
315 	} else {
316 		if (ethertype_print(ndo, ether_type, p, length, caplen, NULL, NULL) == 0) {
317 			/* ether_type not known, print raw packet */
318 			if (!ndo->ndo_eflag)
319 				sll_print(ndo, sllp, length + SLL_HDR_LEN);
320 			if (!ndo->ndo_suppress_default_print)
321 				ND_DEFAULTPRINT(p, caplen);
322 		}
323 	}
324 
325 	return (hdrlen);
326 }
327