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