xref: /freebsd/contrib/tcpdump/print-llc.c (revision a1c2090e)
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[] =
29     "@(#) $Header: /tcpdump/master/tcpdump/print-llc.c,v 1.43 2001/10/08 21:25:22 fenner Exp $";
30 #endif
31 
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35 
36 #include <sys/param.h>
37 #include <sys/time.h>
38 
39 #include <netinet/in.h>
40 
41 #include <ctype.h>
42 #include <netdb.h>
43 #include <stdio.h>
44 #include <string.h>
45 
46 #include "interface.h"
47 #include "addrtoname.h"
48 #include "extract.h"			/* must come after interface.h */
49 
50 #include "llc.h"
51 #include "ethertype.h"
52 
53 static struct tok cmd2str[] = {
54 	{ LLC_UI,	"ui" },
55 	{ LLC_TEST,	"test" },
56 	{ LLC_XID,	"xid" },
57 	{ LLC_UA,	"ua" },
58 	{ LLC_DISC,	"disc" },
59 	{ LLC_DM,	"dm" },
60 	{ LLC_SABME,	"sabme" },
61 	{ LLC_FRMR,	"frmr" },
62 	{ 0,		NULL }
63 };
64 
65 /*
66  * Returns non-zero IFF it succeeds in printing the header
67  */
68 int
69 llc_print(const u_char *p, u_int length, u_int caplen,
70 	  const u_char *esrc, const u_char *edst, u_short *extracted_ethertype)
71 {
72 	struct llc llc;
73 	register u_short et;
74 	u_int16_t control;
75 	register int ret;
76 
77 	if (caplen < 3) {
78 		(void)printf("[|llc]");
79 		default_print((u_char *)p, caplen);
80 		return(0);
81 	}
82 
83 	/* Watch out for possible alignment problems */
84 	memcpy((char *)&llc, (char *)p, min(caplen, sizeof(llc)));
85 
86 	if (llc.ssap == LLCSAP_GLOBAL && llc.dsap == LLCSAP_GLOBAL) {
87 		/*
88 		 * This is an Ethernet_802.3 IPX frame; it has an
89 		 * 802.3 header (i.e., an Ethernet header where the
90 		 * type/length field is <= ETHERMTU, i.e. it's a length
91 		 * field, not a type field), but has no 802.2 header -
92 		 * the IPX packet starts right after the Ethernet header,
93 		 * with a signature of two bytes of 0xFF (which is
94 		 * LLCSAP_GLOBAL).
95 		 *
96 		 * (It might also have been an Ethernet_802.3 IPX at
97 		 * one time, but got bridged onto another network,
98 		 * such as an 802.11 network; this has appeared in at
99 		 * least one capture file.)
100 		 */
101 		ipx_print(p, length);
102 		return (1);
103 	}
104 
105 	if (llc.ssap == LLCSAP_8021D && llc.dsap == LLCSAP_8021D) {
106 		stp_print(p, length);
107 		return (1);
108 	}
109 
110 	if (llc.ssap == LLCSAP_IPX && llc.dsap == LLCSAP_IPX &&
111 	    llc.llcui == LLC_UI) {
112 		/*
113 		 * This is an Ethernet_802.2 IPX frame, with an 802.3
114 		 * header and an 802.2 LLC header with the source and
115 		 * destination SAPs being the IPX SAP.
116 		 *
117 		 * Skip DSAP, LSAP, and control field.
118 		 */
119 		p += 3;
120 		length -= 3;
121 		caplen -= 3;
122 		ipx_print(p, length);
123 		return (1);
124 	}
125 
126 #ifdef TCPDUMP_DO_SMB
127 	if (llc.ssap == LLCSAP_NETBEUI && llc.dsap == LLCSAP_NETBEUI
128 	    && (!(llc.llcu & LLC_S_FMT) || llc.llcu == LLC_U_FMT)) {
129 		/*
130 		 * we don't actually have a full netbeui parser yet, but the
131 		 * smb parser can handle many smb-in-netbeui packets, which
132 		 * is very useful, so we call that
133 		 *
134 		 * We don't call it for S frames, however, just I frames
135 		 * (which are frames that don't have the low-order bit,
136 		 * LLC_S_FMT, set in the first byte of the control field)
137 		 * and UI frames (whose control field is just 3, LLC_U_FMT).
138 		 */
139 
140 		/*
141 		 * Skip the DSAP and LSAP.
142 		 */
143 		p += 2;
144 		length -= 2;
145 		caplen -= 2;
146 
147 		/*
148 		 * OK, what type of LLC frame is this?  The length
149 		 * of the control field depends on that - I frames
150 		 * have a two-byte control field, and U frames have
151 		 * a one-byte control field.
152 		 */
153 		if (llc.llcu == LLC_U_FMT) {
154 			control = llc.llcu;
155 			p += 1;
156 			length -= 1;
157 			caplen -= 1;
158 		} else {
159 			/*
160 			 * The control field in I and S frames is
161 			 * little-endian.
162 			 */
163 			control = EXTRACT_LE_16BITS(&llc.llcu);
164 			p += 2;
165 			length -= 2;
166 			caplen -= 2;
167 		}
168 		netbeui_print(control, p, length);
169 		return (1);
170 	}
171 #endif
172 	if (llc.ssap == LLCSAP_ISONS && llc.dsap == LLCSAP_ISONS
173 	    && llc.llcui == LLC_UI) {
174 		isoclns_print(p + 3, length - 3, caplen - 3, esrc, edst);
175 		return (1);
176 	}
177 
178 	if (llc.ssap == LLCSAP_SNAP && llc.dsap == LLCSAP_SNAP
179 	    && llc.llcui == LLC_UI) {
180 		u_int32_t orgcode;
181 
182 		if (caplen < sizeof(llc)) {
183 			(void)printf("[|llc-snap]");
184 			default_print((u_char *)p, caplen);
185 			return (0);
186 		}
187 		if (vflag)
188 			(void)printf("snap %s ", protoid_string(llc.llcpi));
189 
190 		caplen -= sizeof(llc);
191 		length -= sizeof(llc);
192 		p += sizeof(llc);
193 
194 		orgcode = EXTRACT_24BITS(&llc.llc_orgcode[0]);
195 		et = EXTRACT_16BITS(&llc.llc_ethertype[0]);
196 		switch (orgcode) {
197 		case OUI_ENCAP_ETHER:
198 		case OUI_CISCO_90:
199 			/*
200 			 * This is an encapsulated Ethernet packet,
201 			 * or a packet bridged by some piece of
202 			 * Cisco hardware; the protocol ID is
203 			 * an Ethernet protocol type.
204 			 */
205 			ret = ether_encap_print(et, p, length, caplen,
206 			    extracted_ethertype);
207 			if (ret)
208 				return (ret);
209 			break;
210 
211 		case OUI_APPLETALK:
212 			if (et == ETHERTYPE_ATALK) {
213 				/*
214 				 * No, I have no idea why Apple used one
215 				 * of their own OUIs, rather than
216 				 * 0x000000, and an Ethernet packet
217 				 * type, for Appletalk data packets,
218 				 * but used 0x000000 and an Ethernet
219 				 * packet type for AARP packets.
220 				 */
221 				ret = ether_encap_print(et, p, length, caplen,
222 				    extracted_ethertype);
223 				if (ret)
224 					return (ret);
225 			}
226 			break;
227 
228 		case OUI_CISCO:
229 			if (et == ETHERTYPE_CISCO_CDP) {
230 				cdp_print(p, length, caplen, esrc, edst);
231 				return 1;
232 			}
233 			break;
234 		}
235 	}
236 
237 	if ((llc.ssap & ~LLC_GSAP) == llc.dsap) {
238 		if (eflag || esrc == NULL || edst == NULL)
239 			(void)printf("%s ", llcsap_string(llc.dsap));
240 		else
241 			(void)printf("%s > %s %s ",
242 					etheraddr_string(esrc),
243 					etheraddr_string(edst),
244 					llcsap_string(llc.dsap));
245 	} else {
246 		if (eflag || esrc == NULL || edst == NULL)
247 			(void)printf("%s > %s ",
248 				llcsap_string(llc.ssap & ~LLC_GSAP),
249 				llcsap_string(llc.dsap));
250 		else
251 			(void)printf("%s %s > %s %s ",
252 				etheraddr_string(esrc),
253 				llcsap_string(llc.ssap & ~LLC_GSAP),
254 				etheraddr_string(edst),
255 				llcsap_string(llc.dsap));
256 	}
257 
258 	if ((llc.llcu & LLC_U_FMT) == LLC_U_FMT) {
259 		u_int16_t cmd;
260 		const char *m;
261 		char f;
262 
263 		cmd = LLC_U_CMD(llc.llcu);
264 		m = tok2str(cmd2str, "%02x", cmd);
265 		switch ((llc.ssap & LLC_GSAP) | (llc.llcu & LLC_U_POLL)) {
266 			case 0:			f = 'C'; break;
267 			case LLC_GSAP:		f = 'R'; break;
268 			case LLC_U_POLL:	f = 'P'; break;
269 			case LLC_GSAP|LLC_U_POLL: f = 'F'; break;
270 			default:		f = '?'; break;
271 		}
272 
273 		printf("%s/%c", m, f);
274 
275 		p += 3;
276 		length -= 3;
277 		caplen -= 3;
278 
279 		if ((llc.llcu & ~LLC_U_POLL) == LLC_XID) {
280 			if (*p == LLC_XID_FI) {
281 				printf(": %02x %02x", p[1], p[2]);
282 				p += 3;
283 				length -= 3;
284 				caplen -= 3;
285 			}
286 		}
287 	} else {
288 		char f;
289 
290 		/*
291 		 * The control field in I and S frames is little-endian.
292 		 */
293 		control = EXTRACT_LE_16BITS(&llc.llcu);
294 		switch ((llc.ssap & LLC_GSAP) | (control & LLC_IS_POLL)) {
295 			case 0:			f = 'C'; break;
296 			case LLC_GSAP:		f = 'R'; break;
297 			case LLC_IS_POLL:	f = 'P'; break;
298 			case LLC_GSAP|LLC_IS_POLL: f = 'F'; break;
299 			default:		f = '?'; break;
300 		}
301 
302 		if ((control & LLC_S_FMT) == LLC_S_FMT) {
303 			static char *llc_s[] = { "rr", "rej", "rnr", "03" };
304 			(void)printf("%s (r=%d,%c)",
305 				llc_s[LLC_S_CMD(control)],
306 				LLC_IS_NR(control),
307 				f);
308 		} else {
309 			(void)printf("I (s=%d,r=%d,%c)",
310 				LLC_I_NS(control),
311 				LLC_IS_NR(control),
312 				f);
313 		}
314 		p += 4;
315 		length -= 4;
316 		caplen -= 4;
317 	}
318 	(void)printf(" len=%d", length);
319 	if (caplen > 0 && !qflag) {
320 		default_print_unaligned(p, caplen);
321 	}
322 	return(1);
323 }
324