Enable Lua tcp tap userdata.
[obnox/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 <stdio.h>
32 #include <string.h>
33 #include <glib.h>
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>
41
42 /* Offsets of fields within a BPDU */
43
44 #define BPDU_IDENTIFIER                         0
45 #define BPDU_VERSION_IDENTIFIER                 2
46 #define BPDU_TYPE                               3
47 #define BPDU_FLAGS                              4
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
65 #define BPDU_MSTI                               102
66
67 #define MSTI_FLAGS                              0
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
73
74
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
80
81 /* Values for the Alternative MSTI format */
82
83 #define ALT_BPDU_CIST_BRIDGE_IDENTIFIER         89
84 #define ALT_BPDU_CIST_INTERNAL_ROOT_PATH_COST   97
85
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
93
94 #define ALT_MSTI_MESSAGE_SIZE                   26
95
96 /* Flag bits */
97
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
106
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;
149
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;
157
158 static gboolean bpdu_use_system_id_extensions = TRUE;
159
160 static dissector_handle_t gvrp_handle;
161 static dissector_handle_t gmrp_handle;
162 static dissector_handle_t data_handle;
163
164 static const value_string protocol_id_vals[] = {
165         { 0, "Spanning Tree Protocol" },
166         { 0, NULL }
167 };
168
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 */
172
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" },
177         { 0,                         NULL }
178 };
179
180 #define PROTO_VERSION_STP       0
181 #define PROTO_VERSION_RSTP      2
182 #define PROTO_VERSION_MSTP      3
183
184 #define MSTI_FORMAT_UNKNOWN     0
185 #define MSTI_FORMAT_IEEE_8021S  1
186 #define MSTI_FORMAT_ALTERNATIVE 2
187
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" },
192         { 0,                    NULL}
193 };
194 static const value_string role_vals[] = {
195         { 1, "Alternate or Backup" },
196         { 2, "Root" },
197         { 3, "Designated" },
198         { 0, NULL }
199 };
200
201 static const char initial_sep[] = " (";
202 static const char cont_sep[] = ", ";
203
204 #define APPEND_BOOLEAN_FLAG(flag, item, string) \
205         if(flag){                                                       \
206                 if(item)                                                \
207                         proto_item_append_text(item, string, sep);      \
208                 sep = cont_sep;                                         \
209         }
210
211 static void
212 dissect_bpdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
213 {
214   guint16 protocol_identifier;
215   guint8  protocol_version_identifier;
216   guint8  bpdu_type;
217   guint8  flags;
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;
228   double message_age;
229   double max_age;
230   double hello_time;
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;
239   guint16 msti_mstid;
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;
247
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;
261   const char *sep;
262
263   /* GARP application frames require special interpretation of the
264      destination address field; otherwise, they will be mistaken as
265      BPDU frames.
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.
269
270      Yes - we *do* need to check the destination address type;
271      on Linux cooked captures, there *is* no destination address,
272      so it's AT_NONE. */
273   if (pinfo->dl_dst.type == AT_ETHER) {
274     const guint8 *dstaddr;
275
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)) {
280
281       protocol_identifier = tvb_get_ntohs(tvb, BPDU_IDENTIFIER);
282
283       switch (dstaddr[5]) {
284
285       case 0x20:
286         /* for GMRP */
287         call_dissector(gmrp_handle, tvb, pinfo, tree);
288         return;
289
290       case 0x21:
291         /* for GVRP */
292         call_dissector(gvrp_handle, tvb, pinfo, tree);
293         return;
294       }
295
296       pinfo->current_proto = "GARP";
297
298       if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
299         col_set_str(pinfo->cinfo, COL_PROTOCOL, "GARP");
300         /* Generic Attribute Registration Protocol */
301       }
302
303       if (check_col(pinfo->cinfo, COL_INFO)) {
304         col_add_fstr(pinfo->cinfo, COL_INFO,
305                      "Unknown GARP application (0x%02X)",
306                      dstaddr[5]);
307       }
308
309       return;
310     }
311   }
312
313   if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
314     col_set_str(pinfo->cinfo, COL_PROTOCOL, "STP"); /* Spanning Tree Protocol */
315   }
316   if (check_col(pinfo->cinfo, COL_INFO)) {
317     col_clear(pinfo->cinfo, COL_INFO);
318   }
319
320   bpdu_type = tvb_get_guint8(tvb, BPDU_TYPE);
321
322   protocol_version_identifier = tvb_get_guint8(tvb, BPDU_VERSION_IDENTIFIER);
323
324   switch (bpdu_type) {
325
326   case BPDU_TYPE_CONF:
327   case BPDU_TYPE_RST:
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;
333     }
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);
338     break;
339
340   default:
341     /* Squelch GCC complaints. */
342     flags = 0;
343     root_identifier_bridge_priority = 0;
344     root_identifier_mac = NULL;
345     root_identifier_mac_str = NULL;
346     root_path_cost = 0;
347     port_identifier = 0;
348     break;
349   }
350
351   if (check_col(pinfo->cinfo, COL_INFO)) {
352     switch (bpdu_type) {
353
354     case BPDU_TYPE_CONF:
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);
363       } else {
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);
369       }
370       break;
371
372     case BPDU_TYPE_TOPOLOGY_CHANGE:
373       col_set_str(pinfo->cinfo, COL_INFO, "Topology Change Notification");
374       break;
375
376     case BPDU_TYPE_RST:
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);
386       } else {
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);
393       }
394       break;
395
396     default:
397       col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown BPDU type (%u)", bpdu_type);
398       break;
399     }
400   }
401
402   if (tree) {
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);
406
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);
410
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) {
415
416     case 0:
417       break;
418
419     case 2:
420     case 3:
421       break;
422
423     default:
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)");
426       break;
427     }
428     proto_tree_add_uint(bpdu_tree, hf_bpdu_type, tvb, BPDU_TYPE, 1, bpdu_type);
429
430     if (bpdu_type == BPDU_TYPE_TOPOLOGY_CHANGE) {
431       set_actual_length(tvb, TC_BPDU_SIZE);
432       return;
433     }
434
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");
439       return;
440     }
441
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;
446     }
447     bridge_identifier_mac = tvb_get_ptr(tvb, BPDU_BRIDGE_IDENTIFIER + 2, 6);
448     bridge_identifier_mac_str = ether_to_str(bridge_identifier_mac);
449
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);
453     sep = initial_sep;
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,
460                           "%sAgreement");
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,
464                           "%sForwarding");
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,
468                           "%sLearning");
469       proto_tree_add_boolean(flags_tree, hf_bpdu_flags_learning, tvb,
470                              BPDU_FLAGS, 1, flags);
471       if (flags_item) {
472         guint8 port_role;
473
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,
477                                           "Unknown (%u)"));
478       }
479       sep = cont_sep;
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,
483                           "%sProposal");
484       proto_tree_add_boolean(flags_tree, hf_bpdu_flags_proposal, tvb,
485                              BPDU_FLAGS, 1, flags);
486     }
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, ")");
494     }
495
496     /* add Identifier with format based on preference value
497      * bpdu_use_system_id_extensions
498      * */
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,
515                               root_identifier_mac,
516                               "%s", root_identifier_mac_str);
517     } else {
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,
529                               root_identifier_mac,
530                               "%s", root_identifier_mac_str);
531     }
532     /* end of Identifier formatting */
533
534     proto_tree_add_uint(bpdu_tree, hf_bpdu_root_cost, tvb,
535                         BPDU_ROOT_PATH_COST, 4, root_path_cost);
536
537     /* add Identifier with format based on preference value
538      * bpdu_use_system_id_extensions
539      * */
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);
558     } else {
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);
572     }
573     /* end of Identifier formatting */
574
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,
579                           message_age);
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,
582                           max_age);
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);
589
590     if (bpdu_type == BPDU_TYPE_CONF) {
591       /* Nothing more in this BPDU */
592       set_actual_length(tvb, CONF_BPDU_SIZE);
593       return;
594     }
595
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) {
603       /*
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.
608        */
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);
612
613       /*
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
619        * for the MSTI data.
620        */
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;
626         } else {
627           /*
628            * XXX - there appears to be an ambiguity in the 802.3Q-2003
629            * standard and at least some of the 802.3s drafts.
630            *
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".
635            *
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.
640            *
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
643            * messages.
644            *
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
648            * messages.
649            */
650           total_msti_length = version_3_length * MSTI_MESSAGE_SIZE;
651         }
652       } else {
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;
656         } else {
657           /* 
658            * XXX - Unknown MSTI format, since version_3_length is 0
659            * lets assume there are no msti instances in the packet.
660            */
661           msti_format = MSTI_FORMAT_UNKNOWN;
662           total_msti_length = 0;
663         }
664           
665       }
666       set_actual_length(tvb, BPDU_MSTI + total_msti_length);
667
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);
671                                       
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);
676
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);
681
682       switch(msti_format) {
683
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);
687
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);
691
692         /* add Identifier with format based on preference value
693          * bpdu_use_system_id_extensions
694          * */
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;
698
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);
716         } else {
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);
730         }
731         /* end of Identifier formatting */
732
733         break;
734
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);
739
740         /* add Identifier with format based on preference value
741          * bpdu_use_system_id_extensions
742          * */
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;
746
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);
764         } else {
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);
778         }
779         /* end of Identifier formatting */
780
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);
783
784         break;
785       }
786
787       proto_tree_add_item(mstp_tree, hf_bpdu_cist_remaining_hops, tvb,
788                           BPDU_CIST_REMAINING_HOPS, 1, FALSE);
789       /* MSTI messages */
790       offset = BPDU_MSTI;
791       msti = 1;
792       while (total_msti_length > 0) {
793         switch(msti_format) {
794
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);
802
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);
809
810           /* flags */
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);
815
816           sep = initial_sep;
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);
829           if (flags_item) {
830             guint8 port_role;
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,
834                                    "Unknown (%u)"));
835           }
836           proto_tree_add_uint(flags_tree, hf_bpdu_flags_port_role, tvb,
837                               offset+MSTI_FLAGS, 1, flags);
838           sep = cont_sep;
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, ")");
847           }
848
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);
859
860
861           proto_tree_add_item(msti_tree, hf_bpdu_msti_internal_root_path_cost, tvb,
862                               offset+MSTI_INTERNAL_ROOT_PATH_COST, 4, FALSE);
863
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;
866
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);
873                       
874           proto_tree_add_item(msti_tree, hf_bpdu_msti_remaining_hops, tvb,
875                               offset + MSTI_REMAINING_HOPS, 1, FALSE);
876
877           total_msti_length -= MSTI_MESSAGE_SIZE;
878           offset += MSTI_MESSAGE_SIZE;
879           break;
880
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);
888
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);
895
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);
899
900           /* flags */
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);
905
906           sep = initial_sep;
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);
919           if (flags_item) {
920             guint8 port_role;
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,
924                                    "Unknown (%u)"));
925           }
926           proto_tree_add_uint(flags_tree, hf_bpdu_flags_port_role, tvb,
927                               offset+ALT_MSTI_FLAGS, 1, flags);
928           sep = cont_sep;
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, ")");
937           }
938
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);
949
950
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);
953
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);
962
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);
966  
967           proto_tree_add_item(msti_tree, hf_bpdu_msti_remaining_hops, tvb,
968                               offset + ALT_MSTI_REMAINING_HOPS, 1, FALSE);
969
970           total_msti_length -= ALT_MSTI_MESSAGE_SIZE;
971           offset += ALT_MSTI_MESSAGE_SIZE;
972           break;
973
974         }
975         msti++;
976       }
977     }
978   }
979 }
980
981 void
982 proto_register_bpdu(void)
983 {      
984
985   static hf_register_info hf[] = {
986     { &hf_bpdu_proto_id,
987       { "Protocol Identifier",          "stp.protocol",
988         FT_UINT16,      BASE_HEX,       VALS(&protocol_id_vals), 0x0,
989         "", HFILL }},
990     { &hf_bpdu_version_id,
991       { "Protocol Version Identifier",  "stp.version",
992         FT_UINT8,       BASE_DEC,       VALS(&version_id_vals), 0x0,
993         "", HFILL }},
994     { &hf_bpdu_type,
995       { "BPDU Type",                    "stp.type",
996         FT_UINT8,       BASE_HEX,       VALS(&bpdu_type_vals),  0x0,
997         "", HFILL }},
998     { &hf_bpdu_flags,
999       { "BPDU flags",                   "stp.flags",
1000         FT_UINT8,       BASE_HEX,       NULL,   0x0,
1001         "", HFILL }},
1002     { &hf_bpdu_flags_tcack,
1003       { "Topology Change Acknowledgment",  "stp.flags.tcack",
1004         FT_BOOLEAN,     8,              TFS(&tfs_yes_no),       BPDU_FLAGS_TCACK,
1005         "", HFILL }},
1006     { &hf_bpdu_flags_agreement,
1007       { "Agreement",                    "stp.flags.agreement",
1008         FT_BOOLEAN,     8,              TFS(&tfs_yes_no),       BPDU_FLAGS_AGREEMENT,
1009         "", HFILL }},
1010     { &hf_bpdu_flags_forwarding,
1011       { "Forwarding",                   "stp.flags.forwarding",
1012         FT_BOOLEAN,     8,              TFS(&tfs_yes_no),       BPDU_FLAGS_FORWARDING,
1013         "", HFILL }},
1014     { &hf_bpdu_flags_learning,
1015       { "Learning",                     "stp.flags.learning",
1016         FT_BOOLEAN,     8,              TFS(&tfs_yes_no),       BPDU_FLAGS_LEARNING,
1017         "", HFILL }},
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,
1021         "", HFILL }},
1022     { &hf_bpdu_flags_proposal,
1023       { "Proposal",                     "stp.flags.proposal",
1024         FT_BOOLEAN,     8,              TFS(&tfs_yes_no),       BPDU_FLAGS_PROPOSAL,
1025         "", HFILL }},
1026     { &hf_bpdu_flags_tc,
1027       { "Topology Change",              "stp.flags.tc",
1028         FT_BOOLEAN,     8,              TFS(&tfs_yes_no),       BPDU_FLAGS_TC,
1029         "", HFILL }},
1030     { &hf_bpdu_root_prio,
1031       { "Root Bridge Priority",         "stp.root.prio",
1032         FT_UINT16,      BASE_DEC,       NULL,   0x0,
1033         "", HFILL }},
1034     { &hf_bpdu_root_sys_id_ext,
1035       { "Root Bridge System ID Extension",      "stp.root.ext",
1036         FT_UINT16,      BASE_DEC,       NULL,   0x0,
1037         "", HFILL }},
1038     { &hf_bpdu_root_mac,
1039       { "Root Bridge System ID",        "stp.root.hw",
1040         FT_ETHER,       BASE_NONE,      NULL,   0x0,
1041         "", HFILL }},
1042     { &hf_bpdu_root_cost,
1043       { "Root Path Cost",               "stp.root.cost",
1044         FT_UINT32,      BASE_DEC,       NULL,   0x0,
1045         "", HFILL }},
1046     { &hf_bpdu_bridge_prio,
1047       { "Bridge Priority",              "stp.bridge.prio",
1048         FT_UINT16,      BASE_DEC,       NULL,   0x0,
1049         "", HFILL }},
1050     { &hf_bpdu_bridge_sys_id_ext,
1051       { "Bridge System ID Extension",   "stp.bridge.ext",
1052         FT_UINT16,      BASE_DEC,       NULL,   0x0,
1053         "", HFILL }},
1054     { &hf_bpdu_bridge_mac,
1055       { "Bridge System ID",             "stp.bridge.hw",
1056         FT_ETHER,       BASE_NONE,      NULL,   0x0,
1057         "", HFILL }},
1058     { &hf_bpdu_port_id,
1059       { "Port identifier",              "stp.port",
1060         FT_UINT16,      BASE_HEX,       NULL,   0x0,
1061         "", HFILL }},
1062     { &hf_bpdu_msg_age,
1063       { "Message Age",                  "stp.msg_age",
1064         FT_DOUBLE,      BASE_NONE,      NULL,   0x0,
1065         "", HFILL }},
1066     { &hf_bpdu_max_age,
1067       { "Max Age",                      "stp.max_age",
1068         FT_DOUBLE,      BASE_NONE,      NULL,   0x0,
1069         "", HFILL }},
1070     { &hf_bpdu_hello_time,
1071       { "Hello Time",                   "stp.hello",
1072         FT_DOUBLE,      BASE_NONE,      NULL,   0x0,
1073         "", HFILL }},
1074     { &hf_bpdu_forward_delay,
1075       { "Forward Delay",                "stp.forward",
1076         FT_DOUBLE,      BASE_NONE,      NULL,   0x0,
1077         "", HFILL }},
1078     { &hf_bpdu_version_1_length,
1079       { "Version 1 Length",             "stp.version_1_length",
1080         FT_UINT8,       BASE_DEC,       NULL,   0x0,
1081         "", HFILL }},
1082     { &hf_bpdu_version_3_length,
1083       { "Version 3 Length",             "mstp.version_3_length",
1084         FT_UINT16,      BASE_DEC,       NULL,   0x0,
1085         "", HFILL }},
1086     { &hf_bpdu_mst_config_format_selector,
1087       { "MST Config ID format selector",        "mstp.config_format_selector",
1088         FT_UINT8,       BASE_DEC,       NULL,   0x0,
1089         "", HFILL }},
1090     { &hf_bpdu_mst_config_name,
1091       { "MST Config name",              "mstp.config_name",
1092         FT_STRINGZ,     BASE_NONE,      NULL,   0x0,
1093         "", HFILL }},
1094     { &hf_bpdu_mst_config_revision_level,
1095       { "MST Config revision",          "mstp.config_revision_level",
1096         FT_UINT16,      BASE_DEC,       NULL,   0x0,
1097         "", HFILL }},
1098     { &hf_bpdu_mst_config_digest,
1099       { "MST Config digest",            "mstp.config_digest",
1100         FT_BYTES,       BASE_DEC,       NULL,   0x0,
1101         "", HFILL }},
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,
1105         "", HFILL }},
1106     { &hf_bpdu_cist_bridge_prio,
1107       { "CIST Bridge Priority",         "mstp.cist_bridge.prio",
1108         FT_UINT16,      BASE_DEC,       NULL,   0x0,
1109         "", HFILL }},
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,
1113         "", HFILL }},
1114     { &hf_bpdu_cist_bridge_mac,
1115       { "CIST Bridge Identifier System ID",     "mstp.cist_bridge.hw",
1116         FT_ETHER,       BASE_NONE,      NULL,   0x0,
1117         "", HFILL }},
1118     { &hf_bpdu_cist_remaining_hops,
1119       { "CIST Remaining hops",          "mstp.cist_remaining_hops",
1120         FT_UINT8,       BASE_DEC,       NULL,   0x0,
1121         "", HFILL }},
1122     { &hf_bpdu_msti_flags,
1123       { "MSTI flags",                   "mstp.msti.flags",
1124         FT_UINT8,       BASE_HEX,       NULL,   0x0,
1125         "", HFILL }},
1126     { &hf_bpdu_msti_regional_root_mac,
1127       { "Regional Root",                "mstp.msti.root.hw",
1128         FT_ETHER,       BASE_DEC,       NULL,   0x0,
1129         "", HFILL }},
1130     { &hf_bpdu_msti_internal_root_path_cost,
1131       { "Internal root path cost",              "mstp.msti.root_cost",
1132         FT_UINT32,      BASE_DEC,       NULL,   0x0,
1133         "", HFILL }},
1134     { &hf_bpdu_msti_bridge_identifier_priority,
1135       { "Bridge Identifier Priority",           "mstp.msti.bridge_priority",
1136         FT_UINT8,       BASE_DEC,       NULL,   0x0,
1137         "", HFILL }},
1138     { &hf_bpdu_msti_port_identifier_priority,
1139       { "Port identifier priority",             "mstp.msti.port_priority",
1140         FT_UINT8,       BASE_DEC,       NULL,   0x0,
1141         "", HFILL }},
1142     { &hf_bpdu_msti_port_id,
1143       { "Port identifier",              "mstp.msti.port",
1144         FT_UINT16,      BASE_HEX,       NULL,   0x0,
1145         "", HFILL }},
1146     { &hf_bpdu_msti_remaining_hops,
1147       { "Remaining hops",               "mstp.msti.remaining_hops",
1148         FT_UINT8,       BASE_DEC,       NULL,   0x0,
1149         "", HFILL }},
1150
1151   };
1152   static gint *ett[] = {
1153     &ett_bpdu,
1154     &ett_bpdu_flags,
1155     &ett_root_id,
1156     &ett_bridge_id,
1157     &ett_mstp,
1158     &ett_msti,
1159     &ett_cist_bridge_id
1160   };
1161   module_t *bpdu_module;
1162
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));
1166
1167   register_dissector("bpdu", dissect_bpdu, proto_bpdu);
1168
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);
1174 }
1175
1176 void
1177 proto_reg_handoff_bpdu(void)
1178 {
1179   dissector_handle_t bpdu_handle;
1180
1181   /*
1182    * Get handle for the GVRP dissector.
1183    */
1184   gvrp_handle = find_dissector("gvrp");
1185
1186   /*
1187    * Get handle for the GMRP dissector.
1188    */
1189   gmrp_handle = find_dissector("gmrp");
1190   data_handle = find_dissector("data");
1191
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);
1197 }