1685295f4SBill Fenner /*
2685295f4SBill Fenner * Copyright (c) 2000 Lennert Buytenhek
3685295f4SBill Fenner *
4685295f4SBill Fenner * This software may be distributed either under the terms of the
5685295f4SBill Fenner * BSD-style license that accompanies tcpdump or the GNU General
6685295f4SBill Fenner * Public License
7685295f4SBill Fenner *
8685295f4SBill Fenner * Contributed by Lennert Buytenhek <buytenh@gnu.org>
9685295f4SBill Fenner */
10685295f4SBill Fenner
113340d773SGleb Smirnoff /* \summary: IEEE 802.1d Spanning Tree Protocol (STP) printer */
123340d773SGleb Smirnoff
13ee67461eSJoseph Mingrone #include <config.h>
14685295f4SBill Fenner
15ee67461eSJoseph Mingrone #include "netdissect-stdinc.h"
16685295f4SBill Fenner
17685295f4SBill Fenner #include <stdio.h>
18685295f4SBill Fenner
193340d773SGleb Smirnoff #include "netdissect.h"
20685295f4SBill Fenner #include "extract.h"
21685295f4SBill Fenner
22af20afd0SAndrew Thompson #define RSTP_EXTRACT_PORT_ROLE(x) (((x)&0x0C)>>2)
23af20afd0SAndrew Thompson /* STP timers are expressed in multiples of 1/256th second */
24af20afd0SAndrew Thompson #define STP_TIME_BASE 256
25af20afd0SAndrew Thompson #define STP_BPDU_MSTP_MIN_LEN 102
26af20afd0SAndrew Thompson
27af20afd0SAndrew Thompson struct stp_bpdu_ {
28ee67461eSJoseph Mingrone nd_uint16_t protocol_id;
29ee67461eSJoseph Mingrone nd_uint8_t protocol_version;
30ee67461eSJoseph Mingrone nd_uint8_t bpdu_type;
31ee67461eSJoseph Mingrone nd_uint8_t flags;
32ee67461eSJoseph Mingrone nd_byte root_id[8];
33ee67461eSJoseph Mingrone nd_uint32_t root_path_cost;
34ee67461eSJoseph Mingrone nd_byte bridge_id[8];
35ee67461eSJoseph Mingrone nd_uint16_t port_id;
36ee67461eSJoseph Mingrone nd_uint16_t message_age;
37ee67461eSJoseph Mingrone nd_uint16_t max_age;
38ee67461eSJoseph Mingrone nd_uint16_t hello_time;
39ee67461eSJoseph Mingrone nd_uint16_t forward_delay;
40ee67461eSJoseph Mingrone nd_uint8_t v1_length;
41af20afd0SAndrew Thompson };
42af20afd0SAndrew Thompson
43af20afd0SAndrew Thompson #define STP_PROTO_REGULAR 0x00
44af20afd0SAndrew Thompson #define STP_PROTO_RAPID 0x02
45af20afd0SAndrew Thompson #define STP_PROTO_MSTP 0x03
46d03c0883SXin LI #define STP_PROTO_SPB 0x04
47af20afd0SAndrew Thompson
483c602fabSXin LI static const struct tok stp_proto_values[] = {
49af20afd0SAndrew Thompson { STP_PROTO_REGULAR, "802.1d" },
50af20afd0SAndrew Thompson { STP_PROTO_RAPID, "802.1w" },
51af20afd0SAndrew Thompson { STP_PROTO_MSTP, "802.1s" },
52d03c0883SXin LI { STP_PROTO_SPB, "802.1aq" },
53af20afd0SAndrew Thompson { 0, NULL}
54af20afd0SAndrew Thompson };
55af20afd0SAndrew Thompson
56af20afd0SAndrew Thompson #define STP_BPDU_TYPE_CONFIG 0x00
57af20afd0SAndrew Thompson #define STP_BPDU_TYPE_RSTP 0x02
58af20afd0SAndrew Thompson #define STP_BPDU_TYPE_TOPO_CHANGE 0x80
59af20afd0SAndrew Thompson
603c602fabSXin LI static const struct tok stp_bpdu_flag_values[] = {
61af20afd0SAndrew Thompson { 0x01, "Topology change" },
62af20afd0SAndrew Thompson { 0x02, "Proposal" },
63af20afd0SAndrew Thompson { 0x10, "Learn" },
64af20afd0SAndrew Thompson { 0x20, "Forward" },
65af20afd0SAndrew Thompson { 0x40, "Agreement" },
66af20afd0SAndrew Thompson { 0x80, "Topology change ACK" },
67af20afd0SAndrew Thompson { 0, NULL}
68af20afd0SAndrew Thompson };
69af20afd0SAndrew Thompson
703c602fabSXin LI static const struct tok stp_bpdu_type_values[] = {
71af20afd0SAndrew Thompson { STP_BPDU_TYPE_CONFIG, "Config" },
72af20afd0SAndrew Thompson { STP_BPDU_TYPE_RSTP, "Rapid STP" },
73af20afd0SAndrew Thompson { STP_BPDU_TYPE_TOPO_CHANGE, "Topology Change" },
74af20afd0SAndrew Thompson { 0, NULL}
75af20afd0SAndrew Thompson };
76af20afd0SAndrew Thompson
773c602fabSXin LI static const struct tok rstp_obj_port_role_values[] = {
78af20afd0SAndrew Thompson { 0x00, "Unknown" },
79af20afd0SAndrew Thompson { 0x01, "Alternate" },
80af20afd0SAndrew Thompson { 0x02, "Root" },
81af20afd0SAndrew Thompson { 0x03, "Designated" },
82af20afd0SAndrew Thompson { 0, NULL}
83af20afd0SAndrew Thompson };
84af20afd0SAndrew Thompson
85af20afd0SAndrew Thompson static char *
stp_print_bridge_id(netdissect_options * ndo,const u_char * p)86ee67461eSJoseph Mingrone stp_print_bridge_id(netdissect_options *ndo, const u_char *p)
87685295f4SBill Fenner {
88af20afd0SAndrew Thompson static char bridge_id_str[sizeof("pppp.aa:bb:cc:dd:ee:ff")];
89af20afd0SAndrew Thompson
90af20afd0SAndrew Thompson snprintf(bridge_id_str, sizeof(bridge_id_str),
91af20afd0SAndrew Thompson "%.2x%.2x.%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
92ee67461eSJoseph Mingrone GET_U_1(p), GET_U_1(p + 1), GET_U_1(p + 2),
93ee67461eSJoseph Mingrone GET_U_1(p + 3), GET_U_1(p + 4), GET_U_1(p + 5),
94ee67461eSJoseph Mingrone GET_U_1(p + 6), GET_U_1(p + 7));
95af20afd0SAndrew Thompson
96af20afd0SAndrew Thompson return bridge_id_str;
97685295f4SBill Fenner }
98685295f4SBill Fenner
99ee67461eSJoseph Mingrone static void
stp_print_config_bpdu(netdissect_options * ndo,const struct stp_bpdu_ * stp_bpdu,u_int length)1003c602fabSXin LI stp_print_config_bpdu(netdissect_options *ndo, const struct stp_bpdu_ *stp_bpdu,
1013c602fabSXin LI u_int length)
102685295f4SBill Fenner {
103ee67461eSJoseph Mingrone uint8_t bpdu_flags;
104685295f4SBill Fenner
105ee67461eSJoseph Mingrone bpdu_flags = GET_U_1(stp_bpdu->flags);
106ee67461eSJoseph Mingrone ND_PRINT(", Flags [%s]",
107ee67461eSJoseph Mingrone bittok2str(stp_bpdu_flag_values, "none", bpdu_flags));
108ee67461eSJoseph Mingrone
109ee67461eSJoseph Mingrone ND_PRINT(", bridge-id %s.%04x, length %u",
110ee67461eSJoseph Mingrone stp_print_bridge_id(ndo, stp_bpdu->bridge_id),
111ee67461eSJoseph Mingrone GET_BE_U_2(stp_bpdu->port_id), length);
112685295f4SBill Fenner
113af20afd0SAndrew Thompson /* in non-verbose mode just print the bridge-id */
1143c602fabSXin LI if (!ndo->ndo_vflag) {
115ee67461eSJoseph Mingrone return;
116685295f4SBill Fenner }
117685295f4SBill Fenner
118ee67461eSJoseph Mingrone ND_PRINT("\n\tmessage-age %.2fs, max-age %.2fs"
119af20afd0SAndrew Thompson ", hello-time %.2fs, forwarding-delay %.2fs",
120ee67461eSJoseph Mingrone (float) GET_BE_U_2(stp_bpdu->message_age) / STP_TIME_BASE,
121ee67461eSJoseph Mingrone (float) GET_BE_U_2(stp_bpdu->max_age) / STP_TIME_BASE,
122ee67461eSJoseph Mingrone (float) GET_BE_U_2(stp_bpdu->hello_time) / STP_TIME_BASE,
123ee67461eSJoseph Mingrone (float) GET_BE_U_2(stp_bpdu->forward_delay) / STP_TIME_BASE);
124af20afd0SAndrew Thompson
125ee67461eSJoseph Mingrone ND_PRINT("\n\troot-id %s, root-pathcost %u",
126ee67461eSJoseph Mingrone stp_print_bridge_id(ndo, stp_bpdu->root_id),
127ee67461eSJoseph Mingrone GET_BE_U_4(stp_bpdu->root_path_cost));
128af20afd0SAndrew Thompson
129af20afd0SAndrew Thompson /* Port role is only valid for 802.1w */
130ee67461eSJoseph Mingrone if (GET_U_1(stp_bpdu->protocol_version) == STP_PROTO_RAPID) {
131ee67461eSJoseph Mingrone ND_PRINT(", port-role %s",
132af20afd0SAndrew Thompson tok2str(rstp_obj_port_role_values, "Unknown",
133ee67461eSJoseph Mingrone RSTP_EXTRACT_PORT_ROLE(bpdu_flags)));
134af20afd0SAndrew Thompson }
135685295f4SBill Fenner }
136685295f4SBill Fenner
137685295f4SBill Fenner /*
138af20afd0SAndrew Thompson * MSTP packet format
139af20afd0SAndrew Thompson * Ref. IEEE 802.1Q 2003 Ed. Section 14
140af20afd0SAndrew Thompson *
141af20afd0SAndrew Thompson * MSTP BPDU
142af20afd0SAndrew Thompson *
143af20afd0SAndrew Thompson * 2 - bytes Protocol Id
144af20afd0SAndrew Thompson * 1 - byte Protocol Ver.
145ee67461eSJoseph Mingrone * 1 - byte BPDU type
146af20afd0SAndrew Thompson * 1 - byte Flags
147af20afd0SAndrew Thompson * 8 - bytes CIST Root Identifier
148af20afd0SAndrew Thompson * 4 - bytes CIST External Path Cost
149af20afd0SAndrew Thompson * 8 - bytes CIST Regional Root Identifier
150af20afd0SAndrew Thompson * 2 - bytes CIST Port Identifier
151af20afd0SAndrew Thompson * 2 - bytes Message Age
152af20afd0SAndrew Thompson * 2 - bytes Max age
153af20afd0SAndrew Thompson * 2 - bytes Hello Time
154af20afd0SAndrew Thompson * 2 - bytes Forward delay
155af20afd0SAndrew Thompson * 1 - byte Version 1 length. Must be 0
156af20afd0SAndrew Thompson * 2 - bytes Version 3 length
157af20afd0SAndrew Thompson * 1 - byte Config Identifier
158af20afd0SAndrew Thompson * 32 - bytes Config Name
159af20afd0SAndrew Thompson * 2 - bytes Revision level
160af20afd0SAndrew Thompson * 16 - bytes Config Digest [MD5]
161af20afd0SAndrew Thompson * 4 - bytes CIST Internal Root Path Cost
162af20afd0SAndrew Thompson * 8 - bytes CIST Bridge Identifier
163af20afd0SAndrew Thompson * 1 - byte CIST Remaining Hops
164af20afd0SAndrew Thompson * 16 - bytes MSTI information [Max 64 MSTI, each 16 bytes]
165af20afd0SAndrew Thompson *
166d03c0883SXin LI *
167d03c0883SXin LI * SPB BPDU
168d03c0883SXin LI * Ref. IEEE 802.1aq. Section 14
169d03c0883SXin LI *
170d03c0883SXin LI * 2 - bytes Version 4 length
171d03c0883SXin LI * 1 - byte Aux Config Identifier
172d03c0883SXin LI * 32 - bytes Aux Config Name
173d03c0883SXin LI * 2 - bytes Aux Revision level
174d03c0883SXin LI * 16 - bytes Aux Config Digest [MD5]
175d03c0883SXin LI * 1 - byte (1 - 2) Agreement Number
176d03c0883SXin LI * (3 - 4) Discarded Agreement Number
177d03c0883SXin LI * (5) Agreement Valid Flag
178d03c0883SXin LI * (6) Restricted Role Flag
179d03c0883SXin LI * (7 - 8) Unused sent zero
180d03c0883SXin LI * 1 - byte Unused
181d03c0883SXin LI * 1 - byte (1 - 4) Agreement Digest Format Identifier
182d03c0883SXin LI * (5 - 8) Agreement Digest Format Capabilities
183d03c0883SXin LI * 1 - byte (1 - 4) Agreement Digest Convention Identifier
184d03c0883SXin LI * (5 - 8) Agreement Digest Convention Capabilities
185d03c0883SXin LI * 2 - bytes Agreement Digest Edge Count
186d03c0883SXin LI * 8 - byte Reserved Set
187d03c0883SXin LI * 20 - bytes Computed Topology Digest
188d03c0883SXin LI *
189d03c0883SXin LI *
190af20afd0SAndrew Thompson * MSTI Payload
191af20afd0SAndrew Thompson *
192af20afd0SAndrew Thompson * 1 - byte MSTI flag
193af20afd0SAndrew Thompson * 8 - bytes MSTI Regional Root Identifier
194af20afd0SAndrew Thompson * 4 - bytes MSTI Regional Path Cost
195af20afd0SAndrew Thompson * 1 - byte MSTI Bridge Priority
196af20afd0SAndrew Thompson * 1 - byte MSTI Port Priority
197af20afd0SAndrew Thompson * 1 - byte MSTI Remaining Hops
198d03c0883SXin LI *
199af20afd0SAndrew Thompson */
200af20afd0SAndrew Thompson
201af20afd0SAndrew Thompson #define MST_BPDU_MSTI_LENGTH 16
202af20afd0SAndrew Thompson #define MST_BPDU_CONFIG_INFO_LENGTH 64
203af20afd0SAndrew Thompson
204ee67461eSJoseph Mingrone /* Offsets of fields from the beginning for the packet */
205af20afd0SAndrew Thompson #define MST_BPDU_VER3_LEN_OFFSET 36
206af20afd0SAndrew Thompson #define MST_BPDU_CONFIG_NAME_OFFSET 39
207af20afd0SAndrew Thompson #define MST_BPDU_CONFIG_DIGEST_OFFSET 73
208af20afd0SAndrew Thompson #define MST_BPDU_CIST_INT_PATH_COST_OFFSET 89
209af20afd0SAndrew Thompson #define MST_BPDU_CIST_BRIDGE_ID_OFFSET 93
210af20afd0SAndrew Thompson #define MST_BPDU_CIST_REMAIN_HOPS_OFFSET 101
211af20afd0SAndrew Thompson #define MST_BPDU_MSTI_OFFSET 102
212af20afd0SAndrew Thompson /* Offsets within an MSTI */
213af20afd0SAndrew Thompson #define MST_BPDU_MSTI_ROOT_PRIO_OFFSET 1
214af20afd0SAndrew Thompson #define MST_BPDU_MSTI_ROOT_PATH_COST_OFFSET 9
215af20afd0SAndrew Thompson #define MST_BPDU_MSTI_BRIDGE_PRIO_OFFSET 13
216af20afd0SAndrew Thompson #define MST_BPDU_MSTI_PORT_PRIO_OFFSET 14
217af20afd0SAndrew Thompson #define MST_BPDU_MSTI_REMAIN_HOPS_OFFSET 15
218af20afd0SAndrew Thompson
219d03c0883SXin LI #define SPB_BPDU_MIN_LEN 87
220d03c0883SXin LI #define SPB_BPDU_CONFIG_NAME_OFFSET 3
221d03c0883SXin LI #define SPB_BPDU_CONFIG_REV_OFFSET SPB_BPDU_CONFIG_NAME_OFFSET + 32
222d03c0883SXin LI #define SPB_BPDU_CONFIG_DIGEST_OFFSET SPB_BPDU_CONFIG_REV_OFFSET + 2
223d03c0883SXin LI #define SPB_BPDU_AGREEMENT_OFFSET SPB_BPDU_CONFIG_DIGEST_OFFSET + 16
224d03c0883SXin LI #define SPB_BPDU_AGREEMENT_UNUSED_OFFSET SPB_BPDU_AGREEMENT_OFFSET + 1
225d03c0883SXin LI #define SPB_BPDU_AGREEMENT_FORMAT_OFFSET SPB_BPDU_AGREEMENT_UNUSED_OFFSET + 1
226d03c0883SXin LI #define SPB_BPDU_AGREEMENT_CON_OFFSET SPB_BPDU_AGREEMENT_FORMAT_OFFSET + 1
227d03c0883SXin LI #define SPB_BPDU_AGREEMENT_EDGE_OFFSET SPB_BPDU_AGREEMENT_CON_OFFSET + 1
228d03c0883SXin LI #define SPB_BPDU_AGREEMENT_RES1_OFFSET SPB_BPDU_AGREEMENT_EDGE_OFFSET + 2
229d03c0883SXin LI #define SPB_BPDU_AGREEMENT_RES2_OFFSET SPB_BPDU_AGREEMENT_RES1_OFFSET + 4
230d03c0883SXin LI #define SPB_BPDU_AGREEMENT_DIGEST_OFFSET SPB_BPDU_AGREEMENT_RES2_OFFSET + 4
231d03c0883SXin LI
232ee67461eSJoseph Mingrone static void
stp_print_mstp_bpdu(netdissect_options * ndo,const struct stp_bpdu_ * stp_bpdu,u_int length)2333c602fabSXin LI stp_print_mstp_bpdu(netdissect_options *ndo, const struct stp_bpdu_ *stp_bpdu,
2343c602fabSXin LI u_int length)
235af20afd0SAndrew Thompson {
236af20afd0SAndrew Thompson const u_char *ptr;
237ee67461eSJoseph Mingrone uint8_t bpdu_flags;
2383c602fabSXin LI uint16_t v3len;
2393c602fabSXin LI uint16_t len;
2403c602fabSXin LI uint16_t msti;
2413c602fabSXin LI u_int offset;
242af20afd0SAndrew Thompson
243af20afd0SAndrew Thompson ptr = (const u_char *)stp_bpdu;
244ee67461eSJoseph Mingrone bpdu_flags = GET_U_1(stp_bpdu->flags);
245ee67461eSJoseph Mingrone ND_PRINT(", CIST Flags [%s], length %u",
246ee67461eSJoseph Mingrone bittok2str(stp_bpdu_flag_values, "none", bpdu_flags), length);
247af20afd0SAndrew Thompson
248af20afd0SAndrew Thompson /*
2493c602fabSXin LI * in non-verbose mode just print the flags.
250af20afd0SAndrew Thompson */
2513c602fabSXin LI if (!ndo->ndo_vflag) {
252ee67461eSJoseph Mingrone return;
253af20afd0SAndrew Thompson }
254af20afd0SAndrew Thompson
255ee67461eSJoseph Mingrone ND_PRINT("\n\tport-role %s, ",
256d03c0883SXin LI tok2str(rstp_obj_port_role_values, "Unknown",
257ee67461eSJoseph Mingrone RSTP_EXTRACT_PORT_ROLE(bpdu_flags)));
258af20afd0SAndrew Thompson
259ee67461eSJoseph Mingrone ND_PRINT("CIST root-id %s, CIST ext-pathcost %u",
260ee67461eSJoseph Mingrone stp_print_bridge_id(ndo, stp_bpdu->root_id),
261ee67461eSJoseph Mingrone GET_BE_U_4(stp_bpdu->root_path_cost));
262d03c0883SXin LI
263ee67461eSJoseph Mingrone ND_PRINT("\n\tCIST regional-root-id %s, ",
264ee67461eSJoseph Mingrone stp_print_bridge_id(ndo, stp_bpdu->bridge_id));
265d03c0883SXin LI
266ee67461eSJoseph Mingrone ND_PRINT("CIST port-id %04x,", GET_BE_U_2(stp_bpdu->port_id));
267af20afd0SAndrew Thompson
268ee67461eSJoseph Mingrone ND_PRINT("\n\tmessage-age %.2fs, max-age %.2fs"
269af20afd0SAndrew Thompson ", hello-time %.2fs, forwarding-delay %.2fs",
270ee67461eSJoseph Mingrone (float) GET_BE_U_2(stp_bpdu->message_age) / STP_TIME_BASE,
271ee67461eSJoseph Mingrone (float) GET_BE_U_2(stp_bpdu->max_age) / STP_TIME_BASE,
272ee67461eSJoseph Mingrone (float) GET_BE_U_2(stp_bpdu->hello_time) / STP_TIME_BASE,
273ee67461eSJoseph Mingrone (float) GET_BE_U_2(stp_bpdu->forward_delay) / STP_TIME_BASE);
274af20afd0SAndrew Thompson
275ee67461eSJoseph Mingrone ND_PRINT("\n\tv3len %u, ", GET_BE_U_2(ptr + MST_BPDU_VER3_LEN_OFFSET));
276ee67461eSJoseph Mingrone ND_PRINT("MCID Name ");
277ee67461eSJoseph Mingrone nd_printjnp(ndo, ptr + MST_BPDU_CONFIG_NAME_OFFSET, 32);
278ee67461eSJoseph Mingrone ND_PRINT(", rev %u,"
279d03c0883SXin LI "\n\t\tdigest %08x%08x%08x%08x, ",
280ee67461eSJoseph Mingrone GET_BE_U_2(ptr + MST_BPDU_CONFIG_NAME_OFFSET + 32),
281ee67461eSJoseph Mingrone GET_BE_U_4(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET),
282ee67461eSJoseph Mingrone GET_BE_U_4(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET + 4),
283ee67461eSJoseph Mingrone GET_BE_U_4(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET + 8),
284ee67461eSJoseph Mingrone GET_BE_U_4(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET + 12));
285af20afd0SAndrew Thompson
286ee67461eSJoseph Mingrone ND_PRINT("CIST int-root-pathcost %u,",
287ee67461eSJoseph Mingrone GET_BE_U_4(ptr + MST_BPDU_CIST_INT_PATH_COST_OFFSET));
288d03c0883SXin LI
289ee67461eSJoseph Mingrone ND_PRINT("\n\tCIST bridge-id %s, ",
290ee67461eSJoseph Mingrone stp_print_bridge_id(ndo, ptr + MST_BPDU_CIST_BRIDGE_ID_OFFSET));
291d03c0883SXin LI
292ee67461eSJoseph Mingrone ND_PRINT("CIST remaining-hops %u",
293ee67461eSJoseph Mingrone GET_U_1(ptr + MST_BPDU_CIST_REMAIN_HOPS_OFFSET));
294af20afd0SAndrew Thompson
295af20afd0SAndrew Thompson /* Dump all MSTI's */
296ee67461eSJoseph Mingrone v3len = GET_BE_U_2(ptr + MST_BPDU_VER3_LEN_OFFSET);
297af20afd0SAndrew Thompson if (v3len > MST_BPDU_CONFIG_INFO_LENGTH) {
298af20afd0SAndrew Thompson len = v3len - MST_BPDU_CONFIG_INFO_LENGTH;
299af20afd0SAndrew Thompson offset = MST_BPDU_MSTI_OFFSET;
300af20afd0SAndrew Thompson while (len >= MST_BPDU_MSTI_LENGTH) {
301ee67461eSJoseph Mingrone msti = GET_BE_U_2(ptr + offset + MST_BPDU_MSTI_ROOT_PRIO_OFFSET);
302af20afd0SAndrew Thompson msti = msti & 0x0FFF;
303af20afd0SAndrew Thompson
304ee67461eSJoseph Mingrone ND_PRINT("\n\tMSTI %u, Flags [%s], port-role %s",
305ee67461eSJoseph Mingrone msti,
306ee67461eSJoseph Mingrone bittok2str(stp_bpdu_flag_values, "none", GET_U_1(ptr + offset)),
307af20afd0SAndrew Thompson tok2str(rstp_obj_port_role_values, "Unknown",
308ee67461eSJoseph Mingrone RSTP_EXTRACT_PORT_ROLE(GET_U_1(ptr + offset))));
309ee67461eSJoseph Mingrone ND_PRINT("\n\t\tMSTI regional-root-id %s, pathcost %u",
310ee67461eSJoseph Mingrone stp_print_bridge_id(ndo, ptr + offset +
311af20afd0SAndrew Thompson MST_BPDU_MSTI_ROOT_PRIO_OFFSET),
312ee67461eSJoseph Mingrone GET_BE_U_4(ptr + offset + MST_BPDU_MSTI_ROOT_PATH_COST_OFFSET));
313ee67461eSJoseph Mingrone ND_PRINT("\n\t\tMSTI bridge-prio %u, port-prio %u, hops %u",
314ee67461eSJoseph Mingrone GET_U_1(ptr + offset + MST_BPDU_MSTI_BRIDGE_PRIO_OFFSET) >> 4,
315ee67461eSJoseph Mingrone GET_U_1(ptr + offset + MST_BPDU_MSTI_PORT_PRIO_OFFSET) >> 4,
316ee67461eSJoseph Mingrone GET_U_1(ptr + offset + MST_BPDU_MSTI_REMAIN_HOPS_OFFSET));
317af20afd0SAndrew Thompson
318af20afd0SAndrew Thompson len -= MST_BPDU_MSTI_LENGTH;
319af20afd0SAndrew Thompson offset += MST_BPDU_MSTI_LENGTH;
320af20afd0SAndrew Thompson }
321af20afd0SAndrew Thompson }
3223c602fabSXin LI }
323d03c0883SXin LI
324ee67461eSJoseph Mingrone static void
stp_print_spb_bpdu(netdissect_options * ndo,const struct stp_bpdu_ * stp_bpdu,u_int offset)3253c602fabSXin LI stp_print_spb_bpdu(netdissect_options *ndo, const struct stp_bpdu_ *stp_bpdu,
3263c602fabSXin LI u_int offset)
327d03c0883SXin LI {
3283c602fabSXin LI const u_char *ptr;
3293c602fabSXin LI
3303c602fabSXin LI /*
3313c602fabSXin LI * in non-verbose mode don't print anything.
3323c602fabSXin LI */
3333c602fabSXin LI if (!ndo->ndo_vflag) {
334ee67461eSJoseph Mingrone return;
3353c602fabSXin LI }
3363c602fabSXin LI
3373c602fabSXin LI ptr = (const u_char *)stp_bpdu;
3383340d773SGleb Smirnoff
339ee67461eSJoseph Mingrone ND_PRINT("\n\tv4len %u, ", GET_BE_U_2(ptr + offset));
340ee67461eSJoseph Mingrone ND_PRINT("AUXMCID Name ");
341ee67461eSJoseph Mingrone nd_printjnp(ndo, ptr + offset + SPB_BPDU_CONFIG_NAME_OFFSET, 32);
342ee67461eSJoseph Mingrone ND_PRINT(", Rev %u,\n\t\tdigest %08x%08x%08x%08x",
343ee67461eSJoseph Mingrone GET_BE_U_2(ptr + offset + SPB_BPDU_CONFIG_REV_OFFSET),
344ee67461eSJoseph Mingrone GET_BE_U_4(ptr + offset + SPB_BPDU_CONFIG_DIGEST_OFFSET),
345ee67461eSJoseph Mingrone GET_BE_U_4(ptr + offset + SPB_BPDU_CONFIG_DIGEST_OFFSET + 4),
346ee67461eSJoseph Mingrone GET_BE_U_4(ptr + offset + SPB_BPDU_CONFIG_DIGEST_OFFSET + 8),
347ee67461eSJoseph Mingrone GET_BE_U_4(ptr + offset + SPB_BPDU_CONFIG_DIGEST_OFFSET + 12));
348d03c0883SXin LI
349ee67461eSJoseph Mingrone ND_PRINT("\n\tAgreement num %u, Discarded Agreement num %u, Agreement valid-"
350ee67461eSJoseph Mingrone "flag %u,\n\tRestricted role-flag: %u, Format id %u cap %u, "
351ee67461eSJoseph Mingrone "Convention id %u cap %u,\n\tEdge count %u, "
352ee67461eSJoseph Mingrone "Agreement digest %08x%08x%08x%08x%08x",
353ee67461eSJoseph Mingrone GET_U_1(ptr + offset + SPB_BPDU_AGREEMENT_OFFSET)>>6,
354ee67461eSJoseph Mingrone GET_U_1(ptr + offset + SPB_BPDU_AGREEMENT_OFFSET)>>4 & 0x3,
355ee67461eSJoseph Mingrone GET_U_1(ptr + offset + SPB_BPDU_AGREEMENT_OFFSET)>>3 & 0x1,
356ee67461eSJoseph Mingrone GET_U_1(ptr + offset + SPB_BPDU_AGREEMENT_OFFSET)>>2 & 0x1,
357ee67461eSJoseph Mingrone GET_U_1(ptr + offset + SPB_BPDU_AGREEMENT_FORMAT_OFFSET)>>4,
358ee67461eSJoseph Mingrone GET_U_1(ptr + offset + SPB_BPDU_AGREEMENT_FORMAT_OFFSET)&0x00ff,
359ee67461eSJoseph Mingrone GET_U_1(ptr + offset + SPB_BPDU_AGREEMENT_CON_OFFSET)>>4,
360ee67461eSJoseph Mingrone GET_U_1(ptr + offset + SPB_BPDU_AGREEMENT_CON_OFFSET)&0x00ff,
361ee67461eSJoseph Mingrone GET_BE_U_2(ptr + offset + SPB_BPDU_AGREEMENT_EDGE_OFFSET),
362ee67461eSJoseph Mingrone GET_BE_U_4(ptr + offset + SPB_BPDU_AGREEMENT_DIGEST_OFFSET),
363ee67461eSJoseph Mingrone GET_BE_U_4(ptr + offset + SPB_BPDU_AGREEMENT_DIGEST_OFFSET + 4),
364ee67461eSJoseph Mingrone GET_BE_U_4(ptr + offset + SPB_BPDU_AGREEMENT_DIGEST_OFFSET + 8),
365ee67461eSJoseph Mingrone GET_BE_U_4(ptr + offset + SPB_BPDU_AGREEMENT_DIGEST_OFFSET + 12),
366ee67461eSJoseph Mingrone GET_BE_U_4(ptr + offset + SPB_BPDU_AGREEMENT_DIGEST_OFFSET + 16));
367af20afd0SAndrew Thompson }
368af20afd0SAndrew Thompson
369af20afd0SAndrew Thompson /*
370d03c0883SXin LI * Print 802.1d / 802.1w / 802.1q (mstp) / 802.1aq (spb) packets.
371685295f4SBill Fenner */
372685295f4SBill Fenner void
stp_print(netdissect_options * ndo,const u_char * p,u_int length)3733c602fabSXin LI stp_print(netdissect_options *ndo, const u_char *p, u_int length)
374685295f4SBill Fenner {
375af20afd0SAndrew Thompson const struct stp_bpdu_ *stp_bpdu;
376ee67461eSJoseph Mingrone u_int protocol_version;
377ee67461eSJoseph Mingrone u_int bpdu_type;
3783c602fabSXin LI u_int mstp_len;
3793c602fabSXin LI u_int spb_len;
380af20afd0SAndrew Thompson
381ee67461eSJoseph Mingrone ndo->ndo_protocol = "stp";
3823340d773SGleb Smirnoff stp_bpdu = (const struct stp_bpdu_*)p;
383af20afd0SAndrew Thompson
384af20afd0SAndrew Thompson /* Minimum STP Frame size. */
385f4d0c64aSSam Leffler if (length < 4)
386ee67461eSJoseph Mingrone goto invalid;
387685295f4SBill Fenner
388ee67461eSJoseph Mingrone if (GET_BE_U_2(stp_bpdu->protocol_id)) {
389ee67461eSJoseph Mingrone ND_PRINT("unknown STP version, length %u", length);
390685295f4SBill Fenner return;
391685295f4SBill Fenner }
392685295f4SBill Fenner
393ee67461eSJoseph Mingrone protocol_version = GET_U_1(stp_bpdu->protocol_version);
394ee67461eSJoseph Mingrone ND_PRINT("STP %s", tok2str(stp_proto_values, "Unknown STP protocol (0x%02x)",
395ee67461eSJoseph Mingrone protocol_version));
396af20afd0SAndrew Thompson
397ee67461eSJoseph Mingrone switch (protocol_version) {
398af20afd0SAndrew Thompson case STP_PROTO_REGULAR:
399af20afd0SAndrew Thompson case STP_PROTO_RAPID:
400af20afd0SAndrew Thompson case STP_PROTO_MSTP:
401d03c0883SXin LI case STP_PROTO_SPB:
402af20afd0SAndrew Thompson break;
403af20afd0SAndrew Thompson default:
404af20afd0SAndrew Thompson return;
405af20afd0SAndrew Thompson }
406af20afd0SAndrew Thompson
407ee67461eSJoseph Mingrone bpdu_type = GET_U_1(stp_bpdu->bpdu_type);
408ee67461eSJoseph Mingrone ND_PRINT(", %s", tok2str(stp_bpdu_type_values, "Unknown BPDU Type (0x%02x)",
409ee67461eSJoseph Mingrone bpdu_type));
410af20afd0SAndrew Thompson
411ee67461eSJoseph Mingrone switch (bpdu_type) {
412af20afd0SAndrew Thompson case STP_BPDU_TYPE_CONFIG:
413af20afd0SAndrew Thompson if (length < sizeof(struct stp_bpdu_) - 1) {
414ee67461eSJoseph Mingrone goto invalid;
415af20afd0SAndrew Thompson }
416ee67461eSJoseph Mingrone stp_print_config_bpdu(ndo, stp_bpdu, length);
417685295f4SBill Fenner break;
418685295f4SBill Fenner
419af20afd0SAndrew Thompson case STP_BPDU_TYPE_RSTP:
420ee67461eSJoseph Mingrone if (protocol_version == STP_PROTO_RAPID) {
421af20afd0SAndrew Thompson if (length < sizeof(struct stp_bpdu_)) {
422ee67461eSJoseph Mingrone goto invalid;
423af20afd0SAndrew Thompson }
424ee67461eSJoseph Mingrone stp_print_config_bpdu(ndo, stp_bpdu, length);
425ee67461eSJoseph Mingrone } else if (protocol_version == STP_PROTO_MSTP ||
426ee67461eSJoseph Mingrone protocol_version == STP_PROTO_SPB) {
427af20afd0SAndrew Thompson if (length < STP_BPDU_MSTP_MIN_LEN) {
428ee67461eSJoseph Mingrone goto invalid;
429af20afd0SAndrew Thompson }
430d03c0883SXin LI
431ee67461eSJoseph Mingrone if (GET_U_1(stp_bpdu->v1_length) != 0) {
432af20afd0SAndrew Thompson /* FIX ME: Emit a message here ? */
433ee67461eSJoseph Mingrone goto invalid;
434af20afd0SAndrew Thompson }
435d03c0883SXin LI
436af20afd0SAndrew Thompson /* Validate v3 length */
437ee67461eSJoseph Mingrone mstp_len = GET_BE_U_2(p + MST_BPDU_VER3_LEN_OFFSET);
438af20afd0SAndrew Thompson mstp_len += 2; /* length encoding itself is 2 bytes */
439af20afd0SAndrew Thompson if (length < (sizeof(struct stp_bpdu_) + mstp_len)) {
440ee67461eSJoseph Mingrone goto invalid;
441af20afd0SAndrew Thompson }
442ee67461eSJoseph Mingrone stp_print_mstp_bpdu(ndo, stp_bpdu, length);
443d03c0883SXin LI
444*0a7e5f1fSJoseph Mingrone if (protocol_version == STP_PROTO_SPB) {
445d03c0883SXin LI /* Validate v4 length */
446ee67461eSJoseph Mingrone spb_len = GET_BE_U_2(p + MST_BPDU_VER3_LEN_OFFSET + mstp_len);
447d03c0883SXin LI spb_len += 2;
448d03c0883SXin LI if (length < (sizeof(struct stp_bpdu_) + mstp_len + spb_len) ||
449d03c0883SXin LI spb_len < SPB_BPDU_MIN_LEN) {
450ee67461eSJoseph Mingrone goto invalid;
451d03c0883SXin LI }
452ee67461eSJoseph Mingrone stp_print_spb_bpdu(ndo, stp_bpdu, (sizeof(struct stp_bpdu_) + mstp_len));
453d03c0883SXin LI }
454af20afd0SAndrew Thompson }
455af20afd0SAndrew Thompson break;
456af20afd0SAndrew Thompson
457af20afd0SAndrew Thompson case STP_BPDU_TYPE_TOPO_CHANGE:
458af20afd0SAndrew Thompson /* always empty message - just break out */
459685295f4SBill Fenner break;
460685295f4SBill Fenner
461685295f4SBill Fenner default:
462685295f4SBill Fenner break;
463685295f4SBill Fenner }
464685295f4SBill Fenner return;
465af20afd0SAndrew Thompson
466ee67461eSJoseph Mingrone invalid:
467ee67461eSJoseph Mingrone nd_print_invalid(ndo);
468ee67461eSJoseph Mingrone }
469