xref: /openbsd/usr.sbin/tcpdump/print-llc.c (revision 4cfece93)
1 /*	$OpenBSD: print-llc.c,v 1.22 2020/01/24 22:46:37 procter 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 #include <sys/time.h>
28 
29 #include <netinet/in.h>
30 
31 #include <ctype.h>
32 #include <netdb.h>
33 #include <signal.h>
34 #include <stdio.h>
35 #include <string.h>
36 
37 #include "interface.h"
38 #include "addrtoname.h"
39 #include "extract.h"			/* must come after interface.h */
40 #include "ethertype.h"
41 
42 #include "llc.h"
43 
44 static struct tok cmd2str[] = {
45 	{ LLC_UI,	"ui" },
46 	{ LLC_TEST,	"test" },
47 	{ LLC_XID,	"xid" },
48 	{ LLC_UA,	"ua" },
49 	{ LLC_DISC,	"disc" },
50 	{ LLC_DM,	"dm" },
51 	{ LLC_SABME,	"sabme" },
52 	{ LLC_FRMR,	"frmr" },
53 	{ 0,		NULL }
54 };
55 
56 /*
57  * Returns non-zero IFF it succeeds in printing the header
58  */
59 int
60 llc_print(const u_char *p, u_int length, u_int caplen,
61 	  const u_char *esrc, const u_char *edst)
62 {
63 	struct llc llc;
64 	u_short et;
65 #if 0
66 	u_short control;
67 #endif
68 	int ret;
69 
70 	if (caplen < 3) {
71 		printf("[|llc]");
72 		default_print((u_char *)p, caplen);
73 		return(0);
74 	}
75 
76 	/* Watch out for possible alignment problems */
77 	memcpy((char *)&llc, (char *)p, min(caplen, sizeof(llc)));
78 
79 	if (llc.ssap == LLCSAP_GLOBAL && llc.dsap == LLCSAP_GLOBAL) {
80 		ipx_print(p, length);
81 		return (1);
82 	}
83 #ifdef notyet
84 	else if (p[0] == 0xf0 && p[1] == 0xf0)
85 		netbios_print(p, length);
86 #endif
87 	if (llc.ssap == LLCSAP_ISONS && llc.dsap == LLCSAP_ISONS
88 	    && llc.llcui == LLC_UI) {
89 		isoclns_print(p + 3, length - 3, caplen - 3, esrc, edst);
90 		return (1);
91 	}
92 
93 	if (llc.ssap == LLCSAP_SNAP && llc.dsap == LLCSAP_SNAP
94 	    && llc.llcui == LLC_UI) {
95 		if (caplen < sizeof(llc)) {
96 		    printf("[|llc-snap]");
97 		    default_print((u_char *)p, caplen);
98 		    return (0);
99 		}
100 
101 		/* Cisco Discovery Protocol  - SNAP & ether type 0x2000 */
102 		if (llc.ethertype[0] == 0x20 && llc.ethertype[1] == 0x00) {
103 			cdp_print(p, length, caplen, 8);
104 			return (1);
105 		}
106 		/* Shared Spanning Tree Protocol - SNAP & ether type 0x010b */
107 		if (llc.ethertype[0] == 0x01 && llc.ethertype[1] == 0x0b) {
108 			stp_print(p, length);
109 			return (1);
110 		}
111 
112 		if (vflag)
113 			printf("snap %s ", protoid_string(llc.llcpi));
114 
115 		caplen -= sizeof(llc);
116 		length -= sizeof(llc);
117 		p += sizeof(llc);
118 
119 		/* This is an encapsulated Ethernet packet */
120 		et = EXTRACT_16BITS(&llc.ethertype[0]);
121 
122 		/*
123 		 * Some protocols have special handling if they are 802.3
124 		 * SNAP encapsulated vs vers II encapsulated. Handle
125 		 * those special protocols here, and hand the rest to
126 		 * print-ether.c so we don't have to duplicate
127 		 * all that code here.
128 		 */
129 		switch (et) {
130 		case ETHERTYPE_ATALK:
131 			atalk_print(p, length);
132 			ret = 1;
133 			break;
134 		default:
135 			ret = ether_encap_print(et, p, length, caplen);
136 			break;
137 		}
138 
139 		if (ret)
140 			return (ret);
141 	}
142 
143 	if (llc.ssap == LLCSAP_8021D && llc.dsap == LLCSAP_8021D) {
144 		stp_print(p, length);
145 		return (1);
146 	}
147 
148 #if 0
149 	if (llc.ssap == 0xf0 && llc.dsap == 0xf0) {
150 		/*
151 		 * we don't actually have a full netbeui parser yet, but the
152 		 * smb parser can handle many smb-in-netbeui packets, which
153 		 * is very useful, so we call that
154 		 */
155 
156 		/*
157 		 * Skip the DSAP and LSAP.
158 		 */
159 		p += 2;
160 		length -= 2;
161 		caplen -= 2;
162 
163 		/*
164 		 * OK, what type of LLC frame is this?  The length
165 		 * of the control field depends on that - S or I
166 		 * frames have a two-byte control field, and U frames
167 		 * have a one-byte control field.
168 		 */
169 		if ((llc.llcu & LLC_U_FMT) == LLC_U_FMT) {
170 			control = llc.llcu;
171 			p += 1;
172 			length -= 1;
173 			caplen -= 1;
174 		} else {
175 			control = llc.llcis;
176 			p += 2;
177 			length -= 2;
178 			caplen -= 2;
179 		}
180 
181 		netbeui_print(control, p, p + min(caplen, length));
182 		return (1);
183 	}
184 #endif
185 
186 	if ((llc.ssap & ~LLC_GSAP) == llc.dsap) {
187 		if (eflag)
188 			printf("%s ", llcsap_string(llc.dsap));
189 		else
190 			printf("%s > %s %s ",
191 			    etheraddr_string(esrc),
192 			    etheraddr_string(edst),
193 			    llcsap_string(llc.dsap));
194 	} else {
195 		if (eflag)
196 			printf("%s > %s ",
197 			    llcsap_string(llc.ssap & ~LLC_GSAP),
198 			    llcsap_string(llc.dsap));
199 		else
200 			printf("%s %s > %s %s ",
201 			    etheraddr_string(esrc),
202 			    llcsap_string(llc.ssap & ~LLC_GSAP),
203 			    etheraddr_string(edst),
204 			    llcsap_string(llc.dsap));
205 	}
206 
207 	if ((llc.llcu & LLC_U_FMT) == LLC_U_FMT) {
208 		const char *m;
209 		char f;
210 		m = tok2str(cmd2str, "%02x", LLC_U_CMD(llc.llcu));
211 		switch ((llc.ssap & LLC_GSAP) | (llc.llcu & LLC_U_POLL)) {
212 		    case 0:			f = 'C'; break;
213 		    case LLC_GSAP:		f = 'R'; break;
214 		    case LLC_U_POLL:		f = 'P'; break;
215 		    case LLC_GSAP|LLC_U_POLL:	f = 'F'; break;
216 		    default:			f = '?'; break;
217 		}
218 
219 		printf("%s/%c", m, f);
220 
221 		if (caplen < 6) {
222 			default_print_unaligned(p, caplen);
223 			return (0);
224 		}
225 		p += 3;
226 		length -= 3;
227 		caplen -= 3;
228 
229 		if ((llc.llcu & ~LLC_U_POLL) == LLC_XID) {
230 		    if (*p == LLC_XID_FI) {
231 			printf(": %02x %02x", p[1], p[2]);
232 			p += 3;
233 			length -= 3;
234 			caplen -= 3;
235 		    }
236 		}
237 
238 #if 0
239 		if (!strcmp(m,"ui") && f=='C') {
240 			/*
241 			 * we don't have a proper ipx decoder yet, but there
242 			 * is a partial one in the smb code
243 			 */
244 			ipx_netbios_print(p,p+min(caplen,length));
245 		}
246 #endif
247 
248 	} else {
249 		char f;
250 		if (caplen < 4) {
251 			default_print_unaligned(p, caplen);
252 			return (0);
253 		}
254 		llc.llcis = ntohs(llc.llcis);
255 		switch ((llc.ssap & LLC_GSAP) | (llc.llcu & LLC_U_POLL)) {
256 		    case 0:			f = 'C'; break;
257 		    case LLC_GSAP:		f = 'R'; break;
258 		    case LLC_U_POLL:		f = 'P'; break;
259 		    case LLC_GSAP|LLC_U_POLL:	f = 'F'; break;
260 		    default:			f = '?'; break;
261 		}
262 
263 		if ((llc.llcu & LLC_S_FMT) == LLC_S_FMT) {
264 			static char *llc_s[] = { "rr", "rej", "rnr", "03" };
265 			printf("%s (r=%d,%c)",
266 			    llc_s[LLC_S_CMD(llc.llcis)],
267 			    LLC_IS_NR(llc.llcis),
268 			    f);
269 		} else {
270 			printf("I (s=%d,r=%d,%c)",
271 			    LLC_I_NS(llc.llcis),
272 			    LLC_IS_NR(llc.llcis),
273 			    f);
274 		}
275 		p += 4;
276 		length -= 4;
277 		caplen -= 4;
278 	}
279 	printf(" len=%d", length);
280 	return(1);
281 }
282