Define some fcns & vars as static...
[metze/wireshark/wip.git] / epan / dissectors / packet-bpdu.c
1 /* packet-bpdu.c
2  * Routines for BPDU (Spanning Tree Protocol) disassembly
3  *
4  * $Id$
5  *
6  * Copyright 1999 Christophe Tronche <ch.tronche@computer.org>
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
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.
16  *
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.
21  *
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.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <glib.h>
32 #include <epan/packet.h>
33 #include <epan/llcsaps.h>
34 #include <epan/ppptypes.h>
35 #include <epan/chdlctypes.h>
36 #include <epan/etypes.h>
37 #include <epan/addr_resolv.h>
38 #include <epan/prefs.h>
39
40 /* Offsets of fields within a BPDU */
41
42 #define BPDU_IDENTIFIER                         0
43 #define BPDU_VERSION_IDENTIFIER                 2
44 #define BPDU_TYPE                               3
45 #define BPDU_FLAGS                              4
46 #define BPDU_ROOT_IDENTIFIER                    5
47 #define BPDU_ROOT_PATH_COST                     13
48 #define BPDU_BRIDGE_IDENTIFIER                  17
49 #define BPDU_PORT_IDENTIFIER                    25
50 #define BPDU_MESSAGE_AGE                        27
51 #define BPDU_MAX_AGE                            29
52 #define BPDU_HELLO_TIME                         31
53 #define BPDU_FORWARD_DELAY                      33
54 #define BPDU_VERSION_1_LENGTH                   35
55 #define BPDU_VERSION_3_LENGTH                   36
56 #define BPDU_MST_CONFIG_FORMAT_SELECTOR         38
57 #define BPDU_MST_CONFIG_NAME                    39
58 #define BPDU_MST_CONFIG_REVISION_LEVEL          71
59 #define BPDU_MST_CONFIG_DIGEST                  73
60 #define BPDU_CIST_INTERNAL_ROOT_PATH_COST       89
61 #define BPDU_CIST_BRIDGE_IDENTIFIER             93
62 #define BPDU_CIST_REMAINING_HOPS                101
63 #define BPDU_MSTI                               102
64
65 #define MSTI_FLAGS                              0
66 #define MSTI_REGIONAL_ROOT                      1
67 #define MSTI_INTERNAL_ROOT_PATH_COST            9
68 #define MSTI_BRIDGE_IDENTIFIER_PRIORITY         13
69 #define MSTI_PORT_IDENTIFIER_PRIORITY           14
70 #define MSTI_REMAINING_HOPS                     15
71
72
73 #define CONF_BPDU_SIZE                  35
74 #define TC_BPDU_SIZE                    4
75 #define MST_BPDU_SIZE                   38
76 #define VERSION_3_STATIC_LENGTH         64
77 #define MSTI_MESSAGE_SIZE               16
78
79 /* Values for the Alternative MSTI format */
80
81 #define ALT_BPDU_CIST_BRIDGE_IDENTIFIER         89
82 #define ALT_BPDU_CIST_INTERNAL_ROOT_PATH_COST   97
83
84 #define ALT_MSTI_MSTID                          0
85 #define ALT_MSTI_FLAGS                          2
86 #define ALT_MSTI_REGIONAL_ROOT                  3
87 #define ALT_MSTI_INTERNAL_ROOT_PATH_COST        11
88 #define ALT_MSTI_BRIDGE_IDENTIFIER              15
89 #define ALT_MSTI_PORT_IDENTIFIER                23
90 #define ALT_MSTI_REMAINING_HOPS                 25
91
92 #define ALT_MSTI_MESSAGE_SIZE                   26
93
94 /* Flag bits */
95
96 #define BPDU_FLAGS_TCACK                0x80
97 #define BPDU_FLAGS_AGREEMENT            0x40
98 #define BPDU_FLAGS_FORWARDING           0x20
99 #define BPDU_FLAGS_LEARNING             0x10
100 #define BPDU_FLAGS_PORT_ROLE_MASK       0x0C
101 #define BPDU_FLAGS_PORT_ROLE_SHIFT      2
102 #define BPDU_FLAGS_PROPOSAL             0x02
103 #define BPDU_FLAGS_TC                   0x01
104
105 static int proto_bpdu = -1;
106 static int hf_bpdu_proto_id = -1;
107 static int hf_bpdu_version_id = -1;
108 static int hf_bpdu_type = -1;
109 static int hf_bpdu_flags = -1;
110 static int hf_bpdu_flags_tcack = -1;
111 static int hf_bpdu_flags_agreement = -1;
112 static int hf_bpdu_flags_forwarding = -1;
113 static int hf_bpdu_flags_learning = -1;
114 static int hf_bpdu_flags_port_role = -1;
115 static int hf_bpdu_flags_proposal = -1;
116 static int hf_bpdu_flags_tc = -1;
117 static int hf_bpdu_root_prio = -1;
118 static int hf_bpdu_root_sys_id_ext = -1;
119 static int hf_bpdu_root_mac = -1;
120 static int hf_bpdu_root_cost = -1;
121 static int hf_bpdu_bridge_prio = -1;
122 static int hf_bpdu_bridge_sys_id_ext = -1;
123 static int hf_bpdu_bridge_mac = -1;
124 static int hf_bpdu_port_id = -1;
125 static int hf_bpdu_msg_age = -1;
126 static int hf_bpdu_max_age = -1;
127 static int hf_bpdu_hello_time = -1;
128 static int hf_bpdu_forward_delay = -1;
129 static int hf_bpdu_version_1_length = -1;
130 static int hf_bpdu_version_3_length = -1;
131 static int hf_bpdu_mst_config_format_selector = -1;
132 static int hf_bpdu_mst_config_name = -1;
133 static int hf_bpdu_mst_config_revision_level = -1;
134 static int hf_bpdu_mst_config_digest = -1;
135 static int hf_bpdu_cist_internal_root_path_cost = -1;
136 static int hf_bpdu_cist_bridge_prio = -1;
137 static int hf_bpdu_cist_bridge_sys_id_ext = -1;
138 static int hf_bpdu_cist_bridge_mac = -1;
139 static int hf_bpdu_cist_remaining_hops = -1;
140 static int hf_bpdu_msti_flags = -1;
141 static int hf_bpdu_msti_regional_root_mac = -1;
142 static int hf_bpdu_msti_internal_root_path_cost = -1;
143 static int hf_bpdu_msti_bridge_identifier_priority = -1;
144 static int hf_bpdu_msti_port_identifier_priority = -1;
145 static int hf_bpdu_msti_port_id = -1;
146 static int hf_bpdu_msti_remaining_hops = -1;
147
148 static gint ett_bpdu = -1;
149 static gint ett_bpdu_flags = -1;
150 static gint ett_root_id = -1;
151 static gint ett_bridge_id = -1;
152 static gint ett_mstp = -1;
153 static gint ett_msti = -1;
154 static gint ett_cist_bridge_id = -1;
155
156 static gboolean bpdu_use_system_id_extensions = TRUE;
157
158 static dissector_handle_t gvrp_handle;
159 static dissector_handle_t gmrp_handle;
160 static dissector_handle_t data_handle;
161
162 static const value_string protocol_id_vals[] = {
163   { 0, "Spanning Tree Protocol" },
164   { 0, NULL }
165 };
166
167 #define BPDU_TYPE_CONF                  0x00    /* STP Configuration BPDU */
168 #define BPDU_TYPE_RST                   0x02    /* RST BPDU (or MST) */
169 #define BPDU_TYPE_TOPOLOGY_CHANGE       0x80    /* STP TCN (Topology change notify) BPDU */
170
171 static const value_string bpdu_type_vals[] = {
172   { BPDU_TYPE_CONF,            "Configuration" },
173   { BPDU_TYPE_RST,             "Rapid/Multiple Spanning Tree" },
174   { BPDU_TYPE_TOPOLOGY_CHANGE, "Topology Change Notification" },
175   { 0,                         NULL }
176 };
177
178 #define PROTO_VERSION_STP       0
179 #define PROTO_VERSION_RSTP      2
180 #define PROTO_VERSION_MSTP      3
181
182 #define MSTI_FORMAT_UNKNOWN     0
183 #define MSTI_FORMAT_IEEE_8021S  1
184 #define MSTI_FORMAT_ALTERNATIVE 2
185
186 static const value_string version_id_vals[] = {
187   { PROTO_VERSION_STP,  "Spanning Tree" },
188   { PROTO_VERSION_RSTP, "Rapid Spanning Tree" },
189   { PROTO_VERSION_MSTP, "Multiple Spanning Tree" },
190   { 0,                  NULL}
191 };
192 static const value_string role_vals[] = {
193   { 1, "Alternate or Backup" },
194   { 2, "Root" },
195   { 3, "Designated" },
196   { 0, NULL }
197 };
198
199 static const char initial_sep[] = " (";
200 static const char cont_sep[] = ", ";
201
202 #define APPEND_BOOLEAN_FLAG(flag, item, string)         \
203   if(flag){                                             \
204     if(item)                                            \
205       proto_item_append_text(item, string, sep);        \
206     sep = cont_sep;                                     \
207   }
208
209 static void
210 dissect_bpdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
211 {
212   guint16 protocol_identifier;
213   guint8  protocol_version_identifier;
214   guint8  bpdu_type;
215   guint8  flags;
216   guint16 root_identifier_bridge_priority;
217   guint16 root_identifier_system_id_extension = 0;
218   const guint8  *root_identifier_mac;
219   gchar   *root_identifier_mac_str;
220   guint32 root_path_cost;
221   guint16 bridge_identifier_bridge_priority;
222   guint16 bridge_identifier_system_id_extension = 0;
223   const guint8  *bridge_identifier_mac;
224   gchar   *bridge_identifier_mac_str;
225   guint16 port_identifier;
226   double message_age;
227   double max_age;
228   double hello_time;
229   double forward_delay;
230   guint8 version_1_length;
231   guint16 version_3_length;
232   guint8 config_format_selector;
233   guint16 cist_bridge_identifier_bridge_priority;
234   guint16 cist_bridge_identifier_system_id_extension = 0;
235   const guint8  *cist_bridge_identifier_mac;
236   gchar   *cist_bridge_identifier_mac_str;
237   guint16 msti_mstid;
238   guint32 msti_regional_root_mstid, msti_regional_root_priority;
239   const guint8  *msti_regional_root_mac;
240   gchar   *msti_regional_root_mac_str;
241   guint16 msti_bridge_identifier_priority, msti_port_identifier_priority;
242   const guint8  *msti_bridge_identifier_mac;
243   gchar   *msti_bridge_identifier_mac_str;
244   int   total_msti_length, offset, msti, msti_format;
245
246   proto_tree *bpdu_tree;
247   proto_tree *mstp_tree, *msti_tree;
248   proto_item *bpdu_item;
249   proto_item *mstp_item, *msti_item;
250   proto_tree *flags_tree;
251   proto_item *flags_item;
252   proto_tree *root_id_tree;
253   proto_item *root_id_item;
254   proto_tree *bridge_id_tree;
255   proto_item *bridge_id_item;
256   proto_tree *cist_bridge_id_tree;
257   proto_item *cist_bridge_id_item;
258   proto_item *hidden_item;
259   const char *sep;
260
261   /* GARP application frames require special interpretation of the
262      destination address field; otherwise, they will be mistaken as
263      BPDU frames.
264      Fortunately, they can be recognized by checking the first 6 octets
265      of the destination address, which are in the range from
266      01-80-C2-00-00-20 to 01-80-C2-00-00-2F.
267
268      Yes - we *do* need to check the destination address type;
269      on Linux cooked captures, there *is* no destination address,
270      so it's AT_NONE. */
271   if (pinfo->dl_dst.type == AT_ETHER) {
272     const guint8 *dstaddr;
273
274     dstaddr = pinfo->dl_dst.data;
275     if(dstaddr[0] == 0x01 && dstaddr[1] == 0x80 &&
276        dstaddr[2] == 0xC2 && dstaddr[3] == 0x00 &&
277        dstaddr[4] == 0x00 && ((dstaddr[5] & 0xF0) == 0x20)) {
278
279       switch (dstaddr[5]) {
280
281       case 0x20:
282         /* for GMRP */
283         call_dissector(gmrp_handle, tvb, pinfo, tree);
284         return;
285
286       case 0x21:
287         /* for GVRP */
288         call_dissector(gvrp_handle, tvb, pinfo, tree);
289         return;
290       }
291
292       pinfo->current_proto = "GARP";
293
294       if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
295         col_set_str(pinfo->cinfo, COL_PROTOCOL, "GARP");
296         /* Generic Attribute Registration Protocol */
297       }
298
299       if (check_col(pinfo->cinfo, COL_INFO)) {
300         col_add_fstr(pinfo->cinfo, COL_INFO,
301                      "Unknown GARP application (0x%02X)",
302                      dstaddr[5]);
303       }
304
305       return;
306     }
307   }
308
309   if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
310     col_set_str(pinfo->cinfo, COL_PROTOCOL, "STP"); /* Spanning Tree Protocol */
311   }
312   col_clear(pinfo->cinfo, COL_INFO);
313
314   bpdu_type = tvb_get_guint8(tvb, BPDU_TYPE);
315
316   protocol_version_identifier = tvb_get_guint8(tvb, BPDU_VERSION_IDENTIFIER);
317
318   switch (bpdu_type) {
319
320   case BPDU_TYPE_CONF:
321   case BPDU_TYPE_RST:
322     flags = tvb_get_guint8(tvb, BPDU_FLAGS);
323     root_identifier_bridge_priority = tvb_get_ntohs(tvb,BPDU_ROOT_IDENTIFIER);
324     if (bpdu_use_system_id_extensions ) {
325       root_identifier_system_id_extension = root_identifier_bridge_priority & 0x0fff;
326       root_identifier_bridge_priority &= 0xf000;
327     }
328     root_identifier_mac = tvb_get_ptr(tvb, BPDU_ROOT_IDENTIFIER + 2, 6);
329     root_identifier_mac_str = ether_to_str(root_identifier_mac);
330     root_path_cost = tvb_get_ntohl(tvb, BPDU_ROOT_PATH_COST);
331     port_identifier = tvb_get_ntohs(tvb, BPDU_PORT_IDENTIFIER);
332     break;
333
334   default:
335     /* Squelch GCC complaints. */
336     flags = 0;
337     root_identifier_bridge_priority = 0;
338     root_identifier_mac = NULL;
339     root_identifier_mac_str = NULL;
340     root_path_cost = 0;
341     port_identifier = 0;
342     break;
343   }
344
345   if (check_col(pinfo->cinfo, COL_INFO)) {
346     switch (bpdu_type) {
347
348     case BPDU_TYPE_CONF:
349       if (bpdu_use_system_id_extensions ) {
350         col_add_fstr(pinfo->cinfo, COL_INFO,
351                      "Conf. %sRoot = %d/%d/%s  Cost = %d  Port = 0x%04x",
352                      flags & 0x1 ? "TC + " : "",
353                      root_identifier_bridge_priority, 
354                      root_identifier_system_id_extension, 
355                      root_identifier_mac_str,
356                      root_path_cost, port_identifier);
357       } else {
358         col_add_fstr(pinfo->cinfo, COL_INFO,
359                      "Conf. %sRoot = %d/%s  Cost = %d  Port = 0x%04x",
360                      flags & 0x1 ? "TC + " : "",
361                      root_identifier_bridge_priority, root_identifier_mac_str,
362                      root_path_cost, port_identifier);
363       }
364       break;
365
366     case BPDU_TYPE_TOPOLOGY_CHANGE:
367       col_set_str(pinfo->cinfo, COL_INFO, "Topology Change Notification");
368       break;
369
370     case BPDU_TYPE_RST:
371       if (bpdu_use_system_id_extensions ) {
372         col_add_fstr(pinfo->cinfo, COL_INFO,
373                      "%cST. %sRoot = %d/%d/%s  Cost = %d  Port = 0x%04x",
374                      protocol_version_identifier == 3 ? 'M':'R',
375                      flags & 0x1 ? "TC + " : "",
376                      root_identifier_bridge_priority,
377                      root_identifier_system_id_extension,
378                      root_identifier_mac_str,
379                      root_path_cost, port_identifier);
380       } else {
381         col_add_fstr(pinfo->cinfo, COL_INFO,
382                      "%cST. %sRoot = %d/%s  Cost = %d  Port = 0x%04x",
383                      protocol_version_identifier == 3 ? 'M':'R',
384                      flags & 0x1 ? "TC + " : "",
385                      root_identifier_bridge_priority, root_identifier_mac_str,
386                      root_path_cost, port_identifier);
387       }
388       break;
389
390     default:
391       col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown BPDU type (%u)", bpdu_type);
392       break;
393     }
394   }
395
396   if (tree) {
397     bpdu_item = proto_tree_add_protocol_format(tree, proto_bpdu, tvb, 0, -1,
398                                                "Spanning Tree Protocol");
399     bpdu_tree = proto_item_add_subtree(bpdu_item, ett_bpdu);
400
401     protocol_identifier = tvb_get_ntohs(tvb, BPDU_IDENTIFIER);
402     proto_tree_add_uint(bpdu_tree, hf_bpdu_proto_id, tvb, BPDU_IDENTIFIER, 2,
403                         protocol_identifier);
404
405     proto_tree_add_uint(bpdu_tree, hf_bpdu_version_id, tvb,
406                         BPDU_VERSION_IDENTIFIER, 1,
407                         protocol_version_identifier);
408     switch (protocol_version_identifier) {
409
410     case 0:
411       break;
412
413     case 2:
414     case 3:
415       break;
416
417     default:
418       proto_tree_add_text(bpdu_tree, tvb, BPDU_VERSION_IDENTIFIER, 1,
419                           "   (Warning: this version of Wireshark only knows about versions 0, 2 & 3)");
420       break;
421     }
422     proto_tree_add_uint(bpdu_tree, hf_bpdu_type, tvb, BPDU_TYPE, 1, bpdu_type);
423
424     if (bpdu_type == BPDU_TYPE_TOPOLOGY_CHANGE) {
425       set_actual_length(tvb, TC_BPDU_SIZE);
426       return;
427     }
428
429     if (bpdu_type != BPDU_TYPE_CONF && bpdu_type != BPDU_TYPE_RST) {
430       /* Unknown BPDU type - just display the rest of the PDU as data */
431       proto_tree_add_text(bpdu_tree, tvb, BPDU_TYPE + 1, -1,
432                           "Unknown BPDU type data");
433       return;
434     }
435
436     bridge_identifier_bridge_priority = tvb_get_ntohs(tvb, BPDU_BRIDGE_IDENTIFIER);
437     if (bpdu_use_system_id_extensions ) {
438       bridge_identifier_system_id_extension = bridge_identifier_bridge_priority & 0x0fff;
439       bridge_identifier_bridge_priority &= 0xf000;
440     }
441     bridge_identifier_mac = tvb_get_ptr(tvb, BPDU_BRIDGE_IDENTIFIER + 2, 6);
442     bridge_identifier_mac_str = ether_to_str(bridge_identifier_mac);
443
444     flags_item = proto_tree_add_uint(bpdu_tree, hf_bpdu_flags, tvb,
445                                      BPDU_FLAGS, 1, flags);
446     flags_tree = proto_item_add_subtree(flags_item, ett_bpdu_flags);
447     sep = initial_sep;
448     APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_TCACK, flags_item,
449                         "%sTopology Change Acknowledgment");
450     proto_tree_add_boolean(flags_tree, hf_bpdu_flags_tcack, tvb,
451                            BPDU_FLAGS, 1, flags);
452     if (bpdu_type == BPDU_TYPE_RST) {
453       APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_AGREEMENT, flags_item,
454                           "%sAgreement");
455       proto_tree_add_boolean(flags_tree, hf_bpdu_flags_agreement, tvb,
456                              BPDU_FLAGS, 1, flags);
457       APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_FORWARDING, flags_item,
458                           "%sForwarding");
459       proto_tree_add_boolean(flags_tree, hf_bpdu_flags_forwarding, tvb,
460                              BPDU_FLAGS, 1, flags);
461       APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_LEARNING, flags_item,
462                           "%sLearning");
463       proto_tree_add_boolean(flags_tree, hf_bpdu_flags_learning, tvb,
464                              BPDU_FLAGS, 1, flags);
465       if (flags_item) {
466         guint8 port_role;
467
468         port_role = (flags & BPDU_FLAGS_PORT_ROLE_MASK) >> BPDU_FLAGS_PORT_ROLE_SHIFT;
469         proto_item_append_text(flags_item, "%sPort Role: %s", sep,
470                                val_to_str(port_role, role_vals,
471                                           "Unknown (%u)"));
472       }
473       sep = cont_sep;
474       proto_tree_add_uint(flags_tree, hf_bpdu_flags_port_role, tvb,
475                           BPDU_FLAGS, 1, flags);
476       APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_PROPOSAL, flags_item,
477                           "%sProposal");
478       proto_tree_add_boolean(flags_tree, hf_bpdu_flags_proposal, tvb,
479                              BPDU_FLAGS, 1, flags);
480     }
481     APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_TC, flags_item,
482                         "%sTopology Change");
483     proto_tree_add_boolean(flags_tree, hf_bpdu_flags_tc, tvb,
484                            BPDU_FLAGS, 1, flags);
485     if (sep != initial_sep) {
486       /* We put something in; put in the terminating ")" */
487       proto_item_append_text(flags_item, ")");
488     }
489
490     /* add Identifier with format based on preference value
491      * bpdu_use_system_id_extensions
492      * */
493     if (bpdu_use_system_id_extensions) {
494       root_id_item = proto_tree_add_text(bpdu_tree, tvb,
495                           BPDU_ROOT_IDENTIFIER, 8,
496                           "Root Identifier: %d / %d / %s",
497                           root_identifier_bridge_priority,
498                           root_identifier_system_id_extension,
499                           root_identifier_mac_str);
500       root_id_tree = proto_item_add_subtree(root_id_item, ett_root_id);
501       proto_tree_add_uint(root_id_tree, hf_bpdu_root_prio, tvb,
502                               BPDU_ROOT_IDENTIFIER , 1, 
503                               root_identifier_bridge_priority);
504       proto_tree_add_uint(root_id_tree, hf_bpdu_root_sys_id_ext, tvb,
505                               BPDU_ROOT_IDENTIFIER , 2, 
506                               root_identifier_system_id_extension);
507       proto_tree_add_ether_format_value(root_id_tree, hf_bpdu_root_mac,
508                               tvb, BPDU_ROOT_IDENTIFIER + 2, 6,
509                               root_identifier_mac,
510                               "%s", root_identifier_mac_str);
511     } else {
512       root_id_item = proto_tree_add_text(bpdu_tree, tvb,
513                           BPDU_ROOT_IDENTIFIER, 8,
514                           "Root Identifier: %d / %s",
515                           root_identifier_bridge_priority,
516                           root_identifier_mac_str);
517       root_id_tree = proto_item_add_subtree(root_id_item, ett_root_id);
518       proto_tree_add_uint(root_id_tree, hf_bpdu_root_prio, tvb,
519                               BPDU_ROOT_IDENTIFIER , 2, 
520                               root_identifier_bridge_priority);
521       proto_tree_add_ether_format_value(root_id_tree, hf_bpdu_root_mac,
522                               tvb, BPDU_ROOT_IDENTIFIER + 2, 6,
523                               root_identifier_mac,
524                               "%s", root_identifier_mac_str);
525     }
526     /* end of Identifier formatting */
527
528     proto_tree_add_uint(bpdu_tree, hf_bpdu_root_cost, tvb,
529                         BPDU_ROOT_PATH_COST, 4, root_path_cost);
530
531     /* add Identifier with format based on preference value
532      * bpdu_use_system_id_extensions
533      * */
534     if (bpdu_use_system_id_extensions) {
535       bridge_id_item = proto_tree_add_text(bpdu_tree, tvb,
536                           BPDU_BRIDGE_IDENTIFIER, 8,
537                           "Bridge Identifier: %d / %d / %s",
538                           bridge_identifier_bridge_priority,
539                           bridge_identifier_system_id_extension,
540                           bridge_identifier_mac_str);
541       bridge_id_tree = proto_item_add_subtree(bridge_id_item, ett_bridge_id);
542       proto_tree_add_uint(bridge_id_tree, hf_bpdu_bridge_prio, tvb,
543                               BPDU_BRIDGE_IDENTIFIER , 1, 
544                               bridge_identifier_bridge_priority);
545       proto_tree_add_uint(bridge_id_tree, hf_bpdu_bridge_sys_id_ext, tvb,
546                               BPDU_BRIDGE_IDENTIFIER , 2, 
547                               bridge_identifier_system_id_extension);
548       proto_tree_add_ether_format_value(bridge_id_tree, hf_bpdu_bridge_mac,
549                               tvb, BPDU_BRIDGE_IDENTIFIER + 2, 6,
550                               bridge_identifier_mac,
551                               "%s", bridge_identifier_mac_str);
552     } else {
553       bridge_id_item = proto_tree_add_text(bpdu_tree, tvb, 
554                           BPDU_BRIDGE_IDENTIFIER, 8,
555                           "Bridge Identifier: %d / %s",
556                           bridge_identifier_bridge_priority,
557                           bridge_identifier_mac_str);
558       bridge_id_tree = proto_item_add_subtree(bridge_id_item, ett_bridge_id);
559       proto_tree_add_uint(bridge_id_tree, hf_bpdu_bridge_prio, tvb,
560                               BPDU_BRIDGE_IDENTIFIER , 2, 
561                               bridge_identifier_bridge_priority);
562       proto_tree_add_ether_format_value(bridge_id_tree, hf_bpdu_bridge_mac,
563                               tvb, BPDU_BRIDGE_IDENTIFIER + 2, 6,
564                               bridge_identifier_mac,
565                               "%s", bridge_identifier_mac_str);
566     }
567     /* end of Identifier formatting */
568
569     proto_tree_add_uint(bpdu_tree, hf_bpdu_port_id, tvb,
570                         BPDU_PORT_IDENTIFIER, 2, port_identifier);
571     message_age = tvb_get_ntohs(tvb, BPDU_MESSAGE_AGE) / 256.0;
572     proto_tree_add_double(bpdu_tree, hf_bpdu_msg_age, tvb, BPDU_MESSAGE_AGE, 2,
573                           message_age);
574     max_age = tvb_get_ntohs(tvb, BPDU_MAX_AGE) / 256.0;
575     proto_tree_add_double(bpdu_tree, hf_bpdu_max_age, tvb, BPDU_MAX_AGE, 2,
576                           max_age);
577     hello_time = tvb_get_ntohs(tvb, BPDU_HELLO_TIME) / 256.0;
578     proto_tree_add_double(bpdu_tree, hf_bpdu_hello_time, tvb,
579                           BPDU_HELLO_TIME, 2, hello_time);
580     forward_delay = tvb_get_ntohs(tvb, BPDU_FORWARD_DELAY) / 256.0;
581     proto_tree_add_double(bpdu_tree, hf_bpdu_forward_delay, tvb,
582                           BPDU_FORWARD_DELAY, 2, forward_delay);
583
584     if (bpdu_type == BPDU_TYPE_CONF) {
585       /* Nothing more in this BPDU */
586       set_actual_length(tvb, CONF_BPDU_SIZE);
587       return;
588     }
589
590     /* RST or MST BPDU */
591     version_1_length = tvb_get_guint8(tvb, BPDU_VERSION_1_LENGTH);
592     proto_tree_add_uint(bpdu_tree, hf_bpdu_version_1_length, tvb,
593                         BPDU_VERSION_1_LENGTH, 1, version_1_length);
594     /* Is this an MST BPDU? */
595     if (protocol_version_identifier >= 3 && version_1_length == 0 &&
596         tvb_reported_length(tvb) >= 102) {
597       /*
598        * OK, it passes the "Protocol Identifier is 0000 0000
599        * 0000 0000", "Protocol Version Identifier is 3 or
600        * greater", "BPDU Type is 0000 0010", "contains 102 or
601        * more octets", and "a Version 1 Length of 0" tests.
602        */
603       version_3_length = tvb_get_ntohs(tvb, BPDU_VERSION_3_LENGTH);
604       proto_tree_add_uint(bpdu_tree, hf_bpdu_version_3_length, tvb,
605                           BPDU_VERSION_3_LENGTH, 2, version_3_length);
606
607       /*
608        * Check the Version 3 Length, and see whether it's a
609        * multiple of the MSTI Configuration Message length. Also
610        * check the config_format_selector because some MST BPDU's 
611        * have BPDU_VERSION_3_LENGTH set to 0 and use the 
612        * field BPDU_MST_CONFIG_FORMAT_SELECTOR as a length-field
613        * for the MSTI data.
614        */
615       config_format_selector = tvb_get_guint8(tvb, BPDU_MST_CONFIG_FORMAT_SELECTOR);
616       if (version_3_length != 0) {
617         msti_format = MSTI_FORMAT_IEEE_8021S;
618         if (version_3_length >= VERSION_3_STATIC_LENGTH) {
619           total_msti_length = version_3_length - VERSION_3_STATIC_LENGTH;
620         } else {
621           /*
622            * XXX - there appears to be an ambiguity in the 802.3Q-2003
623            * standard and at least some of the 802.3s drafts.
624            *
625            * The "Version 3 Length" field is defined to be "the number of
626            * octets taken by the parameters that follow in the BPDU", but
627            * it's spoken of as "representing an integral number, from 0 to
628            * 64 inclusive, of MSTI Configuration Messages".
629            *
630            * According to mail from a member of the stds-802-1@ieee.org list,
631            * the latter of those is just saying that the length must not have
632            * a value that implies that there's a partial MSTI message in the
633            * packet; it's still in units of octets, not messages.
634            *
635            * However, it appears that Cisco's C3550 software (C3550-I5Q3L2-M,
636            * Version 12.1(12c)EA1) might be sending out lengths in units of
637            * messages.
638            *
639            * This length can't be the number of octets taken by the parameters
640            * that follow in the BPDU, because it's less than the fixed-length
641            * portion of those parameters, so we assume the length is a count of
642            * messages.
643            */
644           total_msti_length = version_3_length * MSTI_MESSAGE_SIZE;
645         }
646       } else {
647         if (tvb_reported_length(tvb) == (guint)config_format_selector + MST_BPDU_SIZE + 1 ) {
648           msti_format = MSTI_FORMAT_ALTERNATIVE;
649           total_msti_length = config_format_selector - VERSION_3_STATIC_LENGTH;
650         } else {
651           /* 
652            * XXX - Unknown MSTI format, since version_3_length is 0
653            * lets assume there are no msti instances in the packet.
654            */
655           msti_format = MSTI_FORMAT_UNKNOWN;
656           total_msti_length = 0;
657         }
658
659       }
660       set_actual_length(tvb, BPDU_MSTI + total_msti_length);
661
662       mstp_item = proto_tree_add_text(bpdu_tree, tvb, BPDU_VERSION_3_LENGTH,
663                                       -1, "MST Extension");
664       mstp_tree = proto_item_add_subtree(mstp_item, ett_mstp);
665
666       proto_tree_add_item(mstp_tree, hf_bpdu_mst_config_format_selector, tvb,
667                           BPDU_MST_CONFIG_FORMAT_SELECTOR, 1, FALSE);
668       proto_tree_add_item(mstp_tree, hf_bpdu_mst_config_name, tvb,
669                           BPDU_MST_CONFIG_NAME, 32, FALSE);
670
671       proto_tree_add_item(mstp_tree, hf_bpdu_mst_config_revision_level, tvb,
672                           BPDU_MST_CONFIG_REVISION_LEVEL, 2, FALSE);
673       proto_tree_add_item(mstp_tree, hf_bpdu_mst_config_digest, tvb,
674                           BPDU_MST_CONFIG_DIGEST, 16, FALSE);
675
676       switch(msti_format) {
677
678       case MSTI_FORMAT_IEEE_8021S:
679         proto_tree_add_item(mstp_tree, hf_bpdu_cist_internal_root_path_cost, tvb,
680                             BPDU_CIST_INTERNAL_ROOT_PATH_COST, 4, FALSE);
681
682         cist_bridge_identifier_bridge_priority = tvb_get_ntohs(tvb,BPDU_CIST_BRIDGE_IDENTIFIER);
683         cist_bridge_identifier_mac = tvb_get_ptr(tvb, BPDU_CIST_BRIDGE_IDENTIFIER + 2, 6);
684         cist_bridge_identifier_mac_str = ether_to_str(cist_bridge_identifier_mac);
685
686         /* add Identifier with format based on preference value
687          * bpdu_use_system_id_extensions
688          * */
689         if (bpdu_use_system_id_extensions ) {
690           cist_bridge_identifier_system_id_extension = cist_bridge_identifier_bridge_priority & 0x0fff;
691           cist_bridge_identifier_bridge_priority &= 0xf000;
692
693           cist_bridge_id_item = proto_tree_add_text(mstp_tree, tvb,
694                               BPDU_CIST_BRIDGE_IDENTIFIER, 8,
695                               "CIST Bridge Identifier: %d / %d / %s",
696                               cist_bridge_identifier_bridge_priority,
697                               cist_bridge_identifier_system_id_extension,
698                               cist_bridge_identifier_mac_str);
699           cist_bridge_id_tree = proto_item_add_subtree(cist_bridge_id_item, ett_cist_bridge_id);
700           proto_tree_add_uint(cist_bridge_id_tree, hf_bpdu_cist_bridge_prio, tvb,
701                                   BPDU_CIST_BRIDGE_IDENTIFIER , 1, 
702                                   cist_bridge_identifier_bridge_priority);
703           proto_tree_add_uint(cist_bridge_id_tree, hf_bpdu_cist_bridge_sys_id_ext, tvb,
704                                   BPDU_CIST_BRIDGE_IDENTIFIER , 2, 
705                                   cist_bridge_identifier_system_id_extension);
706           proto_tree_add_ether_format_value(cist_bridge_id_tree, hf_bpdu_cist_bridge_mac,
707                                   tvb, BPDU_CIST_BRIDGE_IDENTIFIER + 2, 6,
708                                   cist_bridge_identifier_mac,
709                                   "%s", cist_bridge_identifier_mac_str);
710         } else {
711           cist_bridge_id_item = proto_tree_add_text(mstp_tree, tvb,
712                               BPDU_CIST_BRIDGE_IDENTIFIER, 8,
713                               "CIST Bridge Identifier: %d / %s",
714                               cist_bridge_identifier_bridge_priority,
715                               cist_bridge_identifier_mac_str);
716           cist_bridge_id_tree = proto_item_add_subtree(cist_bridge_id_item, ett_cist_bridge_id);
717           proto_tree_add_uint(cist_bridge_id_tree, hf_bpdu_cist_bridge_prio, tvb,
718                                   BPDU_CIST_BRIDGE_IDENTIFIER , 2, 
719                                   cist_bridge_identifier_bridge_priority);
720           proto_tree_add_ether_format_value(cist_bridge_id_tree, hf_bpdu_cist_bridge_mac,
721                                   tvb, BPDU_CIST_BRIDGE_IDENTIFIER + 2, 6,
722                                   cist_bridge_identifier_mac,
723                                   "%s", cist_bridge_identifier_mac_str);
724         }
725         /* end of Identifier formatting */
726
727         break;
728
729       case MSTI_FORMAT_ALTERNATIVE:
730         cist_bridge_identifier_bridge_priority = tvb_get_ntohs(tvb,ALT_BPDU_CIST_BRIDGE_IDENTIFIER);
731         cist_bridge_identifier_mac = tvb_get_ptr(tvb, ALT_BPDU_CIST_BRIDGE_IDENTIFIER + 2, 6);
732         cist_bridge_identifier_mac_str = ether_to_str(cist_bridge_identifier_mac);
733
734         /* add Identifier with format based on preference value
735          * bpdu_use_system_id_extensions
736          * */
737         if (bpdu_use_system_id_extensions ) {
738           cist_bridge_identifier_system_id_extension = cist_bridge_identifier_bridge_priority & 0x0fff;
739           cist_bridge_identifier_bridge_priority &= 0xf000;
740
741           cist_bridge_id_item = proto_tree_add_text(mstp_tree, tvb,
742                               ALT_BPDU_CIST_BRIDGE_IDENTIFIER, 8,
743                               "CIST Bridge Identifier: %d / %d / %s",
744                               cist_bridge_identifier_bridge_priority,
745                               cist_bridge_identifier_system_id_extension,
746                               cist_bridge_identifier_mac_str);
747           cist_bridge_id_tree = proto_item_add_subtree(cist_bridge_id_item, ett_cist_bridge_id);
748           proto_tree_add_uint(cist_bridge_id_tree, hf_bpdu_cist_bridge_prio, tvb,
749                                   ALT_BPDU_CIST_BRIDGE_IDENTIFIER , 1, 
750                                   cist_bridge_identifier_bridge_priority);
751           proto_tree_add_uint(cist_bridge_id_tree, hf_bpdu_cist_bridge_sys_id_ext, tvb,
752                                   ALT_BPDU_CIST_BRIDGE_IDENTIFIER , 2, 
753                                   cist_bridge_identifier_system_id_extension);
754           proto_tree_add_ether_format_value(cist_bridge_id_tree, hf_bpdu_cist_bridge_mac,
755                                   tvb, ALT_BPDU_CIST_BRIDGE_IDENTIFIER + 2, 6,
756                                   cist_bridge_identifier_mac,
757                                   "%s", cist_bridge_identifier_mac_str);
758         } else {
759           cist_bridge_id_item = proto_tree_add_text(mstp_tree, tvb,
760                               ALT_BPDU_CIST_BRIDGE_IDENTIFIER, 8,
761                               "CIST Bridge Identifier: %d / %s",
762                               cist_bridge_identifier_bridge_priority,
763                               cist_bridge_identifier_mac_str);
764           cist_bridge_id_tree = proto_item_add_subtree(cist_bridge_id_item, ett_cist_bridge_id);
765           proto_tree_add_uint(cist_bridge_id_tree, hf_bpdu_cist_bridge_prio, tvb,
766                                   ALT_BPDU_CIST_BRIDGE_IDENTIFIER , 2, 
767                                   cist_bridge_identifier_bridge_priority);
768           proto_tree_add_ether_format_value(cist_bridge_id_tree, hf_bpdu_cist_bridge_mac,
769                                   tvb, ALT_BPDU_CIST_BRIDGE_IDENTIFIER + 2, 6,
770                                   cist_bridge_identifier_mac,
771                                   "%s", cist_bridge_identifier_mac_str);
772         }
773         /* end of Identifier formatting */
774
775         proto_tree_add_item(mstp_tree, hf_bpdu_cist_internal_root_path_cost, tvb,
776                             ALT_BPDU_CIST_INTERNAL_ROOT_PATH_COST, 4, FALSE);
777
778         break;
779       }
780
781       proto_tree_add_item(mstp_tree, hf_bpdu_cist_remaining_hops, tvb,
782                           BPDU_CIST_REMAINING_HOPS, 1, FALSE);
783       /* MSTI messages */
784       offset = BPDU_MSTI;
785       msti = 1;
786       while (total_msti_length > 0) {
787         switch(msti_format) {
788
789         case MSTI_FORMAT_IEEE_8021S:
790           msti_regional_root_mstid = tvb_get_guint8(tvb,  offset+ MSTI_REGIONAL_ROOT);
791           msti_regional_root_priority = (msti_regional_root_mstid &0xf0) << 8;
792           msti_regional_root_mstid = ((msti_regional_root_mstid & 0x0f) << 8) +
793                                      tvb_get_guint8(tvb,  offset+ MSTI_REGIONAL_ROOT+1);
794           msti_regional_root_mac = tvb_get_ptr(tvb, offset+ MSTI_REGIONAL_ROOT + 2, 6);
795           msti_regional_root_mac_str = ether_to_str(msti_regional_root_mac);
796
797           msti_item = proto_tree_add_text(mstp_tree, tvb, offset, 16,
798                                           "MSTID %d, Regional Root Identifier %d / %s",
799                                           msti_regional_root_mstid,
800                                           msti_regional_root_priority,
801                                           msti_regional_root_mac_str);
802           msti_tree = proto_item_add_subtree(msti_item, ett_msti);
803
804           /* flags */
805           flags = tvb_get_guint8(tvb, offset+MSTI_FLAGS);
806           flags_item = proto_tree_add_uint(msti_tree, hf_bpdu_msti_flags, tvb,
807                                            offset+MSTI_FLAGS, 1, flags);
808           flags_tree = proto_item_add_subtree(flags_item, ett_bpdu_flags);
809
810           sep = initial_sep;
811           APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_TCACK, flags_item, "%sMaster");
812           proto_tree_add_boolean(flags_tree, hf_bpdu_flags_tcack, tvb,
813                                  offset+MSTI_FLAGS, 1, flags);
814           APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_AGREEMENT, flags_item, "%sAgreement");
815           proto_tree_add_boolean(flags_tree, hf_bpdu_flags_agreement, tvb,
816                                  offset+MSTI_FLAGS, 1, flags);
817           APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_FORWARDING, flags_item, "%sForwarding");
818           proto_tree_add_boolean(flags_tree, hf_bpdu_flags_forwarding, tvb,
819                                  offset+MSTI_FLAGS, 1, flags);
820           APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_LEARNING, flags_item, "%sLearning");
821           proto_tree_add_boolean(flags_tree, hf_bpdu_flags_learning, tvb,
822                                  offset+MSTI_FLAGS, 1, flags);
823           if (flags_item) {
824             guint8 port_role;
825             port_role = (flags & BPDU_FLAGS_PORT_ROLE_MASK) >> BPDU_FLAGS_PORT_ROLE_SHIFT;
826             proto_item_append_text(flags_item, "%sPort Role: %s", sep,
827                                    val_to_str(port_role, role_vals,
828                                    "Unknown (%u)"));
829           }
830           proto_tree_add_uint(flags_tree, hf_bpdu_flags_port_role, tvb,
831                               offset+MSTI_FLAGS, 1, flags);
832           sep = cont_sep;
833           APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_PROPOSAL, flags_item, "%sProposal");
834           proto_tree_add_boolean(flags_tree, hf_bpdu_flags_proposal, tvb,
835                                  offset+MSTI_FLAGS, 1, flags);
836           APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_TC, flags_item, "%sTopology Change");
837           proto_tree_add_boolean(flags_tree, hf_bpdu_flags_tc, tvb,
838                                  offset+MSTI_FLAGS, 1, flags);
839           if (sep != initial_sep) {           /* We put something in; put in the terminating ")" */
840             proto_item_append_text(flags_item, ")");
841           }
842
843           /* pri, MSTID, Regional root */
844           hidden_item = proto_tree_add_ether(msti_tree, hf_bpdu_msti_regional_root_mac, tvb,
845                                       offset + MSTI_REGIONAL_ROOT + 2, 6,
846                                       msti_regional_root_mac);
847           PROTO_ITEM_SET_HIDDEN(hidden_item);
848           proto_tree_add_text(msti_tree, tvb, offset + MSTI_REGIONAL_ROOT, 8,
849                               "MSTID %d, priority %d Root Identifier %s",
850                               msti_regional_root_mstid,
851                               msti_regional_root_priority,
852                               msti_regional_root_mac_str);
853
854
855           proto_tree_add_item(msti_tree, hf_bpdu_msti_internal_root_path_cost, tvb,
856                               offset+MSTI_INTERNAL_ROOT_PATH_COST, 4, FALSE);
857
858           msti_bridge_identifier_priority = tvb_get_guint8(tvb, offset+MSTI_BRIDGE_IDENTIFIER_PRIORITY) >> 4;
859           msti_port_identifier_priority = tvb_get_guint8(tvb, offset+MSTI_PORT_IDENTIFIER_PRIORITY) >> 4;
860
861           proto_tree_add_uint(msti_tree, hf_bpdu_msti_bridge_identifier_priority, tvb,
862                               offset+MSTI_BRIDGE_IDENTIFIER_PRIORITY, 1,
863                               msti_bridge_identifier_priority);
864           proto_tree_add_uint(msti_tree, hf_bpdu_msti_port_identifier_priority, tvb,
865                               offset+MSTI_PORT_IDENTIFIER_PRIORITY, 1,
866                               msti_port_identifier_priority);
867
868           proto_tree_add_item(msti_tree, hf_bpdu_msti_remaining_hops, tvb,
869                               offset + MSTI_REMAINING_HOPS, 1, FALSE);
870
871           total_msti_length -= MSTI_MESSAGE_SIZE;
872           offset += MSTI_MESSAGE_SIZE;
873           break;
874
875         case MSTI_FORMAT_ALTERNATIVE:
876           msti_regional_root_mstid = tvb_get_guint8(tvb,  offset+ ALT_MSTI_REGIONAL_ROOT);
877           msti_regional_root_priority = (msti_regional_root_mstid &0xf0) << 8;
878           msti_regional_root_mstid = ((msti_regional_root_mstid & 0x0f) << 8) +
879                                      tvb_get_guint8(tvb,  offset+ ALT_MSTI_REGIONAL_ROOT+1);
880           msti_regional_root_mac = tvb_get_ptr(tvb, offset+ ALT_MSTI_REGIONAL_ROOT + 2, 6);
881           msti_regional_root_mac_str = ether_to_str(msti_regional_root_mac);
882
883           msti_item = proto_tree_add_text(mstp_tree, tvb, offset, 16,
884                                           "MSTID %d, Regional Root Identifier %d / %s",
885                                           msti_regional_root_mstid,
886                                           msti_regional_root_priority,
887                                           msti_regional_root_mac_str);
888           msti_tree = proto_item_add_subtree(msti_item, ett_msti);
889
890           msti_mstid = tvb_get_ntohs(tvb,  offset+ ALT_MSTI_MSTID);
891           proto_tree_add_text(msti_tree, tvb, offset+ALT_MSTI_MSTID, 2, 
892                               "MSTID: %d", msti_mstid);
893
894           /* flags */
895           flags = tvb_get_guint8(tvb, offset+ALT_MSTI_FLAGS);
896           flags_item = proto_tree_add_uint(msti_tree, hf_bpdu_msti_flags, tvb,
897                                            offset+ALT_MSTI_FLAGS, 1, flags);
898           flags_tree = proto_item_add_subtree(flags_item, ett_bpdu_flags);
899
900           sep = initial_sep;
901           APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_TCACK, flags_item, "%sMaster");
902           proto_tree_add_boolean(flags_tree, hf_bpdu_flags_tcack, tvb,
903                                  offset+ALT_MSTI_FLAGS, 1, flags);
904           APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_AGREEMENT, flags_item, "%sAgreement");
905           proto_tree_add_boolean(flags_tree, hf_bpdu_flags_agreement, tvb,
906                                  offset+ALT_MSTI_FLAGS, 1, flags);
907           APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_FORWARDING, flags_item, "%sForwarding");
908           proto_tree_add_boolean(flags_tree, hf_bpdu_flags_forwarding, tvb,
909                                  offset+ALT_MSTI_FLAGS, 1, flags);
910           APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_LEARNING, flags_item, "%sLearning");
911           proto_tree_add_boolean(flags_tree, hf_bpdu_flags_learning, tvb,
912                                  offset+ALT_MSTI_FLAGS, 1, flags);
913           if (flags_item) {
914             guint8 port_role;
915             port_role = (flags & BPDU_FLAGS_PORT_ROLE_MASK) >> BPDU_FLAGS_PORT_ROLE_SHIFT;
916             proto_item_append_text(flags_item, "%sPort Role: %s", sep,
917                                    val_to_str(port_role, role_vals,
918                                    "Unknown (%u)"));
919           }
920           proto_tree_add_uint(flags_tree, hf_bpdu_flags_port_role, tvb,
921                               offset+ALT_MSTI_FLAGS, 1, flags);
922           sep = cont_sep;
923           APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_PROPOSAL, flags_item, "%sProposal");
924           proto_tree_add_boolean(flags_tree, hf_bpdu_flags_proposal, tvb,
925                                  offset+ALT_MSTI_FLAGS, 1, flags);
926           APPEND_BOOLEAN_FLAG(flags & BPDU_FLAGS_TC, flags_item, "%sTopology Change");
927           proto_tree_add_boolean(flags_tree, hf_bpdu_flags_tc, tvb,
928                                  offset+ALT_MSTI_FLAGS, 1, flags);
929           if (sep != initial_sep) {           /* We put something in; put in the terminating ")" */
930             proto_item_append_text(flags_item, ")");
931           }
932
933           /* pri, MSTID, Regional root */
934           hidden_item = proto_tree_add_ether(msti_tree, hf_bpdu_msti_regional_root_mac, tvb,
935                                       offset + ALT_MSTI_REGIONAL_ROOT + 2, 6,
936                                       msti_regional_root_mac);
937           PROTO_ITEM_SET_HIDDEN(hidden_item);
938           proto_tree_add_text(msti_tree, tvb, offset + ALT_MSTI_REGIONAL_ROOT, 8,
939                               "MSTI Regional Root Identifier: %d / %d / %s",
940                               msti_regional_root_mstid,
941                               msti_regional_root_priority,
942                               msti_regional_root_mac_str);
943
944
945           proto_tree_add_item(msti_tree, hf_bpdu_msti_internal_root_path_cost, tvb,
946                               offset+ALT_MSTI_INTERNAL_ROOT_PATH_COST, 4, FALSE);
947
948           msti_bridge_identifier_priority = tvb_get_ntohs(tvb, offset+ALT_MSTI_BRIDGE_IDENTIFIER);
949           msti_bridge_identifier_mac = tvb_get_ptr(tvb, offset+ALT_MSTI_BRIDGE_IDENTIFIER + 2, 6);
950           msti_bridge_identifier_mac_str = ether_to_str(msti_bridge_identifier_mac);
951           proto_tree_add_text(msti_tree, tvb, offset+ALT_MSTI_BRIDGE_IDENTIFIER, 8,
952                               "MSTI Bridge Identifier: %d / %d / %s",
953                               msti_bridge_identifier_priority & 0x0fff,
954                               msti_bridge_identifier_priority & 0xf000,
955                               msti_bridge_identifier_mac_str);
956
957           msti_port_identifier_priority = tvb_get_ntohs(tvb, offset+ALT_MSTI_PORT_IDENTIFIER);
958           proto_tree_add_uint(msti_tree, hf_bpdu_msti_port_id, tvb, 
959                               offset+ALT_MSTI_PORT_IDENTIFIER, 2, msti_port_identifier_priority);
960
961           proto_tree_add_item(msti_tree, hf_bpdu_msti_remaining_hops, tvb,
962                               offset + ALT_MSTI_REMAINING_HOPS, 1, FALSE);
963
964           total_msti_length -= ALT_MSTI_MESSAGE_SIZE;
965           offset += ALT_MSTI_MESSAGE_SIZE;
966           break;
967
968         }
969         msti++;
970       }
971     }
972   }
973 }
974
975 void
976 proto_register_bpdu(void)
977 {      
978
979   static hf_register_info hf[] = {
980     { &hf_bpdu_proto_id,
981       { "Protocol Identifier",          "stp.protocol",
982         FT_UINT16,      BASE_HEX,       VALS(protocol_id_vals), 0x0,
983         NULL, HFILL }},
984     { &hf_bpdu_version_id,
985       { "Protocol Version Identifier",  "stp.version",
986         FT_UINT8,       BASE_DEC,       VALS(version_id_vals),  0x0,
987         NULL, HFILL }},
988     { &hf_bpdu_type,
989       { "BPDU Type",                    "stp.type",
990         FT_UINT8,       BASE_HEX,       VALS(bpdu_type_vals),   0x0,
991         NULL, HFILL }},
992     { &hf_bpdu_flags,
993       { "BPDU flags",                   "stp.flags",
994         FT_UINT8,       BASE_HEX,       NULL,   0x0,
995         NULL, HFILL }},
996     { &hf_bpdu_flags_tcack,
997       { "Topology Change Acknowledgment",  "stp.flags.tcack",
998         FT_BOOLEAN,     8,              TFS(&tfs_yes_no),       BPDU_FLAGS_TCACK,
999         NULL, HFILL }},
1000     { &hf_bpdu_flags_agreement,
1001       { "Agreement",                    "stp.flags.agreement",
1002         FT_BOOLEAN,     8,              TFS(&tfs_yes_no),       BPDU_FLAGS_AGREEMENT,
1003         NULL, HFILL }},
1004     { &hf_bpdu_flags_forwarding,
1005       { "Forwarding",                   "stp.flags.forwarding",
1006         FT_BOOLEAN,     8,              TFS(&tfs_yes_no),       BPDU_FLAGS_FORWARDING,
1007         NULL, HFILL }},
1008     { &hf_bpdu_flags_learning,
1009       { "Learning",                     "stp.flags.learning",
1010         FT_BOOLEAN,     8,              TFS(&tfs_yes_no),       BPDU_FLAGS_LEARNING,
1011         NULL, HFILL }},
1012     { &hf_bpdu_flags_port_role,
1013       { "Port Role",                    "stp.flags.port_role",
1014         FT_UINT8,       BASE_DEC,       VALS(role_vals),        BPDU_FLAGS_PORT_ROLE_MASK,
1015         NULL, HFILL }},
1016     { &hf_bpdu_flags_proposal,
1017       { "Proposal",                     "stp.flags.proposal",
1018         FT_BOOLEAN,     8,              TFS(&tfs_yes_no),       BPDU_FLAGS_PROPOSAL,
1019         NULL, HFILL }},
1020     { &hf_bpdu_flags_tc,
1021       { "Topology Change",              "stp.flags.tc",
1022         FT_BOOLEAN,     8,              TFS(&tfs_yes_no),       BPDU_FLAGS_TC,
1023         NULL, HFILL }},
1024     { &hf_bpdu_root_prio,
1025       { "Root Bridge Priority",         "stp.root.prio",
1026         FT_UINT16,      BASE_DEC,       NULL,   0x0,
1027         NULL, HFILL }},
1028     { &hf_bpdu_root_sys_id_ext,
1029       { "Root Bridge System ID Extension",      "stp.root.ext",
1030         FT_UINT16,      BASE_DEC,       NULL,   0x0,
1031         NULL, HFILL }},
1032     { &hf_bpdu_root_mac,
1033       { "Root Bridge System ID",        "stp.root.hw",
1034         FT_ETHER,       BASE_NONE,      NULL,   0x0,
1035         NULL, HFILL }},
1036     { &hf_bpdu_root_cost,
1037       { "Root Path Cost",               "stp.root.cost",
1038         FT_UINT32,      BASE_DEC,       NULL,   0x0,
1039         NULL, HFILL }},
1040     { &hf_bpdu_bridge_prio,
1041       { "Bridge Priority",              "stp.bridge.prio",
1042         FT_UINT16,      BASE_DEC,       NULL,   0x0,
1043         NULL, HFILL }},
1044     { &hf_bpdu_bridge_sys_id_ext,
1045       { "Bridge System ID Extension",   "stp.bridge.ext",
1046         FT_UINT16,      BASE_DEC,       NULL,   0x0,
1047         NULL, HFILL }},
1048     { &hf_bpdu_bridge_mac,
1049       { "Bridge System ID",             "stp.bridge.hw",
1050         FT_ETHER,       BASE_NONE,      NULL,   0x0,
1051         NULL, HFILL }},
1052     { &hf_bpdu_port_id,
1053       { "Port identifier",              "stp.port",
1054         FT_UINT16,      BASE_HEX,       NULL,   0x0,
1055         NULL, HFILL }},
1056     { &hf_bpdu_msg_age,
1057       { "Message Age",                  "stp.msg_age",
1058         FT_DOUBLE,      BASE_NONE,      NULL,   0x0,
1059         NULL, HFILL }},
1060     { &hf_bpdu_max_age,
1061       { "Max Age",                      "stp.max_age",
1062         FT_DOUBLE,      BASE_NONE,      NULL,   0x0,
1063         NULL, HFILL }},
1064     { &hf_bpdu_hello_time,
1065       { "Hello Time",                   "stp.hello",
1066         FT_DOUBLE,      BASE_NONE,      NULL,   0x0,
1067         NULL, HFILL }},
1068     { &hf_bpdu_forward_delay,
1069       { "Forward Delay",                "stp.forward",
1070         FT_DOUBLE,      BASE_NONE,      NULL,   0x0,
1071         NULL, HFILL }},
1072     { &hf_bpdu_version_1_length,
1073       { "Version 1 Length",             "stp.version_1_length",
1074         FT_UINT8,       BASE_DEC,       NULL,   0x0,
1075         NULL, HFILL }},
1076     { &hf_bpdu_version_3_length,
1077       { "Version 3 Length",             "mstp.version_3_length",
1078         FT_UINT16,      BASE_DEC,       NULL,   0x0,
1079         NULL, HFILL }},
1080     { &hf_bpdu_mst_config_format_selector,
1081       { "MST Config ID format selector",        "mstp.config_format_selector",
1082         FT_UINT8,       BASE_DEC,       NULL,   0x0,
1083         NULL, HFILL }},
1084     { &hf_bpdu_mst_config_name,
1085       { "MST Config name",              "mstp.config_name",
1086         FT_STRINGZ,     BASE_NONE,      NULL,   0x0,
1087         NULL, HFILL }},
1088     { &hf_bpdu_mst_config_revision_level,
1089       { "MST Config revision",          "mstp.config_revision_level",
1090         FT_UINT16,      BASE_DEC,       NULL,   0x0,
1091         NULL, HFILL }},
1092     { &hf_bpdu_mst_config_digest,
1093       { "MST Config digest",            "mstp.config_digest",
1094         FT_BYTES,       BASE_NONE,      NULL,   0x0,
1095         NULL, HFILL }},
1096     { &hf_bpdu_cist_internal_root_path_cost,
1097       { "CIST Internal Root Path Cost",         "mstp.cist_internal_root_path_cost",
1098         FT_UINT32,      BASE_DEC,       NULL,   0x0,
1099         NULL, HFILL }},
1100     { &hf_bpdu_cist_bridge_prio,
1101       { "CIST Bridge Priority",         "mstp.cist_bridge.prio",
1102         FT_UINT16,      BASE_DEC,       NULL,   0x0,
1103         NULL, HFILL }},
1104     { &hf_bpdu_cist_bridge_sys_id_ext,
1105       { "CIST Bridge Identifier System ID Extension",   "mstp.cist_bridge.ext",
1106         FT_UINT16,      BASE_DEC,       NULL,   0x0,
1107         NULL, HFILL }},
1108     { &hf_bpdu_cist_bridge_mac,
1109       { "CIST Bridge Identifier System ID",     "mstp.cist_bridge.hw",
1110         FT_ETHER,       BASE_NONE,      NULL,   0x0,
1111         NULL, HFILL }},
1112     { &hf_bpdu_cist_remaining_hops,
1113       { "CIST Remaining hops",          "mstp.cist_remaining_hops",
1114         FT_UINT8,       BASE_DEC,       NULL,   0x0,
1115         NULL, HFILL }},
1116     { &hf_bpdu_msti_flags,
1117       { "MSTI flags",                   "mstp.msti.flags",
1118         FT_UINT8,       BASE_HEX,       NULL,   0x0,
1119         NULL, HFILL }},
1120     { &hf_bpdu_msti_regional_root_mac,
1121       { "Regional Root",                "mstp.msti.root.hw",
1122         FT_ETHER,       BASE_NONE,      NULL,   0x0,
1123         NULL, HFILL }},
1124     { &hf_bpdu_msti_internal_root_path_cost,
1125       { "Internal root path cost",              "mstp.msti.root_cost",
1126         FT_UINT32,      BASE_DEC,       NULL,   0x0,
1127         NULL, HFILL }},
1128     { &hf_bpdu_msti_bridge_identifier_priority,
1129       { "Bridge Identifier Priority",           "mstp.msti.bridge_priority",
1130         FT_UINT8,       BASE_DEC,       NULL,   0x0,
1131         NULL, HFILL }},
1132     { &hf_bpdu_msti_port_identifier_priority,
1133       { "Port identifier priority",             "mstp.msti.port_priority",
1134         FT_UINT8,       BASE_DEC,       NULL,   0x0,
1135         NULL, HFILL }},
1136     { &hf_bpdu_msti_port_id,
1137       { "Port identifier",              "mstp.msti.port",
1138         FT_UINT16,      BASE_HEX,       NULL,   0x0,
1139         NULL, HFILL }},
1140     { &hf_bpdu_msti_remaining_hops,
1141       { "Remaining hops",               "mstp.msti.remaining_hops",
1142         FT_UINT8,       BASE_DEC,       NULL,   0x0,
1143         NULL, HFILL }},
1144
1145   };
1146   static gint *ett[] = {
1147     &ett_bpdu,
1148     &ett_bpdu_flags,
1149     &ett_root_id,
1150     &ett_bridge_id,
1151     &ett_mstp,
1152     &ett_msti,
1153     &ett_cist_bridge_id
1154   };
1155   module_t *bpdu_module;
1156
1157   proto_bpdu = proto_register_protocol("Spanning Tree Protocol", "STP", "stp");
1158   proto_register_field_array(proto_bpdu, hf, array_length(hf));
1159   proto_register_subtree_array(ett, array_length(ett));
1160
1161   register_dissector("bpdu", dissect_bpdu, proto_bpdu);
1162
1163   bpdu_module = prefs_register_protocol(proto_bpdu, NULL);
1164   prefs_register_bool_preference(bpdu_module, "use_system_id_extension",
1165     "Use 802.1t System ID Extensions",
1166     "Whether the BPDU dissector should use 802.1t System ID Extensions when dissecting the Bridge Identifier",
1167     &bpdu_use_system_id_extensions);
1168 }
1169
1170 void
1171 proto_reg_handoff_bpdu(void)
1172 {
1173   dissector_handle_t bpdu_handle;
1174
1175   /*
1176    * Get handle for the GVRP dissector.
1177    */
1178   gvrp_handle = find_dissector("gvrp");
1179
1180   /*
1181    * Get handle for the GMRP dissector.
1182    */
1183   gmrp_handle = find_dissector("gmrp");
1184   data_handle = find_dissector("data");
1185
1186   bpdu_handle = find_dissector("bpdu");
1187   dissector_add("llc.dsap", SAP_BPDU, bpdu_handle);
1188   dissector_add("chdlctype", CHDLCTYPE_BPDU, bpdu_handle);
1189   dissector_add("llc.cisco_pid", 0x010b, bpdu_handle);
1190   dissector_add("ethertype", ETHERTYPE_STP, bpdu_handle);
1191 }