xref: /netbsd-src/external/bsd/tcpdump/dist/print-sll.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
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.8 2017/02/05 04:05:05 spz 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 ether_type;
207 	int llc_hdrlen;
208 	u_int hdrlen;
209 
210 	if (caplen < SLL_HDR_LEN) {
211 		/*
212 		 * XXX - this "can't happen" because "pcap-linux.c" always
213 		 * adds this many bytes of header to every packet in a
214 		 * cooked socket capture.
215 		 */
216 		ND_PRINT((ndo, "[|sll]"));
217 		return (caplen);
218 	}
219 
220 	sllp = (const struct sll_header *)p;
221 
222 	if (ndo->ndo_eflag)
223 		sll_print(ndo, sllp, length);
224 
225 	/*
226 	 * Go past the cooked-mode header.
227 	 */
228 	length -= SLL_HDR_LEN;
229 	caplen -= SLL_HDR_LEN;
230 	p += SLL_HDR_LEN;
231 	hdrlen = SLL_HDR_LEN;
232 
233 	ether_type = EXTRACT_16BITS(&sllp->sll_protocol);
234 
235 recurse:
236 	/*
237 	 * Is it (gag) an 802.3 encapsulation, or some non-Ethernet
238 	 * packet type?
239 	 */
240 	if (ether_type <= ETHERMTU) {
241 		/*
242 		 * Yes - what type is it?
243 		 */
244 		switch (ether_type) {
245 
246 		case LINUX_SLL_P_802_3:
247 			/*
248 			 * Ethernet_802.3 IPX frame.
249 			 */
250 			ipx_print(ndo, p, length);
251 			break;
252 
253 		case LINUX_SLL_P_802_2:
254 			/*
255 			 * 802.2.
256 			 * Try to print the LLC-layer header & higher layers.
257 			 */
258 			llc_hdrlen = llc_print(ndo, p, length, caplen, NULL, NULL);
259 			if (llc_hdrlen < 0)
260 				goto unknown;	/* unknown LLC type */
261 			hdrlen += llc_hdrlen;
262 			break;
263 
264 		default:
265 			/*FALLTHROUGH*/
266 
267 		unknown:
268 			/* packet type not known, print raw packet */
269 			if (!ndo->ndo_suppress_default_print)
270 				ND_DEFAULTPRINT(p, caplen);
271 			break;
272 		}
273 	} else if (ether_type == ETHERTYPE_8021Q) {
274 		/*
275 		 * Print VLAN information, and then go back and process
276 		 * the enclosed type field.
277 		 */
278 		if (caplen < 4) {
279 			ND_PRINT((ndo, "[|vlan]"));
280 			return (hdrlen + caplen);
281 		}
282 		if (length < 4) {
283 			ND_PRINT((ndo, "[|vlan]"));
284 			return (hdrlen + length);
285 		}
286 	        if (ndo->ndo_eflag) {
287 	        	uint16_t tag = EXTRACT_16BITS(p);
288 
289 			ND_PRINT((ndo, "%s, ", ieee8021q_tci_string(tag)));
290 		}
291 
292 		ether_type = EXTRACT_16BITS(p + 2);
293 		if (ether_type <= ETHERMTU)
294 			ether_type = LINUX_SLL_P_802_2;
295 		if (!ndo->ndo_qflag) {
296 			ND_PRINT((ndo, "ethertype %s, ",
297 			    tok2str(ethertype_values, "Unknown", ether_type)));
298 		}
299 		p += 4;
300 		length -= 4;
301 		caplen -= 4;
302 		hdrlen += 4;
303 		goto recurse;
304 	} else {
305 		if (ethertype_print(ndo, ether_type, p, length, caplen, NULL, NULL) == 0) {
306 			/* ether_type not known, print raw packet */
307 			if (!ndo->ndo_eflag)
308 				sll_print(ndo, sllp, length + SLL_HDR_LEN);
309 			if (!ndo->ndo_suppress_default_print)
310 				ND_DEFAULTPRINT(p, caplen);
311 		}
312 	}
313 
314 	return (hdrlen);
315 }
316