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