Include files from the "epan" directory and subdirectories thereof with
[obnox/wireshark/wip.git] / packet-vtp.c
1 /* packet-vtp.c
2  * Routines for the disassembly of Cisco's Virtual Trunking Protocol
3  *
4  * $Id: packet-vtp.c,v 1.18 2002/01/21 07:36:44 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  * 
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  * 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  * 
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24  
25 #include "config.h"
26
27 #ifdef HAVE_SYS_TYPES_H
28 #include <sys/types.h>
29 #endif
30
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include <glib.h>
35 #include <epan/packet.h>
36
37 /*
38  * See
39  *
40  *      http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm
41  *
42  * for some information on VTP.
43  *
44  * It's incomplete, and it appears to be inaccurate in a number of places,
45  * but it's all I could find....
46  */
47
48 static int proto_vtp = -1;
49 static int hf_vtp_version = -1;
50 static int hf_vtp_code = -1;
51 static int hf_vtp_followers = -1;
52 static int hf_vtp_md_len = -1;
53 static int hf_vtp_md = -1;
54 static int hf_vtp_conf_rev_num = -1;
55 static int hf_vtp_upd_id = -1;
56 static int hf_vtp_upd_ts = -1;
57 static int hf_vtp_md5_digest = -1;
58 static int hf_vtp_seq_num = -1;
59 static int hf_vtp_start_value = -1;
60 static int hf_vtp_vlan_info_len = -1;
61 static int hf_vtp_vlan_status_vlan_susp = -1;
62 static int hf_vtp_vlan_type = -1;
63 static int hf_vtp_vlan_name_len = -1;
64 static int hf_vtp_isl_vlan_id = -1;
65 static int hf_vtp_mtu_size = -1;
66 static int hf_vtp_802_10_index = -1;
67 static int hf_vtp_vlan_name = -1;
68 static int hf_vtp_vlan_tlvtype = -1;
69 static int hf_vtp_vlan_tlvlength = -1;
70
71 static gint ett_vtp = -1;
72 static gint ett_vtp_vlan_info = -1;
73 static gint ett_vtp_vlan_status = -1;
74 static gint ett_vtp_tlv = -1;
75
76 static int
77 dissect_vlan_info(tvbuff_t *tvb, int offset, proto_tree *tree);
78 static void
79 dissect_vlan_info_tlv(tvbuff_t *tvb, int offset, int length,
80     proto_tree *tree, proto_item *ti, guint8 type);
81
82 #define SUMMARY_ADVERT          0x01
83 #define SUBSET_ADVERT           0x02
84 #define ADVERT_REQUEST          0x03
85
86 static const value_string type_vals[] = {
87         { SUMMARY_ADVERT, "Summary-Advert" },
88         { SUBSET_ADVERT,  "Subset-Advert" },
89         { ADVERT_REQUEST, "Advert-Request" },
90         { 0,              NULL },
91 };
92         
93 static void 
94 dissect_vtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
95 {
96         proto_item *ti; 
97         proto_tree *vtp_tree = NULL;
98         int offset = 0;
99         guint8 code;
100         guint8 md_len;
101         const guint8 *upd_timestamp;
102         int vlan_info_len;
103
104         if (check_col(pinfo->cinfo, COL_PROTOCOL))
105                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "VTP");
106         if (check_col(pinfo->cinfo, COL_INFO))
107                 col_set_str(pinfo->cinfo, COL_INFO, "Virtual Trunking Protocol"); 
108
109         if (tree) {
110                 ti = proto_tree_add_item(tree, proto_vtp, tvb, offset,
111                     tvb_length_remaining(tvb, offset), FALSE);
112                 vtp_tree = proto_item_add_subtree(ti, ett_vtp);
113
114                 proto_tree_add_item(vtp_tree, hf_vtp_version, tvb, offset, 1,
115                     FALSE);
116                 offset += 1;
117
118                 code = tvb_get_guint8(tvb, offset);
119                 proto_tree_add_uint(vtp_tree, hf_vtp_code, tvb, offset, 1,
120                     code);
121                 offset += 1;
122                 
123                 switch (code) {
124
125                 case SUMMARY_ADVERT:
126                         proto_tree_add_item(vtp_tree, hf_vtp_followers, tvb, offset,
127                             1, FALSE);
128                         offset += 1;
129
130                         md_len = tvb_get_guint8(tvb, offset);
131                         proto_tree_add_uint(vtp_tree, hf_vtp_md_len, tvb, offset,
132                             1, md_len);
133                         offset += 1;
134
135                         proto_tree_add_item(vtp_tree, hf_vtp_md, tvb, offset,
136                             32, FALSE);
137                         offset += 32;
138
139                         proto_tree_add_item(vtp_tree, hf_vtp_conf_rev_num, tvb,
140                             offset, 4, FALSE);
141                         offset += 4;
142
143                         proto_tree_add_item(vtp_tree, hf_vtp_upd_id, tvb,
144                             offset, 4, FALSE);
145                         offset += 4;
146
147                         upd_timestamp = tvb_get_ptr(tvb, offset, 12);
148                         proto_tree_add_string_format(vtp_tree, hf_vtp_upd_ts, tvb,
149                             offset, 12, upd_timestamp,
150                             "Update Timestamp: %.2s-%.2s-%.2s %.2s:%.2s:%.2s",
151                             &upd_timestamp[0], &upd_timestamp[2], &upd_timestamp[4],
152                             &upd_timestamp[6], &upd_timestamp[8], &upd_timestamp[10]);
153                         offset += 12;
154
155                         proto_tree_add_item(vtp_tree, hf_vtp_md5_digest, tvb,
156                             offset, 16, FALSE);
157                         break;
158
159                 case SUBSET_ADVERT:
160                         proto_tree_add_item(vtp_tree, hf_vtp_seq_num, tvb, offset,
161                             1, FALSE);
162                         offset += 1;
163
164                         md_len = tvb_get_guint8(tvb, offset);
165                         proto_tree_add_uint(vtp_tree, hf_vtp_md_len, tvb, offset,
166                             1, md_len);
167                         offset += 1;
168
169                         proto_tree_add_item(vtp_tree, hf_vtp_md, tvb, offset,
170                             32, FALSE);
171                         offset += 32;
172
173                         proto_tree_add_item(vtp_tree, hf_vtp_conf_rev_num, tvb,
174                             offset, 4, FALSE);
175                         offset += 4;
176
177                         while (tvb_reported_length_remaining(tvb, offset) > 0) {
178                                 vlan_info_len = 
179                                     dissect_vlan_info(tvb, offset, vtp_tree);
180                                 if (vlan_info_len < 0)
181                                         break;
182                                 offset += vlan_info_len;
183                         }
184                         break;
185
186                 case ADVERT_REQUEST:
187                         offset += 1;    /* skip reserved field */
188
189                         md_len = tvb_get_guint8(tvb, offset);
190                         proto_tree_add_uint(vtp_tree, hf_vtp_md_len, tvb, offset,
191                             1, md_len);
192                         offset += 1;
193
194                         proto_tree_add_item(vtp_tree, hf_vtp_start_value, tvb,
195                             offset, 2, FALSE);
196                         break;
197
198                 case 0x04:
199                         /*
200                          * Mysterious type, seen a lot.
201                          * Is this some mutant variant of Advert-Request?
202                          */
203                         offset += 1;    /* skip unknown field */
204
205                         md_len = tvb_get_guint8(tvb, offset);
206                         proto_tree_add_uint(vtp_tree, hf_vtp_md_len, tvb, offset,
207                             1, md_len);
208                         offset += 1;
209
210                         proto_tree_add_item(vtp_tree, hf_vtp_md, tvb, offset,
211                             32, FALSE);
212                         offset += 32;
213
214                         offset += 2;    /* skip unknown field */
215
216                         proto_tree_add_text(vtp_tree, tvb, offset, 2,
217                             "VLAN ID of some sort: 0x%04x",
218                             tvb_get_ntohs(tvb, offset));
219                         offset += 2;
220                         break;
221                 }
222         }
223 }
224
225 #define VLAN_SUSPENDED  0x01
226
227 static const value_string vlan_type_vals[] = {
228         { 0x01, "Ethernet" },
229         { 0x02, "FDDI" },
230         { 0x03, "TrCRF" },
231         { 0x04, "FDDI-net" },
232         { 0x05, "TrBRF" },
233         { 0,    NULL },
234 };
235
236 #define SR_RING_NUM             0x01
237 #define SR_BRIDGE_NUM           0x02
238 #define STP_TYPE                0x03
239 #define PARENT_VLAN             0x04
240 #define TR_BRIDGED_VLANS        0x05
241 #define PRUNING                 0x06
242 #define BRIDGE_TYPE             0x07
243 #define MAX_ARE_HOP_CNT         0x08
244 #define MAX_STE_HOP_CNT         0x09
245 #define BACKUP_CRF_MODE         0x0A
246
247 static const value_string vlan_tlv_type_vals[] = {
248         { SR_RING_NUM,      "Source-Routing Ring Number" },
249         { SR_BRIDGE_NUM,    "Source-Routing Bridge Number" },
250         { STP_TYPE,         "Spanning-Tree Protocol Type" },
251         { PARENT_VLAN,      "Parent VLAN" },
252         { TR_BRIDGED_VLANS, "Translationally Bridged VLANs" },
253         { PRUNING,          "Pruning" },
254         { BRIDGE_TYPE,      "Bridge Type" },
255         { MAX_ARE_HOP_CNT,  "Max ARE Hop Count" },
256         { MAX_STE_HOP_CNT,  "Max STE Hop Count" },
257         { BACKUP_CRF_MODE,  "Backup CRF Mode" },
258         { 0,                NULL },
259 };
260
261 static int
262 dissect_vlan_info(tvbuff_t *tvb, int offset, proto_tree *tree)
263 {
264         proto_item *ti; 
265         proto_tree *vlan_info_tree;
266         proto_tree *status_tree;
267         guint8 vlan_info_len;
268         int vlan_info_left;
269         guint8 status;
270         guint8 vlan_name_len;
271         guint8 type;
272         int length;
273         proto_tree *tlv_tree;
274
275         vlan_info_len = tvb_get_guint8(tvb, offset);
276         ti = proto_tree_add_text(tree, tvb, offset, vlan_info_len,
277             "VLAN Information");
278         vlan_info_tree = proto_item_add_subtree(ti, ett_vtp_vlan_info);
279         vlan_info_left = vlan_info_len;
280
281         proto_tree_add_uint(vlan_info_tree, hf_vtp_vlan_info_len, tvb, offset, 1,
282             vlan_info_len);
283         offset += 1;
284         vlan_info_left -= 1;
285
286         if (vlan_info_left < 1)
287                 return -1;
288         status = tvb_get_guint8(tvb, offset);
289         ti = proto_tree_add_text(vlan_info_tree, tvb, offset, 1,
290             "Status: 0x%02x%s", status,
291             (status & VLAN_SUSPENDED) ? "(VLAN suspended)" : "");
292         status_tree = proto_item_add_subtree(ti, ett_vtp_vlan_status);
293         proto_tree_add_boolean(status_tree, hf_vtp_vlan_status_vlan_susp, tvb, offset, 1,
294             status);
295         offset += 1;
296         vlan_info_left -= 1;
297
298         if (vlan_info_left < 1)
299                 return -1;
300         proto_tree_add_item(vlan_info_tree, hf_vtp_vlan_type, tvb, offset, 1,
301             FALSE);
302         offset += 1;
303         vlan_info_left -= 1;
304
305         if (vlan_info_left < 1)
306                 return -1;
307         vlan_name_len = tvb_get_guint8(tvb, offset);
308         proto_tree_add_uint(vlan_info_tree, hf_vtp_vlan_name_len, tvb, offset, 1,
309             vlan_name_len);
310         offset += 1;
311         vlan_info_left -= 1;
312
313         if (vlan_info_left < 2)
314                 return -1;
315         proto_tree_add_item(vlan_info_tree, hf_vtp_isl_vlan_id, tvb, offset, 2,
316             FALSE);
317         offset += 2;
318         vlan_info_left -= 2;
319
320         if (vlan_info_left < 2)
321                 return -1;
322         proto_tree_add_item(vlan_info_tree, hf_vtp_mtu_size, tvb, offset, 2,
323             FALSE);
324         offset += 2;
325         vlan_info_left -= 2;
326
327         if (vlan_info_left < 4)
328                 return -1;
329         proto_tree_add_item(vlan_info_tree, hf_vtp_802_10_index, tvb, offset, 4,
330             FALSE);
331         offset += 4;
332         vlan_info_left -= 4;
333
334         /* VLAN name length appears to be rounded up to a multiple of 4. */
335         vlan_name_len = 4*((vlan_name_len + 3)/4);
336         if (vlan_info_left < vlan_name_len)
337                 return -1;
338         proto_tree_add_item(vlan_info_tree, hf_vtp_vlan_name, tvb, offset,
339             vlan_name_len, FALSE);
340         offset += vlan_name_len;
341         vlan_info_left -= vlan_name_len;
342
343         while (vlan_info_left > 0) {
344                 type = tvb_get_guint8(tvb, offset + 0);
345                 length = tvb_get_guint8(tvb, offset + 1);
346
347                 ti = proto_tree_add_text(vlan_info_tree, tvb, offset,
348                     2 + length*2, "%s",
349                     val_to_str(type, vlan_tlv_type_vals,
350                       "Unknown TLV type: 0x%02x"));
351                 tlv_tree = proto_item_add_subtree(ti, ett_vtp_tlv);
352                 proto_tree_add_uint(tlv_tree, hf_vtp_vlan_tlvtype, tvb, offset,
353                     1, type);
354                 proto_tree_add_uint(tlv_tree, hf_vtp_vlan_tlvlength, tvb, offset+1,
355                     1, length);
356                 offset += 2;
357                 vlan_info_left -= 2;
358                 if (length > 0) {
359                         dissect_vlan_info_tlv(tvb, offset, length*2, tlv_tree,
360                             ti, type);
361                 }
362                 offset += length*2;
363                 vlan_info_left -= length*2;
364         }
365
366         return vlan_info_len;
367 }
368
369 static const value_string stp_type_vals[] = {
370         { 1, "SRT" },
371         { 2, "SRB" },
372         { 3, "Auto" },
373         { 0, NULL },
374 };
375
376 static const value_string pruning_vals[] = {
377         { 1, "Enabled" },
378         { 2, "Disabled" },
379         { 0, NULL },
380 };
381
382 static const value_string bridge_type_vals[] = {
383         { 1, "SRT" },
384         { 2, "SRB" },
385         { 0, NULL },
386 };
387
388 static const value_string backup_crf_mode_vals[] = {
389         { 1, "TrCRF is configured as a backup" },
390         { 2, "TrCRF is not configured as a backup" },
391         { 0, NULL },
392 };
393
394 static void
395 dissect_vlan_info_tlv(tvbuff_t *tvb, int offset, int length,
396     proto_tree *tree, proto_item *ti, guint8 type)
397 {
398         switch (type) {
399
400         case SR_RING_NUM:
401                 if (length == 2) {
402                         proto_item_set_text(ti,
403                             "Source-Routing Ring Number: 0x%04x",
404                             tvb_get_ntohs(tvb, offset));
405                         proto_tree_add_text(tree, tvb, offset, 2,
406                             "Source-Routing Ring Number: 0x%04x",
407                             tvb_get_ntohs(tvb, offset));
408                 } else {
409                         proto_item_set_text(ti,
410                             "Source-Routing Ring Number: Bad length %u",
411                             length);
412                         proto_tree_add_text(tree, tvb, offset, length,
413                             "Source-Routing Ring Number: Bad length %u",
414                             length);
415                 }
416                 break;
417
418         case SR_BRIDGE_NUM:
419                 if (length == 2) {
420                         proto_item_set_text(ti,
421                             "Source-Routing Bridge Number: 0x%04x",
422                             tvb_get_ntohs(tvb, offset));
423                         proto_tree_add_text(tree, tvb, offset, 2,
424                             "Source-Routing Bridge Number: 0x%04x",
425                             tvb_get_ntohs(tvb, offset));
426                 } else {
427                         proto_item_set_text(ti,
428                             "Source-Routing Bridge Number: Bad length %u",
429                             length);
430                         proto_tree_add_text(tree, tvb, offset, length,
431                             "Source-Routing Bridge Number: Bad length %u",
432                             length);
433                 }
434                 break;
435
436         case STP_TYPE:
437                 if (length == 2) {
438                         proto_item_set_text(ti,
439                             "Spanning-Tree Protocol Type: %s",
440                             val_to_str(tvb_get_ntohs(tvb, offset), stp_type_vals,
441                               "Unknown (0x%04x)"));
442                         proto_tree_add_text(tree, tvb, offset, 2,
443                             "Spanning-Tree Protocol Type: %s",
444                             val_to_str(tvb_get_ntohs(tvb, offset), stp_type_vals,
445                               "Unknown (0x%04x)"));
446                 } else {
447                         proto_item_set_text(ti,
448                             "Spanning-Tree Protocol Type: Bad length %u",
449                             length);
450                         proto_tree_add_text(tree, tvb, offset, length,
451                             "Spanning-Tree Protocol Type: Bad length %u",
452                             length);
453                 }
454                 break;
455
456         case PARENT_VLAN:
457                 if (length == 2) {
458                         proto_item_set_text(ti,
459                             "Parent VLAN: 0x%04x",
460                             tvb_get_ntohs(tvb, offset));
461                         proto_tree_add_text(tree, tvb, offset, 2,
462                             "Parent VLAN: 0x%04x",
463                             tvb_get_ntohs(tvb, offset));
464                 } else {
465                         proto_item_set_text(ti,
466                             "Parent VLAN: Bad length %u",
467                             length);
468                         proto_tree_add_text(tree, tvb, offset, length,
469                             "Parent VLAN: Bad length %u",
470                             length);
471                 }
472                 break;
473
474         case TR_BRIDGED_VLANS:
475                 if (length == 2) {
476                         proto_item_set_text(ti,
477                             "Translationally Bridged VLANs: 0x%04x",
478                             tvb_get_ntohs(tvb, offset));
479                         proto_tree_add_text(tree, tvb, offset, 2,
480                             "Translationally Bridged VLANs: 0x%04x",
481                             tvb_get_ntohs(tvb, offset));
482                 } else {
483                         proto_item_set_text(ti,
484                             "Translationally Bridged VLANs: Bad length %u",
485                             length);
486                         proto_tree_add_text(tree, tvb, offset, length,
487                             "Translationally Bridged VLANs: Bad length %u",
488                             length);
489                 }
490                 break;
491
492         case PRUNING:
493                 if (length == 2) {
494                         proto_item_set_text(ti,
495                             "Pruning: %s",
496                             val_to_str(tvb_get_ntohs(tvb, offset), pruning_vals,
497                               "Unknown (0x%04x)"));
498                         proto_tree_add_text(tree, tvb, offset, 2,
499                             "Pruning: %s",
500                             val_to_str(tvb_get_ntohs(tvb, offset), pruning_vals,
501                               "Unknown (0x%04x)"));
502                 } else {
503                         proto_item_set_text(ti,
504                             "Pruning: Bad length %u",
505                             length);
506                         proto_tree_add_text(tree, tvb, offset, length,
507                             "Pruning: Bad length %u",
508                             length);
509                 }
510                 break;
511
512         case BRIDGE_TYPE:
513                 if (length == 2) {
514                         proto_item_set_text(ti,
515                             "Bridge Type: %s",
516                             val_to_str(tvb_get_ntohs(tvb, offset), bridge_type_vals,
517                               "Unknown (0x%04x)"));
518                         proto_tree_add_text(tree, tvb, offset, 2,
519                             "Bridge Type: %s",
520                             val_to_str(tvb_get_ntohs(tvb, offset), bridge_type_vals,
521                               "Unknown (0x%04x)"));
522                 } else {
523                         proto_item_set_text(ti,
524                             "Bridge Type: Bad length %u",
525                             length);
526                         proto_tree_add_text(tree, tvb, offset, length,
527                             "Bridge Type: Bad length %u",
528                             length);
529                 }
530                 break;
531
532         case MAX_ARE_HOP_CNT:
533                 if (length == 2) {
534                         proto_item_set_text(ti,
535                             "Max ARE Hop Count: %u",
536                             tvb_get_ntohs(tvb, offset));
537                         proto_tree_add_text(tree, tvb, offset, 2,
538                             "Max ARE Hop Count: %u",
539                             tvb_get_ntohs(tvb, offset));
540                 } else {
541                         proto_item_set_text(ti,
542                             "Max ARE Hop Count: Bad length %u",
543                             length);
544                         proto_tree_add_text(tree, tvb, offset, length,
545                             "Max ARE Hop Count: Bad length %u",
546                             length);
547                 }
548                 break;
549
550         case MAX_STE_HOP_CNT:
551                 if (length == 2) {
552                         proto_item_set_text(ti,
553                             "Max STE Hop Count: %u",
554                             tvb_get_ntohs(tvb, offset));
555                         proto_tree_add_text(tree, tvb, offset, 2,
556                             "Max STE Hop Count: %u",
557                             tvb_get_ntohs(tvb, offset));
558                 } else {
559                         proto_item_set_text(ti,
560                             "Max STE Hop Count: Bad length %u",
561                             length);
562                         proto_tree_add_text(tree, tvb, offset, length,
563                             "Max STE Hop Count: Bad length %u",
564                             length);
565                 }
566                 break;
567
568         case BACKUP_CRF_MODE:
569                 if (length == 2) {
570                         proto_item_set_text(ti,
571                             "Backup CRF Mode: %s",
572                             val_to_str(tvb_get_ntohs(tvb, offset), backup_crf_mode_vals,
573                               "Unknown (0x%04x)"));
574                         proto_tree_add_text(tree, tvb, offset, 2,
575                             "Backup CRF Mode: %s",
576                             val_to_str(tvb_get_ntohs(tvb, offset), backup_crf_mode_vals,
577                               "Unknown (0x%04x)"));
578                 } else {
579                         proto_item_set_text(ti,
580                             "Backup CRF Mode: Bad length %u",
581                             length);
582                         proto_tree_add_text(tree, tvb, offset, length,
583                             "Backup CRF Mode: Bad length %u",
584                             length);
585                 }
586                 break;
587
588         default:
589                 proto_tree_add_text(tree, tvb, offset, length, "Data");
590                 break;
591         }
592 }
593
594 void
595 proto_register_vtp(void)
596 {
597         static hf_register_info hf[] = {
598                 { &hf_vtp_version,
599                 { "Version",    "vtp.version", FT_UINT8, BASE_HEX, NULL, 0x0,
600                         "", HFILL }},
601
602                 { &hf_vtp_code,
603                 { "Code",       "vtp.code", FT_UINT8, BASE_HEX, VALS(type_vals), 0x0,
604                         "", HFILL }},
605
606                 { &hf_vtp_followers,
607                 { "Followers",  "vtp.followers", FT_UINT8, BASE_DEC, NULL, 0x0,
608                         "Number of following Subset-Advert messages", HFILL }},
609
610                 { &hf_vtp_md_len,
611                 { "Management Domain Length", "vtp.md_len", FT_UINT8, BASE_DEC, NULL, 0x0,
612                         "Length of management domain string", HFILL }},
613
614                 { &hf_vtp_md,
615                 { "Management Domain", "vtp.md", FT_STRING, BASE_DEC, NULL, 0,
616                         "Management domain", HFILL }},
617
618                 { &hf_vtp_conf_rev_num,
619                 { "Configuration Revision Number", "vtp.conf_rev_num", FT_UINT32, BASE_DEC, NULL, 0x0,
620                         "Revision number of the configuration information", HFILL }},
621
622                 { &hf_vtp_upd_id,
623                 { "Updater Identity", "vtp.upd_id", FT_IPv4, BASE_NONE, NULL, 0x0,
624                         "IP address of the updater", HFILL }},
625
626                 { &hf_vtp_upd_ts,
627                 { "Update Timestamp", "vtp.upd_ts", FT_STRING, BASE_DEC, NULL, 0,
628                         "Time stamp of the current configuration revision", HFILL }},
629
630                 { &hf_vtp_md5_digest,
631                 { "MD5 Digest", "vtp.md5_digest", FT_BYTES, BASE_HEX, NULL, 0x0,
632                         "", HFILL }},
633
634                 { &hf_vtp_seq_num,
635                 { "Sequence Number",    "vtp.seq_num", FT_UINT8, BASE_DEC, NULL, 0x0,
636                         "Order of this frame in the sequence of Subset-Advert frames", HFILL }},
637
638                 { &hf_vtp_start_value,
639                 { "Start Value",        "vtp.start_value", FT_UINT16, BASE_HEX, NULL, 0x0,
640                         "Virtual LAN ID of first VLAN for which information is requested", HFILL }},
641
642                 { &hf_vtp_vlan_info_len,
643                 { "VLAN Information Length",    "vtp.vlan_info.len", FT_UINT8, BASE_DEC, NULL, 0x0,
644                         "Length of the VLAN information field", HFILL }},
645
646                 { &hf_vtp_vlan_status_vlan_susp,
647                 { "VLAN suspended",     "vtp.vlan_info.status.vlan_susp", FT_BOOLEAN, 8, NULL, VLAN_SUSPENDED,
648                         "VLAN suspended", HFILL }},
649
650                 { &hf_vtp_vlan_type,
651                 { "VLAN Type",  "vtp.vlan_info.vlan_type", FT_UINT8, BASE_HEX, VALS(vlan_type_vals), 0x0,
652                         "Type of VLAN", HFILL }},
653
654                 { &hf_vtp_vlan_name_len,
655                 { "VLAN Name Length", "vtp.vlan_info.vlan_name_len", FT_UINT8, BASE_DEC, NULL, 0x0,
656                         "Length of VLAN name string", HFILL }},
657
658                 { &hf_vtp_isl_vlan_id,
659                 { "ISL VLAN ID",        "vtp.vlan_info.isl_vlan_id", FT_UINT16, BASE_HEX, NULL, 0x0,
660                         "ID of this VLAN on ISL trunks", HFILL }},
661
662                 { &hf_vtp_mtu_size,
663                 { "MTU Size",   "vtp.vlan_info.mtu_size", FT_UINT16, BASE_DEC, NULL, 0x0,
664                         "MTU for this VLAN", HFILL }},
665
666                 { &hf_vtp_802_10_index,
667                 { "802.10 Index", "vtp.vlan_info.802_10_index", FT_UINT32, BASE_HEX, NULL, 0x0,
668                         "IEEE 802.10 security association identifier for this VLAN", HFILL }},
669
670                 { &hf_vtp_vlan_name,
671                 { "VLAN Name", "vtp.vlan_info.vlan_name", FT_STRING, BASE_DEC, NULL, 0,
672                         "VLAN name", HFILL }},
673
674                 { &hf_vtp_vlan_tlvtype,
675                 { "Type",       "vtp.vlan_info.tlv_type", FT_UINT8, BASE_HEX, VALS(vlan_tlv_type_vals), 0x0,
676                         "", HFILL }},
677
678                 { &hf_vtp_vlan_tlvlength,
679                 { "Length",     "vtp.vlan_info.tlv_len", FT_UINT8, BASE_DEC, NULL, 0x0,
680                         "", HFILL }},
681         };
682         static gint *ett[] = {
683                 &ett_vtp,
684                 &ett_vtp_vlan_info,
685                 &ett_vtp_vlan_status,
686                 &ett_vtp_tlv,
687         };
688
689         proto_vtp = proto_register_protocol("Virtual Trunking Protocol",
690             "VTP", "vtp");
691         proto_register_field_array(proto_vtp, hf, array_length(hf));
692         proto_register_subtree_array(ett, array_length(ett));
693 }
694
695 void
696 proto_reg_handoff_vtp(void)
697 {
698         dissector_handle_t vtp_handle;
699
700         vtp_handle = create_dissector_handle(dissect_vtp, proto_vtp);
701         dissector_add("llc.cisco_pid", 0x2003, vtp_handle);
702 }