Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-dtp.c
blob14f28fa95115ed9548c7c57ba613045474955206
1 /* packet-dtp.c
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
22 #include "config.h"
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;
38 static int proto_dtp;
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;
50 static int ett_dtp;
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;
59 static void
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" },
112 { 0, NULL }
115 static const value_string dtp_tos_vals[] = {
116 { DTP_TOS_ACCESS, "Access" },
117 { DTP_TOS_TRUNK, "Trunk"},
119 { 0, NULL }
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" },
128 { 0, NULL }
131 static const value_string dtp_tot_vals[] = {
132 { DTP_TOT_NATIVE, "Native" },
133 { DTP_TOT_ISL, "ISL" },
134 { DTP_TOT_DOT1Q, "802.1Q" },
136 { 0, NULL }
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" },
145 { 0, NULL }
148 static int
149 dissect_dtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
151 proto_item *ti;
152 proto_tree *dtp_tree;
153 proto_tree *tlv_tree;
154 int offset = 0;
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);
164 offset += 1;
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);
173 break;
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);
183 offset+=2;
185 tlv_length_item = proto_tree_add_uint(tlv_tree, hf_dtp_tlvlength, tvb, offset, 2, length);
186 offset+=2;
188 if (length <= 4) {
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);
193 break;
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);
202 static void
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)
206 switch (type) {
208 case DTP_TLV_DOMAIN:
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);
213 else
214 expert_add_info(pinfo, tlv_length_item, &ei_dtp_tlv_length_invalid);
216 break;
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"),
227 trunk_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"),
231 trunk_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);
235 else
236 expert_add_info(pinfo, tlv_length_item, &ei_dtp_tlv_length_invalid);
238 break;
240 case DTP_TLV_TRTYPE:
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"),
248 trunk_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"),
252 trunk_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);
256 else
257 expert_add_info(pinfo, tlv_length_item, &ei_dtp_tlv_length_invalid);
259 break;
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);
267 else
268 expert_add_info(pinfo, tlv_length_item, &ei_dtp_tlv_length_invalid);
270 break;
272 default:
273 proto_tree_add_item(tree, hf_dtp_data, tvb, offset, length, ENC_NA);
274 break;
278 void
279 proto_register_dtp(void)
281 static hf_register_info hf[] = {
282 { &hf_dtp_version,
283 { "Version", "dtp.version", FT_UINT8, BASE_DEC,
284 NULL, 0x0, NULL, HFILL }},
286 { &hf_dtp_domain,
287 { "Domain", "dtp.domain", FT_STRING, BASE_NONE,
288 NULL, 0x0, NULL, HFILL }},
290 { &hf_dtp_tlvtype,
291 { "Type", "dtp.tlv_type", FT_UINT16, BASE_HEX,
292 VALS(dtp_tlv_type_vals), 0x0, NULL, HFILL }},
294 { &hf_dtp_tlvlength,
295 { "Length", "dtp.tlv_len", FT_UINT16, BASE_DEC,
296 NULL, 0x0, NULL, HFILL }},
298 { &hf_dtp_tos,
299 { "Trunk Operating Status", "dtp.tos", FT_UINT8, BASE_HEX,
300 VALS(dtp_tos_vals), DTP_TOS_MASK, NULL, HFILL }},
302 { &hf_dtp_tas,
303 { "Trunk Administrative Status", "dtp.tas", FT_UINT8, BASE_HEX,
304 VALS(dtp_tas_vals), DTP_TAS_MASK, NULL, HFILL }},
306 { &hf_dtp_tot,
307 { "Trunk Operating Type", "dtp.tot", FT_UINT8, BASE_HEX,
308 VALS(dtp_tot_vals), DTP_TOT_MASK, NULL, HFILL }},
310 { &hf_dtp_tat,
311 { "Trunk Administrative Type", "dtp.tat", FT_UINT8, BASE_HEX,
312 VALS(dtp_tat_vals), DTP_TAT_MASK, NULL, HFILL }},
314 { &hf_dtp_senderid,
315 { "Sender ID", "dtp.senderid", FT_ETHER, BASE_NONE,
316 NULL, 0x0, "MAC Address of neighbor", HFILL }},
318 { &hf_dtp_data,
319 { "Data", "dtp.data", FT_ETHER, BASE_NONE,
320 NULL, 0x0, NULL, HFILL }},
323 static int *ett[] = {
324 &ett_dtp,
325 &ett_dtp_tlv,
326 &ett_dtp_status,
327 &ett_dtp_type,
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 }},
339 { &ei_dtp_truncated,
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);
357 void
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
366 * Local variables:
367 * c-basic-offset: 8
368 * tab-width: 8
369 * indent-tabs-mode: t
370 * End:
372 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
373 * :indentSize=8:tabSize=8:noTabs=false: