xref: /freebsd/contrib/tcpdump/print-stp.c (revision 0a7e5f1f02aad2ff5fff1c60f44c6975fd07e1d9)
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