Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-udld.c
blob123af64eb4384a52e415219431e0e6630257fefe
1 /* packet-udld.c
2 * Routines for the disassembly of the "UniDirectional Link Detection"
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
11 #include "config.h"
13 #include <epan/packet.h>
14 #include <epan/expert.h>
15 #include <epan/cisco_pid.h>
18 * See
20 * https://tools.ietf.org/rfc/rfc5171
22 * for some information on UDLD.
25 /* Offsets in TLV structure. */
26 #define TLV_TYPE 0
27 #define TLV_LENGTH 2
29 void proto_register_udld(void);
30 void proto_reg_handoff_udld(void);
32 static dissector_handle_t udld_handle;
34 static int proto_udld;
35 static int hf_udld_version;
36 static int hf_udld_opcode;
37 static int hf_udld_flags;
38 static int hf_udld_flags_rt;
39 static int hf_udld_flags_rsy;
40 static int hf_udld_checksum;
41 static int hf_udld_tlvtype;
42 static int hf_udld_tlvlength;
43 static int hf_udld_device_id;
44 static int hf_udld_sent_through_interface;
45 static int hf_udld_data;
48 static expert_field ei_udld_tlvlength;
50 static int ett_udld;
51 static int ett_udld_flags;
52 static int ett_udld_tlv;
54 #define TYPE_DEVICE_ID 0x0001
55 #define TYPE_PORT_ID 0x0002
56 #define TYPE_ECHO 0x0003
57 #define TYPE_MESSAGE_INTERVAL 0x0004
58 #define TYPE_TIMEOUT_INTERVAL 0x0005
59 #define TYPE_DEVICE_NAME 0x0006
60 #define TYPE_SEQUENCE_NUMBER 0x0007
63 static const value_string type_vals[] = {
64 { TYPE_DEVICE_ID, "Device ID" },
65 { TYPE_PORT_ID, "Port ID" },
66 { TYPE_ECHO, "Echo" },
67 { TYPE_MESSAGE_INTERVAL, "Message interval" },
68 { TYPE_TIMEOUT_INTERVAL, "Timeout interval" },
69 { TYPE_DEVICE_NAME, "Device name" },
70 { TYPE_SEQUENCE_NUMBER, "Sequence number" },
71 { 0, NULL }
74 #define OPCODE_RESERVED 0x00
75 #define OPCODE_PROBE 0x01
76 #define OPCODE_ECHO 0x02
77 #define OPCODE_FLUSH 0x03
79 static const value_string opcode_vals[] = {
80 { OPCODE_RESERVED, "Reserved" },
81 { OPCODE_PROBE, "Probe" },
82 { OPCODE_ECHO, "Echo" },
83 { OPCODE_FLUSH, "Flush" },
84 { 0, NULL }
87 static int
88 dissect_udld(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
90 proto_item *ti;
91 proto_tree *udld_tree = NULL;
92 int offset = 0;
93 uint16_t type;
94 uint16_t length;
95 proto_tree *tlv_tree;
96 int real_length;
98 col_set_str(pinfo->cinfo, COL_PROTOCOL, "UDLD");
99 col_clear(pinfo->cinfo, COL_INFO);
101 if (tree) {
102 proto_item *flags_ti;
103 proto_tree *flags_tree;
105 ti = proto_tree_add_item(tree, proto_udld, tvb, offset, -1, ENC_NA);
106 udld_tree = proto_item_add_subtree(ti, ett_udld);
108 /* UDLD header */
109 proto_tree_add_item(udld_tree, hf_udld_version, tvb, offset, 1, ENC_BIG_ENDIAN);
110 proto_tree_add_item(udld_tree, hf_udld_opcode, tvb, offset, 1, ENC_BIG_ENDIAN);
111 offset += 1;
112 flags_ti = proto_tree_add_item(udld_tree, hf_udld_flags, tvb, offset, 1, ENC_BIG_ENDIAN);
113 flags_tree = proto_item_add_subtree(flags_ti, ett_udld_flags);
114 proto_tree_add_item(flags_tree, hf_udld_flags_rt, tvb, offset, 1, ENC_BIG_ENDIAN);
115 proto_tree_add_item(flags_tree, hf_udld_flags_rsy, tvb, offset, 1, ENC_BIG_ENDIAN);
116 offset += 1;
117 proto_tree_add_checksum(udld_tree, tvb, offset, hf_udld_checksum, -1, NULL, pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
118 offset += 2;
119 } else {
120 offset += 4; /* The version/opcode/flags/checksum fields from above */
123 while (tvb_reported_length_remaining(tvb, offset) != 0) {
124 type = tvb_get_ntohs(tvb, offset + TLV_TYPE);
125 length = tvb_get_ntohs(tvb, offset + TLV_LENGTH);
126 if (length < 4) {
127 tlv_tree = proto_tree_add_subtree_format(udld_tree, tvb, offset, 4,
128 ett_udld_tlv, NULL, "TLV with invalid length %u (< 4)", length);
129 proto_tree_add_uint(tlv_tree, hf_udld_tlvtype, tvb,
130 offset + TLV_TYPE, 2, type);
131 ti = proto_tree_add_uint(tlv_tree, hf_udld_tlvlength, tvb,
132 offset + TLV_LENGTH, 2, length);
133 expert_add_info(pinfo, ti, &ei_udld_tlvlength);
134 offset += 4;
135 break;
138 switch (type) {
140 case TYPE_DEVICE_ID:
141 /* Device ID */
143 col_append_fstr(pinfo->cinfo, COL_INFO,
144 "Device ID: %s ",
145 tvb_format_stringzpad(pinfo->pool, tvb, offset + 4,
146 length - 4));
148 if (tree) {
149 tlv_tree = proto_tree_add_subtree_format(udld_tree, tvb, offset,
150 length, ett_udld_tlv, NULL, "Device ID: %s",
151 tvb_format_stringzpad(pinfo->pool, tvb, offset + 4, length - 4));
152 proto_tree_add_uint(tlv_tree, hf_udld_tlvtype, tvb,
153 offset + TLV_TYPE, 2, type);
154 proto_tree_add_uint(tlv_tree, hf_udld_tlvlength, tvb,
155 offset + TLV_LENGTH, 2, length);
156 proto_tree_add_item(tlv_tree, hf_udld_device_id, tvb, offset + 4,
157 length - 4, ENC_ASCII);
159 offset += length;
160 break;
162 case TYPE_PORT_ID:
163 real_length = length;
164 if (tvb_get_uint8(tvb, offset + real_length) != 0x00) {
165 /* The length in the TLV doesn't appear to be the
166 length of the TLV, as the byte just past it
167 isn't the first byte of a 2-byte big-endian
168 small integer; make the length of the TLV the length
169 in the TLV, plus 4 bytes for the TLV type and length,
170 minus 1 because that's what makes one capture work. */
171 real_length = length + 3;
174 col_append_fstr(pinfo->cinfo, COL_INFO,
175 "Port ID: %s ",
176 tvb_format_stringzpad(pinfo->pool, tvb, offset + 4, length - 4));
178 if (tree) {
179 tlv_tree = proto_tree_add_subtree_format(udld_tree, tvb, offset,
180 real_length, ett_udld_tlv, NULL, "Port ID: %s",
181 tvb_format_text(pinfo->pool, tvb, offset + 4, real_length - 4));
182 proto_tree_add_uint(tlv_tree, hf_udld_tlvtype, tvb,
183 offset + TLV_TYPE, 2, type);
184 proto_tree_add_uint(tlv_tree, hf_udld_tlvlength, tvb,
185 offset + TLV_LENGTH, 2, length);
186 proto_tree_add_item(tlv_tree, hf_udld_sent_through_interface, tvb, offset + 4,
187 real_length - 4, ENC_ASCII);
189 offset += real_length;
190 break;
192 case TYPE_ECHO:
193 case TYPE_MESSAGE_INTERVAL:
194 case TYPE_TIMEOUT_INTERVAL:
195 case TYPE_DEVICE_NAME:
196 case TYPE_SEQUENCE_NUMBER:
197 default:
198 tlv_tree = proto_tree_add_subtree_format(udld_tree, tvb, offset,
199 length, ett_udld_tlv, NULL, "Type: %s, length: %u",
200 val_to_str(type, type_vals, "Unknown (0x%04x)"),
201 length);
202 proto_tree_add_uint(tlv_tree, hf_udld_tlvtype, tvb,
203 offset + TLV_TYPE, 2, type);
204 proto_tree_add_uint(tlv_tree, hf_udld_tlvlength, tvb,
205 offset + TLV_LENGTH, 2, length);
206 if (length > 4) {
207 proto_tree_add_item(tlv_tree, hf_udld_data, tvb, offset + 4,
208 length - 4, ENC_NA);
209 } else {
210 return offset;
212 offset += length;
216 call_data_dissector(tvb_new_subset_remaining(tvb, offset), pinfo, udld_tree);
217 return tvb_captured_length(tvb);
220 void
221 proto_register_udld(void)
223 static hf_register_info hf[] = {
224 { &hf_udld_version,
225 { "Version", "udld.version", FT_UINT8, BASE_DEC, NULL, 0xE0,
226 NULL, HFILL }},
228 { &hf_udld_opcode,
229 { "Opcode", "udld.opcode", FT_UINT8, BASE_DEC, VALS(opcode_vals), 0x1F,
230 NULL, HFILL }},
232 { &hf_udld_flags,
233 { "Flags", "udld.flags", FT_UINT8, BASE_DEC, NULL, 0x0,
234 NULL, HFILL }},
236 { &hf_udld_flags_rt,
237 { "Recommended timeout", "udld.flags.rt", FT_UINT8, BASE_HEX, NULL, 0x01,
238 NULL, HFILL }},
240 { &hf_udld_flags_rsy,
241 { "ReSynch", "udld.flags.rsy", FT_UINT8, BASE_HEX, NULL, 0x02,
242 NULL, HFILL }},
244 { &hf_udld_checksum,
245 { "Checksum", "udld.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
246 NULL, HFILL }},
248 { &hf_udld_tlvtype,
249 { "Type", "udld.tlv.type", FT_UINT16, BASE_HEX, VALS(type_vals), 0x0,
250 NULL, HFILL }},
252 { &hf_udld_tlvlength,
253 { "Length", "udld.tlv.len", FT_UINT16, BASE_DEC, NULL, 0x0,
254 NULL, HFILL }},
256 { &hf_udld_device_id,
257 { "Device ID", "udld.device_id", FT_STRINGZ, BASE_NONE, NULL, 0x0,
258 NULL, HFILL }},
260 { &hf_udld_sent_through_interface,
261 { "Sent through Interface", "udld.sent_through_interface", FT_STRING, BASE_NONE, NULL, 0x0,
262 NULL, HFILL }},
264 { &hf_udld_data,
265 { "Data", "udld.data", FT_BYTES, BASE_NONE, NULL, 0x0,
266 NULL, HFILL }},
269 static int *ett[] = {
270 &ett_udld,
271 &ett_udld_flags,
272 &ett_udld_tlv
275 static ei_register_info ei[] = {
276 { &ei_udld_tlvlength, { "udld.tlv.len.invalid", PI_PROTOCOL, PI_WARN, "TLV with invalid length (< 4)", EXPFILL }},
279 expert_module_t* expert_udld;
281 proto_udld = proto_register_protocol("Unidirectional Link Detection",
282 "UDLD", "udld");
283 proto_register_field_array(proto_udld, hf, array_length(hf));
284 proto_register_subtree_array(ett, array_length(ett));
285 expert_udld = expert_register_protocol(proto_udld);
286 expert_register_field_array(expert_udld, ei, array_length(ei));
287 udld_handle = register_dissector("udld", dissect_udld, proto_udld);
290 void
291 proto_reg_handoff_udld(void)
293 dissector_add_uint("llc.cisco_pid", CISCO_PID_UDLD, udld_handle);
294 dissector_add_uint("chdlc.protocol", 0x0111, udld_handle);
298 * Editor modelines - https://www.wireshark.org/tools/modelines.html
300 * Local variables:
301 * c-basic-offset: 4
302 * tab-width: 8
303 * indent-tabs-mode: nil
304 * End:
306 * vi: set shiftwidth=4 tabstop=8 expandtab:
307 * :indentSize=4:tabSize=8:noTabs=true: