xref: /freebsd/contrib/tcpdump/print-llc.c (revision c98323078dede7579020518ec84cdcb478e5c142)
1 /*
2  * Copyright (c) 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  * Code by Matt Thomas, Digital Equipment Corporation
22  *	with an awful lot of hacking by Jeffrey Mogul, DECWRL
23  *
24  * $FreeBSD$
25  */
26 
27 #ifndef lint
28 static const char rcsid[] _U_ =
29     "@(#) $Header: /tcpdump/master/tcpdump/print-llc.c,v 1.53.2.3 2003/12/29 22:33:18 hannes Exp $";
30 #endif
31 
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35 
36 #include <tcpdump-stdinc.h>
37 
38 #include <stdio.h>
39 #include <string.h>
40 
41 #include "interface.h"
42 #include "addrtoname.h"
43 #include "extract.h"			/* must come after interface.h */
44 
45 #include "llc.h"
46 #include "ethertype.h"
47 
48 static struct tok llc_values[] = {
49         { LLCSAP_NULL,     "Null" },
50         { LLCSAP_GLOBAL,   "Global" },
51         { LLCSAP_8021B_I,  "802.1B I" },
52         { LLCSAP_8021B_G,  "802.1B G" },
53         { LLCSAP_IP,       "IP" },
54         { LLCSAP_PROWAYNM, "ProWay NM" },
55         { LLCSAP_8021D,    "STP" },
56         { LLCSAP_RS511,    "RS511" },
57         { LLCSAP_ISO8208,  "ISO8208" },
58         { LLCSAP_PROWAY,   "ProWay" },
59         { LLCSAP_SNAP,     "SNAP" },
60         { LLCSAP_IPX,      "IPX" },
61         { LLCSAP_NETBEUI,  "NetBeui" },
62         { LLCSAP_ISONS,    "OSI" },
63 };
64 
65 static struct tok cmd2str[] = {
66 	{ LLC_UI,	"ui" },
67 	{ LLC_TEST,	"test" },
68 	{ LLC_XID,	"xid" },
69 	{ LLC_UA,	"ua" },
70 	{ LLC_DISC,	"disc" },
71 	{ LLC_DM,	"dm" },
72 	{ LLC_SABME,	"sabme" },
73 	{ LLC_FRMR,	"frmr" },
74 	{ 0,		NULL }
75 };
76 
77 /*
78  * Returns non-zero IFF it succeeds in printing the header
79  */
80 int
81 llc_print(const u_char *p, u_int length, u_int caplen,
82 	  const u_char *esrc, const u_char *edst, u_short *extracted_ethertype)
83 {
84 	struct llc llc;
85 	register u_short et;
86 	u_int16_t control;
87 	register int ret;
88 
89 	if (caplen < 3) {
90 		(void)printf("[|llc]");
91 		default_print((u_char *)p, caplen);
92 		return(0);
93 	}
94 
95 	/* Watch out for possible alignment problems */
96 	memcpy((char *)&llc, (char *)p, min(caplen, sizeof(llc)));
97 
98 	if (eflag)
99 	  printf("LLC, dsap %s (0x%02x), ssap %s (0x%02x), cmd 0x%02x, ",
100                  tok2str(llc_values,"Unknown",llc.dsap),
101 		 llc.dsap,
102                  tok2str(llc_values,"Unknown",llc.ssap),
103 		 llc.ssap,
104 		 llc.llcu);
105 
106 	if (llc.ssap == LLCSAP_GLOBAL && llc.dsap == LLCSAP_GLOBAL) {
107 		/*
108 		 * This is an Ethernet_802.3 IPX frame; it has an
109 		 * 802.3 header (i.e., an Ethernet header where the
110 		 * type/length field is <= ETHERMTU, i.e. it's a length
111 		 * field, not a type field), but has no 802.2 header -
112 		 * the IPX packet starts right after the Ethernet header,
113 		 * with a signature of two bytes of 0xFF (which is
114 		 * LLCSAP_GLOBAL).
115 		 *
116 		 * (It might also have been an Ethernet_802.3 IPX at
117 		 * one time, but got bridged onto another network,
118 		 * such as an 802.11 network; this has appeared in at
119 		 * least one capture file.)
120 		 */
121 		printf("(NOV-802.3) ");
122 		ipx_print(p, length);
123 		return (1);
124 	}
125 
126 	if (llc.ssap == LLCSAP_8021D && llc.dsap == LLCSAP_8021D) {
127 		stp_print(p, length);
128 		return (1);
129 	}
130 
131 	if (llc.ssap == LLCSAP_IP && llc.dsap == LLCSAP_IP) {
132 		ip_print(p+4, length-4);
133 		return (1);
134 	}
135 
136 	if (llc.ssap == LLCSAP_IPX && llc.dsap == LLCSAP_IPX &&
137 	    llc.llcui == LLC_UI) {
138 		/*
139 		 * This is an Ethernet_802.2 IPX frame, with an 802.3
140 		 * header and an 802.2 LLC header with the source and
141 		 * destination SAPs being the IPX SAP.
142 		 *
143 		 * Skip DSAP, LSAP, and control field.
144 		 */
145 		printf("(NOV-802.2) ");
146 		p += 3;
147 		length -= 3;
148 		caplen -= 3;
149 		ipx_print(p, length);
150 		return (1);
151 	}
152 
153 #ifdef TCPDUMP_DO_SMB
154 	if (llc.ssap == LLCSAP_NETBEUI && llc.dsap == LLCSAP_NETBEUI
155 	    && (!(llc.llcu & LLC_S_FMT) || llc.llcu == LLC_U_FMT)) {
156 		/*
157 		 * we don't actually have a full netbeui parser yet, but the
158 		 * smb parser can handle many smb-in-netbeui packets, which
159 		 * is very useful, so we call that
160 		 *
161 		 * We don't call it for S frames, however, just I frames
162 		 * (which are frames that don't have the low-order bit,
163 		 * LLC_S_FMT, set in the first byte of the control field)
164 		 * and UI frames (whose control field is just 3, LLC_U_FMT).
165 		 */
166 
167 		/*
168 		 * Skip the DSAP and LSAP.
169 		 */
170 		p += 2;
171 		length -= 2;
172 		caplen -= 2;
173 
174 		/*
175 		 * OK, what type of LLC frame is this?  The length
176 		 * of the control field depends on that - I frames
177 		 * have a two-byte control field, and U frames have
178 		 * a one-byte control field.
179 		 */
180 		if (llc.llcu == LLC_U_FMT) {
181 			control = llc.llcu;
182 			p += 1;
183 			length -= 1;
184 			caplen -= 1;
185 		} else {
186 			/*
187 			 * The control field in I and S frames is
188 			 * little-endian.
189 			 */
190 			control = EXTRACT_LE_16BITS(&llc.llcu);
191 			p += 2;
192 			length -= 2;
193 			caplen -= 2;
194 		}
195 		netbeui_print(control, p, length);
196 		return (1);
197 	}
198 #endif
199 	if (llc.ssap == LLCSAP_ISONS && llc.dsap == LLCSAP_ISONS
200 	    && llc.llcui == LLC_UI) {
201 		isoclns_print(p + 3, length - 3, caplen - 3);
202 		return (1);
203 	}
204 
205 	if (llc.ssap == LLCSAP_SNAP && llc.dsap == LLCSAP_SNAP
206 	    && llc.llcui == LLC_UI) {
207 		u_int32_t orgcode;
208 
209 		if (caplen < sizeof(llc)) {
210 			(void)printf("[|llc-snap]");
211 			default_print((u_char *)p, caplen);
212 			return (0);
213 		}
214 
215 		caplen -= sizeof(llc);
216 		length -= sizeof(llc);
217 		p += sizeof(llc);
218 
219 		orgcode = EXTRACT_24BITS(&llc.llc_orgcode[0]);
220 		et = EXTRACT_16BITS(&llc.llc_ethertype[0]);
221 		/*
222 		 * XXX - what *is* the right bridge pad value here?
223 		 * Does anybody ever bridge one form of LAN traffic
224 		 * over a networking type that uses 802.2 LLC?
225 		 */
226 		ret = snap_print(p, length, caplen, extracted_ethertype,
227 		    orgcode, et, 2);
228 		if (ret)
229 			return (ret);
230 	}
231 
232 	if ((llc.ssap & ~LLC_GSAP) == llc.dsap) {
233 		if (eflag || esrc == NULL || edst == NULL)
234 			(void)printf("%s ", llcsap_string(llc.dsap));
235 		else
236 			(void)printf("%s > %s %s ",
237 					etheraddr_string(esrc),
238 					etheraddr_string(edst),
239 					llcsap_string(llc.dsap));
240 	} else {
241 		if (eflag || esrc == NULL || edst == NULL)
242 			(void)printf("%s > %s ",
243 				llcsap_string(llc.ssap & ~LLC_GSAP),
244 				llcsap_string(llc.dsap));
245 		else
246 			(void)printf("%s %s > %s %s ",
247 				etheraddr_string(esrc),
248 				llcsap_string(llc.ssap & ~LLC_GSAP),
249 				etheraddr_string(edst),
250 				llcsap_string(llc.dsap));
251 	}
252 
253 	if ((llc.llcu & LLC_U_FMT) == LLC_U_FMT) {
254 		u_int16_t cmd;
255 		const char *m;
256 		char f;
257 
258 		cmd = LLC_U_CMD(llc.llcu);
259 		m = tok2str(cmd2str, "%02x", cmd);
260 		switch ((llc.ssap & LLC_GSAP) | (llc.llcu & LLC_U_POLL)) {
261 			case 0:			f = 'C'; break;
262 			case LLC_GSAP:		f = 'R'; break;
263 			case LLC_U_POLL:	f = 'P'; break;
264 			case LLC_GSAP|LLC_U_POLL: f = 'F'; break;
265 			default:		f = '?'; break;
266 		}
267 
268 		printf("%s/%c", m, f);
269 
270 		p += 3;
271 		length -= 3;
272 		caplen -= 3;
273 
274 		if ((llc.llcu & ~LLC_U_POLL) == LLC_XID) {
275 			if (*p == LLC_XID_FI) {
276 				printf(": %02x %02x", p[1], p[2]);
277 				p += 3;
278 				length -= 3;
279 				caplen -= 3;
280 			}
281 		}
282 	} else {
283 		char f;
284 
285 		/*
286 		 * The control field in I and S frames is little-endian.
287 		 */
288 		control = EXTRACT_LE_16BITS(&llc.llcu);
289 		switch ((llc.ssap & LLC_GSAP) | (control & LLC_IS_POLL)) {
290 			case 0:			f = 'C'; break;
291 			case LLC_GSAP:		f = 'R'; break;
292 			case LLC_IS_POLL:	f = 'P'; break;
293 			case LLC_GSAP|LLC_IS_POLL: f = 'F'; break;
294 			default:		f = '?'; break;
295 		}
296 
297 		if ((control & LLC_S_FMT) == LLC_S_FMT) {
298 			static const char *llc_s[] = { "rr", "rej", "rnr", "03" };
299 			(void)printf("%s (r=%d,%c)",
300 				llc_s[LLC_S_CMD(control)],
301 				LLC_IS_NR(control),
302 				f);
303 		} else {
304 			(void)printf("I (s=%d,r=%d,%c)",
305 				LLC_I_NS(control),
306 				LLC_IS_NR(control),
307 				f);
308 		}
309 		p += 4;
310 		length -= 4;
311 		caplen -= 4;
312 	}
313 	(void)printf(" len=%d", length);
314 	return(1);
315 }
316 
317 int
318 snap_print(const u_char *p, u_int length, u_int caplen,
319     u_short *extracted_ethertype, u_int32_t orgcode, u_short et,
320     u_int bridge_pad)
321 {
322 	register int ret;
323 
324 	switch (orgcode) {
325 	case OUI_ENCAP_ETHER:
326 	case OUI_CISCO_90:
327 		/*
328 		 * This is an encapsulated Ethernet packet,
329 		 * or a packet bridged by some piece of
330 		 * Cisco hardware; the protocol ID is
331 		 * an Ethernet protocol type.
332 		 */
333 		ret = ether_encap_print(et, p, length, caplen,
334 		    extracted_ethertype);
335 		if (ret)
336 			return (ret);
337 		break;
338 
339 	case OUI_APPLETALK:
340 		if (et == ETHERTYPE_ATALK) {
341 			/*
342 			 * No, I have no idea why Apple used one
343 			 * of their own OUIs, rather than
344 			 * 0x000000, and an Ethernet packet
345 			 * type, for Appletalk data packets,
346 			 * but used 0x000000 and an Ethernet
347 			 * packet type for AARP packets.
348 			 */
349 			ret = ether_encap_print(et, p, length, caplen,
350 			    extracted_ethertype);
351 			if (ret)
352 				return (ret);
353 		}
354 		break;
355 
356 	case OUI_CISCO:
357 		if (et == PID_CISCO_CDP) {
358 			cdp_print(p, length, caplen);
359 			return (1);
360 		}
361 		break;
362 
363 	case OUI_RFC2684:
364 		switch (et) {
365 
366 		case PID_RFC2684_ETH_FCS:
367 		case PID_RFC2684_ETH_NOFCS:
368 			/*
369 			 * XXX - remove the last two bytes for
370 			 * PID_RFC2684_ETH_FCS?
371 			 */
372 			/*
373 			 * Skip the padding.
374 			 */
375 			caplen -= bridge_pad;
376 			length -= bridge_pad;
377 			p += bridge_pad;
378 
379 			/*
380 			 * What remains is an Ethernet packet.
381 			 */
382 			ether_print(p, length, caplen);
383 			return (1);
384 
385 		case PID_RFC2684_802_5_FCS:
386 		case PID_RFC2684_802_5_NOFCS:
387 			/*
388 			 * XXX - remove the last two bytes for
389 			 * PID_RFC2684_ETH_FCS?
390 			 */
391 			/*
392 			 * Skip the padding, but not the Access
393 			 * Control field.
394 			 */
395 			caplen -= bridge_pad;
396 			length -= bridge_pad;
397 			p += bridge_pad;
398 
399 			/*
400 			 * What remains is an 802.5 Token Ring
401 			 * packet.
402 			 */
403 			token_print(p, length, caplen);
404 			return (1);
405 
406 		case PID_RFC2684_FDDI_FCS:
407 		case PID_RFC2684_FDDI_NOFCS:
408 			/*
409 			 * XXX - remove the last two bytes for
410 			 * PID_RFC2684_ETH_FCS?
411 			 */
412 			/*
413 			 * Skip the padding.
414 			 */
415 			caplen -= bridge_pad + 1;
416 			length -= bridge_pad + 1;
417 			p += bridge_pad + 1;
418 
419 			/*
420 			 * What remains is an FDDI packet.
421 			 */
422 			fddi_print(p, length, caplen);
423 			return (1);
424 
425 		case PID_RFC2684_BPDU:
426 			stp_print(p, length);
427 			return (1);
428 		}
429 	}
430 	return (0);
431 }
432