2 * Routines for the disassembly for Cisco Dynamic Trunk Protocol
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * DTP support added by Charlie Lenahan <clenahan@fortresstech.com>
10 * Additional information comes from Yersinia (http://www.yersinia.net/)
11 * by Alfredo Andres and David Barroso
13 * Improved dissection for Trunk Status and Trunk Type TLVs
14 * based on DTP description in U.S. Patent #6,445,715 and
15 * consultations with Aninda Chatterjee @ Cisco
16 * by Peter Paluch <Peter.Paluch@fri.uniza.sk>
18 * SPDX-License-Identifier: GPL-2.0-or-later
24 #include <epan/packet.h>
25 #include <epan/to_str.h>
26 #include <epan/expert.h>
27 #include <epan/cisco_pid.h>
30 * It's incomplete, and it appears to be inaccurate in a number of places,
31 * but it's all I could find....
33 void proto_register_dtp(void);
34 void proto_reg_handoff_dtp(void);
36 static dissector_handle_t dtp_handle
;
39 static int hf_dtp_version
;
40 static int hf_dtp_domain
;
41 static int hf_dtp_tlvtype
;
42 static int hf_dtp_tlvlength
;
43 static int hf_dtp_senderid
;
44 static int hf_dtp_tot
;
45 static int hf_dtp_tat
;
46 static int hf_dtp_tos
;
47 static int hf_dtp_tas
;
48 static int hf_dtp_data
;
51 static int ett_dtp_tlv
;
52 static int ett_dtp_status
;
53 static int ett_dtp_type
;
55 static expert_field ei_dtp_tlv_length_too_short
;
56 static expert_field ei_dtp_tlv_length_invalid
;
57 static expert_field ei_dtp_truncated
;
60 dissect_dtp_tlv(packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, int length
,
61 proto_tree
*tree
, proto_item
*ti
, proto_item
*tlv_length_item
, uint8_t type
);
64 #define DTP_TLV_DOMAIN 0x01 /* VTP Domain Name */
65 #define DTP_TLV_TRSTATUS 0x02 /* Trunk Status */
66 #define DTP_TLV_TRTYPE 0x03 /* Trunk Type */
67 #define DTP_TLV_SENDERID 0x04 /* Sender ID (MAC) */
69 #define DTP_TOS_SHIFT 7
70 #define DTP_TOT_SHIFT 5
72 #define DTP_TOS_MASK 0x80
73 #define DTP_TAS_MASK 0x07
75 #define DTP_TOT_MASK 0xE0
76 #define DTP_TAT_MASK 0x07
78 #define DTP_TOSVALUE(status) (((status) & DTP_TOS_MASK) >> DTP_TOS_SHIFT)
79 #define DTP_TASVALUE(status) ((status) & DTP_TAS_MASK)
81 #define DTP_TOTVALUE(type) (((type) & DTP_TOT_MASK) >> DTP_TOT_SHIFT)
82 #define DTP_TATVALUE(type) ((type) & DTP_TAT_MASK)
84 /* Trunk Operating Status */
85 #define DTP_TOS_ACCESS 0x0
86 #define DTP_TOS_TRUNK 0x1
88 /* Trunk Administrative Status */
89 #define DTP_TAS_ON 0x1
90 #define DTP_TAS_OFF 0x2
91 #define DTP_TAS_DESIRABLE 0x3
92 #define DTP_TAS_AUTO 0x4
94 /* Trunk Operating Type */
95 #define DTP_TOT_NATIVE 0x1
96 #define DTP_TOT_ISL 0x2
97 #define DTP_TOT_DOT1Q 0x5
99 /* Trunk Administrative Type */
100 #define DTP_TAT_NEGOTIATED 0x0
101 #define DTP_TAT_NATIVE 0x1
102 #define DTP_TAT_ISL 0x2
103 #define DTP_TAT_DOT1Q 0x5
106 static const value_string dtp_tlv_type_vals
[] = {
107 { DTP_TLV_DOMAIN
, "Domain" },
108 { DTP_TLV_TRSTATUS
, "Trunk Status" },
109 { DTP_TLV_TRTYPE
, "Trunk Type" },
110 { DTP_TLV_SENDERID
, "Sender ID" },
115 static const value_string dtp_tos_vals
[] = {
116 { DTP_TOS_ACCESS
, "Access" },
117 { DTP_TOS_TRUNK
, "Trunk"},
122 static const value_string dtp_tas_vals
[] = {
123 { DTP_TAS_ON
, "On" },
124 { DTP_TAS_OFF
, "Off" },
125 { DTP_TAS_DESIRABLE
, "Desirable" },
126 { DTP_TAS_AUTO
, "Auto" },
131 static const value_string dtp_tot_vals
[] = {
132 { DTP_TOT_NATIVE
, "Native" },
133 { DTP_TOT_ISL
, "ISL" },
134 { DTP_TOT_DOT1Q
, "802.1Q" },
139 static const value_string dtp_tat_vals
[] = {
140 { DTP_TAT_NEGOTIATED
, "Negotiated" },
141 { DTP_TAT_NATIVE
, "Native" },
142 { DTP_TAT_ISL
, "ISL" },
143 { DTP_TAT_DOT1Q
, "802.1Q" },
149 dissect_dtp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
152 proto_tree
*dtp_tree
;
153 proto_tree
*tlv_tree
;
156 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DTP");
157 col_set_str(pinfo
->cinfo
, COL_INFO
, "Dynamic Trunk Protocol");
159 ti
= proto_tree_add_item(tree
, proto_dtp
, tvb
, offset
, -1, ENC_NA
);
160 dtp_tree
= proto_item_add_subtree(ti
, ett_dtp
);
162 /* We assume version */
163 proto_tree_add_item(dtp_tree
, hf_dtp_version
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
166 while (tvb_reported_length_remaining(tvb
, offset
) > 0) {
167 int type
, length
, valuelength
;
168 proto_item
* tlv_length_item
;
170 /* XXX - why not just let tvbuff exceptions handle this? */
171 if (tvb_reported_length_remaining(tvb
, offset
) < 4) {
172 expert_add_info(pinfo
, dtp_tree
, &ei_dtp_truncated
);
176 type
= tvb_get_ntohs(tvb
, offset
);
177 length
= tvb_get_ntohs(tvb
, offset
+ 2);
179 tlv_tree
= proto_tree_add_subtree(dtp_tree
, tvb
, offset
, length
, ett_dtp_tlv
, NULL
,
180 val_to_str(type
, dtp_tlv_type_vals
, "Unknown TLV type: 0x%02x"));
182 proto_tree_add_uint(tlv_tree
, hf_dtp_tlvtype
, tvb
, offset
, 2, type
);
185 tlv_length_item
= proto_tree_add_uint(tlv_tree
, hf_dtp_tlvlength
, tvb
, offset
, 2, length
);
189 /* Length includes type and length fields, so it
190 must be >= 4, and no known TLVs have a value
191 length of 0, so it must be > 4. */
192 expert_add_info(pinfo
, tlv_length_item
, &ei_dtp_tlv_length_too_short
);
195 valuelength
= (length
-4);
196 dissect_dtp_tlv(pinfo
, tvb
, offset
, valuelength
, tlv_tree
, ti
, tlv_length_item
, (uint8_t) type
);
197 offset
+= valuelength
;
199 return tvb_captured_length(tvb
);
203 dissect_dtp_tlv(packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, int length
,
204 proto_tree
*tree
, proto_item
*ti
, proto_item
*tlv_length_item
, uint8_t type
)
209 if (length
<= 33) { /* VTP domain name is at most 32 bytes long and is null-terminated */
210 proto_item_append_text(ti
, ": %s", tvb_format_text(pinfo
->pool
, tvb
, offset
, length
- 1));
211 proto_tree_add_item(tree
, hf_dtp_domain
, tvb
, offset
, length
, ENC_ASCII
);
214 expert_add_info(pinfo
, tlv_length_item
, &ei_dtp_tlv_length_invalid
);
218 case DTP_TLV_TRSTATUS
:
219 if (length
== 1) { /* Value field length must be 1 byte */
220 proto_tree
* field_tree
= NULL
;
221 uint8_t trunk_status
= tvb_get_uint8(tvb
, offset
);
223 proto_item_append_text(ti
,
224 " (Operating/Administrative): %s/%s (0x%02x)",
225 val_to_str_const(DTP_TOSVALUE(trunk_status
), dtp_tos_vals
, "Unknown operating status"),
226 val_to_str_const(DTP_TASVALUE(trunk_status
), dtp_tas_vals
, "Unknown administrative status"),
228 field_tree
= proto_tree_add_subtree_format(tree
, tvb
, offset
, length
, ett_dtp_status
, NULL
, "Value: %s/%s (0x%02x)",
229 val_to_str_const(DTP_TOSVALUE(trunk_status
), dtp_tos_vals
, "Unknown operating status"),
230 val_to_str_const(DTP_TASVALUE(trunk_status
), dtp_tas_vals
, "Unknown administrative status"),
232 proto_tree_add_item(field_tree
, hf_dtp_tos
, tvb
, offset
, length
, ENC_BIG_ENDIAN
);
233 proto_tree_add_item(field_tree
, hf_dtp_tas
, tvb
, offset
, length
, ENC_BIG_ENDIAN
);
236 expert_add_info(pinfo
, tlv_length_item
, &ei_dtp_tlv_length_invalid
);
241 if (length
== 1) { /* Value field length must be 1 byte */
242 proto_tree
* field_tree
;
243 uint8_t trunk_type
= tvb_get_uint8(tvb
, offset
);
244 proto_item_append_text(ti
,
245 " (Operating/Administrative): %s/%s (0x%02x)",
246 val_to_str_const(DTP_TOTVALUE(trunk_type
), dtp_tot_vals
, "Unknown operating type"),
247 val_to_str_const(DTP_TATVALUE(trunk_type
), dtp_tat_vals
, "Unknown administrative type"),
249 field_tree
= proto_tree_add_subtree_format(tree
, tvb
, offset
, length
, ett_dtp_type
, NULL
, "Value: %s/%s (0x%02x)",
250 val_to_str_const(DTP_TOTVALUE(trunk_type
), dtp_tot_vals
, "Unknown operating type"),
251 val_to_str_const(DTP_TATVALUE(trunk_type
), dtp_tat_vals
, "Unknown administrative type"),
253 proto_tree_add_item(field_tree
, hf_dtp_tot
, tvb
, offset
, length
, ENC_BIG_ENDIAN
);
254 proto_tree_add_item(field_tree
, hf_dtp_tat
, tvb
, offset
, length
, ENC_BIG_ENDIAN
);
257 expert_add_info(pinfo
, tlv_length_item
, &ei_dtp_tlv_length_invalid
);
261 case DTP_TLV_SENDERID
:
262 if (length
== 6) { /* Value length must be 6 bytes for a MAC address */
263 proto_item_append_text(ti
, ": %s",
264 tvb_ether_to_str(pinfo
->pool
, tvb
, offset
)); /* XXX - resolve? */
265 proto_tree_add_item(tree
, hf_dtp_senderid
, tvb
, offset
, length
, ENC_NA
);
268 expert_add_info(pinfo
, tlv_length_item
, &ei_dtp_tlv_length_invalid
);
273 proto_tree_add_item(tree
, hf_dtp_data
, tvb
, offset
, length
, ENC_NA
);
279 proto_register_dtp(void)
281 static hf_register_info hf
[] = {
283 { "Version", "dtp.version", FT_UINT8
, BASE_DEC
,
284 NULL
, 0x0, NULL
, HFILL
}},
287 { "Domain", "dtp.domain", FT_STRING
, BASE_NONE
,
288 NULL
, 0x0, NULL
, HFILL
}},
291 { "Type", "dtp.tlv_type", FT_UINT16
, BASE_HEX
,
292 VALS(dtp_tlv_type_vals
), 0x0, NULL
, HFILL
}},
295 { "Length", "dtp.tlv_len", FT_UINT16
, BASE_DEC
,
296 NULL
, 0x0, NULL
, HFILL
}},
299 { "Trunk Operating Status", "dtp.tos", FT_UINT8
, BASE_HEX
,
300 VALS(dtp_tos_vals
), DTP_TOS_MASK
, NULL
, HFILL
}},
303 { "Trunk Administrative Status", "dtp.tas", FT_UINT8
, BASE_HEX
,
304 VALS(dtp_tas_vals
), DTP_TAS_MASK
, NULL
, HFILL
}},
307 { "Trunk Operating Type", "dtp.tot", FT_UINT8
, BASE_HEX
,
308 VALS(dtp_tot_vals
), DTP_TOT_MASK
, NULL
, HFILL
}},
311 { "Trunk Administrative Type", "dtp.tat", FT_UINT8
, BASE_HEX
,
312 VALS(dtp_tat_vals
), DTP_TAT_MASK
, NULL
, HFILL
}},
315 { "Sender ID", "dtp.senderid", FT_ETHER
, BASE_NONE
,
316 NULL
, 0x0, "MAC Address of neighbor", HFILL
}},
319 { "Data", "dtp.data", FT_ETHER
, BASE_NONE
,
320 NULL
, 0x0, NULL
, HFILL
}},
323 static int *ett
[] = {
330 static ei_register_info ei
[] = {
331 { &ei_dtp_tlv_length_too_short
,
332 { "dtp.tlv_len.too_short", PI_MALFORMED
, PI_ERROR
,
333 "Indicated length is less than the minimum length", EXPFILL
}},
335 { &ei_dtp_tlv_length_invalid
,
336 { "dtp.tlv_len.invalid", PI_MALFORMED
, PI_ERROR
,
337 "Indicated length does not correspond to this record type", EXPFILL
}},
340 { "dtp.truncated", PI_MALFORMED
, PI_ERROR
,
341 "DTP message is truncated prematurely", EXPFILL
}}
345 expert_module_t
*expert_dtp
;
347 proto_dtp
= proto_register_protocol("Dynamic Trunk Protocol", "DTP", "dtp");
348 proto_register_field_array(proto_dtp
, hf
, array_length(hf
));
349 proto_register_subtree_array(ett
, array_length(ett
));
351 expert_dtp
= expert_register_protocol(proto_dtp
);
352 expert_register_field_array(expert_dtp
, ei
, array_length(ei
));
354 dtp_handle
= register_dissector("dtp", dissect_dtp
, proto_dtp
);
358 proto_reg_handoff_dtp(void)
360 dissector_add_uint("llc.cisco_pid", CISCO_PID_DTP
, dtp_handle
);
364 * Editor modelines - https://www.wireshark.org/tools/modelines.html
369 * indent-tabs-mode: t
372 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
373 * :indentSize=8:tabSize=8:noTabs=false: