141c99275SPeter Avalos /*
241c99275SPeter Avalos * Copyright (c) 2000 Lennert Buytenhek
341c99275SPeter Avalos *
441c99275SPeter Avalos * This software may be distributed either under the terms of the
541c99275SPeter Avalos * BSD-style license that accompanies tcpdump or the GNU General
641c99275SPeter Avalos * Public License
741c99275SPeter Avalos *
841c99275SPeter Avalos * Contributed by Lennert Buytenhek <buytenh@gnu.org>
941c99275SPeter Avalos */
1041c99275SPeter Avalos
11411677aeSAaron LI /* \summary: IEEE 802.1d Spanning Tree Protocol (STP) printer */
1241c99275SPeter Avalos
1341c99275SPeter Avalos #ifdef HAVE_CONFIG_H
14*ed775ee7SAntonio Huete Jimenez #include <config.h>
1541c99275SPeter Avalos #endif
1641c99275SPeter Avalos
17*ed775ee7SAntonio Huete Jimenez #include "netdissect-stdinc.h"
1841c99275SPeter Avalos
1941c99275SPeter Avalos #include <stdio.h>
2041c99275SPeter Avalos
21411677aeSAaron LI #include "netdissect.h"
2241c99275SPeter Avalos #include "extract.h"
2341c99275SPeter Avalos
2441c99275SPeter Avalos #define RSTP_EXTRACT_PORT_ROLE(x) (((x)&0x0C)>>2)
2541c99275SPeter Avalos /* STP timers are expressed in multiples of 1/256th second */
2641c99275SPeter Avalos #define STP_TIME_BASE 256
2741c99275SPeter Avalos #define STP_BPDU_MSTP_MIN_LEN 102
2841c99275SPeter Avalos
2941c99275SPeter Avalos struct stp_bpdu_ {
30*ed775ee7SAntonio Huete Jimenez nd_uint16_t protocol_id;
31*ed775ee7SAntonio Huete Jimenez nd_uint8_t protocol_version;
32*ed775ee7SAntonio Huete Jimenez nd_uint8_t bpdu_type;
33*ed775ee7SAntonio Huete Jimenez nd_uint8_t flags;
34*ed775ee7SAntonio Huete Jimenez nd_byte root_id[8];
35*ed775ee7SAntonio Huete Jimenez nd_uint32_t root_path_cost;
36*ed775ee7SAntonio Huete Jimenez nd_byte bridge_id[8];
37*ed775ee7SAntonio Huete Jimenez nd_uint16_t port_id;
38*ed775ee7SAntonio Huete Jimenez nd_uint16_t message_age;
39*ed775ee7SAntonio Huete Jimenez nd_uint16_t max_age;
40*ed775ee7SAntonio Huete Jimenez nd_uint16_t hello_time;
41*ed775ee7SAntonio Huete Jimenez nd_uint16_t forward_delay;
42*ed775ee7SAntonio Huete Jimenez nd_uint8_t v1_length;
4341c99275SPeter Avalos };
4441c99275SPeter Avalos
4541c99275SPeter Avalos #define STP_PROTO_REGULAR 0x00
4641c99275SPeter Avalos #define STP_PROTO_RAPID 0x02
4741c99275SPeter Avalos #define STP_PROTO_MSTP 0x03
48411677aeSAaron LI #define STP_PROTO_SPB 0x04
4941c99275SPeter Avalos
50411677aeSAaron LI static const struct tok stp_proto_values[] = {
5141c99275SPeter Avalos { STP_PROTO_REGULAR, "802.1d" },
5241c99275SPeter Avalos { STP_PROTO_RAPID, "802.1w" },
5341c99275SPeter Avalos { STP_PROTO_MSTP, "802.1s" },
54411677aeSAaron LI { STP_PROTO_SPB, "802.1aq" },
5541c99275SPeter Avalos { 0, NULL}
5641c99275SPeter Avalos };
5741c99275SPeter Avalos
5841c99275SPeter Avalos #define STP_BPDU_TYPE_CONFIG 0x00
5941c99275SPeter Avalos #define STP_BPDU_TYPE_RSTP 0x02
6041c99275SPeter Avalos #define STP_BPDU_TYPE_TOPO_CHANGE 0x80
6141c99275SPeter Avalos
62411677aeSAaron LI static const struct tok stp_bpdu_flag_values[] = {
6341c99275SPeter Avalos { 0x01, "Topology change" },
6441c99275SPeter Avalos { 0x02, "Proposal" },
6541c99275SPeter Avalos { 0x10, "Learn" },
6641c99275SPeter Avalos { 0x20, "Forward" },
6741c99275SPeter Avalos { 0x40, "Agreement" },
6841c99275SPeter Avalos { 0x80, "Topology change ACK" },
6941c99275SPeter Avalos { 0, NULL}
7041c99275SPeter Avalos };
7141c99275SPeter Avalos
72411677aeSAaron LI static const struct tok stp_bpdu_type_values[] = {
7341c99275SPeter Avalos { STP_BPDU_TYPE_CONFIG, "Config" },
7441c99275SPeter Avalos { STP_BPDU_TYPE_RSTP, "Rapid STP" },
7541c99275SPeter Avalos { STP_BPDU_TYPE_TOPO_CHANGE, "Topology Change" },
7641c99275SPeter Avalos { 0, NULL}
7741c99275SPeter Avalos };
7841c99275SPeter Avalos
79411677aeSAaron LI static const struct tok rstp_obj_port_role_values[] = {
8041c99275SPeter Avalos { 0x00, "Unknown" },
8141c99275SPeter Avalos { 0x01, "Alternate" },
8241c99275SPeter Avalos { 0x02, "Root" },
8341c99275SPeter Avalos { 0x03, "Designated" },
8441c99275SPeter Avalos { 0, NULL}
8541c99275SPeter Avalos };
8641c99275SPeter Avalos
8741c99275SPeter Avalos static char *
stp_print_bridge_id(netdissect_options * ndo,const u_char * p)88*ed775ee7SAntonio Huete Jimenez stp_print_bridge_id(netdissect_options *ndo, const u_char *p)
8941c99275SPeter Avalos {
9041c99275SPeter Avalos static char bridge_id_str[sizeof("pppp.aa:bb:cc:dd:ee:ff")];
9141c99275SPeter Avalos
9241c99275SPeter Avalos snprintf(bridge_id_str, sizeof(bridge_id_str),
9341c99275SPeter Avalos "%.2x%.2x.%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
94*ed775ee7SAntonio Huete Jimenez GET_U_1(p), GET_U_1(p + 1), GET_U_1(p + 2),
95*ed775ee7SAntonio Huete Jimenez GET_U_1(p + 3), GET_U_1(p + 4), GET_U_1(p + 5),
96*ed775ee7SAntonio Huete Jimenez GET_U_1(p + 6), GET_U_1(p + 7));
9741c99275SPeter Avalos
9841c99275SPeter Avalos return bridge_id_str;
9941c99275SPeter Avalos }
10041c99275SPeter Avalos
101*ed775ee7SAntonio Huete Jimenez static void
stp_print_config_bpdu(netdissect_options * ndo,const struct stp_bpdu_ * stp_bpdu,u_int length)102411677aeSAaron LI stp_print_config_bpdu(netdissect_options *ndo, const struct stp_bpdu_ *stp_bpdu,
103411677aeSAaron LI u_int length)
10441c99275SPeter Avalos {
105*ed775ee7SAntonio Huete Jimenez uint8_t bpdu_flags;
10641c99275SPeter Avalos
107*ed775ee7SAntonio Huete Jimenez bpdu_flags = GET_U_1(stp_bpdu->flags);
108*ed775ee7SAntonio Huete Jimenez ND_PRINT(", Flags [%s]",
109*ed775ee7SAntonio Huete Jimenez bittok2str(stp_bpdu_flag_values, "none", bpdu_flags));
110*ed775ee7SAntonio Huete Jimenez
111*ed775ee7SAntonio Huete Jimenez ND_PRINT(", bridge-id %s.%04x, length %u",
112*ed775ee7SAntonio Huete Jimenez stp_print_bridge_id(ndo, stp_bpdu->bridge_id),
113*ed775ee7SAntonio Huete Jimenez GET_BE_U_2(stp_bpdu->port_id), length);
11441c99275SPeter Avalos
11541c99275SPeter Avalos /* in non-verbose mode just print the bridge-id */
116411677aeSAaron LI if (!ndo->ndo_vflag) {
117*ed775ee7SAntonio Huete Jimenez return;
11841c99275SPeter Avalos }
11941c99275SPeter Avalos
120*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\tmessage-age %.2fs, max-age %.2fs"
12141c99275SPeter Avalos ", hello-time %.2fs, forwarding-delay %.2fs",
122*ed775ee7SAntonio Huete Jimenez (float) GET_BE_U_2(stp_bpdu->message_age) / STP_TIME_BASE,
123*ed775ee7SAntonio Huete Jimenez (float) GET_BE_U_2(stp_bpdu->max_age) / STP_TIME_BASE,
124*ed775ee7SAntonio Huete Jimenez (float) GET_BE_U_2(stp_bpdu->hello_time) / STP_TIME_BASE,
125*ed775ee7SAntonio Huete Jimenez (float) GET_BE_U_2(stp_bpdu->forward_delay) / STP_TIME_BASE);
12641c99275SPeter Avalos
127*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\troot-id %s, root-pathcost %u",
128*ed775ee7SAntonio Huete Jimenez stp_print_bridge_id(ndo, stp_bpdu->root_id),
129*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(stp_bpdu->root_path_cost));
13041c99275SPeter Avalos
13141c99275SPeter Avalos /* Port role is only valid for 802.1w */
132*ed775ee7SAntonio Huete Jimenez if (GET_U_1(stp_bpdu->protocol_version) == STP_PROTO_RAPID) {
133*ed775ee7SAntonio Huete Jimenez ND_PRINT(", port-role %s",
13441c99275SPeter Avalos tok2str(rstp_obj_port_role_values, "Unknown",
135*ed775ee7SAntonio Huete Jimenez RSTP_EXTRACT_PORT_ROLE(bpdu_flags)));
13641c99275SPeter Avalos }
13741c99275SPeter Avalos }
13841c99275SPeter Avalos
13941c99275SPeter Avalos /*
14041c99275SPeter Avalos * MSTP packet format
14141c99275SPeter Avalos * Ref. IEEE 802.1Q 2003 Ed. Section 14
14241c99275SPeter Avalos *
14341c99275SPeter Avalos * MSTP BPDU
14441c99275SPeter Avalos *
14541c99275SPeter Avalos * 2 - bytes Protocol Id
14641c99275SPeter Avalos * 1 - byte Protocol Ver.
14741c99275SPeter Avalos * 1 - byte BPDU tye
14841c99275SPeter Avalos * 1 - byte Flags
14941c99275SPeter Avalos * 8 - bytes CIST Root Identifier
15041c99275SPeter Avalos * 4 - bytes CIST External Path Cost
15141c99275SPeter Avalos * 8 - bytes CIST Regional Root Identifier
15241c99275SPeter Avalos * 2 - bytes CIST Port Identifier
15341c99275SPeter Avalos * 2 - bytes Message Age
15441c99275SPeter Avalos * 2 - bytes Max age
15541c99275SPeter Avalos * 2 - bytes Hello Time
15641c99275SPeter Avalos * 2 - bytes Forward delay
15741c99275SPeter Avalos * 1 - byte Version 1 length. Must be 0
15841c99275SPeter Avalos * 2 - bytes Version 3 length
15941c99275SPeter Avalos * 1 - byte Config Identifier
16041c99275SPeter Avalos * 32 - bytes Config Name
16141c99275SPeter Avalos * 2 - bytes Revision level
16241c99275SPeter Avalos * 16 - bytes Config Digest [MD5]
16341c99275SPeter Avalos * 4 - bytes CIST Internal Root Path Cost
16441c99275SPeter Avalos * 8 - bytes CIST Bridge Identifier
16541c99275SPeter Avalos * 1 - byte CIST Remaining Hops
16641c99275SPeter Avalos * 16 - bytes MSTI information [Max 64 MSTI, each 16 bytes]
16741c99275SPeter Avalos *
168411677aeSAaron LI *
169411677aeSAaron LI * SPB BPDU
170411677aeSAaron LI * Ref. IEEE 802.1aq. Section 14
171411677aeSAaron LI *
172411677aeSAaron LI * 2 - bytes Version 4 length
173411677aeSAaron LI * 1 - byte Aux Config Identifier
174411677aeSAaron LI * 32 - bytes Aux Config Name
175411677aeSAaron LI * 2 - bytes Aux Revision level
176411677aeSAaron LI * 16 - bytes Aux Config Digest [MD5]
177411677aeSAaron LI * 1 - byte (1 - 2) Agreement Number
178411677aeSAaron LI * (3 - 4) Discarded Agreement Number
179411677aeSAaron LI * (5) Agreement Valid Flag
180411677aeSAaron LI * (6) Restricted Role Flag
181411677aeSAaron LI * (7 - 8) Unused sent zero
182411677aeSAaron LI * 1 - byte Unused
183411677aeSAaron LI * 1 - byte (1 - 4) Agreement Digest Format Identifier
184411677aeSAaron LI * (5 - 8) Agreement Digest Format Capabilities
185411677aeSAaron LI * 1 - byte (1 - 4) Agreement Digest Convention Identifier
186411677aeSAaron LI * (5 - 8) Agreement Digest Convention Capabilities
187411677aeSAaron LI * 2 - bytes Agreement Digest Edge Count
188411677aeSAaron LI * 8 - byte Reserved Set
189411677aeSAaron LI * 20 - bytes Computed Topology Digest
190411677aeSAaron LI *
191411677aeSAaron LI *
19241c99275SPeter Avalos * MSTI Payload
19341c99275SPeter Avalos *
19441c99275SPeter Avalos * 1 - byte MSTI flag
19541c99275SPeter Avalos * 8 - bytes MSTI Regional Root Identifier
19641c99275SPeter Avalos * 4 - bytes MSTI Regional Path Cost
19741c99275SPeter Avalos * 1 - byte MSTI Bridge Priority
19841c99275SPeter Avalos * 1 - byte MSTI Port Priority
19941c99275SPeter Avalos * 1 - byte MSTI Remaining Hops
200411677aeSAaron LI *
20141c99275SPeter Avalos */
20241c99275SPeter Avalos
20341c99275SPeter Avalos #define MST_BPDU_MSTI_LENGTH 16
20441c99275SPeter Avalos #define MST_BPDU_CONFIG_INFO_LENGTH 64
20541c99275SPeter Avalos
206*ed775ee7SAntonio Huete Jimenez /* Offsets of fields from the beginning for the packet */
20741c99275SPeter Avalos #define MST_BPDU_VER3_LEN_OFFSET 36
20841c99275SPeter Avalos #define MST_BPDU_CONFIG_NAME_OFFSET 39
20941c99275SPeter Avalos #define MST_BPDU_CONFIG_DIGEST_OFFSET 73
21041c99275SPeter Avalos #define MST_BPDU_CIST_INT_PATH_COST_OFFSET 89
21141c99275SPeter Avalos #define MST_BPDU_CIST_BRIDGE_ID_OFFSET 93
21241c99275SPeter Avalos #define MST_BPDU_CIST_REMAIN_HOPS_OFFSET 101
21341c99275SPeter Avalos #define MST_BPDU_MSTI_OFFSET 102
21441c99275SPeter Avalos /* Offsets within an MSTI */
21541c99275SPeter Avalos #define MST_BPDU_MSTI_ROOT_PRIO_OFFSET 1
21641c99275SPeter Avalos #define MST_BPDU_MSTI_ROOT_PATH_COST_OFFSET 9
21741c99275SPeter Avalos #define MST_BPDU_MSTI_BRIDGE_PRIO_OFFSET 13
21841c99275SPeter Avalos #define MST_BPDU_MSTI_PORT_PRIO_OFFSET 14
21941c99275SPeter Avalos #define MST_BPDU_MSTI_REMAIN_HOPS_OFFSET 15
22041c99275SPeter Avalos
221411677aeSAaron LI #define SPB_BPDU_MIN_LEN 87
222411677aeSAaron LI #define SPB_BPDU_CONFIG_NAME_OFFSET 3
223411677aeSAaron LI #define SPB_BPDU_CONFIG_REV_OFFSET SPB_BPDU_CONFIG_NAME_OFFSET + 32
224411677aeSAaron LI #define SPB_BPDU_CONFIG_DIGEST_OFFSET SPB_BPDU_CONFIG_REV_OFFSET + 2
225411677aeSAaron LI #define SPB_BPDU_AGREEMENT_OFFSET SPB_BPDU_CONFIG_DIGEST_OFFSET + 16
226411677aeSAaron LI #define SPB_BPDU_AGREEMENT_UNUSED_OFFSET SPB_BPDU_AGREEMENT_OFFSET + 1
227411677aeSAaron LI #define SPB_BPDU_AGREEMENT_FORMAT_OFFSET SPB_BPDU_AGREEMENT_UNUSED_OFFSET + 1
228411677aeSAaron LI #define SPB_BPDU_AGREEMENT_CON_OFFSET SPB_BPDU_AGREEMENT_FORMAT_OFFSET + 1
229411677aeSAaron LI #define SPB_BPDU_AGREEMENT_EDGE_OFFSET SPB_BPDU_AGREEMENT_CON_OFFSET + 1
230411677aeSAaron LI #define SPB_BPDU_AGREEMENT_RES1_OFFSET SPB_BPDU_AGREEMENT_EDGE_OFFSET + 2
231411677aeSAaron LI #define SPB_BPDU_AGREEMENT_RES2_OFFSET SPB_BPDU_AGREEMENT_RES1_OFFSET + 4
232411677aeSAaron LI #define SPB_BPDU_AGREEMENT_DIGEST_OFFSET SPB_BPDU_AGREEMENT_RES2_OFFSET + 4
233411677aeSAaron LI
234*ed775ee7SAntonio Huete Jimenez static void
stp_print_mstp_bpdu(netdissect_options * ndo,const struct stp_bpdu_ * stp_bpdu,u_int length)235411677aeSAaron LI stp_print_mstp_bpdu(netdissect_options *ndo, const struct stp_bpdu_ *stp_bpdu,
236411677aeSAaron LI u_int length)
23741c99275SPeter Avalos {
23841c99275SPeter Avalos const u_char *ptr;
239*ed775ee7SAntonio Huete Jimenez uint8_t bpdu_flags;
240411677aeSAaron LI uint16_t v3len;
241411677aeSAaron LI uint16_t len;
242411677aeSAaron LI uint16_t msti;
243411677aeSAaron LI u_int offset;
24441c99275SPeter Avalos
24541c99275SPeter Avalos ptr = (const u_char *)stp_bpdu;
246*ed775ee7SAntonio Huete Jimenez bpdu_flags = GET_U_1(stp_bpdu->flags);
247*ed775ee7SAntonio Huete Jimenez ND_PRINT(", CIST Flags [%s], length %u",
248*ed775ee7SAntonio Huete Jimenez bittok2str(stp_bpdu_flag_values, "none", bpdu_flags), length);
24941c99275SPeter Avalos
25041c99275SPeter Avalos /*
251411677aeSAaron LI * in non-verbose mode just print the flags.
25241c99275SPeter Avalos */
253411677aeSAaron LI if (!ndo->ndo_vflag) {
254*ed775ee7SAntonio Huete Jimenez return;
25541c99275SPeter Avalos }
25641c99275SPeter Avalos
257*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\tport-role %s, ",
258411677aeSAaron LI tok2str(rstp_obj_port_role_values, "Unknown",
259*ed775ee7SAntonio Huete Jimenez RSTP_EXTRACT_PORT_ROLE(bpdu_flags)));
26041c99275SPeter Avalos
261*ed775ee7SAntonio Huete Jimenez ND_PRINT("CIST root-id %s, CIST ext-pathcost %u",
262*ed775ee7SAntonio Huete Jimenez stp_print_bridge_id(ndo, stp_bpdu->root_id),
263*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(stp_bpdu->root_path_cost));
26441c99275SPeter Avalos
265*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\tCIST regional-root-id %s, ",
266*ed775ee7SAntonio Huete Jimenez stp_print_bridge_id(ndo, stp_bpdu->bridge_id));
267411677aeSAaron LI
268*ed775ee7SAntonio Huete Jimenez ND_PRINT("CIST port-id %04x,", GET_BE_U_2(stp_bpdu->port_id));
269411677aeSAaron LI
270*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\tmessage-age %.2fs, max-age %.2fs"
27141c99275SPeter Avalos ", hello-time %.2fs, forwarding-delay %.2fs",
272*ed775ee7SAntonio Huete Jimenez (float) GET_BE_U_2(stp_bpdu->message_age) / STP_TIME_BASE,
273*ed775ee7SAntonio Huete Jimenez (float) GET_BE_U_2(stp_bpdu->max_age) / STP_TIME_BASE,
274*ed775ee7SAntonio Huete Jimenez (float) GET_BE_U_2(stp_bpdu->hello_time) / STP_TIME_BASE,
275*ed775ee7SAntonio Huete Jimenez (float) GET_BE_U_2(stp_bpdu->forward_delay) / STP_TIME_BASE);
27641c99275SPeter Avalos
277*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\tv3len %u, ", GET_BE_U_2(ptr + MST_BPDU_VER3_LEN_OFFSET));
278*ed775ee7SAntonio Huete Jimenez ND_PRINT("MCID Name ");
279*ed775ee7SAntonio Huete Jimenez nd_printjnp(ndo, ptr + MST_BPDU_CONFIG_NAME_OFFSET, 32);
280*ed775ee7SAntonio Huete Jimenez ND_PRINT(", rev %u,"
281411677aeSAaron LI "\n\t\tdigest %08x%08x%08x%08x, ",
282*ed775ee7SAntonio Huete Jimenez GET_BE_U_2(ptr + MST_BPDU_CONFIG_NAME_OFFSET + 32),
283*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET),
284*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET + 4),
285*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET + 8),
286*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET + 12));
28741c99275SPeter Avalos
288*ed775ee7SAntonio Huete Jimenez ND_PRINT("CIST int-root-pathcost %u,",
289*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(ptr + MST_BPDU_CIST_INT_PATH_COST_OFFSET));
290411677aeSAaron LI
291*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\tCIST bridge-id %s, ",
292*ed775ee7SAntonio Huete Jimenez stp_print_bridge_id(ndo, ptr + MST_BPDU_CIST_BRIDGE_ID_OFFSET));
293411677aeSAaron LI
294*ed775ee7SAntonio Huete Jimenez ND_PRINT("CIST remaining-hops %u",
295*ed775ee7SAntonio Huete Jimenez GET_U_1(ptr + MST_BPDU_CIST_REMAIN_HOPS_OFFSET));
29641c99275SPeter Avalos
29741c99275SPeter Avalos /* Dump all MSTI's */
298*ed775ee7SAntonio Huete Jimenez v3len = GET_BE_U_2(ptr + MST_BPDU_VER3_LEN_OFFSET);
29941c99275SPeter Avalos if (v3len > MST_BPDU_CONFIG_INFO_LENGTH) {
30041c99275SPeter Avalos len = v3len - MST_BPDU_CONFIG_INFO_LENGTH;
30141c99275SPeter Avalos offset = MST_BPDU_MSTI_OFFSET;
30241c99275SPeter Avalos while (len >= MST_BPDU_MSTI_LENGTH) {
303*ed775ee7SAntonio Huete Jimenez msti = GET_BE_U_2(ptr + offset + MST_BPDU_MSTI_ROOT_PRIO_OFFSET);
30441c99275SPeter Avalos msti = msti & 0x0FFF;
30541c99275SPeter Avalos
306*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\tMSTI %u, Flags [%s], port-role %s",
307*ed775ee7SAntonio Huete Jimenez msti,
308*ed775ee7SAntonio Huete Jimenez bittok2str(stp_bpdu_flag_values, "none", GET_U_1(ptr + offset)),
30941c99275SPeter Avalos tok2str(rstp_obj_port_role_values, "Unknown",
310*ed775ee7SAntonio Huete Jimenez RSTP_EXTRACT_PORT_ROLE(GET_U_1(ptr + offset))));
311*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\t\tMSTI regional-root-id %s, pathcost %u",
312*ed775ee7SAntonio Huete Jimenez stp_print_bridge_id(ndo, ptr + offset +
31341c99275SPeter Avalos MST_BPDU_MSTI_ROOT_PRIO_OFFSET),
314*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(ptr + offset + MST_BPDU_MSTI_ROOT_PATH_COST_OFFSET));
315*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\t\tMSTI bridge-prio %u, port-prio %u, hops %u",
316*ed775ee7SAntonio Huete Jimenez GET_U_1(ptr + offset + MST_BPDU_MSTI_BRIDGE_PRIO_OFFSET) >> 4,
317*ed775ee7SAntonio Huete Jimenez GET_U_1(ptr + offset + MST_BPDU_MSTI_PORT_PRIO_OFFSET) >> 4,
318*ed775ee7SAntonio Huete Jimenez GET_U_1(ptr + offset + MST_BPDU_MSTI_REMAIN_HOPS_OFFSET));
31941c99275SPeter Avalos
32041c99275SPeter Avalos len -= MST_BPDU_MSTI_LENGTH;
32141c99275SPeter Avalos offset += MST_BPDU_MSTI_LENGTH;
32241c99275SPeter Avalos }
32341c99275SPeter Avalos }
324411677aeSAaron LI }
325411677aeSAaron LI
326*ed775ee7SAntonio Huete Jimenez static void
stp_print_spb_bpdu(netdissect_options * ndo,const struct stp_bpdu_ * stp_bpdu,u_int offset)327411677aeSAaron LI stp_print_spb_bpdu(netdissect_options *ndo, const struct stp_bpdu_ *stp_bpdu,
328411677aeSAaron LI u_int offset)
329411677aeSAaron LI {
330411677aeSAaron LI const u_char *ptr;
331411677aeSAaron LI
332411677aeSAaron LI /*
333411677aeSAaron LI * in non-verbose mode don't print anything.
334411677aeSAaron LI */
335411677aeSAaron LI if (!ndo->ndo_vflag) {
336*ed775ee7SAntonio Huete Jimenez return;
337411677aeSAaron LI }
338411677aeSAaron LI
339411677aeSAaron LI ptr = (const u_char *)stp_bpdu;
340411677aeSAaron LI
341*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\tv4len %u, ", GET_BE_U_2(ptr + offset));
342*ed775ee7SAntonio Huete Jimenez ND_PRINT("AUXMCID Name ");
343*ed775ee7SAntonio Huete Jimenez nd_printjnp(ndo, ptr + offset + SPB_BPDU_CONFIG_NAME_OFFSET, 32);
344*ed775ee7SAntonio Huete Jimenez ND_PRINT(", Rev %u,\n\t\tdigest %08x%08x%08x%08x",
345*ed775ee7SAntonio Huete Jimenez GET_BE_U_2(ptr + offset + SPB_BPDU_CONFIG_REV_OFFSET),
346*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(ptr + offset + SPB_BPDU_CONFIG_DIGEST_OFFSET),
347*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(ptr + offset + SPB_BPDU_CONFIG_DIGEST_OFFSET + 4),
348*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(ptr + offset + SPB_BPDU_CONFIG_DIGEST_OFFSET + 8),
349*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(ptr + offset + SPB_BPDU_CONFIG_DIGEST_OFFSET + 12));
350411677aeSAaron LI
351*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\tAgreement num %u, Discarded Agreement num %u, Agreement valid-"
352*ed775ee7SAntonio Huete Jimenez "flag %u,\n\tRestricted role-flag: %u, Format id %u cap %u, "
353*ed775ee7SAntonio Huete Jimenez "Convention id %u cap %u,\n\tEdge count %u, "
354*ed775ee7SAntonio Huete Jimenez "Agreement digest %08x%08x%08x%08x%08x",
355*ed775ee7SAntonio Huete Jimenez GET_U_1(ptr + offset + SPB_BPDU_AGREEMENT_OFFSET)>>6,
356*ed775ee7SAntonio Huete Jimenez GET_U_1(ptr + offset + SPB_BPDU_AGREEMENT_OFFSET)>>4 & 0x3,
357*ed775ee7SAntonio Huete Jimenez GET_U_1(ptr + offset + SPB_BPDU_AGREEMENT_OFFSET)>>3 & 0x1,
358*ed775ee7SAntonio Huete Jimenez GET_U_1(ptr + offset + SPB_BPDU_AGREEMENT_OFFSET)>>2 & 0x1,
359*ed775ee7SAntonio Huete Jimenez GET_U_1(ptr + offset + SPB_BPDU_AGREEMENT_FORMAT_OFFSET)>>4,
360*ed775ee7SAntonio Huete Jimenez GET_U_1(ptr + offset + SPB_BPDU_AGREEMENT_FORMAT_OFFSET)&0x00ff,
361*ed775ee7SAntonio Huete Jimenez GET_U_1(ptr + offset + SPB_BPDU_AGREEMENT_CON_OFFSET)>>4,
362*ed775ee7SAntonio Huete Jimenez GET_U_1(ptr + offset + SPB_BPDU_AGREEMENT_CON_OFFSET)&0x00ff,
363*ed775ee7SAntonio Huete Jimenez GET_BE_U_2(ptr + offset + SPB_BPDU_AGREEMENT_EDGE_OFFSET),
364*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(ptr + offset + SPB_BPDU_AGREEMENT_DIGEST_OFFSET),
365*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(ptr + offset + SPB_BPDU_AGREEMENT_DIGEST_OFFSET + 4),
366*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(ptr + offset + SPB_BPDU_AGREEMENT_DIGEST_OFFSET + 8),
367*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(ptr + offset + SPB_BPDU_AGREEMENT_DIGEST_OFFSET + 12),
368*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(ptr + offset + SPB_BPDU_AGREEMENT_DIGEST_OFFSET + 16));
36941c99275SPeter Avalos }
37041c99275SPeter Avalos
37141c99275SPeter Avalos /*
372411677aeSAaron LI * Print 802.1d / 802.1w / 802.1q (mstp) / 802.1aq (spb) packets.
37341c99275SPeter Avalos */
37441c99275SPeter Avalos void
stp_print(netdissect_options * ndo,const u_char * p,u_int length)375411677aeSAaron LI stp_print(netdissect_options *ndo, const u_char *p, u_int length)
37641c99275SPeter Avalos {
37741c99275SPeter Avalos const struct stp_bpdu_ *stp_bpdu;
378*ed775ee7SAntonio Huete Jimenez u_int protocol_version;
379*ed775ee7SAntonio Huete Jimenez u_int bpdu_type;
380411677aeSAaron LI u_int mstp_len;
381411677aeSAaron LI u_int spb_len;
38241c99275SPeter Avalos
383*ed775ee7SAntonio Huete Jimenez ndo->ndo_protocol = "stp";
384411677aeSAaron LI stp_bpdu = (const struct stp_bpdu_*)p;
38541c99275SPeter Avalos
38641c99275SPeter Avalos /* Minimum STP Frame size. */
38741c99275SPeter Avalos if (length < 4)
388*ed775ee7SAntonio Huete Jimenez goto invalid;
38941c99275SPeter Avalos
390*ed775ee7SAntonio Huete Jimenez if (GET_BE_U_2(stp_bpdu->protocol_id)) {
391*ed775ee7SAntonio Huete Jimenez ND_PRINT("unknown STP version, length %u", length);
39241c99275SPeter Avalos return;
39341c99275SPeter Avalos }
39441c99275SPeter Avalos
395*ed775ee7SAntonio Huete Jimenez protocol_version = GET_U_1(stp_bpdu->protocol_version);
396*ed775ee7SAntonio Huete Jimenez ND_PRINT("STP %s", tok2str(stp_proto_values, "Unknown STP protocol (0x%02x)",
397*ed775ee7SAntonio Huete Jimenez protocol_version));
39841c99275SPeter Avalos
399*ed775ee7SAntonio Huete Jimenez switch (protocol_version) {
40041c99275SPeter Avalos case STP_PROTO_REGULAR:
40141c99275SPeter Avalos case STP_PROTO_RAPID:
40241c99275SPeter Avalos case STP_PROTO_MSTP:
403411677aeSAaron LI case STP_PROTO_SPB:
40441c99275SPeter Avalos break;
40541c99275SPeter Avalos default:
40641c99275SPeter Avalos return;
40741c99275SPeter Avalos }
40841c99275SPeter Avalos
409*ed775ee7SAntonio Huete Jimenez bpdu_type = GET_U_1(stp_bpdu->bpdu_type);
410*ed775ee7SAntonio Huete Jimenez ND_PRINT(", %s", tok2str(stp_bpdu_type_values, "Unknown BPDU Type (0x%02x)",
411*ed775ee7SAntonio Huete Jimenez bpdu_type));
41241c99275SPeter Avalos
413*ed775ee7SAntonio Huete Jimenez switch (bpdu_type) {
41441c99275SPeter Avalos case STP_BPDU_TYPE_CONFIG:
41541c99275SPeter Avalos if (length < sizeof(struct stp_bpdu_) - 1) {
416*ed775ee7SAntonio Huete Jimenez goto invalid;
41741c99275SPeter Avalos }
418*ed775ee7SAntonio Huete Jimenez stp_print_config_bpdu(ndo, stp_bpdu, length);
41941c99275SPeter Avalos break;
42041c99275SPeter Avalos
42141c99275SPeter Avalos case STP_BPDU_TYPE_RSTP:
422*ed775ee7SAntonio Huete Jimenez if (protocol_version == STP_PROTO_RAPID) {
42341c99275SPeter Avalos if (length < sizeof(struct stp_bpdu_)) {
424*ed775ee7SAntonio Huete Jimenez goto invalid;
42541c99275SPeter Avalos }
426*ed775ee7SAntonio Huete Jimenez stp_print_config_bpdu(ndo, stp_bpdu, length);
427*ed775ee7SAntonio Huete Jimenez } else if (protocol_version == STP_PROTO_MSTP ||
428*ed775ee7SAntonio Huete Jimenez protocol_version == STP_PROTO_SPB) {
42941c99275SPeter Avalos if (length < STP_BPDU_MSTP_MIN_LEN) {
430*ed775ee7SAntonio Huete Jimenez goto invalid;
43141c99275SPeter Avalos }
432411677aeSAaron LI
433*ed775ee7SAntonio Huete Jimenez if (GET_U_1(stp_bpdu->v1_length) != 0) {
43441c99275SPeter Avalos /* FIX ME: Emit a message here ? */
435*ed775ee7SAntonio Huete Jimenez goto invalid;
43641c99275SPeter Avalos }
437411677aeSAaron LI
43841c99275SPeter Avalos /* Validate v3 length */
439*ed775ee7SAntonio Huete Jimenez mstp_len = GET_BE_U_2(p + MST_BPDU_VER3_LEN_OFFSET);
44041c99275SPeter Avalos mstp_len += 2; /* length encoding itself is 2 bytes */
44141c99275SPeter Avalos if (length < (sizeof(struct stp_bpdu_) + mstp_len)) {
442*ed775ee7SAntonio Huete Jimenez goto invalid;
44341c99275SPeter Avalos }
444*ed775ee7SAntonio Huete Jimenez stp_print_mstp_bpdu(ndo, stp_bpdu, length);
445411677aeSAaron LI
446*ed775ee7SAntonio Huete Jimenez if (protocol_version == STP_PROTO_SPB)
447411677aeSAaron LI {
448411677aeSAaron LI /* Validate v4 length */
449*ed775ee7SAntonio Huete Jimenez spb_len = GET_BE_U_2(p + MST_BPDU_VER3_LEN_OFFSET + mstp_len);
450411677aeSAaron LI spb_len += 2;
451411677aeSAaron LI if (length < (sizeof(struct stp_bpdu_) + mstp_len + spb_len) ||
452411677aeSAaron LI spb_len < SPB_BPDU_MIN_LEN) {
453*ed775ee7SAntonio Huete Jimenez goto invalid;
454411677aeSAaron LI }
455*ed775ee7SAntonio Huete Jimenez stp_print_spb_bpdu(ndo, stp_bpdu, (sizeof(struct stp_bpdu_) + mstp_len));
456411677aeSAaron LI }
45741c99275SPeter Avalos }
45841c99275SPeter Avalos break;
45941c99275SPeter Avalos
46041c99275SPeter Avalos case STP_BPDU_TYPE_TOPO_CHANGE:
46141c99275SPeter Avalos /* always empty message - just break out */
46241c99275SPeter Avalos break;
46341c99275SPeter Avalos
46441c99275SPeter Avalos default:
46541c99275SPeter Avalos break;
46641c99275SPeter Avalos }
46741c99275SPeter Avalos return;
46841c99275SPeter Avalos
469*ed775ee7SAntonio Huete Jimenez invalid:
470*ed775ee7SAntonio Huete Jimenez nd_print_invalid(ndo);
471*ed775ee7SAntonio Huete Jimenez }
472