2 * Routines for BPDU (Spanning Tree Protocol) disassembly
6 * Copyright 1999 Christophe Tronche <ch.tronche@computer.org>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
34 #include <epan/packet.h>
35 #include <epan/llcsaps.h>
36 #include <epan/ppptypes.h>
37 #include <epan/chdlctypes.h>
38 #include <epan/etypes.h>
39 #include <epan/addr_resolv.h>
40 #include <epan/prefs.h>
42 /* Offsets of fields within a BPDU */
44 #define BPDU_IDENTIFIER 0
45 #define BPDU_VERSION_IDENTIFIER 2
48 #define BPDU_ROOT_IDENTIFIER 5
49 #define BPDU_ROOT_PATH_COST 13
50 #define BPDU_BRIDGE_IDENTIFIER 17
51 #define BPDU_PORT_IDENTIFIER 25
52 #define BPDU_MESSAGE_AGE 27
53 #define BPDU_MAX_AGE 29
54 #define BPDU_HELLO_TIME 31
55 #define BPDU_FORWARD_DELAY 33
56 #define BPDU_VERSION_1_LENGTH 35
57 #define BPDU_VERSION_3_LENGTH 36
58 #define BPDU_MST_CONFIG_FORMAT_SELECTOR 38
59 #define BPDU_MST_CONFIG_NAME 39
60 #define BPDU_MST_CONFIG_REVISION_LEVEL 71
61 #define BPDU_MST_CONFIG_DIGEST 73
62 #define BPDU_CIST_INTERNAL_ROOT_PATH_COST 89
63 #define BPDU_CIST_BRIDGE_IDENTIFIER 93
64 #define BPDU_CIST_REMAINING_HOPS 101
68 #define MSTI_REGIONAL_ROOT 1
69 #define MSTI_INTERNAL_ROOT_PATH_COST 9
70 #define MSTI_BRIDGE_IDENTIFIER_PRIORITY 13
71 #define MSTI_PORT_IDENTIFIER_PRIORITY 14
72 #define MSTI_REMAINING_HOPS 15
75 #define CONF_BPDU_SIZE 35
76 #define TC_BPDU_SIZE 4
77 #define MST_BPDU_SIZE 38
78 #define VERSION_3_STATIC_LENGTH 64
79 #define MSTI_MESSAGE_SIZE 16
81 /* Values for the Alternative MSTI format */
83 #define ALT_BPDU_CIST_BRIDGE_IDENTIFIER 89
84 #define ALT_BPDU_CIST_INTERNAL_ROOT_PATH_COST 97
86 #define ALT_MSTI_MSTID 0
87 #define ALT_MSTI_FLAGS 2
88 #define ALT_MSTI_REGIONAL_ROOT 3
89 #define ALT_MSTI_INTERNAL_ROOT_PATH_COST 11
90 #define ALT_MSTI_BRIDGE_IDENTIFIER 15
91 #define ALT_MSTI_PORT_IDENTIFIER 23
92 #define ALT_MSTI_REMAINING_HOPS 25
94 #define ALT_MSTI_MESSAGE_SIZE 26
98 #define BPDU_FLAGS_TCACK 0x80
99 #define BPDU_FLAGS_AGREEMENT 0x40
100 #define BPDU_FLAGS_FORWARDING 0x20
101 #define BPDU_FLAGS_LEARNING 0x10
102 #define BPDU_FLAGS_PORT_ROLE_MASK 0x0C
103 #define BPDU_FLAGS_PORT_ROLE_SHIFT 2
104 #define BPDU_FLAGS_PROPOSAL 0x02
105 #define BPDU_FLAGS_TC 0x01
107 static int proto_bpdu = -1;
108 static int hf_bpdu_proto_id = -1;
109 static int hf_bpdu_version_id = -1;
110 static int hf_bpdu_type = -1;
111 static int hf_bpdu_flags = -1;
112 static int hf_bpdu_flags_tcack = -1;
113 static int hf_bpdu_flags_agreement = -1;
114 static int hf_bpdu_flags_forwarding = -1;
115 static int hf_bpdu_flags_learning = -1;
116 static int hf_bpdu_flags_port_role = -1;
117 static int hf_bpdu_flags_proposal = -1;
118 static int hf_bpdu_flags_tc = -1;
119 static int hf_bpdu_root_prio = -1;
120 static int hf_bpdu_root_sys_id_ext = -1;
121 static int hf_bpdu_root_mac = -1;
122 static int hf_bpdu_root_cost = -1;
123 static int hf_bpdu_bridge_prio = -1;
124 static int hf_bpdu_bridge_sys_id_ext = -1;
125 static int hf_bpdu_bridge_mac = -1;
126 static int hf_bpdu_port_id = -1;
127 static int hf_bpdu_msg_age = -1;
128 static int hf_bpdu_max_age = -1;
129 static int hf_bpdu_hello_time = -1;
130 static int hf_bpdu_forward_delay = -1;
131 static int hf_bpdu_version_1_length = -1;
132 static int hf_bpdu_version_3_length = -1;
133 static int hf_bpdu_mst_config_format_selector = -1;
134 static int hf_bpdu_mst_config_name = -1;
135 static int hf_bpdu_mst_config_revision_level = -1;
136 static int hf_bpdu_mst_config_digest = -1;
137 static int hf_bpdu_cist_internal_root_path_cost = -1;
138 static int hf_bpdu_cist_bridge_prio = -1;
139 static int hf_bpdu_cist_bridge_sys_id_ext = -1;
140 static int hf_bpdu_cist_bridge_mac = -1;
141 static int hf_bpdu_cist_remaining_hops = -1;
142 static int hf_bpdu_msti_flags = -1;
143 static int hf_bpdu_msti_regional_root_mac = -1;
144 static int hf_bpdu_msti_internal_root_path_cost = -1;
145 static int hf_bpdu_msti_bridge_identifier_priority = -1;
146 static int hf_bpdu_msti_port_identifier_priority = -1;
147 static int hf_bpdu_msti_port_id = -1;
148 static int hf_bpdu_msti_remaining_hops = -1;
150 static gint ett_bpdu = -1;
151 static gint ett_bpdu_flags = -1;
152 static gint ett_root_id = -1;
153 static gint ett_bridge_id = -1;
154 static gint ett_mstp = -1;
155 static gint ett_msti = -1;
156 static gint ett_cist_bridge_id = -1;
158 static gboolean bpdu_use_system_id_extensions = TRUE;
160 static dissector_handle_t gvrp_handle;
161 static dissector_handle_t gmrp_handle;
162 static dissector_handle_t data_handle;
164 static const value_string protocol_id_vals[] = {
165 { 0, "Spanning Tree Protocol" },
169 #define BPDU_TYPE_CONF 0x00 /* STP Configuration BPDU */
170 #define BPDU_TYPE_RST 0x02 /* RST BPDU (or MST) */
171 #define BPDU_TYPE_TOPOLOGY_CHANGE 0x80 /* STP TCN (Topology change notify) BPDU */
173 static const value_string bpdu_type_vals[] = {
174 { BPDU_TYPE_CONF, "Configuration" },
175 { BPDU_TYPE_RST, "Rapid/Multiple Spanning Tree" },
176 { BPDU_TYPE_TOPOLOGY_CHANGE, "Topology Change Notification" },
180 #define PROTO_VERSION_STP 0
181 #define PROTO_VERSION_RSTP 2
182 #define PROTO_VERSION_MSTP 3
184 #define MSTI_FORMAT_UNKNOWN 0
185 #define MSTI_FORMAT_IEEE_8021S 1
186 #define MSTI_FORMAT_ALTERNATIVE 2
188 static const value_string version_id_vals[] = {
189 { PROTO_VERSION_STP, "Spanning Tree" },
190 { PROTO_VERSION_RSTP, "Rapid Spanning Tree" },
191 { PROTO_VERSION_MSTP, "Multiple Spanning Tree" },
194 static const value_string role_vals[] = {
195 { 1, "Alternate or Backup" },
201 static const char initial_sep[] = " (";
202 static const char cont_sep[] = ", ";
204 #define APPEND_BOOLEAN_FLAG(flag, item, string) \
207 proto_item_append_text(item, string, sep); \
212 dissect_bpdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
214 guint16 protocol_identifier;
215 guint8 protocol_version_identifier;
218 guint16 root_identifier_bridge_priority;
219 guint16 root_identifier_system_id_extension = 0;
220 const guint8 *root_identifier_mac;
221 gchar *root_identifier_mac_str;
222 guint32 root_path_cost;
223 guint16 bridge_identifier_bridge_priority;
224 guint16 bridge_identifier_system_id_extension = 0;
225 const guint8 *bridge_identifier_mac;
226 gchar *bridge_identifier_mac_str;
227 guint16 port_identifier;
231 double forward_delay;
232 guint8 version_1_length;
233 guint16 version_3_length;
234 guint8 config_format_selector;
235 guint16 cist_bridge_identifier_bridge_priority;
236 guint16 cist_bridge_identifier_system_id_extension = 0;
237 const guint8 *cist_bridge_identifier_mac;
238 gchar *cist_bridge_identifier_mac_str;
240 guint32 msti_regional_root_mstid, msti_regional_root_priority;
241 const guint8 *msti_regional_root_mac;
242 gchar *msti_regional_root_mac_str;
243 guint16 msti_bridge_identifier_priority, msti_port_identifier_priority;
244 const guint8 *msti_bridge_identifier_mac;
245 gchar *msti_bridge_identifier_mac_str;
246 int total_msti_length, offset, msti, msti_format;
248 proto_tree *bpdu_tree;
249 proto_tree *mstp_tree, *msti_tree;
250 proto_item *bpdu_item;
251 proto_item *mstp_item, *msti_item;
252 proto_tree *flags_tree;
253 proto_item *flags_item;
254 proto_tree *root_id_tree;
255 proto_item *root_id_item;
256 proto_tree *bridge_id_tree;
257 proto_item *bridge_id_item;
258 proto_tree *cist_bridge_id_tree;
259 proto_item *cist_bridge_id_item;
260 proto_item *hidden_item;
263 /* GARP application frames require special interpretation of the
264 destination address field; otherwise, they will be mistaken as
266 Fortunately, they can be recognized by checking the first 6 octets
267 of the destination address, which are in the range from
268 01-80-C2-00-00-20 to 01-80-C2-00-00-2F.
270 Yes - we *do* need to check the destination address type;
271 on Linux cooked captures, there *is* no destination address,
273 if (pinfo->dl_dst.type == AT_ETHER) {
274 const guint8 *dstaddr;
276 dstaddr = pinfo->dl_dst.data;
277 if(dstaddr[0] == 0x01 && dstaddr[1] == 0x80 &&
278 dstaddr[2] == 0xC2 && dstaddr[3] == 0x00 &&
279 dstaddr[4] == 0x00 && ((dstaddr[5] & 0xF0) == 0x20)) {
281 protocol_identifier = tvb_get_ntohs(tvb, BPDU_IDENTIFIER);
283 switch (dstaddr[5]) {
287 call_dissector(gmrp_handle, tvb, pinfo, tree);
292 call_dissector(gvrp_handle, tvb, pinfo, tree);
296 pinfo->current_proto = "GARP";
298 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
299 col_set_str(pinfo->cinfo, COL_PROTOCOL, "GARP");
300 /* Generic Attribute Registration Protocol */
303 if (check_col(pinfo->cinfo, COL_INFO)) {
304 col_add_fstr(pinfo->cinfo, COL_INFO,
305 "Unknown GARP application (0x%02X)",
313 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
314 col_set_str(pinfo->cinfo, COL_PROTOCOL, "STP"); /* Spanning Tree Protocol */
316 if (check_col(pinfo->cinfo, COL_INFO)) {
317 col_clear(pinfo->cinfo, COL_INFO);
320 bpdu_type = tvb_get_guint8(tvb, BPDU_TYPE);
322 protocol_version_identifier = tvb_get_guint8(tvb, BPDU_VERSION_IDENTIFIER);
328 flags = tvb_get_guint8(tvb, BPDU_FLAGS);
329 root_identifier_bridge_priority = tvb_get_ntohs(tvb,BPDU_ROOT_IDENTIFIER);
330 if (bpdu_use_system_id_extensions ) {
331 root_identifier_system_id_extension = root_identifier_bridge_priority & 0x0fff;
332 root_identifier_bridge_priority &= 0xf000;
334 root_identifier_mac = tvb_get_ptr(tvb, BPDU_ROOT_IDENTIFIER + 2, 6);
335 root_identifier_mac_str = ether_to_str(root_identifier_mac);
336 root_path_cost = tvb_get_ntohl(tvb, BPDU_ROOT_PATH_COST);
337 port_identifier = tvb_get_ntohs(tvb, BPDU_PORT_IDENTIFIER);
341 /* Squelch GCC complaints. */
343 root_identifier_bridge_priority = 0;
344 root_identifier_mac = NULL;
345 root_identifier_mac_str = NULL;
351 if (check_col(pinfo->cinfo, COL_INFO)) {
355 if (bpdu_use_system_id_extensions ) {
356 col_add_fstr(pinfo->cinfo, COL_INFO,
357 "Conf. %sRoot = %d/%d/%s Cost = %d Port = 0x%04x",
358 flags & 0x1 ? "TC + " : "",
359 root_identifier_bridge_priority,
360 root_identifier_system_id_extension,
361 root_identifier_mac_str,
362 root_path_cost, port_identifier);
364 col_add_fstr(pinfo->cinfo, COL_INFO,
365 "Conf. %sRoot = %d/%s Cost = %d Port = 0x%04x",
366 flags & 0x1 ? "TC + " : "",
367 root_identifier_bridge_priority, root_identifier_mac_str,
368 root_path_cost, port_identifier);
372 case BPDU_TYPE_TOPOLOGY_CHANGE:
373 col_set_str(pinfo->cinfo, COL_INFO, "Topology Change Notification");
377 if (bpdu_use_system_id_extensions ) {
378 col_add_fstr(pinfo->cinfo, COL_INFO,
379 "%cST. %sRoot = %d/%d/%s Cost = %d Port = 0x%04x",
380 protocol_version_identifier == 3 ? 'M':'R',
381 flags & 0x1 ? "TC + " : "",
382 root_identifier_bridge_priority,
383 root_identifier_system_id_extension,
384 root_identifier_mac_str,
385 root_path_cost, port_identifier);
387 col_add_fstr(pinfo->cinfo, COL_INFO,
388 "%cST. %sRoot = %d/%s Cost = %d Port = 0x%04x",
389 protocol_version_identifier == 3 ? 'M':'R',
390 flags & 0x1 ? "TC + " : "",
391 root_identifier_bridge_priority, root_identifier_mac_str,
392 root_path_cost, port_identifier);
397 col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown BPDU type (%u)", bpdu_type);
403 bpdu_item = proto_tree_add_protocol_format(tree, proto_bpdu, tvb, 0, -1,
404 "Spanning Tree Protocol");
405 bpdu_tree = proto_item_add_subtree(bpdu_item, ett_bpdu);
407 protocol_identifier = tvb_get_ntohs(tvb, BPDU_IDENTIFIER);
408 proto_tree_add_uint(bpdu_tree, hf_bpdu_proto_id, tvb, BPDU_IDENTIFIER, 2,
409 protocol_identifier);
411 proto_tree_add_uint(bpdu_tree, hf_bpdu_version_id, tvb,
412 BPDU_VERSION_IDENTIFIER, 1,
413 protocol_version_identifier);
414 switch (protocol_version_identifier) {
424 proto_tree_add_text(bpdu_tree, tvb, BPDU_VERSION_IDENTIFIER, 1,
425 " (Warning: this version of Wireshark only knows about versions 0, 2 & 3)");
428 proto_tree_add_uint(bpdu_tree, hf_bpdu_type, tvb, BPDU_TYPE, 1, bpdu_type);
430 if (bpdu_type == BPDU_TYPE_TOPOLOGY_CHANGE) {
431 set_actual_length(tvb, TC_BPDU_SIZE);
435 if (bpdu_type != BPDU_TYPE_CONF && bpdu_type != BPDU_TYPE_RST) {
436 /* Unknown BPDU type - just display the rest of the PDU as data */
437 proto_tree_add_text(bpdu_tree, tvb, BPDU_TYPE + 1, -1,
438 "Unknown BPDU type data");
442 bridge_identifier_bridge_priority = tvb_get_ntohs(tvb, BPDU_BRIDGE_IDENTIFIER);
443 if (bpdu_use_system_id_extensions ) {
444 bridge_identifier_system_id_extension = bridge_identifier_bridge_priority & 0x0fff;
445 bridge_identifier_bridge_priority &= 0xf000;
447 bridge_identifier_mac = tvb_get_ptr(tvb, BPDU_BRIDGE_IDENTIFIER + 2, 6);
448 bridge_identifier_mac_str = ether_to_str(bridge_identifier_mac);
450 flags_item = proto_tree_add_uint(bpdu_tree, hf_bpdu_flags, tvb,
451 BPDU_FLAGS, 1, flags);
452 flags_tree = proto_item_add_subtree(flags_item, ett_bpdu_flags);
454 APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_TCACK, flags_item,
455 "%sTopology Change Acknowledgment");
456 proto_tree_add_boolean(flags_tree, hf_bpdu_flags_tcack, tvb,
457 BPDU_FLAGS, 1, flags);
458 if (bpdu_type == BPDU_TYPE_RST) {
459 APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_AGREEMENT, flags_item,
461 proto_tree_add_boolean(flags_tree, hf_bpdu_flags_agreement, tvb,
462 BPDU_FLAGS, 1, flags);
463 APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_FORWARDING, flags_item,
465 proto_tree_add_boolean(flags_tree, hf_bpdu_flags_forwarding, tvb,
466 BPDU_FLAGS, 1, flags);
467 APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_LEARNING, flags_item,
469 proto_tree_add_boolean(flags_tree, hf_bpdu_flags_learning, tvb,
470 BPDU_FLAGS, 1, flags);
474 port_role = (flags & BPDU_FLAGS_PORT_ROLE_MASK) >> BPDU_FLAGS_PORT_ROLE_SHIFT;
475 proto_item_append_text(flags_item, "%sPort Role: %s", sep,
476 val_to_str(port_role, role_vals,
480 proto_tree_add_uint(flags_tree, hf_bpdu_flags_port_role, tvb,
481 BPDU_FLAGS, 1, flags);
482 APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_PROPOSAL, flags_item,
484 proto_tree_add_boolean(flags_tree, hf_bpdu_flags_proposal, tvb,
485 BPDU_FLAGS, 1, flags);
487 APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_TC, flags_item,
488 "%sTopology Change");
489 proto_tree_add_boolean(flags_tree, hf_bpdu_flags_tc, tvb,
490 BPDU_FLAGS, 1, flags);
491 if (sep != initial_sep) {
492 /* We put something in; put in the terminating ")" */
493 proto_item_append_text(flags_item, ")");
496 /* add Identifier with format based on preference value
497 * bpdu_use_system_id_extensions
499 if (bpdu_use_system_id_extensions) {
500 root_id_item = proto_tree_add_text(bpdu_tree, tvb,
501 BPDU_ROOT_IDENTIFIER, 8,
502 "Root Identifier: %d / %d / %s",
503 root_identifier_bridge_priority,
504 root_identifier_system_id_extension,
505 root_identifier_mac_str);
506 root_id_tree = proto_item_add_subtree(root_id_item, ett_root_id);
507 proto_tree_add_uint(root_id_tree, hf_bpdu_root_prio, tvb,
508 BPDU_ROOT_IDENTIFIER , 1,
509 root_identifier_bridge_priority);
510 proto_tree_add_uint(root_id_tree, hf_bpdu_root_sys_id_ext, tvb,
511 BPDU_ROOT_IDENTIFIER , 2,
512 root_identifier_system_id_extension);
513 proto_tree_add_ether_format_value(root_id_tree, hf_bpdu_root_mac,
514 tvb, BPDU_ROOT_IDENTIFIER + 2, 6,
516 "%s", root_identifier_mac_str);
518 root_id_item = proto_tree_add_text(bpdu_tree, tvb,
519 BPDU_ROOT_IDENTIFIER, 8,
520 "Root Identifier: %d / %s",
521 root_identifier_bridge_priority,
522 root_identifier_mac_str);
523 root_id_tree = proto_item_add_subtree(root_id_item, ett_root_id);
524 proto_tree_add_uint(root_id_tree, hf_bpdu_root_prio, tvb,
525 BPDU_ROOT_IDENTIFIER , 2,
526 root_identifier_bridge_priority);
527 proto_tree_add_ether_format_value(root_id_tree, hf_bpdu_root_mac,
528 tvb, BPDU_ROOT_IDENTIFIER + 2, 6,
530 "%s", root_identifier_mac_str);
532 /* end of Identifier formatting */
534 proto_tree_add_uint(bpdu_tree, hf_bpdu_root_cost, tvb,
535 BPDU_ROOT_PATH_COST, 4, root_path_cost);
537 /* add Identifier with format based on preference value
538 * bpdu_use_system_id_extensions
540 if (bpdu_use_system_id_extensions) {
541 bridge_id_item = proto_tree_add_text(bpdu_tree, tvb,
542 BPDU_BRIDGE_IDENTIFIER, 8,
543 "Bridge Identifier: %d / %d / %s",
544 bridge_identifier_bridge_priority,
545 bridge_identifier_system_id_extension,
546 bridge_identifier_mac_str);
547 bridge_id_tree = proto_item_add_subtree(bridge_id_item, ett_bridge_id);
548 proto_tree_add_uint(bridge_id_tree, hf_bpdu_bridge_prio, tvb,
549 BPDU_BRIDGE_IDENTIFIER , 1,
550 bridge_identifier_bridge_priority);
551 proto_tree_add_uint(bridge_id_tree, hf_bpdu_bridge_sys_id_ext, tvb,
552 BPDU_BRIDGE_IDENTIFIER , 2,
553 bridge_identifier_system_id_extension);
554 proto_tree_add_ether_format_value(bridge_id_tree, hf_bpdu_bridge_mac,
555 tvb, BPDU_BRIDGE_IDENTIFIER + 2, 6,
556 bridge_identifier_mac,
557 "%s", bridge_identifier_mac_str);
559 bridge_id_item = proto_tree_add_text(bpdu_tree, tvb,
560 BPDU_BRIDGE_IDENTIFIER, 8,
561 "Bridge Identifier: %d / %s",
562 bridge_identifier_bridge_priority,
563 bridge_identifier_mac_str);
564 bridge_id_tree = proto_item_add_subtree(bridge_id_item, ett_bridge_id);
565 proto_tree_add_uint(bridge_id_tree, hf_bpdu_bridge_prio, tvb,
566 BPDU_BRIDGE_IDENTIFIER , 2,
567 bridge_identifier_bridge_priority);
568 proto_tree_add_ether_format_value(bridge_id_tree, hf_bpdu_bridge_mac,
569 tvb, BPDU_BRIDGE_IDENTIFIER + 2, 6,
570 bridge_identifier_mac,
571 "%s", bridge_identifier_mac_str);
573 /* end of Identifier formatting */
575 proto_tree_add_uint(bpdu_tree, hf_bpdu_port_id, tvb,
576 BPDU_PORT_IDENTIFIER, 2, port_identifier);
577 message_age = tvb_get_ntohs(tvb, BPDU_MESSAGE_AGE) / 256.0;
578 proto_tree_add_double(bpdu_tree, hf_bpdu_msg_age, tvb, BPDU_MESSAGE_AGE, 2,
580 max_age = tvb_get_ntohs(tvb, BPDU_MAX_AGE) / 256.0;
581 proto_tree_add_double(bpdu_tree, hf_bpdu_max_age, tvb, BPDU_MAX_AGE, 2,
583 hello_time = tvb_get_ntohs(tvb, BPDU_HELLO_TIME) / 256.0;
584 proto_tree_add_double(bpdu_tree, hf_bpdu_hello_time, tvb,
585 BPDU_HELLO_TIME, 2, hello_time);
586 forward_delay = tvb_get_ntohs(tvb, BPDU_FORWARD_DELAY) / 256.0;
587 proto_tree_add_double(bpdu_tree, hf_bpdu_forward_delay, tvb,
588 BPDU_FORWARD_DELAY, 2, forward_delay);
590 if (bpdu_type == BPDU_TYPE_CONF) {
591 /* Nothing more in this BPDU */
592 set_actual_length(tvb, CONF_BPDU_SIZE);
596 /* RST or MST BPDU */
597 version_1_length = tvb_get_guint8(tvb, BPDU_VERSION_1_LENGTH);
598 proto_tree_add_uint(bpdu_tree, hf_bpdu_version_1_length, tvb,
599 BPDU_VERSION_1_LENGTH, 1, version_1_length);
600 /* Is this an MST BPDU? */
601 if (protocol_version_identifier >= 3 && version_1_length == 0 &&
602 tvb_reported_length(tvb) >= 102) {
604 * OK, it passes the "Protocol Identifier is 0000 0000
605 * 0000 0000", "Protocol Version Identifier is 3 or
606 * greater", "BPDU Type is 0000 0010", "contains 102 or
607 * more octets", and "a Version 1 Length of 0" tests.
609 version_3_length = tvb_get_ntohs(tvb, BPDU_VERSION_3_LENGTH);
610 proto_tree_add_uint(bpdu_tree, hf_bpdu_version_3_length, tvb,
611 BPDU_VERSION_3_LENGTH, 2, version_3_length);
614 * Check the Version 3 Length, and see whether it's a
615 * multiple of the MSTI Configuration Message length. Also
616 * check the config_format_selector because some MST BPDU's
617 * have BPDU_VERSION_3_LENGTH set to 0 and use the
618 * field BPDU_MST_CONFIG_FORMAT_SELECTOR as a length-field
621 config_format_selector = tvb_get_guint8(tvb, BPDU_MST_CONFIG_FORMAT_SELECTOR);
622 if (version_3_length != 0) {
623 msti_format = MSTI_FORMAT_IEEE_8021S;
624 if (version_3_length >= VERSION_3_STATIC_LENGTH) {
625 total_msti_length = version_3_length - VERSION_3_STATIC_LENGTH;
628 * XXX - there appears to be an ambiguity in the 802.3Q-2003
629 * standard and at least some of the 802.3s drafts.
631 * The "Version 3 Length" field is defined to be "the number of
632 * octets taken by the parameters that follow in the BPDU", but
633 * it's spoken of as "representing an integral number, from 0 to
634 * 64 inclusive, of MSTI Configuration Messages".
636 * According to mail from a member of the stds-802-1@ieee.org list,
637 * the latter of those is just saying that the length must not have
638 * a value that implies that there's a partial MSTI message in the
639 * packet; it's still in units of octets, not messages.
641 * However, it appears that Cisco's C3550 software (C3550-I5Q3L2-M,
642 * Version 12.1(12c)EA1) might be sending out lengths in units of
645 * This length can't be the number of octets taken by the parameters
646 * that follow in the BPDU, because it's less than the fixed-length
647 * portion of those parameters, so we assume the length is a count of
650 total_msti_length = version_3_length * MSTI_MESSAGE_SIZE;
653 if (tvb_reported_length(tvb) == (guint)config_format_selector + MST_BPDU_SIZE + 1 ) {
654 msti_format = MSTI_FORMAT_ALTERNATIVE;
655 total_msti_length = config_format_selector - VERSION_3_STATIC_LENGTH;
658 * XXX - Unknown MSTI format, since version_3_length is 0
659 * lets assume there are no msti instances in the packet.
661 msti_format = MSTI_FORMAT_UNKNOWN;
662 total_msti_length = 0;
666 set_actual_length(tvb, BPDU_MSTI + total_msti_length);
668 mstp_item = proto_tree_add_text(bpdu_tree, tvb, BPDU_VERSION_3_LENGTH,
669 -1, "MST Extension");
670 mstp_tree = proto_item_add_subtree(mstp_item, ett_mstp);
672 proto_tree_add_item(mstp_tree, hf_bpdu_mst_config_format_selector, tvb,
673 BPDU_MST_CONFIG_FORMAT_SELECTOR, 1, FALSE);
674 proto_tree_add_item(mstp_tree, hf_bpdu_mst_config_name, tvb,
675 BPDU_MST_CONFIG_NAME, 32, FALSE);
677 proto_tree_add_item(mstp_tree, hf_bpdu_mst_config_revision_level, tvb,
678 BPDU_MST_CONFIG_REVISION_LEVEL, 2, FALSE);
679 proto_tree_add_item(mstp_tree, hf_bpdu_mst_config_digest, tvb,
680 BPDU_MST_CONFIG_DIGEST, 16, FALSE);
682 switch(msti_format) {
684 case MSTI_FORMAT_IEEE_8021S:
685 proto_tree_add_item(mstp_tree, hf_bpdu_cist_internal_root_path_cost, tvb,
686 BPDU_CIST_INTERNAL_ROOT_PATH_COST, 4, FALSE);
688 cist_bridge_identifier_bridge_priority = tvb_get_ntohs(tvb,BPDU_CIST_BRIDGE_IDENTIFIER);
689 cist_bridge_identifier_mac = tvb_get_ptr(tvb, BPDU_CIST_BRIDGE_IDENTIFIER + 2, 6);
690 cist_bridge_identifier_mac_str = ether_to_str(cist_bridge_identifier_mac);
692 /* add Identifier with format based on preference value
693 * bpdu_use_system_id_extensions
695 if (bpdu_use_system_id_extensions ) {
696 cist_bridge_identifier_system_id_extension = cist_bridge_identifier_bridge_priority & 0x0fff;
697 cist_bridge_identifier_bridge_priority &= 0xf000;
699 cist_bridge_id_item = proto_tree_add_text(mstp_tree, tvb,
700 BPDU_CIST_BRIDGE_IDENTIFIER, 8,
701 "CIST Bridge Identifier: %d / %d / %s",
702 cist_bridge_identifier_bridge_priority,
703 cist_bridge_identifier_system_id_extension,
704 cist_bridge_identifier_mac_str);
705 cist_bridge_id_tree = proto_item_add_subtree(cist_bridge_id_item, ett_cist_bridge_id);
706 proto_tree_add_uint(cist_bridge_id_tree, hf_bpdu_cist_bridge_prio, tvb,
707 BPDU_CIST_BRIDGE_IDENTIFIER , 1,
708 cist_bridge_identifier_bridge_priority);
709 proto_tree_add_uint(cist_bridge_id_tree, hf_bpdu_cist_bridge_sys_id_ext, tvb,
710 BPDU_CIST_BRIDGE_IDENTIFIER , 2,
711 cist_bridge_identifier_system_id_extension);
712 proto_tree_add_ether_format_value(cist_bridge_id_tree, hf_bpdu_cist_bridge_mac,
713 tvb, BPDU_CIST_BRIDGE_IDENTIFIER + 2, 6,
714 cist_bridge_identifier_mac,
715 "%s", cist_bridge_identifier_mac_str);
717 cist_bridge_id_item = proto_tree_add_text(mstp_tree, tvb,
718 BPDU_CIST_BRIDGE_IDENTIFIER, 8,
719 "CIST Bridge Identifier: %d / %s",
720 cist_bridge_identifier_bridge_priority,
721 cist_bridge_identifier_mac_str);
722 cist_bridge_id_tree = proto_item_add_subtree(cist_bridge_id_item, ett_cist_bridge_id);
723 proto_tree_add_uint(cist_bridge_id_tree, hf_bpdu_cist_bridge_prio, tvb,
724 BPDU_CIST_BRIDGE_IDENTIFIER , 2,
725 cist_bridge_identifier_bridge_priority);
726 proto_tree_add_ether_format_value(cist_bridge_id_tree, hf_bpdu_cist_bridge_mac,
727 tvb, BPDU_CIST_BRIDGE_IDENTIFIER + 2, 6,
728 cist_bridge_identifier_mac,
729 "%s", cist_bridge_identifier_mac_str);
731 /* end of Identifier formatting */
735 case MSTI_FORMAT_ALTERNATIVE:
736 cist_bridge_identifier_bridge_priority = tvb_get_ntohs(tvb,ALT_BPDU_CIST_BRIDGE_IDENTIFIER);
737 cist_bridge_identifier_mac = tvb_get_ptr(tvb, ALT_BPDU_CIST_BRIDGE_IDENTIFIER + 2, 6);
738 cist_bridge_identifier_mac_str = ether_to_str(cist_bridge_identifier_mac);
740 /* add Identifier with format based on preference value
741 * bpdu_use_system_id_extensions
743 if (bpdu_use_system_id_extensions ) {
744 cist_bridge_identifier_system_id_extension = cist_bridge_identifier_bridge_priority & 0x0fff;
745 cist_bridge_identifier_bridge_priority &= 0xf000;
747 cist_bridge_id_item = proto_tree_add_text(mstp_tree, tvb,
748 ALT_BPDU_CIST_BRIDGE_IDENTIFIER, 8,
749 "CIST Bridge Identifier: %d / %d / %s",
750 cist_bridge_identifier_bridge_priority,
751 cist_bridge_identifier_system_id_extension,
752 cist_bridge_identifier_mac_str);
753 cist_bridge_id_tree = proto_item_add_subtree(cist_bridge_id_item, ett_cist_bridge_id);
754 proto_tree_add_uint(cist_bridge_id_tree, hf_bpdu_cist_bridge_prio, tvb,
755 ALT_BPDU_CIST_BRIDGE_IDENTIFIER , 1,
756 cist_bridge_identifier_bridge_priority);
757 proto_tree_add_uint(cist_bridge_id_tree, hf_bpdu_cist_bridge_sys_id_ext, tvb,
758 ALT_BPDU_CIST_BRIDGE_IDENTIFIER , 2,
759 cist_bridge_identifier_system_id_extension);
760 proto_tree_add_ether_format_value(cist_bridge_id_tree, hf_bpdu_cist_bridge_mac,
761 tvb, ALT_BPDU_CIST_BRIDGE_IDENTIFIER + 2, 6,
762 cist_bridge_identifier_mac,
763 "%s", cist_bridge_identifier_mac_str);
765 cist_bridge_id_item = proto_tree_add_text(mstp_tree, tvb,
766 ALT_BPDU_CIST_BRIDGE_IDENTIFIER, 8,
767 "CIST Bridge Identifier: %d / %s",
768 cist_bridge_identifier_bridge_priority,
769 cist_bridge_identifier_mac_str);
770 cist_bridge_id_tree = proto_item_add_subtree(cist_bridge_id_item, ett_cist_bridge_id);
771 proto_tree_add_uint(cist_bridge_id_tree, hf_bpdu_cist_bridge_prio, tvb,
772 ALT_BPDU_CIST_BRIDGE_IDENTIFIER , 2,
773 cist_bridge_identifier_bridge_priority);
774 proto_tree_add_ether_format_value(cist_bridge_id_tree, hf_bpdu_cist_bridge_mac,
775 tvb, ALT_BPDU_CIST_BRIDGE_IDENTIFIER + 2, 6,
776 cist_bridge_identifier_mac,
777 "%s", cist_bridge_identifier_mac_str);
779 /* end of Identifier formatting */
781 proto_tree_add_item(mstp_tree, hf_bpdu_cist_internal_root_path_cost, tvb,
782 ALT_BPDU_CIST_INTERNAL_ROOT_PATH_COST, 4, FALSE);
787 proto_tree_add_item(mstp_tree, hf_bpdu_cist_remaining_hops, tvb,
788 BPDU_CIST_REMAINING_HOPS, 1, FALSE);
792 while (total_msti_length > 0) {
793 switch(msti_format) {
795 case MSTI_FORMAT_IEEE_8021S:
796 msti_regional_root_mstid = tvb_get_guint8(tvb, offset+ MSTI_REGIONAL_ROOT);
797 msti_regional_root_priority = (msti_regional_root_mstid &0xf0) << 8;
798 msti_regional_root_mstid = ((msti_regional_root_mstid & 0x0f) << 8) +
799 tvb_get_guint8(tvb, offset+ MSTI_REGIONAL_ROOT+1);
800 msti_regional_root_mac = tvb_get_ptr(tvb, offset+ MSTI_REGIONAL_ROOT + 2, 6);
801 msti_regional_root_mac_str = ether_to_str(msti_regional_root_mac);
803 msti_item = proto_tree_add_text(mstp_tree, tvb, offset, 16,
804 "MSTID %d, Regional Root Identifier %d / %s",
805 msti_regional_root_mstid,
806 msti_regional_root_priority,
807 msti_regional_root_mac_str);
808 msti_tree = proto_item_add_subtree(msti_item, ett_msti);
811 flags = tvb_get_guint8(tvb, offset+MSTI_FLAGS);
812 flags_item = proto_tree_add_uint(msti_tree, hf_bpdu_msti_flags, tvb,
813 offset+MSTI_FLAGS, 1, flags);
814 flags_tree = proto_item_add_subtree(flags_item, ett_bpdu_flags);
817 APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_TCACK, flags_item, "%sMaster");
818 proto_tree_add_boolean(flags_tree, hf_bpdu_flags_tcack, tvb,
819 offset+MSTI_FLAGS, 1, flags);
820 APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_AGREEMENT, flags_item, "%sAgreement");
821 proto_tree_add_boolean(flags_tree, hf_bpdu_flags_agreement, tvb,
822 offset+MSTI_FLAGS, 1, flags);
823 APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_FORWARDING, flags_item, "%sForwarding");
824 proto_tree_add_boolean(flags_tree, hf_bpdu_flags_forwarding, tvb,
825 offset+MSTI_FLAGS, 1, flags);
826 APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_LEARNING, flags_item, "%sLearning");
827 proto_tree_add_boolean(flags_tree, hf_bpdu_flags_learning, tvb,
828 offset+MSTI_FLAGS, 1, flags);
831 port_role = (flags & BPDU_FLAGS_PORT_ROLE_MASK) >> BPDU_FLAGS_PORT_ROLE_SHIFT;
832 proto_item_append_text(flags_item, "%sPort Role: %s", sep,
833 val_to_str(port_role, role_vals,
836 proto_tree_add_uint(flags_tree, hf_bpdu_flags_port_role, tvb,
837 offset+MSTI_FLAGS, 1, flags);
839 APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_PROPOSAL, flags_item, "%sProposal");
840 proto_tree_add_boolean(flags_tree, hf_bpdu_flags_proposal, tvb,
841 offset+MSTI_FLAGS, 1, flags);
842 APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_TC, flags_item, "%sTopology Change");
843 proto_tree_add_boolean(flags_tree, hf_bpdu_flags_tc, tvb,
844 offset+MSTI_FLAGS, 1, flags);
845 if (sep != initial_sep) { /* We put something in; put in the terminating ")" */
846 proto_item_append_text(flags_item, ")");
849 /* pri, MSTID, Regional root */
850 hidden_item = proto_tree_add_ether(msti_tree, hf_bpdu_msti_regional_root_mac, tvb,
851 offset + MSTI_REGIONAL_ROOT + 2, 6,
852 msti_regional_root_mac);
853 PROTO_ITEM_SET_HIDDEN(hidden_item);
854 proto_tree_add_text(msti_tree, tvb, offset + MSTI_REGIONAL_ROOT, 8,
855 "MSTID %d, priority %d Root Identifier %s",
856 msti_regional_root_mstid,
857 msti_regional_root_priority,
858 msti_regional_root_mac_str);
861 proto_tree_add_item(msti_tree, hf_bpdu_msti_internal_root_path_cost, tvb,
862 offset+MSTI_INTERNAL_ROOT_PATH_COST, 4, FALSE);
864 msti_bridge_identifier_priority = tvb_get_guint8(tvb, offset+MSTI_BRIDGE_IDENTIFIER_PRIORITY) >> 4;
865 msti_port_identifier_priority = tvb_get_guint8(tvb, offset+MSTI_PORT_IDENTIFIER_PRIORITY) >> 4;
867 proto_tree_add_uint(msti_tree, hf_bpdu_msti_bridge_identifier_priority, tvb,
868 offset+MSTI_BRIDGE_IDENTIFIER_PRIORITY, 1,
869 msti_bridge_identifier_priority);
870 proto_tree_add_uint(msti_tree, hf_bpdu_msti_port_identifier_priority, tvb,
871 offset+MSTI_PORT_IDENTIFIER_PRIORITY, 1,
872 msti_port_identifier_priority);
874 proto_tree_add_item(msti_tree, hf_bpdu_msti_remaining_hops, tvb,
875 offset + MSTI_REMAINING_HOPS, 1, FALSE);
877 total_msti_length -= MSTI_MESSAGE_SIZE;
878 offset += MSTI_MESSAGE_SIZE;
881 case MSTI_FORMAT_ALTERNATIVE:
882 msti_regional_root_mstid = tvb_get_guint8(tvb, offset+ ALT_MSTI_REGIONAL_ROOT);
883 msti_regional_root_priority = (msti_regional_root_mstid &0xf0) << 8;
884 msti_regional_root_mstid = ((msti_regional_root_mstid & 0x0f) << 8) +
885 tvb_get_guint8(tvb, offset+ ALT_MSTI_REGIONAL_ROOT+1);
886 msti_regional_root_mac = tvb_get_ptr(tvb, offset+ ALT_MSTI_REGIONAL_ROOT + 2, 6);
887 msti_regional_root_mac_str = ether_to_str(msti_regional_root_mac);
889 msti_item = proto_tree_add_text(mstp_tree, tvb, offset, 16,
890 "MSTID %d, Regional Root Identifier %d / %s",
891 msti_regional_root_mstid,
892 msti_regional_root_priority,
893 msti_regional_root_mac_str);
894 msti_tree = proto_item_add_subtree(msti_item, ett_msti);
896 msti_mstid = tvb_get_ntohs(tvb, offset+ ALT_MSTI_MSTID);
897 proto_tree_add_text(msti_tree, tvb, offset+ALT_MSTI_MSTID, 2,
898 "MSTID: %d", msti_mstid);
901 flags = tvb_get_guint8(tvb, offset+ALT_MSTI_FLAGS);
902 flags_item = proto_tree_add_uint(msti_tree, hf_bpdu_msti_flags, tvb,
903 offset+ALT_MSTI_FLAGS, 1, flags);
904 flags_tree = proto_item_add_subtree(flags_item, ett_bpdu_flags);
907 APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_TCACK, flags_item, "%sMaster");
908 proto_tree_add_boolean(flags_tree, hf_bpdu_flags_tcack, tvb,
909 offset+ALT_MSTI_FLAGS, 1, flags);
910 APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_AGREEMENT, flags_item, "%sAgreement");
911 proto_tree_add_boolean(flags_tree, hf_bpdu_flags_agreement, tvb,
912 offset+ALT_MSTI_FLAGS, 1, flags);
913 APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_FORWARDING, flags_item, "%sForwarding");
914 proto_tree_add_boolean(flags_tree, hf_bpdu_flags_forwarding, tvb,
915 offset+ALT_MSTI_FLAGS, 1, flags);
916 APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_LEARNING, flags_item, "%sLearning");
917 proto_tree_add_boolean(flags_tree, hf_bpdu_flags_learning, tvb,
918 offset+ALT_MSTI_FLAGS, 1, flags);
921 port_role = (flags & BPDU_FLAGS_PORT_ROLE_MASK) >> BPDU_FLAGS_PORT_ROLE_SHIFT;
922 proto_item_append_text(flags_item, "%sPort Role: %s", sep,
923 val_to_str(port_role, role_vals,
926 proto_tree_add_uint(flags_tree, hf_bpdu_flags_port_role, tvb,
927 offset+ALT_MSTI_FLAGS, 1, flags);
929 APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_PROPOSAL, flags_item, "%sProposal");
930 proto_tree_add_boolean(flags_tree, hf_bpdu_flags_proposal, tvb,
931 offset+ALT_MSTI_FLAGS, 1, flags);
932 APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_TC, flags_item, "%sTopology Change");
933 proto_tree_add_boolean(flags_tree, hf_bpdu_flags_tc, tvb,
934 offset+ALT_MSTI_FLAGS, 1, flags);
935 if (sep != initial_sep) { /* We put something in; put in the terminating ")" */
936 proto_item_append_text(flags_item, ")");
939 /* pri, MSTID, Regional root */
940 hidden_item = proto_tree_add_ether(msti_tree, hf_bpdu_msti_regional_root_mac, tvb,
941 offset + ALT_MSTI_REGIONAL_ROOT + 2, 6,
942 msti_regional_root_mac);
943 PROTO_ITEM_SET_HIDDEN(hidden_item);
944 proto_tree_add_text(msti_tree, tvb, offset + ALT_MSTI_REGIONAL_ROOT, 8,
945 "MSTI Regional Root Identifier: %d / %d / %s",
946 msti_regional_root_mstid,
947 msti_regional_root_priority,
948 msti_regional_root_mac_str);
951 proto_tree_add_item(msti_tree, hf_bpdu_msti_internal_root_path_cost, tvb,
952 offset+ALT_MSTI_INTERNAL_ROOT_PATH_COST, 4, FALSE);
954 msti_bridge_identifier_priority = tvb_get_ntohs(tvb, offset+ALT_MSTI_BRIDGE_IDENTIFIER);
955 msti_bridge_identifier_mac = tvb_get_ptr(tvb, offset+ALT_MSTI_BRIDGE_IDENTIFIER + 2, 6);
956 msti_bridge_identifier_mac_str = ether_to_str(msti_bridge_identifier_mac);
957 proto_tree_add_text(msti_tree, tvb, offset+ALT_MSTI_BRIDGE_IDENTIFIER, 8,
958 "MSTI Bridge Identifier: %d / %d / %s",
959 msti_bridge_identifier_priority & 0x0fff,
960 msti_bridge_identifier_priority & 0xf000,
961 msti_bridge_identifier_mac_str);
963 msti_port_identifier_priority = tvb_get_ntohs(tvb, offset+ALT_MSTI_PORT_IDENTIFIER);
964 proto_tree_add_uint(msti_tree, hf_bpdu_msti_port_id, tvb,
965 offset+ALT_MSTI_PORT_IDENTIFIER, 2, msti_port_identifier_priority);
967 proto_tree_add_item(msti_tree, hf_bpdu_msti_remaining_hops, tvb,
968 offset + ALT_MSTI_REMAINING_HOPS, 1, FALSE);
970 total_msti_length -= ALT_MSTI_MESSAGE_SIZE;
971 offset += ALT_MSTI_MESSAGE_SIZE;
982 proto_register_bpdu(void)
985 static hf_register_info hf[] = {
987 { "Protocol Identifier", "stp.protocol",
988 FT_UINT16, BASE_HEX, VALS(&protocol_id_vals), 0x0,
990 { &hf_bpdu_version_id,
991 { "Protocol Version Identifier", "stp.version",
992 FT_UINT8, BASE_DEC, VALS(&version_id_vals), 0x0,
995 { "BPDU Type", "stp.type",
996 FT_UINT8, BASE_HEX, VALS(&bpdu_type_vals), 0x0,
999 { "BPDU flags", "stp.flags",
1000 FT_UINT8, BASE_HEX, NULL, 0x0,
1002 { &hf_bpdu_flags_tcack,
1003 { "Topology Change Acknowledgment", "stp.flags.tcack",
1004 FT_BOOLEAN, 8, TFS(&tfs_yes_no), BPDU_FLAGS_TCACK,
1006 { &hf_bpdu_flags_agreement,
1007 { "Agreement", "stp.flags.agreement",
1008 FT_BOOLEAN, 8, TFS(&tfs_yes_no), BPDU_FLAGS_AGREEMENT,
1010 { &hf_bpdu_flags_forwarding,
1011 { "Forwarding", "stp.flags.forwarding",
1012 FT_BOOLEAN, 8, TFS(&tfs_yes_no), BPDU_FLAGS_FORWARDING,
1014 { &hf_bpdu_flags_learning,
1015 { "Learning", "stp.flags.learning",
1016 FT_BOOLEAN, 8, TFS(&tfs_yes_no), BPDU_FLAGS_LEARNING,
1018 { &hf_bpdu_flags_port_role,
1019 { "Port Role", "stp.flags.port_role",
1020 FT_UINT8, BASE_DEC, VALS(role_vals), BPDU_FLAGS_PORT_ROLE_MASK,
1022 { &hf_bpdu_flags_proposal,
1023 { "Proposal", "stp.flags.proposal",
1024 FT_BOOLEAN, 8, TFS(&tfs_yes_no), BPDU_FLAGS_PROPOSAL,
1026 { &hf_bpdu_flags_tc,
1027 { "Topology Change", "stp.flags.tc",
1028 FT_BOOLEAN, 8, TFS(&tfs_yes_no), BPDU_FLAGS_TC,
1030 { &hf_bpdu_root_prio,
1031 { "Root Bridge Priority", "stp.root.prio",
1032 FT_UINT16, BASE_DEC, NULL, 0x0,
1034 { &hf_bpdu_root_sys_id_ext,
1035 { "Root Bridge System ID Extension", "stp.root.ext",
1036 FT_UINT16, BASE_DEC, NULL, 0x0,
1038 { &hf_bpdu_root_mac,
1039 { "Root Bridge System ID", "stp.root.hw",
1040 FT_ETHER, BASE_NONE, NULL, 0x0,
1042 { &hf_bpdu_root_cost,
1043 { "Root Path Cost", "stp.root.cost",
1044 FT_UINT32, BASE_DEC, NULL, 0x0,
1046 { &hf_bpdu_bridge_prio,
1047 { "Bridge Priority", "stp.bridge.prio",
1048 FT_UINT16, BASE_DEC, NULL, 0x0,
1050 { &hf_bpdu_bridge_sys_id_ext,
1051 { "Bridge System ID Extension", "stp.bridge.ext",
1052 FT_UINT16, BASE_DEC, NULL, 0x0,
1054 { &hf_bpdu_bridge_mac,
1055 { "Bridge System ID", "stp.bridge.hw",
1056 FT_ETHER, BASE_NONE, NULL, 0x0,
1059 { "Port identifier", "stp.port",
1060 FT_UINT16, BASE_HEX, NULL, 0x0,
1063 { "Message Age", "stp.msg_age",
1064 FT_DOUBLE, BASE_NONE, NULL, 0x0,
1067 { "Max Age", "stp.max_age",
1068 FT_DOUBLE, BASE_NONE, NULL, 0x0,
1070 { &hf_bpdu_hello_time,
1071 { "Hello Time", "stp.hello",
1072 FT_DOUBLE, BASE_NONE, NULL, 0x0,
1074 { &hf_bpdu_forward_delay,
1075 { "Forward Delay", "stp.forward",
1076 FT_DOUBLE, BASE_NONE, NULL, 0x0,
1078 { &hf_bpdu_version_1_length,
1079 { "Version 1 Length", "stp.version_1_length",
1080 FT_UINT8, BASE_DEC, NULL, 0x0,
1082 { &hf_bpdu_version_3_length,
1083 { "Version 3 Length", "mstp.version_3_length",
1084 FT_UINT16, BASE_DEC, NULL, 0x0,
1086 { &hf_bpdu_mst_config_format_selector,
1087 { "MST Config ID format selector", "mstp.config_format_selector",
1088 FT_UINT8, BASE_DEC, NULL, 0x0,
1090 { &hf_bpdu_mst_config_name,
1091 { "MST Config name", "mstp.config_name",
1092 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1094 { &hf_bpdu_mst_config_revision_level,
1095 { "MST Config revision", "mstp.config_revision_level",
1096 FT_UINT16, BASE_DEC, NULL, 0x0,
1098 { &hf_bpdu_mst_config_digest,
1099 { "MST Config digest", "mstp.config_digest",
1100 FT_BYTES, BASE_DEC, NULL, 0x0,
1102 { &hf_bpdu_cist_internal_root_path_cost,
1103 { "CIST Internal Root Path Cost", "mstp.cist_internal_root_path_cost",
1104 FT_UINT32, BASE_DEC, NULL, 0x0,
1106 { &hf_bpdu_cist_bridge_prio,
1107 { "CIST Bridge Priority", "mstp.cist_bridge.prio",
1108 FT_UINT16, BASE_DEC, NULL, 0x0,
1110 { &hf_bpdu_cist_bridge_sys_id_ext,
1111 { "CIST Bridge Identifier System ID Extension", "mstp.cist_bridge.ext",
1112 FT_UINT16, BASE_DEC, NULL, 0x0,
1114 { &hf_bpdu_cist_bridge_mac,
1115 { "CIST Bridge Identifier System ID", "mstp.cist_bridge.hw",
1116 FT_ETHER, BASE_NONE, NULL, 0x0,
1118 { &hf_bpdu_cist_remaining_hops,
1119 { "CIST Remaining hops", "mstp.cist_remaining_hops",
1120 FT_UINT8, BASE_DEC, NULL, 0x0,
1122 { &hf_bpdu_msti_flags,
1123 { "MSTI flags", "mstp.msti.flags",
1124 FT_UINT8, BASE_HEX, NULL, 0x0,
1126 { &hf_bpdu_msti_regional_root_mac,
1127 { "Regional Root", "mstp.msti.root.hw",
1128 FT_ETHER, BASE_DEC, NULL, 0x0,
1130 { &hf_bpdu_msti_internal_root_path_cost,
1131 { "Internal root path cost", "mstp.msti.root_cost",
1132 FT_UINT32, BASE_DEC, NULL, 0x0,
1134 { &hf_bpdu_msti_bridge_identifier_priority,
1135 { "Bridge Identifier Priority", "mstp.msti.bridge_priority",
1136 FT_UINT8, BASE_DEC, NULL, 0x0,
1138 { &hf_bpdu_msti_port_identifier_priority,
1139 { "Port identifier priority", "mstp.msti.port_priority",
1140 FT_UINT8, BASE_DEC, NULL, 0x0,
1142 { &hf_bpdu_msti_port_id,
1143 { "Port identifier", "mstp.msti.port",
1144 FT_UINT16, BASE_HEX, NULL, 0x0,
1146 { &hf_bpdu_msti_remaining_hops,
1147 { "Remaining hops", "mstp.msti.remaining_hops",
1148 FT_UINT8, BASE_DEC, NULL, 0x0,
1152 static gint *ett[] = {
1161 module_t *bpdu_module;
1163 proto_bpdu = proto_register_protocol("Spanning Tree Protocol", "STP", "stp");
1164 proto_register_field_array(proto_bpdu, hf, array_length(hf));
1165 proto_register_subtree_array(ett, array_length(ett));
1167 register_dissector("bpdu", dissect_bpdu, proto_bpdu);
1169 bpdu_module = prefs_register_protocol(proto_bpdu, NULL);
1170 prefs_register_bool_preference(bpdu_module, "use_system_id_extension",
1171 "Use 802.1t System ID Extensions",
1172 "Whether the BPDU dissector should use 802.1t System ID Extensions when dissecting the Bridge Identifier",
1173 &bpdu_use_system_id_extensions);
1177 proto_reg_handoff_bpdu(void)
1179 dissector_handle_t bpdu_handle;
1182 * Get handle for the GVRP dissector.
1184 gvrp_handle = find_dissector("gvrp");
1187 * Get handle for the GMRP dissector.
1189 gmrp_handle = find_dissector("gmrp");
1190 data_handle = find_dissector("data");
1192 bpdu_handle = find_dissector("bpdu");
1193 dissector_add("llc.dsap", SAP_BPDU, bpdu_handle);
1194 dissector_add("chdlctype", CHDLCTYPE_BPDU, bpdu_handle);
1195 dissector_add("llc.cisco_pid", 0x010b, bpdu_handle);
1196 dissector_add("ethertype", ETHERTYPE_STP, bpdu_handle);