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
stp_print(const u_char * p,u_int len)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
stp_print_cbpdu(const u_char * p,u_int len,int proto)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
stp_print_tbpdu(const u_char * p,u_int len)292 stp_print_tbpdu(const u_char *p, u_int len)
293 {
294 printf(" tcn");
295 }
296