xref: /openbsd-src/usr.sbin/tcpdump/print-stp.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: print-stp.c,v 1.7 2007/06/04 15:10:12 henning 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/param.h>
34 #include <sys/time.h>
35 #include <sys/socket.h>
36 #include <sys/file.h>
37 #include <sys/ioctl.h>
38 
39 struct mbuf;
40 struct rtentry;
41 #include <net/if.h>
42 
43 #include <netinet/in.h>
44 #include <netinet/in_systm.h>
45 #include <netinet/ip.h>
46 
47 #include <ctype.h>
48 #include <netdb.h>
49 #include <pcap.h>
50 #include <signal.h>
51 #include <stdio.h>
52 
53 #include <netinet/if_ether.h>
54 #include "ethertype.h"
55 
56 #include <net/ppp_defs.h>
57 #include "interface.h"
58 #include "addrtoname.h"
59 #include "extract.h"
60 #include "llc.h"
61 
62 #define	STP_MSGTYPE_CBPDU	0x00
63 #define	STP_MSGTYPE_RSTP	0x02
64 #define	STP_MSGTYPE_TBPDU	0x80
65 
66 #define	STP_FLAGS_STPMASK	0x81		/* strip unused STP flags */
67 #define	STP_FLAGS_RSTPMASK	0x7f		/* strip unused RSTP flags */
68 #define	STP_FLAGS_TC		0x01		/* Topology change */
69 #define	STP_FLAGS_P		0x02		/* Proposal flag */
70 #define	STP_FLAGS_ROLE		0x0c		/* Port Role */
71 #define	STP_FLAGS_ROLE_S	2		/* Port Role offset */
72 #define	STP_FLAGS_ROLE_ALT	1		/* Alt/Backup port */
73 #define	STP_FLAGS_ROLE_ROOT	2		/* Root port */
74 #define	STP_FLAGS_ROLE_DESG	3		/* Designated port */
75 #define	STP_FLAGS_L		0x10		/* Learning flag */
76 #define	STP_FLAGS_F		0x20		/* Forwarding flag */
77 #define	STP_FLAGS_A		0x40		/* Agreement flag */
78 #define	STP_FLAGS_TCA		0x80		/* Topology change ack */
79 #define STP_FLAGS_BITS								\
80 	"\20\1TC\2PROPOSAL\5LEARNING\6FORWARDING\7AGREED\10TCACK"
81 
82 enum {
83 	STP_PROTO_STP	= 0x00,
84 	STP_PROTO_RSTP	= 0x02,
85 	STP_PROTO_SSTP	= 0x10	/* Cizzco-Eeeh */
86 };
87 
88 static void stp_print_cbpdu(const u_char *, u_int, int);
89 static void stp_print_tbpdu(const u_char *, u_int);
90 
91 void
92 stp_print(p, len)
93 	const u_char *p;
94 	u_int len;
95 {
96 	u_int16_t id;
97 	int proto = STP_PROTO_STP;
98 
99 	if (len < 3)
100 		goto truncated;
101 	if (p[0] == LLCSAP_8021D && p[1] == LLCSAP_8021D && p[2] == LLC_UI)
102 		printf("802.1d");
103 	else if (p[0] == LLCSAP_SNAP && p[1] == LLCSAP_SNAP && p[2] == LLC_UI) {
104 		proto = STP_PROTO_SSTP;
105 		printf("SSTP");
106 		p += 5;
107 		len -= 5;
108 	} else {
109 		printf("invalid protocol");
110 		return;
111 	}
112 	p += 3;
113 	len -= 3;
114 
115 	if (len < 3)
116 		goto truncated;
117 	id = EXTRACT_16BITS(p);
118 	if (id != 0) {
119 		printf(" unknown protocol id(0x%x)", id);
120 		return;
121 	}
122 	switch (p[2]) {
123 	case STP_PROTO_STP:
124 		printf(" STP");
125 		break;
126 	case STP_PROTO_RSTP:
127 		printf(" RSTP");
128 		break;
129 	default:
130 		printf(" unknown protocol ver(0x%x)", p[2]);
131 		return;
132 	}
133 	p += 3;
134 	len -= 3;
135 
136 	if (len < 1)
137 		goto truncated;
138 	switch (*p) {
139 	case STP_MSGTYPE_CBPDU:
140 		stp_print_cbpdu(p, len, proto);
141 		break;
142 	case STP_MSGTYPE_RSTP:
143 		stp_print_cbpdu(p, len, STP_PROTO_RSTP);
144 		break;
145 	case STP_MSGTYPE_TBPDU:
146 		stp_print_tbpdu(p, len);
147 		break;
148 	default:
149 		printf(" unknown message (0x%02x)", *p);
150 		break;
151 	}
152 
153 	return;
154 
155 truncated:
156 	printf("[|802.1d]");
157 }
158 
159 static void
160 stp_print_cbpdu(p, len, proto)
161 	const u_char *p;
162 	u_int len;
163 	int proto;
164 {
165 	u_int32_t cost;
166 	u_int16_t t;
167 	u_int8_t flags, role;
168 	int x;
169 
170 	p += 1;
171 	len -= 1;
172 
173 	printf(" config");
174 
175 	if (len < 1)
176 		goto truncated;
177 	if (*p) {
178 		switch (proto) {
179 		case STP_PROTO_STP:
180 		case STP_PROTO_SSTP:
181 			flags = *p & STP_FLAGS_STPMASK;
182 			role = STP_FLAGS_ROLE_DESG;
183 			break;
184 		case STP_PROTO_RSTP:
185 		default:
186 			flags = *p & STP_FLAGS_RSTPMASK;
187 			role = (flags & STP_FLAGS_ROLE) >> STP_FLAGS_ROLE_S;
188 			break;
189 		}
190 
191 		printb(" flags", flags, STP_FLAGS_BITS);
192 		switch (role) {
193 		case STP_FLAGS_ROLE_ALT:
194 			printf(" role=ALT/BACKUP");
195 			break;
196 		case STP_FLAGS_ROLE_ROOT:
197 			printf(" role=ROOT");
198 			break;
199 		case STP_FLAGS_ROLE_DESG:
200 			printf(" role=DESIGNATED");
201 			break;
202 		}
203 	}
204 	p += 1;
205 	len -= 1;
206 
207 	if (len < 8)
208 		goto truncated;
209 	printf(" root=");
210 	printf("%x.", EXTRACT_16BITS(p));
211 	p += 2;
212 	len -= 2;
213 	for (x = 0; x < 6; x++) {
214 		printf("%s%x", (x != 0) ? ":" : "", *p);
215 		p++;
216 		len--;
217 	}
218 
219 	if (len < 4)
220 		goto truncated;
221 	cost = EXTRACT_32BITS(p);
222 	printf(" rootcost=%u", cost);
223 	p += 4;
224 	len -= 4;
225 
226 	if (len < 8)
227 		goto truncated;
228 	printf(" bridge=");
229 	printf("%x.", EXTRACT_16BITS(p));
230 	p += 2;
231 	len -= 2;
232 	for (x = 0; x < 6; x++) {
233 		printf("%s%x", (x != 0) ? ":" : "", *p);
234 		p++;
235 		len--;
236 	}
237 
238 	if (len < 2)
239 		goto truncated;
240 	t = EXTRACT_16BITS(p);
241 	switch (proto) {
242 	case STP_PROTO_STP:
243 	case STP_PROTO_SSTP:
244 		printf(" port=%u", t & 0xff);
245 		printf(" ifcost=%u", t >> 8);
246 		break;
247 	case STP_PROTO_RSTP:
248 	default:
249 		printf(" port=%u", t & 0xfff);
250 		printf(" ifcost=%u", t >> 8);
251 		break;
252 	}
253 	p += 2;
254 	len -= 2;
255 
256 	if (len < 2)
257 		goto truncated;
258 	printf(" age=%u/%u", p[0], p[1]);
259 	p += 2;
260 	len -= 2;
261 
262 	if (len < 2)
263 		goto truncated;
264 	printf(" max=%u/%u", p[0], p[1]);
265 	p += 2;
266 	len -= 2;
267 
268 	if (len < 2)
269 		goto truncated;
270 	printf(" hello=%u/%u", p[0], p[1]);
271 	p += 2;
272 	len -= 2;
273 
274 	if (len < 2)
275 		goto truncated;
276 	printf(" fwdelay=%u/%u", p[0], p[1]);
277 	p += 2;
278 	len -= 2;
279 
280 	if (proto == STP_PROTO_SSTP) {
281 		if (len < 7)
282 			goto truncated;
283 		p += 1;
284 		len -= 1;
285 		if (EXTRACT_16BITS(p) == 0 && EXTRACT_16BITS(p + 2) == 0x02) {
286 			printf(" pvid=%u", EXTRACT_16BITS(p + 4));
287 			p += 6;
288 			len -= 6;
289 		}
290 	}
291 
292 	return;
293 
294 truncated:
295 	printf("[|802.1d]");
296 }
297 
298 static void
299 stp_print_tbpdu(p, len)
300 	const u_char *p;
301 	u_int len;
302 {
303 	printf(" tcn");
304 }
305