xref: /openbsd-src/usr.sbin/tcpdump/print-llc.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: print-llc.c,v 1.13 2001/06/25 19:56:11 itojun Exp $	*/
2 
3 /*
4  * Copyright (c) 1992, 1993, 1994, 1995, 1996, 1997
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that: (1) source code distributions
9  * retain the above copyright notice and this paragraph in its entirety, (2)
10  * distributions including binary code include the above copyright notice and
11  * this paragraph in its entirety in the documentation or other materials
12  * provided with the distribution, and (3) all advertising materials mentioning
13  * features or use of this software display the following acknowledgement:
14  * ``This product includes software developed by the University of California,
15  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16  * the University nor the names of its contributors may be used to endorse
17  * or promote products derived from this software without specific prior
18  * written permission.
19  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22  *
23  * Code by Matt Thomas, Digital Equipment Corporation
24  *	with an awful lot of hacking by Jeffrey Mogul, DECWRL
25  */
26 
27 #ifndef lint
28 static const char rcsid[] =
29     "@(#) $Header: /home/cvs/src/usr.sbin/tcpdump/print-llc.c,v 1.13 2001/06/25 19:56:11 itojun Exp $";
30 #endif
31 
32 #include <sys/param.h>
33 #include <sys/time.h>
34 
35 #include <netinet/in.h>
36 
37 #include <ctype.h>
38 #include <netdb.h>
39 #include <signal.h>
40 #include <stdio.h>
41 #include <string.h>
42 
43 #include "interface.h"
44 #include "addrtoname.h"
45 #include "extract.h"			/* must come after interface.h */
46 #include "ethertype.h"
47 
48 #include "llc.h"
49 
50 static struct tok cmd2str[] = {
51 	{ LLC_UI,	"ui" },
52 	{ LLC_TEST,	"test" },
53 	{ LLC_XID,	"xid" },
54 	{ LLC_UA,	"ua" },
55 	{ LLC_DISC,	"disc" },
56 	{ LLC_DM,	"dm" },
57 	{ LLC_SABME,	"sabme" },
58 	{ LLC_FRMR,	"frmr" },
59 	{ 0,		NULL }
60 };
61 
62 /*
63  * Returns non-zero IFF it succeeds in printing the header
64  */
65 int
66 llc_print(const u_char *p, u_int length, u_int caplen,
67 	  const u_char *esrc, const u_char *edst)
68 {
69 	struct llc llc;
70 	register u_short et;
71 #if 0
72 	u_short control;
73 #endif
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 #ifdef notyet
90 	else if (p[0] == 0xf0 && p[1] == 0xf0)
91 		netbios_print(p, length);
92 #endif
93 
94 	/* Cisco Discovery Protocol  - SNAP & ether type 0x2000 */
95 	if(llc.ssap == LLCSAP_SNAP && llc.dsap == LLCSAP_SNAP &&
96 		llc.llcui == LLC_UI &&
97 		llc.ethertype[0] == 0x20 && llc.ethertype[1] == 0x00 ) {
98 		    cdp_print( p, length, caplen, esrc, edst);
99 		    return (1);
100 	}
101 
102 	if (llc.ssap == LLCSAP_ISONS && llc.dsap == LLCSAP_ISONS
103 	    && llc.llcui == LLC_UI) {
104 		isoclns_print(p + 3, length - 3, caplen - 3, esrc, edst);
105 		return (1);
106 	}
107 
108 	if (llc.ssap == LLCSAP_SNAP && llc.dsap == LLCSAP_SNAP
109 	    && llc.llcui == LLC_UI) {
110 		if (caplen < sizeof(llc)) {
111 		    (void)printf("[|llc-snap]");
112 		    default_print((u_char *)p, caplen);
113 		    return (0);
114 		}
115 		if (vflag)
116 			(void)printf("snap %s ", protoid_string(llc.llcpi));
117 
118 		caplen -= sizeof(llc);
119 		length -= sizeof(llc);
120 		p += sizeof(llc);
121 
122 		/* This is an encapsulated Ethernet packet */
123 		et = EXTRACT_16BITS(&llc.ethertype[0]);
124 
125 		/*
126 		 * Some protocols have special handling if they are 802.3
127 		 * SNAP encapsulated vs vers II encapsulated. Handle
128 		 * those special protocols here, and hand the rest to
129 		 * print-ether.c so we don't have to duplicate
130 		 * all that code here.
131 		 */
132 		switch (et) {
133 		case ETHERTYPE_ATALK:
134 			atalk_print(p, length);
135 			ret = 1;
136 			break;
137 		default:
138 			ret = ether_encap_print(et, p, length, caplen);
139 			break;
140 		}
141 
142 		if (ret)
143 			return (ret);
144 	}
145 
146 	if (llc.ssap == LLCSAP_8021D && llc.dsap == LLCSAP_8021D) {
147 		stp_print(p, length);
148 		return (1);
149 	}
150 
151 #if 0
152 	if (llc.ssap == 0xf0 && llc.dsap == 0xf0) {
153 		/*
154 		 * we don't actually have a full netbeui parser yet, but the
155 		 * smb parser can handle many smb-in-netbeui packets, which
156 		 * is very useful, so we call that
157 		 */
158 
159 		/*
160 		 * Skip the DSAP and LSAP.
161 		 */
162 		p += 2;
163 		length -= 2;
164 		caplen -= 2;
165 
166 		/*
167 		 * OK, what type of LLC frame is this?  The length
168 		 * of the control field depends on that - S or I
169 		 * frames have a two-byte control field, and U frames
170 		 * have a one-byte control field.
171 		 */
172 		if ((llc.llcu & LLC_U_FMT) == LLC_U_FMT) {
173 			control = llc.llcu;
174 			p += 1;
175 			length -= 1;
176 			caplen -= 1;
177 		} else {
178 			control = llc.llcis;
179 			p += 2;
180 			length -= 2;
181 			caplen -= 2;
182 		}
183 
184 		netbeui_print(control, p, p + min(caplen, length));
185 		return (1);
186 	}
187 #endif
188 
189 	if ((llc.ssap & ~LLC_GSAP) == llc.dsap) {
190 		if (eflag)
191 			(void)printf("%s ", llcsap_string(llc.dsap));
192 		else
193 			(void)printf("%s > %s %s ",
194 					etheraddr_string(esrc),
195 					etheraddr_string(edst),
196 					llcsap_string(llc.dsap));
197 	} else {
198 		if (eflag)
199 			(void)printf("%s > %s ",
200 				llcsap_string(llc.ssap & ~LLC_GSAP),
201 				llcsap_string(llc.dsap));
202 		else
203 			(void)printf("%s %s > %s %s ",
204 				etheraddr_string(esrc),
205 				llcsap_string(llc.ssap & ~LLC_GSAP),
206 				etheraddr_string(edst),
207 				llcsap_string(llc.dsap));
208 	}
209 
210 	if ((llc.llcu & LLC_U_FMT) == LLC_U_FMT) {
211 		const char *m;
212 		char f;
213 		m = tok2str(cmd2str, "%02x", LLC_U_CMD(llc.llcu));
214 		switch ((llc.ssap & LLC_GSAP) | (llc.llcu & LLC_U_POLL)) {
215 		    case 0:			f = 'C'; break;
216 		    case LLC_GSAP:		f = 'R'; break;
217 		    case LLC_U_POLL:		f = 'P'; break;
218 		    case LLC_GSAP|LLC_U_POLL:	f = 'F'; break;
219 		    default:			f = '?'; break;
220 		}
221 
222 		printf("%s/%c", m, f);
223 
224 		if (caplen < 6) {
225 			default_print_unaligned(p, caplen);
226 			return (0);
227 		}
228 		p += 3;
229 		length -= 3;
230 		caplen -= 3;
231 
232 		if ((llc.llcu & ~LLC_U_POLL) == LLC_XID) {
233 		    if (*p == LLC_XID_FI) {
234 			printf(": %02x %02x", p[1], p[2]);
235 			p += 3;
236 			length -= 3;
237 			caplen -= 3;
238 		    }
239 		}
240 
241 #if 0
242 		if (!strcmp(m,"ui") && f=='C') {
243 			/*
244 			 * we don't have a proper ipx decoder yet, but there
245 			 * is a partial one in the smb code
246 			 */
247 			ipx_netbios_print(p,p+min(caplen,length));
248 		}
249 #endif
250 
251 	} else {
252 		char f;
253 		llc.llcis = ntohs(llc.llcis);
254 		switch ((llc.ssap & LLC_GSAP) | (llc.llcu & LLC_U_POLL)) {
255 		    case 0:			f = 'C'; break;
256 		    case LLC_GSAP:		f = 'R'; break;
257 		    case LLC_U_POLL:		f = 'P'; break;
258 		    case LLC_GSAP|LLC_U_POLL:	f = 'F'; break;
259 		    default:			f = '?'; break;
260 		}
261 
262 		if ((llc.llcu & LLC_S_FMT) == LLC_S_FMT) {
263 			static char *llc_s[] = { "rr", "rej", "rnr", "03" };
264 			(void)printf("%s (r=%d,%c)",
265 				llc_s[LLC_S_CMD(llc.llcis)],
266 				LLC_IS_NR(llc.llcis),
267 				f);
268 		} else {
269 			(void)printf("I (s=%d,r=%d,%c)",
270 				LLC_I_NS(llc.llcis),
271 				LLC_IS_NR(llc.llcis),
272 				f);
273 		}
274 		p += 4;
275 		length -= 4;
276 		caplen -= 4;
277 	}
278 	(void)printf(" len=%d", length);
279 	return(1);
280 }
281