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