xref: /openbsd/usr.sbin/tcpdump/print-stp.c (revision d415bd75)
1 /*	$OpenBSD: print-stp.c,v 1.12 2023/09/06 05:54:07 jsg Exp $	*/
2 
3 /*
4  * Copyright (c) 2000 Jason L. Wright (jason@thought.net)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /*
30  * Pretty print 802.1D Bridge Protocol Data Units
31  */
32 
33 #include <sys/time.h>
34 #include <sys/socket.h>
35 #include <sys/file.h>
36 #include <sys/ioctl.h>
37 
38 #include <net/if.h>
39 
40 #include <netinet/in.h>
41 #include <netinet/ip.h>
42 
43 #include <ctype.h>
44 #include <netdb.h>
45 #include <pcap.h>
46 #include <signal.h>
47 #include <stdio.h>
48 
49 #include <netinet/if_ether.h>
50 #include "ethertype.h"
51 
52 #include <net/ppp_defs.h>
53 #include "interface.h"
54 #include "addrtoname.h"
55 #include "extract.h"
56 #include "llc.h"
57 
58 #define	STP_MSGTYPE_CBPDU	0x00
59 #define	STP_MSGTYPE_RSTP	0x02
60 #define	STP_MSGTYPE_TBPDU	0x80
61 
62 #define	STP_FLAGS_STPMASK	0x81		/* strip unused STP flags */
63 #define	STP_FLAGS_RSTPMASK	0x7f		/* strip unused RSTP flags */
64 #define	STP_FLAGS_TC		0x01		/* Topology change */
65 #define	STP_FLAGS_P		0x02		/* Proposal flag */
66 #define	STP_FLAGS_ROLE		0x0c		/* Port Role */
67 #define	STP_FLAGS_ROLE_S	2		/* Port Role offset */
68 #define	STP_FLAGS_ROLE_ALT	1		/* Alt/Backup port */
69 #define	STP_FLAGS_ROLE_ROOT	2		/* Root port */
70 #define	STP_FLAGS_ROLE_DESG	3		/* Designated port */
71 #define	STP_FLAGS_L		0x10		/* Learning flag */
72 #define	STP_FLAGS_F		0x20		/* Forwarding flag */
73 #define	STP_FLAGS_A		0x40		/* Agreement flag */
74 #define	STP_FLAGS_TCA		0x80		/* Topology change ack */
75 #define STP_FLAGS_BITS								\
76 	"\20\1TC\2PROPOSAL\5LEARNING\6FORWARDING\7AGREED\10TCACK"
77 
78 enum {
79 	STP_PROTO_STP	= 0x00,
80 	STP_PROTO_RSTP	= 0x02,
81 	STP_PROTO_SSTP	= 0x10	/* Cizzco-Eeeh */
82 };
83 
84 static void stp_print_cbpdu(const u_char *, u_int, int);
85 static void stp_print_tbpdu(const u_char *, u_int);
86 
87 void
88 stp_print(const u_char *p, u_int len)
89 {
90 	u_int16_t id;
91 	int proto = STP_PROTO_STP;
92 
93 	if (len < 3)
94 		goto truncated;
95 	if (p[0] == LLCSAP_8021D && p[1] == LLCSAP_8021D && p[2] == LLC_UI)
96 		printf("802.1d");
97 	else if (p[0] == LLCSAP_SNAP && p[1] == LLCSAP_SNAP && p[2] == LLC_UI) {
98 		proto = STP_PROTO_SSTP;
99 		printf("SSTP");
100 		if (len < 8)
101 			goto truncated;
102 		p += 5;
103 		len -= 5;
104 	} else {
105 		printf("invalid protocol");
106 		return;
107 	}
108 	p += 3;
109 	len -= 3;
110 
111 	if (len < 3)
112 		goto truncated;
113 	id = EXTRACT_16BITS(p);
114 	if (id != 0) {
115 		printf(" unknown protocol id(0x%x)", id);
116 		return;
117 	}
118 	switch (p[2]) {
119 	case STP_PROTO_STP:
120 		printf(" STP");
121 		break;
122 	case STP_PROTO_RSTP:
123 		printf(" RSTP");
124 		break;
125 	default:
126 		printf(" unknown protocol ver(0x%x)", p[2]);
127 		return;
128 	}
129 	p += 3;
130 	len -= 3;
131 
132 	if (len < 1)
133 		goto truncated;
134 	switch (*p) {
135 	case STP_MSGTYPE_CBPDU:
136 		stp_print_cbpdu(p, len, proto);
137 		break;
138 	case STP_MSGTYPE_RSTP:
139 		stp_print_cbpdu(p, len, STP_PROTO_RSTP);
140 		break;
141 	case STP_MSGTYPE_TBPDU:
142 		stp_print_tbpdu(p, len);
143 		break;
144 	default:
145 		printf(" unknown message (0x%02x)", *p);
146 		break;
147 	}
148 
149 	return;
150 
151 truncated:
152 	printf("[|802.1d]");
153 }
154 
155 static void
156 stp_print_cbpdu(const u_char *p, u_int len, int proto)
157 {
158 	u_int32_t cost;
159 	u_int16_t t;
160 	u_int8_t flags, role;
161 	int x;
162 
163 	p += 1;
164 	len -= 1;
165 
166 	printf(" config");
167 
168 	if (len < 1)
169 		goto truncated;
170 	if (*p) {
171 		switch (proto) {
172 		case STP_PROTO_STP:
173 		case STP_PROTO_SSTP:
174 			flags = *p & STP_FLAGS_STPMASK;
175 			role = STP_FLAGS_ROLE_DESG;
176 			break;
177 		case STP_PROTO_RSTP:
178 		default:
179 			flags = *p & STP_FLAGS_RSTPMASK;
180 			role = (flags & STP_FLAGS_ROLE) >> STP_FLAGS_ROLE_S;
181 			break;
182 		}
183 
184 		printb(" flags", flags, STP_FLAGS_BITS);
185 		switch (role) {
186 		case STP_FLAGS_ROLE_ALT:
187 			printf(" role=ALT/BACKUP");
188 			break;
189 		case STP_FLAGS_ROLE_ROOT:
190 			printf(" role=ROOT");
191 			break;
192 		case STP_FLAGS_ROLE_DESG:
193 			printf(" role=DESIGNATED");
194 			break;
195 		}
196 	}
197 	p += 1;
198 	len -= 1;
199 
200 	if (len < 8)
201 		goto truncated;
202 	printf(" root=");
203 	printf("%x.", EXTRACT_16BITS(p));
204 	p += 2;
205 	len -= 2;
206 	for (x = 0; x < 6; x++) {
207 		printf("%s%x", (x != 0) ? ":" : "", *p);
208 		p++;
209 		len--;
210 	}
211 
212 	if (len < 4)
213 		goto truncated;
214 	cost = EXTRACT_32BITS(p);
215 	printf(" rootcost=%u", cost);
216 	p += 4;
217 	len -= 4;
218 
219 	if (len < 8)
220 		goto truncated;
221 	printf(" bridge=");
222 	printf("%x.", EXTRACT_16BITS(p));
223 	p += 2;
224 	len -= 2;
225 	for (x = 0; x < 6; x++) {
226 		printf("%s%x", (x != 0) ? ":" : "", *p);
227 		p++;
228 		len--;
229 	}
230 
231 	if (len < 2)
232 		goto truncated;
233 	t = EXTRACT_16BITS(p);
234 	switch (proto) {
235 	case STP_PROTO_STP:
236 	case STP_PROTO_SSTP:
237 		printf(" port=%u", t & 0xff);
238 		printf(" ifcost=%u", t >> 8);
239 		break;
240 	case STP_PROTO_RSTP:
241 	default:
242 		printf(" port=%u", t & 0xfff);
243 		printf(" ifcost=%u", t >> 8);
244 		break;
245 	}
246 	p += 2;
247 	len -= 2;
248 
249 	if (len < 2)
250 		goto truncated;
251 	printf(" age=%u/%u", p[0], p[1]);
252 	p += 2;
253 	len -= 2;
254 
255 	if (len < 2)
256 		goto truncated;
257 	printf(" max=%u/%u", p[0], p[1]);
258 	p += 2;
259 	len -= 2;
260 
261 	if (len < 2)
262 		goto truncated;
263 	printf(" hello=%u/%u", p[0], p[1]);
264 	p += 2;
265 	len -= 2;
266 
267 	if (len < 2)
268 		goto truncated;
269 	printf(" fwdelay=%u/%u", p[0], p[1]);
270 	p += 2;
271 	len -= 2;
272 
273 	if (proto == STP_PROTO_SSTP) {
274 		if (len < 7)
275 			goto truncated;
276 		p += 1;
277 		len -= 1;
278 		if (EXTRACT_16BITS(p) == 0 && EXTRACT_16BITS(p + 2) == 0x02) {
279 			printf(" pvid=%u", EXTRACT_16BITS(p + 4));
280 			p += 6;
281 			len -= 6;
282 		}
283 	}
284 
285 	return;
286 
287 truncated:
288 	printf("[|802.1d]");
289 }
290 
291 static void
292 stp_print_tbpdu(const u_char *p, u_int len)
293 {
294 	printf(" tcn");
295 }
296