xref: /dflybsd-src/contrib/tcpdump/print-stp.c (revision 59c07fbdf8168fa08c76c515186d561b5a92690c)
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