xref: /freebsd/contrib/tcpdump/print-llc.c (revision 6990ffd8a95caaba6858ad44ff1b3157d1efba8f)
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.32 2000/12/18 07:55:36 guy 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 
52 static struct tok cmd2str[] = {
53 	{ LLC_UI,	"ui" },
54 	{ LLC_TEST,	"test" },
55 	{ LLC_XID,	"xid" },
56 	{ LLC_UA,	"ua" },
57 	{ LLC_DISC,	"disc" },
58 	{ LLC_DM,	"dm" },
59 	{ LLC_SABME,	"sabme" },
60 	{ LLC_FRMR,	"frmr" },
61 	{ 0,		NULL }
62 };
63 
64 /*
65  * Returns non-zero IFF it succeeds in printing the header
66  */
67 int
68 llc_print(const u_char *p, u_int length, u_int caplen,
69 	  const u_char *esrc, const u_char *edst, u_short *extracted_ethertype)
70 {
71 	struct llc llc;
72 	register u_short et;
73 	u_int16_t control;
74 	register int ret;
75 
76 	if (caplen < 3) {
77 		(void)printf("[|llc]");
78 		default_print((u_char *)p, caplen);
79 		return(0);
80 	}
81 
82 	/* Watch out for possible alignment problems */
83 	memcpy((char *)&llc, (char *)p, min(caplen, sizeof(llc)));
84 
85 	if (llc.ssap == LLCSAP_GLOBAL && llc.dsap == LLCSAP_GLOBAL) {
86 		ipx_print(p, length);
87 		return (1);
88 	}
89 
90 	/* Cisco Discovery Protocol  - SNAP & ether type 0x2000 */
91 	if(llc.ssap == LLCSAP_SNAP && llc.dsap == LLCSAP_SNAP &&
92 		llc.llcui == LLC_UI &&
93 		llc.ethertype[0] == 0x20 && llc.ethertype[1] == 0x00 ) {
94 		    cdp_print( p, length, caplen, esrc, edst);
95 		    return (1);
96 	}
97 
98 	if (llc.ssap == LLCSAP_8021D && llc.dsap == LLCSAP_8021D) {
99 		stp_print(p, length);
100 		return (1);
101 	}
102 	if (llc.ssap == 0xf0 && llc.dsap == 0xf0
103 	    && (!(llc.llcu & LLC_S_FMT) || llc.llcu == LLC_U_FMT)) {
104 		/*
105 		 * we don't actually have a full netbeui parser yet, but the
106 		 * smb parser can handle many smb-in-netbeui packets, which
107 		 * is very useful, so we call that
108 		 *
109 		 * We don't call it for S frames, however, just I frames
110 		 * (which are frames that don't have the low-order bit,
111 		 * LLC_S_FMT, set in the first byte of the control field)
112 		 * and UI frames (whose control field is just 3, LLC_U_FMT).
113 		 */
114 
115 		/*
116 		 * Skip the DSAP and LSAP.
117 		 */
118 		p += 2;
119 		length -= 2;
120 		caplen -= 2;
121 
122 		/*
123 		 * OK, what type of LLC frame is this?  The length
124 		 * of the control field depends on that - I frames
125 		 * have a two-byte control field, and U frames have
126 		 * a one-byte control field.
127 		 */
128 		if (llc.llcu == LLC_U_FMT) {
129 			control = llc.llcu;
130 			p += 1;
131 			length -= 1;
132 			caplen -= 1;
133 		} else {
134 			/*
135 			 * The control field in I and S frames is
136 			 * little-endian.
137 			 */
138 			control = EXTRACT_LE_16BITS(&llc.llcu);
139 			p += 2;
140 			length -= 2;
141 			caplen -= 2;
142 		}
143 		netbeui_print(control, p, p + min(caplen, length));
144 		return (1);
145 	}
146 	if (llc.ssap == LLCSAP_ISONS && llc.dsap == LLCSAP_ISONS
147 	    && llc.llcui == LLC_UI) {
148 		isoclns_print(p + 3, length - 3, caplen - 3, esrc, edst);
149 		return (1);
150 	}
151 
152 	if (llc.ssap == LLCSAP_SNAP && llc.dsap == LLCSAP_SNAP
153 	    && llc.llcui == LLC_UI) {
154 		if (caplen < sizeof(llc)) {
155 			(void)printf("[|llc-snap]");
156 			default_print((u_char *)p, caplen);
157 			return (0);
158 		}
159 		if (vflag)
160 			(void)printf("snap %s ", protoid_string(llc.llcpi));
161 
162 		caplen -= sizeof(llc);
163 		length -= sizeof(llc);
164 		p += sizeof(llc);
165 
166 		/* This is an encapsulated Ethernet packet */
167 		et = EXTRACT_16BITS(&llc.ethertype[0]);
168 		ret = ether_encap_print(et, p, length, caplen,
169 		    extracted_ethertype);
170 		if (ret)
171 			return (ret);
172 	}
173 
174 	if ((llc.ssap & ~LLC_GSAP) == llc.dsap) {
175 		if (eflag)
176 			(void)printf("%s ", llcsap_string(llc.dsap));
177 		else
178 			(void)printf("%s > %s %s ",
179 					etheraddr_string(esrc),
180 					etheraddr_string(edst),
181 					llcsap_string(llc.dsap));
182 	} else {
183 		if (eflag)
184 			(void)printf("%s > %s ",
185 				llcsap_string(llc.ssap & ~LLC_GSAP),
186 				llcsap_string(llc.dsap));
187 		else
188 			(void)printf("%s %s > %s %s ",
189 				etheraddr_string(esrc),
190 				llcsap_string(llc.ssap & ~LLC_GSAP),
191 				etheraddr_string(edst),
192 				llcsap_string(llc.dsap));
193 	}
194 
195 	if ((llc.llcu & LLC_U_FMT) == LLC_U_FMT) {
196 		u_int16_t cmd;
197 		const char *m;
198 		char f;
199 
200 		cmd = LLC_U_CMD(llc.llcu);
201 		m = tok2str(cmd2str, "%02x", cmd);
202 		switch ((llc.ssap & LLC_GSAP) | (llc.llcu & LLC_U_POLL)) {
203 			case 0:			f = 'C'; break;
204 			case LLC_GSAP:		f = 'R'; break;
205 			case LLC_U_POLL:	f = 'P'; break;
206 			case LLC_GSAP|LLC_U_POLL: f = 'F'; break;
207 			default:		f = '?'; break;
208 		}
209 
210 		printf("%s/%c", m, f);
211 
212 		p += 3;
213 		length -= 3;
214 		caplen -= 3;
215 
216 		if ((llc.llcu & ~LLC_U_POLL) == LLC_XID) {
217 			if (*p == LLC_XID_FI) {
218 				printf(": %02x %02x", p[1], p[2]);
219 				p += 3;
220 				length -= 3;
221 				caplen -= 3;
222 			}
223 		}
224 
225 		if (cmd == LLC_UI && f == 'C') {
226 			/*
227 			 * we don't have a proper ipx decoder yet, but there
228 			 * is a partial one in the smb code
229 			 */
230 			ipx_netbios_print(p,p+min(caplen,length));
231 		}
232 	} else {
233 		char f;
234 
235 		/*
236 		 * The control field in I and S frames is little-endian.
237 		 */
238 		control = EXTRACT_LE_16BITS(&llc.llcu);
239 		switch ((llc.ssap & LLC_GSAP) | (control & LLC_IS_POLL)) {
240 			case 0:			f = 'C'; break;
241 			case LLC_GSAP:		f = 'R'; break;
242 			case LLC_IS_POLL:	f = 'P'; break;
243 			case LLC_GSAP|LLC_IS_POLL: f = 'F'; break;
244 			default:		f = '?'; break;
245 		}
246 
247 		if ((control & LLC_S_FMT) == LLC_S_FMT) {
248 			static char *llc_s[] = { "rr", "rej", "rnr", "03" };
249 			(void)printf("%s (r=%d,%c)",
250 				llc_s[LLC_S_CMD(control)],
251 				LLC_IS_NR(control),
252 				f);
253 		} else {
254 			(void)printf("I (s=%d,r=%d,%c)",
255 				LLC_I_NS(control),
256 				LLC_IS_NR(control),
257 				f);
258 		}
259 		p += 4;
260 		length -= 4;
261 		caplen -= 4;
262 	}
263 	(void)printf(" len=%d", length);
264 	if (caplen > 0 && !qflag) {
265 		default_print_unaligned(p, caplen);
266 	}
267 	return(1);
268 }
269