1 /* packet-cdp.c
2  * Routines for the disassembly of the "Cisco Discovery Protocol"
3  * (c) Copyright Hannes R. Boehm <hannes@boehm.org>
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * SPDX-License-Identifier: GPL-2.0-or-later
10  */
11 
12 #include "config.h"
13 
14 #include <epan/packet.h>
15 #include <epan/expert.h>
16 #include <epan/to_str.h>
17 #include <epan/in_cksum.h>
18 #include <epan/nlpid.h>
19 #include <epan/etypes.h>
20 #include <epan/cisco_pid.h>
21 
22 /*
23  * See
24  *
25  *    http://www.cisco.com/c/en/us/td/docs/ios-xml/ios/cdp/configuration/15-mt/cdp-15-mt-book/nm-cdp-discover.html#GUID-84FBA50B-677C-4D90-AF56-2FB96F2DC085
26  *
27  * and
28  *
29  *    http://www.cisco.com/c/en/us/support/docs/switches/catalyst-4500-series-switches/13414-103.html#cdp
30  *
31  * for some more information on CDP version 2 (a superset of version 1).
32  *
33  * Also see
34  *
35  *    http://www.rhyshaden.com/cdp.htm
36  */
37 
38 void proto_register_cdp(void);
39 void proto_reg_handoff_cdp(void);
40 
41 /* Offsets in TLV structure. */
42 #define TLV_TYPE        0
43 #define TLV_LENGTH      2
44 
45 static int proto_cdp = -1;
46 static int hf_cdp_version = -1;
47 static int hf_cdp_checksum = -1;
48 static int hf_cdp_checksum_status = -1;
49 static int hf_cdp_ttl = -1;
50 static int hf_cdp_tlvtype = -1;
51 static int hf_cdp_tlvlength = -1;
52 static int hf_cdp_nrgyz_tlvtype = -1;
53 static int hf_cdp_nrgyz_tlvlength = -1;
54 static int hf_cdp_deviceid = -1;
55 static int hf_cdp_platform = -1;
56 static int hf_cdp_portid = -1;
57 static int hf_cdp_capabilities = -1;
58 static int hf_cdp_capabilities_router = -1;
59 static int hf_cdp_capabilities_trans_bridge = -1;
60 static int hf_cdp_capabilities_src_bridge = -1;
61 static int hf_cdp_capabilities_switch = -1;
62 static int hf_cdp_capabilities_host = -1;
63 static int hf_cdp_capabilities_igmp_capable = -1;
64 static int hf_cdp_capabilities_repeater = -1;
65 static int hf_cdp_capabilities_voip_phone = -1;
66 static int hf_cdp_capabilities_remote = -1;
67 static int hf_cdp_capabilities_cvta = -1;
68 static int hf_cdp_capabilities_mac_relay = -1;
69 static int hf_cdp_spare_poe_tlv = -1;
70 static int hf_cdp_spare_poe_tlv_poe = -1;
71 static int hf_cdp_spare_poe_tlv_spare_pair_arch = -1;
72 static int hf_cdp_spare_poe_tlv_req_spare_pair_poe = -1;
73 static int hf_cdp_spare_poe_tlv_pse_spare_pair_poe = -1;
74 
75 /* Generated from convert_proto_tree_add_text.pl */
76 static int hf_cdp_num_tlvs_table = -1;
77 static int hf_cdp_encrypted_data = -1;
78 static int hf_cdp_cluster_ip = -1;
79 static int hf_cdp_nrgyz_reply_to_backup_server_ip = -1;
80 static int hf_cdp_nrgyz_reply_to_port = -1;
81 static int hf_cdp_unknown_pad = -1;
82 static int hf_cdp_cluster_version = -1;
83 static int hf_cdp_hello_unknown = -1;
84 static int hf_cdp_management_id = -1;
85 static int hf_cdp_data = -1;
86 static int hf_cdp_nrgyz_reply_to_ip_address = -1;
87 static int hf_cdp_nrgyz_reply_to_name = -1;
88 static int hf_cdp_nrgyz_reply_to_domain = -1;
89 static int hf_cdp_nrgyz_reply_to_role = -1;
90 static int hf_cdp_nrgyz_ip_address = -1;
91 static int hf_cdp_nrgyz_ip6_address = -1;
92 static int hf_cdp_model_number = -1;
93 static int hf_cdp_nrgyz_reply_to_unknown_field = -1;
94 static int hf_cdp_len_tlv_table = -1;
95 static int hf_cdp_vtp_management_domain = -1;
96 static int hf_cdp_hardware_version_id = -1;
97 static int hf_cdp_cluster_unknown = -1;
98 static int hf_cdp_native_vlan = -1;
99 static int hf_cdp_ip_prefix = -1;
100 static int hf_cdp_odr_default_gateway = -1;
101 static int hf_cdp_power_consumption = -1;
102 static int hf_cdp_cluster_status = -1;
103 static int hf_cdp_power_requested = -1;
104 static int hf_cdp_trust_bitmap = -1;
105 static int hf_cdp_seen_sequence = -1;
106 static int hf_cdp_system_name = -1;
107 static int hf_cdp_power_available = -1;
108 static int hf_cdp_cluster_commander_mac = -1;
109 static int hf_cdp_mtu = -1;
110 static int hf_cdp_protocol_length = -1;
111 static int hf_cdp_system_serial_number = -1;
112 static int hf_cdp_sequence_number = -1;
113 static int hf_cdp_duplex = -1;
114 static int hf_cdp_voice_vlan = -1;
115 static int hf_cdp_request_id = -1;
116 static int hf_cdp_cluster_sub_version = -1;
117 static int hf_cdp_oui = -1;
118 static int hf_cdp_nrgyz_reply_to_backup_server_port = -1;
119 static int hf_cdp_cluster_master_ip = -1;
120 static int hf_cdp_protocol = -1;
121 static int hf_cdp_protocol_type = -1;
122 static int hf_cdp_address = -1;
123 static int hf_cdp_system_object_identifier = -1;
124 static int hf_cdp_location_unknown = -1;
125 static int hf_cdp_nrgyz_unknown_values = -1;
126 static int hf_cdp_address_length = -1;
127 static int hf_cdp_protocol_id = -1;
128 static int hf_cdp_cluster_switch_mac = -1;
129 static int hf_cdp_location = -1;
130 static int hf_cdp_untrusted_port_cos = -1;
131 static int hf_cdp_number_of_addresses = -1;
132 static int hf_cdp_cluster_management_vlan = -1;
133 static int hf_cdp_software_version = -1;
134 
135 static gint ett_cdp = -1;
136 static gint ett_cdp_tlv = -1;
137 static gint ett_cdp_nrgyz_tlv = -1;
138 static gint ett_cdp_address = -1;
139 static gint ett_cdp_capabilities = -1;
140 static gint ett_cdp_spare_poe_tlv = -1;
141 static gint ett_cdp_checksum = -1;
142 
143 static expert_field ei_cdp_invalid_data = EI_INIT;
144 static expert_field ei_cdp_nrgyz_tlvlength = EI_INIT;
145 static expert_field ei_cdp_checksum = EI_INIT;
146 
147 static int
148 dissect_address_tlv(tvbuff_t *tvb, packet_info* pinfo, int offset, int length, proto_tree *tree);
149 static void
150 dissect_capabilities(tvbuff_t *tvb, int offset, int length, proto_tree *tree);
151 static void
152 dissect_nrgyz_tlv(tvbuff_t *tvb, packet_info* pinfo, int offset, guint16 length, guint16 num,
153   proto_tree *tree);
154 static void
155 dissect_spare_poe_tlv(tvbuff_t *tvb, int offset, int length, proto_tree *tree);
156 static void
157 add_multi_line_string_to_tree(proto_tree *tree, tvbuff_t *tvb, gint start,
158   gint len, int hf);
159 
160 #define TYPE_DEVICE_ID          0x0001
161 #define TYPE_ADDRESS            0x0002
162 #define TYPE_PORT_ID            0x0003
163 #define TYPE_CAPABILITIES       0x0004
164 #define TYPE_IOS_VERSION        0x0005
165 #define TYPE_PLATFORM           0x0006
166 #define TYPE_IP_PREFIX          0x0007
167 #define TYPE_PROTOCOL_HELLO     0x0008 /* Protocol Hello */
168 #define TYPE_VTP_MGMT_DOMAIN    0x0009 /* VTP Domain, CTPv2 - see second URL */
169 #define TYPE_NATIVE_VLAN        0x000a /* Native VLAN, CTPv2 - see second URL */
170 #define TYPE_DUPLEX             0x000b /* Full/Half Duplex - see second URL */
171 /*                              0x000c */
172 /*                              0x000d */
173 #define TYPE_VOIP_VLAN_REPLY    0x000e /* VoIP VLAN reply */
174 #define TYPE_VOIP_VLAN_QUERY    0x000f /* VoIP VLAN query */
175 #define TYPE_POWER              0x0010 /* Power consumption */
176 #define TYPE_MTU                0x0011 /* MTU */
177 #define TYPE_TRUST_BITMAP       0x0012 /* Trust bitmap */
178 #define TYPE_UNTRUSTED_COS      0x0013 /* Untrusted port CoS */
179 #define TYPE_SYSTEM_NAME        0x0014 /* System Name */
180 #define TYPE_SYSTEM_OID         0x0015 /* System OID */
181 #define TYPE_MANAGEMENT_ADDR    0x0016 /* Management Address(es) */
182 #define TYPE_LOCATION           0x0017 /* Location */
183 #define TYPE_EXT_PORT_ID        0x0018 /* External Port-ID */
184 #define TYPE_POWER_REQUESTED    0x0019 /* Power Requested */
185 #define TYPE_POWER_AVAILABLE    0x001a /* Power Available */
186 #define TYPE_PORT_UNIDIR        0x001b /* Port Unidirectional */
187 #define TYPE_NRGYZ              0x001d /* EnergyWise over CDP */
188 #define TYPE_SPARE_POE          0x001f /* Spare Pair PoE */
189 
190 #define TYPE_HP_BSSID           0x1000 /* BSSID */
191 #define TYPE_HP_SERIAL          0x1001 /* Serial number */
192 #define TYPE_HP_SSID            0x1002 /* SSID */
193 #define TYPE_HP_RADIO1_CH       0x1003 /* Radio1 channel */
194 /*                              0x1004 */
195 /*                              0x1005 */
196 #define TYPE_HP_SNMP_PORT       0x1006 /* SNMP listening UDP port */
197 #define TYPE_HP_MGMT_PORT       0x1007 /* Web interface TCP port */
198 #define TYPE_HP_SOURCE_MAC      0x1008 /* Sender MAC address for the AP, bouth wired and wireless */
199 #define TYPE_HP_RADIO2_CH       0x1009 /* Radio2 channel */
200 #define TYPE_HP_RADIO1_OMODE    0x100A /* Radio1 Operating mode */
201 #define TYPE_HP_RADIO2_OMODE    0x100B /* Radio2 Operating mode */
202 #define TYPE_HP_RADIO1_RMODE    0x100C /* Radio1 Radio mode */
203 #define TYPE_HP_RADIO2_RMODE    0x100D /* Radio2 Radio mode */
204 
205 static const value_string type_vals[] = {
206     { TYPE_DEVICE_ID,       "Device ID" },
207     { TYPE_ADDRESS,         "Addresses" },
208     { TYPE_PORT_ID,         "Port ID" },
209     { TYPE_CAPABILITIES,    "Capabilities" },
210     { TYPE_IOS_VERSION,     "Software version" },
211     { TYPE_PLATFORM,        "Platform" },
212     { TYPE_IP_PREFIX,       "IP Prefix/Gateway (used for ODR)" },
213     { TYPE_PROTOCOL_HELLO,  "Protocol Hello" },
214     { TYPE_VTP_MGMT_DOMAIN, "VTP Management Domain" },
215     { TYPE_NATIVE_VLAN,     "Native VLAN" },
216     { TYPE_DUPLEX,          "Duplex" },
217     { TYPE_VOIP_VLAN_REPLY, "VoIP VLAN Reply" },
218     { TYPE_VOIP_VLAN_QUERY, "VoIP VLAN Query" },
219     { TYPE_POWER,           "Power consumption" },
220     { TYPE_MTU,             "MTU"},
221     { TYPE_TRUST_BITMAP,    "Trust Bitmap" },
222     { TYPE_UNTRUSTED_COS,   "Untrusted Port CoS" },
223     { TYPE_SYSTEM_NAME,     "System Name" },
224     { TYPE_SYSTEM_OID,      "System Object ID" },
225     { TYPE_MANAGEMENT_ADDR, "Management Address" },
226     { TYPE_LOCATION,        "Location" },
227     { TYPE_EXT_PORT_ID,     "External Port-ID" },
228     { TYPE_POWER_REQUESTED, "Power Requested" },
229     { TYPE_POWER_AVAILABLE, "Power Available" },
230     { TYPE_PORT_UNIDIR,     "Port Unidirectional" },
231     { TYPE_NRGYZ,           "EnergyWise" },
232     { TYPE_SPARE_POE,       "Spare PoE" },
233     { TYPE_HP_BSSID,        "BSSID" },
234     { TYPE_HP_SERIAL,       "Serial number" },
235     { TYPE_HP_SSID,         "SSID" },
236     { TYPE_HP_RADIO1_CH,    "Radio1 channel" },
237     { TYPE_HP_SNMP_PORT,    "SNMP UDP port" },
238     { TYPE_HP_MGMT_PORT,    "Web TCP port" },
239     { TYPE_HP_SOURCE_MAC,   "Source MAC address" },
240     { TYPE_HP_RADIO2_CH,    "Radio2 channel" },
241     { TYPE_HP_RADIO1_OMODE, "Radio1 Operating mode" },
242     { TYPE_HP_RADIO2_OMODE, "Radio2 Operating mode" },
243     { TYPE_HP_RADIO1_RMODE, "Radio1 Radio mode" },
244     { TYPE_HP_RADIO2_RMODE, "Radio2 Radio mode" },
245     { 0, NULL }
246 };
247 
248 #define TYPE_HELLO_CLUSTER_MGMT    0x0112
249 
250 static const value_string type_hello_vals[] = {
251     { TYPE_HELLO_CLUSTER_MGMT,   "Cluster Management" },
252     { 0, NULL }
253 };
254 
255 #define TYPE_NRGYZ_ROLE    0x00000007
256 #define TYPE_NRGYZ_DOMAIN  0x00000008
257 #define TYPE_NRGYZ_NAME    0x00000009
258 #define TYPE_NRGYZ_REPLYTO 0x00000017
259 
260 static const value_string type_nrgyz_vals[] = {
261     { TYPE_NRGYZ_ROLE,    "Role" },
262     { TYPE_NRGYZ_DOMAIN,  "Domain" },
263     { TYPE_NRGYZ_NAME,    "Name" },
264     { TYPE_NRGYZ_REPLYTO, "Reply To" },
265     { 0, NULL }
266 };
267 
268 static const unit_name_string units_mw = { "mW", NULL };
269 
270 static int
dissect_cdp(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)271 dissect_cdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
272 {
273     proto_item *ti;
274     proto_tree *cdp_tree;
275     int         offset   = 0;
276     guint16     type;
277     guint16     length, data_length;
278     proto_item *tlvi;
279     proto_tree *tlv_tree;
280     int         real_length;
281     guint32     naddresses;
282     guint32     power_avail_len, power_avail;
283     guint32     power_req_len, power_req;
284     gboolean    first;
285     int         addr_length;
286     vec_t       cksum_vec[1];
287 
288     col_set_str(pinfo->cinfo, COL_PROTOCOL, "CDP");
289     col_clear(pinfo->cinfo, COL_INFO);
290 
291     ti = proto_tree_add_item(tree, proto_cdp, tvb, offset, -1, ENC_NA);
292     cdp_tree = proto_item_add_subtree(ti, ett_cdp);
293 
294     /* CDP header */
295     proto_tree_add_item(cdp_tree, hf_cdp_version, tvb, offset, 1, ENC_BIG_ENDIAN);
296     offset += 1;
297 
298     proto_tree_add_item(cdp_tree, hf_cdp_ttl, tvb, offset, 1, ENC_NA);
299     offset += 1;
300 
301     /* Checksum display & verification code */
302 
303     data_length = tvb_reported_length(tvb);
304 
305     /* CDP doesn't adhere to RFC 1071 section 2. (B). It incorrectly assumes
306      * checksums are calculated on a big endian platform, therefore i.s.o.
307      * padding odd sized data with a zero byte _at the end_ it sets the last
308      * big endian _word_ to contain the last network _octet_. This byteswap
309      * has to be done on the last octet of network data before feeding it to
310      * the Internet checksum routine.
311      * CDP checksumming code has a bug in the addition of this last _word_
312      * as a signed number into the long word intermediate checksum. When
313      * reducing this long to word size checksum an off-by-one error can be
314      * made. This off-by-one error is compensated for in the last _word_ of
315      * the network data.
316      */
317     if (data_length & 1) {
318         guint8 *padded_buffer;
319         /* Allocate new buffer */
320         padded_buffer = (guint8 *)wmem_alloc(pinfo->pool, data_length+1);
321         tvb_memcpy(tvb, padded_buffer, 0, data_length);
322         /* Swap bytes in last word */
323         padded_buffer[data_length] = padded_buffer[data_length-1];
324         padded_buffer[data_length-1] = 0;
325         /* Compensate off-by-one error */
326         if (padded_buffer[data_length] & 0x80) {
327           padded_buffer[data_length]--;
328           padded_buffer[data_length-1]--;
329         }
330         /* Setup checksum routine data buffer */
331         SET_CKSUM_VEC_PTR(cksum_vec[0], padded_buffer, data_length+1);
332     } else {
333         /* Setup checksum routine data buffer */
334         SET_CKSUM_VEC_TVB(cksum_vec[0], tvb, 0, data_length);
335     }
336 
337     proto_tree_add_checksum(cdp_tree, tvb, offset, hf_cdp_checksum, hf_cdp_checksum_status, &ei_cdp_checksum, pinfo, in_cksum(cksum_vec, 1),
338                                 ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY|PROTO_CHECKSUM_IN_CKSUM);
339     offset += 2;
340 
341     while (tvb_reported_length_remaining(tvb, offset) != 0) {
342         tlv_tree = NULL;
343         type = tvb_get_ntohs(tvb, offset + TLV_TYPE);
344         length = tvb_get_ntohs(tvb, offset + TLV_LENGTH);
345         if (length < 4) {
346             if (tree) {
347                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb, offset, 4,
348                                            ett_cdp_tlv, NULL, "TLV with invalid length %u (< 4)",
349                                            length);
350                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
351                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
352             }
353             offset += 4;
354             break;
355         }
356 
357         switch (type) {
358 
359         case TYPE_DEVICE_ID:
360             /* Device ID */
361 
362             col_append_fstr(pinfo->cinfo, COL_INFO,
363                             "Device ID: %s  ",
364                             tvb_format_stringzpad(pinfo->pool, tvb, offset + 4, length - 4));
365 
366             if (tree) {
367                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb, offset,
368                                            length, ett_cdp_tlv, NULL, "Device ID: %s",
369                                            tvb_format_stringzpad(pinfo->pool, tvb, offset + 4, length - 4));
370                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
371                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
372                 proto_tree_add_item(tlv_tree, hf_cdp_deviceid, tvb, offset + 4, length - 4, ENC_ASCII|ENC_NA);
373             }
374             offset += length;
375             break;
376 
377         case TYPE_PORT_ID:
378             real_length = length;
379             if ((tvb_reported_length_remaining(tvb, offset) >= length + 3) &&
380                 (tvb_get_guint8(tvb, offset + real_length) != 0x00) &&
381                 (tvb_get_guint8(tvb, offset + real_length) != 0x10)) {
382                 /* The length in the TLV doesn't appear to be the
383                    length of the TLV, as the byte just past it
384                    isn't the first byte of a 2-byte big-endian
385                    small integer; make the length of the TLV the length
386                    in the TLV, plus 4 bytes for the TLV type and length,
387                    minus 1 because that's what makes one capture work. */
388                 real_length = length + 3;
389             }
390 
391             col_append_fstr(pinfo->cinfo, COL_INFO,
392                             "Port ID: %s  ",
393                             tvb_format_stringzpad(pinfo->pool, tvb, offset + 4,
394                                                   length - 4));
395 
396             if (tree) {
397                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb, offset,
398                                            real_length, ett_cdp_tlv, NULL, "Port ID: %s",
399                                            tvb_format_text(pinfo->pool, tvb, offset + 4, real_length - 4));
400                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
401                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
402                 proto_tree_add_item(tlv_tree, hf_cdp_portid, tvb, offset + 4, real_length - 4, ENC_ASCII|ENC_NA);
403             }
404             offset += real_length;
405             break;
406 
407         case TYPE_ADDRESS:
408             /* Addresses */
409             if (tree) {
410                 tlv_tree = proto_tree_add_subtree(cdp_tree, tvb, offset,
411                                            length, ett_cdp_tlv, NULL, "Addresses");
412                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
413                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
414             }
415             offset += 4;
416             length -= 4;
417             naddresses = tvb_get_ntohl(tvb, offset);
418             proto_tree_add_item(tlv_tree, hf_cdp_number_of_addresses, tvb, offset, 4, ENC_BIG_ENDIAN);
419             offset += 4;
420             length -= 4;
421             while (naddresses != 0) {
422                 addr_length = dissect_address_tlv(tvb, pinfo, offset, length,
423                                                   tlv_tree);
424                 if (addr_length < 0)
425                     break;
426                 offset += addr_length;
427                 length -= addr_length;
428 
429                 naddresses--;
430             }
431             offset += length;
432             break;
433 
434         case TYPE_CAPABILITIES:
435             if (tree) {
436                 tlv_tree = proto_tree_add_subtree(cdp_tree, tvb, offset,
437                                            length, ett_cdp_tlv, NULL, "Capabilities");
438                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
439                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
440             }
441             offset += 4;
442             length -= 4;
443             dissect_capabilities(tvb, offset, length, tlv_tree);
444             offset += length;
445             break;
446 
447         case TYPE_IOS_VERSION:
448             if (tree) {
449                 tlv_tree = proto_tree_add_subtree(cdp_tree, tvb, offset,
450                                            length, ett_cdp_tlv, NULL, "Software Version");
451                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
452                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
453                 add_multi_line_string_to_tree(tlv_tree, tvb, offset + 4,
454                                               length - 4, hf_cdp_software_version);
455             }
456             offset += length;
457             break;
458 
459         case TYPE_PLATFORM:
460             /* ??? platform */
461             if (tree) {
462                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb,
463                                            offset, length, ett_cdp_tlv, NULL, "Platform: %s",
464                                            tvb_format_text(pinfo->pool, tvb, offset + 4, length - 4));
465                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
466                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
467                 proto_tree_add_item(tlv_tree, hf_cdp_platform, tvb, offset + 4, length - 4, ENC_ASCII|ENC_NA);
468             }
469             offset += length;
470             break;
471 
472         case TYPE_IP_PREFIX:
473             if (length == 8) {
474                 /* if length is 8 then this is default gw not prefix */
475                 if (tree) {
476                     tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb, offset,
477                                                length, ett_cdp_tlv, NULL, "ODR Default gateway: %s",
478                                                tvb_ip_to_str(pinfo->pool, tvb, offset+4));
479                     proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
480                     proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
481                     proto_tree_add_item(tlv_tree, hf_cdp_odr_default_gateway, tvb, offset+4, 4, ENC_BIG_ENDIAN);
482                 }
483                 offset += 8;
484             } else {
485                 if (tree) {
486                     tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb, offset,
487                                                length, ett_cdp_tlv, NULL, "IP Prefixes: %d",length/5);
488 
489                     /* the actual number of prefixes is (length-4)/5
490                        but if the variable is not a "float" but "integer"
491                        then length/5=(length-4)/5  :)  */
492 
493                     proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
494                     proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
495                 }
496                 offset += 4;
497                 length -= 4;
498                 while (length > 0) {
499                     proto_tree_add_ipv4_format_value(tlv_tree, hf_cdp_ip_prefix, tvb, offset, 5, tvb_get_ntohl(tvb, offset),
500                                     "%s/%u", tvb_ip_to_str(pinfo->pool, tvb, offset), tvb_get_guint8(tvb,offset+4));
501                     offset += 5;
502                     length -= 5;
503                 }
504             }
505             break;
506 
507         case TYPE_PROTOCOL_HELLO:
508             if (tree) {
509                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb,
510                                            offset,length, ett_cdp_tlv, NULL, "Protocol Hello: %s",
511                                            val_to_str(tvb_get_ntohs(tvb, offset+7), type_hello_vals, "Unknown (0x%04x)"));
512                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
513                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
514                 proto_tree_add_item(tlv_tree, hf_cdp_oui, tvb, offset+4, 3, ENC_BIG_ENDIAN);
515                 proto_tree_add_item(tlv_tree, hf_cdp_protocol_id, tvb, offset+7, 2, ENC_BIG_ENDIAN);
516 
517                 switch(tvb_get_ntohs(tvb, offset+7)) {
518 
519                 case TYPE_HELLO_CLUSTER_MGMT:
520                     proto_tree_add_item(tlv_tree, hf_cdp_cluster_master_ip, tvb, offset+9, 4, ENC_BIG_ENDIAN);
521                     proto_tree_add_item(tlv_tree, hf_cdp_cluster_ip, tvb, offset+13, 4, ENC_BIG_ENDIAN);
522                     proto_tree_add_item(tlv_tree, hf_cdp_cluster_version, tvb, offset+17, 1, ENC_BIG_ENDIAN);
523                     proto_tree_add_item(tlv_tree, hf_cdp_cluster_sub_version, tvb, offset+18, 1, ENC_BIG_ENDIAN);
524                     proto_tree_add_item(tlv_tree, hf_cdp_cluster_status, tvb, offset+19, 1, ENC_BIG_ENDIAN);
525                     proto_tree_add_item(tlv_tree, hf_cdp_cluster_unknown, tvb, offset+20, 1, ENC_BIG_ENDIAN);
526                     proto_tree_add_item(tlv_tree, hf_cdp_cluster_commander_mac, tvb, offset+21, 6, ENC_NA);
527                     proto_tree_add_item(tlv_tree, hf_cdp_cluster_switch_mac, tvb, offset+27, 6, ENC_NA);
528                     proto_tree_add_item(tlv_tree, hf_cdp_cluster_unknown, tvb, offset+33, 1, ENC_BIG_ENDIAN);
529                     proto_tree_add_item(tlv_tree, hf_cdp_cluster_management_vlan, tvb, offset+34, 2, ENC_BIG_ENDIAN);
530                     break;
531                 default:
532                     proto_tree_add_item(tlv_tree, hf_cdp_hello_unknown, tvb, offset + 9, length - 9, ENC_NA);
533                     break;
534                 }
535             }
536             offset += length;
537             break;
538 
539         case TYPE_VTP_MGMT_DOMAIN:
540             if (tree) {
541                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb,
542                                            offset, length, ett_cdp_tlv, NULL, "VTP Management Domain: %s",
543                                            tvb_format_text(pinfo->pool, tvb, offset + 4, length - 4));
544                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
545                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
546                 proto_tree_add_item(tlv_tree, hf_cdp_vtp_management_domain, tvb, offset + 4, length - 4, ENC_NA|ENC_ASCII);
547             }
548             offset += length;
549             break;
550 
551         case TYPE_NATIVE_VLAN:
552             if (tree) {
553                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb,
554                                            offset, length, ett_cdp_tlv, NULL, "Native VLAN: %u",
555                                            tvb_get_ntohs(tvb, offset + 4));
556                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
557                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
558                 proto_tree_add_item(tlv_tree, hf_cdp_native_vlan, tvb, offset + 4, 2, ENC_BIG_ENDIAN);
559             }
560             offset += length;
561             break;
562 
563         case TYPE_DUPLEX:
564             if (tree) {
565                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb,
566                                            offset, length, ett_cdp_tlv, NULL, "Duplex: %s",
567                                            tvb_get_guint8(tvb, offset + 4) ?
568                                            "Full" : "Half" );
569                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
570                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
571                 proto_tree_add_item(tlv_tree, hf_cdp_duplex, tvb, offset + 4, 1, ENC_NA);
572             }
573             offset += length;
574             break;
575 
576         case TYPE_VOIP_VLAN_REPLY:
577             tlvi = NULL;
578             if (tree) {
579                 guint32 vlan_id;
580 
581                 tlv_tree = proto_tree_add_subtree(cdp_tree, tvb,
582                                            offset, length, ett_cdp_tlv, &tlvi,
583                                            "VoIP VLAN Reply");
584                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
585                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
586                 if (length == 6) {
587                     /*
588                      * XXX - this doesn't appear to happen, so report it
589                      * as an error.
590                      */
591                     proto_tree_add_item(tlv_tree, hf_cdp_data, tvb, offset + 4, 2, ENC_NA);
592                 } else {
593                     /*
594                      * XXX - the first byte appears to be a 1-byte
595                      * "appliance type" code.
596                      */
597                     proto_tree_add_item(tlv_tree, hf_cdp_data, tvb, offset + 4, 1, ENC_NA);
598                     proto_tree_add_item_ret_uint(tlv_tree, hf_cdp_voice_vlan, tvb, offset + 5, 2, ENC_BIG_ENDIAN, &vlan_id);
599                     proto_item_append_text(tlvi, ": VLAN %u", vlan_id);
600                 }
601             }
602             offset += length;
603             break;
604 
605         case TYPE_VOIP_VLAN_QUERY:
606             tlvi = NULL;
607             if (tree) {
608                 guint32 vlan_id;
609 
610                 tlv_tree = proto_tree_add_subtree(cdp_tree, tvb,
611                                            offset, length, ett_cdp_tlv, &tlvi,
612                                            "VoIP VLAN Query");
613                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
614                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
615                 if (length == 6) {
616                     /*
617                      * This is some unknown value; it's typically 0x20 0x00,
618                      * which, as a big-endian value, is not a VLAN ID, as
619                      * VLAN IDs are 12 bits long.
620                      */
621                     proto_tree_add_item(tlv_tree, hf_cdp_data, tvb, offset + 4, 2, ENC_NA);
622                 } else {
623                     /*
624                      * XXX - is this a 1-byte "appliance type" code?
625                      */
626                     proto_tree_add_item(tlv_tree, hf_cdp_data, tvb, offset + 4, 1, ENC_NA);
627                     proto_tree_add_item_ret_uint(tlv_tree, hf_cdp_voice_vlan, tvb, offset + 5, 2, ENC_BIG_ENDIAN, &vlan_id);
628                     proto_item_append_text(tlvi, ": VLAN %u", vlan_id);
629                 }
630             }
631             offset += length;
632             break;
633 
634         case TYPE_POWER:
635             if (tree) {
636                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb,
637                                            offset, length, ett_cdp_tlv, NULL, "Power Consumption: %u mW",
638                                            tvb_get_ntohs(tvb, offset + 4));
639                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
640                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
641                 proto_tree_add_item(tlv_tree, hf_cdp_power_consumption, tvb, offset + 4, 2, ENC_BIG_ENDIAN);
642             }
643             offset += length;
644             break;
645 
646         case TYPE_MTU:
647             if (tree) {
648                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb,
649                                            offset, length, ett_cdp_tlv, NULL, "MTU: %u",
650                                            tvb_get_ntohl(tvb,offset + 4));
651                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
652                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
653                 proto_tree_add_item(tlv_tree, hf_cdp_mtu, tvb, offset + 4, 4, ENC_BIG_ENDIAN);
654             }
655             offset += length;
656             break;
657 
658         case TYPE_TRUST_BITMAP:
659             if (tree) {
660                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb,
661                                            offset, length, ett_cdp_tlv, NULL, "Trust Bitmap: 0x%02X",
662                                            tvb_get_guint8(tvb, offset + 4));
663                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
664                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
665                 proto_tree_add_item(tlv_tree, hf_cdp_trust_bitmap, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
666             }
667             offset += length;
668             break;
669 
670         case TYPE_UNTRUSTED_COS:
671             if (tree) {
672                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb,
673                                            offset, length, ett_cdp_tlv, NULL, "Untrusted port CoS: 0x%02X",
674                                            tvb_get_guint8(tvb, offset + 4));
675                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
676                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
677                 proto_tree_add_item(tlv_tree, hf_cdp_untrusted_port_cos, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
678             }
679             offset += length;
680             break;
681 
682         case TYPE_SYSTEM_NAME:
683             if (tree) {
684                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb,
685                                            offset, length, ett_cdp_tlv, NULL, "System Name: %s",
686                                            tvb_format_text(pinfo->pool, tvb, offset + 4, length - 4));
687                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
688                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
689                 proto_tree_add_item(tlv_tree, hf_cdp_system_name, tvb, offset + 4, length - 4, ENC_NA|ENC_ASCII);
690             }
691             offset += length;
692             break;
693 
694         case TYPE_SYSTEM_OID:
695             if (tree) {
696                 tlv_tree = proto_tree_add_subtree(cdp_tree, tvb,
697                                            offset, length, ett_cdp_tlv, NULL, "System Object Identifier");
698                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
699                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
700                 proto_tree_add_item(tlv_tree, hf_cdp_system_object_identifier, tvb, offset + 4, length - 4, ENC_NA);
701             }
702             offset += length;
703             break;
704 
705         case TYPE_MANAGEMENT_ADDR:
706             if (tree) {
707                 tlv_tree = proto_tree_add_subtree(cdp_tree, tvb,
708                                            offset, length, ett_cdp_tlv, NULL, "Management Addresses");
709                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
710                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
711             }
712             offset += 4;
713             length -= 4;
714             naddresses = tvb_get_ntohl(tvb, offset);
715             if (tree) {
716                 proto_tree_add_item(tlv_tree, hf_cdp_number_of_addresses, tvb, offset, 4, ENC_BIG_ENDIAN);
717             }
718             offset += 4;
719             length -= 4;
720             while (naddresses != 0) {
721                 addr_length = dissect_address_tlv(tvb, pinfo, offset, length,
722                                                   tlv_tree);
723                 if (addr_length < 0)
724                     break;
725                 offset += addr_length;
726                 length -= addr_length;
727 
728                 naddresses--;
729             }
730             offset += length;
731             break;
732 
733         case TYPE_LOCATION:
734             if (tree) {
735                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb,
736                                            offset, length, ett_cdp_tlv, NULL, "Location: %s",
737                                            tvb_format_text(pinfo->pool, tvb, offset + 5, length - 5));
738                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
739                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
740                 proto_tree_add_item(tlv_tree, hf_cdp_location_unknown, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
741                 proto_tree_add_item(tlv_tree, hf_cdp_location, tvb, offset + 5, length - 5, ENC_NA|ENC_ASCII);
742             }
743             offset += length;
744             break;
745 
746         case TYPE_POWER_REQUESTED:
747             tlvi = NULL;
748             if (tree) {
749                 tlv_tree = proto_tree_add_subtree(cdp_tree, tvb,
750                                            offset, length, ett_cdp_tlv, &tlvi,
751                                            "Power Request");
752                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
753                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
754                 proto_tree_add_item(tlv_tree, hf_cdp_request_id, tvb, offset + 4, 2, ENC_BIG_ENDIAN);
755                 proto_tree_add_item(tlv_tree, hf_cdp_management_id, tvb, offset + 6, 2, ENC_BIG_ENDIAN);
756             }
757             power_req_len = tvb_get_ntohs(tvb, offset + TLV_LENGTH);
758             if (power_req_len < 8) {
759                 offset += power_req_len;
760                 break;
761             }
762             power_req_len -= 8;
763             /* Move offset to where the list of Power Request Values Exist */
764             offset += 8;
765             first = TRUE;
766             while (power_req_len >= 4) {
767                 proto_tree_add_item_ret_uint(tlv_tree, hf_cdp_power_requested, tvb, offset, 4, ENC_BIG_ENDIAN, &power_req);
768                 if (first) {
769                     proto_item_append_text(tlvi, ": %u mW", power_req);
770                     first = FALSE;
771                 } else
772                     proto_item_append_text(tlvi, ", %u mW", power_req);
773                 power_req_len -= 4;
774                 offset += 4;
775             }
776             offset += power_req_len;
777             break;
778 
779         case TYPE_POWER_AVAILABLE:
780             tlvi = NULL;
781             if (tree) {
782                 tlv_tree = proto_tree_add_subtree(cdp_tree, tvb,
783                                            offset, length, ett_cdp_tlv, &tlvi,
784                                            "Power Available");
785                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
786                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
787                 proto_tree_add_item(tlv_tree, hf_cdp_request_id, tvb, offset + 4, 2, ENC_BIG_ENDIAN);
788                 proto_tree_add_item(tlv_tree, hf_cdp_management_id, tvb, offset + 6, 2, ENC_BIG_ENDIAN);
789             }
790             power_avail_len = tvb_get_ntohs(tvb, offset + TLV_LENGTH);
791             if (power_avail_len < 8) {
792                 offset += power_avail_len;
793                 break;
794             }
795             power_avail_len -= 8;
796             /* Move offset to where the list of Power Available Values Exist */
797             offset += 8;
798             first = TRUE;
799             while (power_avail_len >= 4) {
800                 proto_tree_add_item_ret_uint(tlv_tree, hf_cdp_power_available, tvb, offset, 4, ENC_BIG_ENDIAN, &power_avail);
801                 if (first) {
802                     proto_item_append_text(tlvi, ": %u mW", power_avail);
803                     first = FALSE;
804                 } else
805                     proto_item_append_text(tlvi, ", %u mW", power_avail);
806                 power_avail_len -= 4;
807                 offset += 4;
808             }
809             offset += power_avail_len;
810             break;
811 
812         case TYPE_NRGYZ:
813             if (tree) {
814                 tlv_tree = proto_tree_add_subtree(cdp_tree, tvb,
815                                            offset, length, ett_cdp_tlv, NULL, "EnergyWise");
816                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
817                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
818                 proto_tree_add_item(tlv_tree, hf_cdp_encrypted_data, tvb, offset + 4, 20, ENC_NA);
819                 proto_tree_add_item(tlv_tree, hf_cdp_seen_sequence, tvb, offset + 24, 4, ENC_BIG_ENDIAN);
820                 proto_tree_add_item(tlv_tree, hf_cdp_sequence_number, tvb, offset + 28, 4, ENC_BIG_ENDIAN);
821                 proto_tree_add_item(tlv_tree, hf_cdp_model_number, tvb, offset + 32, 16, ENC_NA|ENC_ASCII);
822                 proto_tree_add_item(tlv_tree, hf_cdp_unknown_pad, tvb, offset + 48, 2, ENC_BIG_ENDIAN);
823                 proto_tree_add_item(tlv_tree, hf_cdp_hardware_version_id, tvb, offset + 50, 3, ENC_NA|ENC_ASCII);
824                 proto_tree_add_item(tlv_tree, hf_cdp_system_serial_number, tvb, offset + 53, 11, ENC_NA|ENC_ASCII);
825                 proto_tree_add_item(tlv_tree, hf_cdp_nrgyz_unknown_values, tvb, offset + 64, 8, ENC_NA);
826                 proto_tree_add_item(tlv_tree, hf_cdp_len_tlv_table, tvb, offset + 72, 2, ENC_BIG_ENDIAN);
827                 proto_tree_add_item(tlv_tree, hf_cdp_num_tlvs_table, tvb, offset + 74, 2, ENC_BIG_ENDIAN);
828 
829                 dissect_nrgyz_tlv(tvb, pinfo, offset + 76,
830                                   tvb_get_ntohs(tvb, offset + 72),
831                                   tvb_get_ntohs(tvb, offset + 74),
832                                   tlv_tree);
833 
834 
835             }
836             offset += length;
837             break;
838 
839         case TYPE_SPARE_POE:
840             if (tree) {
841                 tlv_tree = proto_tree_add_subtree(cdp_tree, tvb, offset, length,
842                                            ett_cdp_tlv, NULL, "Spare Pair PoE");
843 
844                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
845                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
846             }
847             offset += 4;
848             length -= 4;
849             dissect_spare_poe_tlv(tvb, offset, length, tlv_tree);
850             offset += length;
851             break;
852 
853         case TYPE_HP_BSSID:
854             /* BSSID */
855             if (tree) {
856                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb,
857                                            offset, length, ett_cdp_tlv, NULL, "BSSID: %s",
858                                            tvb_format_text(pinfo->pool, tvb, offset + 4, length - 4));
859                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
860                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
861                 proto_tree_add_item(tlv_tree, hf_cdp_platform, tvb, offset + 4, length - 4, ENC_ASCII|ENC_NA);
862             }
863             offset += length;
864             break;
865 
866         case TYPE_HP_SERIAL:
867             /* Serial number */
868             if (tree) {
869                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb,
870                                            offset, length, ett_cdp_tlv, NULL, "Serial: %s",
871                                            tvb_format_text(pinfo->pool, tvb, offset + 4, length - 4));
872                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
873                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
874                 proto_tree_add_item(tlv_tree, hf_cdp_platform, tvb, offset + 4, length - 4, ENC_ASCII|ENC_NA);
875             }
876             offset += length;
877             break;
878 
879         case TYPE_HP_SSID:
880             /* SSID */
881             if (tree) {
882                 if (length == 4) {
883                     tlv_tree = proto_tree_add_subtree(cdp_tree, tvb,
884                                                offset, length, ett_cdp_tlv, NULL, "SSID: [Empty]");
885                     proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
886                     proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
887                 } else {
888                     tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb,
889                                                offset, length, ett_cdp_tlv, NULL, "SSID: %s",
890                                                tvb_format_text(pinfo->pool, tvb, offset + 4, length - 4));
891                     proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
892                     proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
893                     proto_tree_add_item(tlv_tree, hf_cdp_platform, tvb, offset + 4, length - 4, ENC_ASCII|ENC_NA);
894                 }
895             }
896             offset += length;
897             break;
898 
899         case TYPE_HP_RADIO1_CH:
900             /* Radio1 channel */
901             if (tree) {
902                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb,
903                                            offset, length, ett_cdp_tlv, NULL, "Radio 1 channel: %s",
904                                            tvb_format_text(pinfo->pool, tvb, offset + 4, length - 4));
905                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
906                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
907                 proto_tree_add_item(tlv_tree, hf_cdp_platform, tvb, offset + 4, length - 4, ENC_ASCII|ENC_NA);
908             }
909             offset += length;
910             break;
911 
912         case TYPE_HP_SNMP_PORT:
913             /* SNMP listening UDP port */
914             if (tree) {
915                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb,
916                                            offset, length, ett_cdp_tlv, NULL, "SNMP port: %s",
917                                            tvb_format_text(pinfo->pool, tvb, offset + 4, length - 4));
918                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
919                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
920                 proto_tree_add_item(tlv_tree, hf_cdp_platform, tvb, offset + 4, length - 4, ENC_ASCII|ENC_NA);
921             }
922             offset += length;
923             break;
924 
925         case TYPE_HP_MGMT_PORT:
926             /* Web interface TCP port */
927             if (tree) {
928                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb,
929                                            offset, length, ett_cdp_tlv, NULL, "Web mgmt port: %s",
930                                            tvb_format_text(pinfo->pool, tvb, offset + 4, length - 4));
931                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
932                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
933                 proto_tree_add_item(tlv_tree, hf_cdp_platform, tvb, offset + 4, length - 4, ENC_ASCII|ENC_NA);
934             }
935             offset += length;
936             break;
937 
938         case TYPE_HP_SOURCE_MAC:
939             /* Sender MAC address for the AP, bouth wired and wireless */
940             if (tree) {
941                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb,
942                                            offset, length, ett_cdp_tlv, NULL, "Source MAC: %s",
943                                            tvb_format_text(pinfo->pool, tvb, offset + 4, length - 4));
944                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
945                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
946                 proto_tree_add_item(tlv_tree, hf_cdp_platform, tvb, offset + 4, length - 4, ENC_ASCII|ENC_NA);
947             }
948             offset += length;
949             break;
950 
951         case TYPE_HP_RADIO2_CH:
952             /* Radio2 channel */
953             if (tree) {
954                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb,
955                                            offset, length, ett_cdp_tlv, NULL, "Radio 2 channel: %s",
956                                            tvb_format_text(pinfo->pool, tvb, offset + 4, length - 4));
957                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
958                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
959                 proto_tree_add_item(tlv_tree, hf_cdp_platform, tvb, offset + 4, length - 4, ENC_ASCII|ENC_NA);
960             }
961             offset += length;
962             break;
963 
964         case TYPE_HP_RADIO1_OMODE:
965             /* Radio1 Operating mode */
966             if (tree) {
967                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb,
968                                            offset, length, ett_cdp_tlv, NULL, "Radio 1 operating mode: %s",
969                                            tvb_format_text(pinfo->pool, tvb, offset + 4, length - 4));
970                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
971                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
972                 proto_tree_add_item(tlv_tree, hf_cdp_platform, tvb, offset + 4, length - 4, ENC_ASCII|ENC_NA);
973             }
974             offset += length;
975             break;
976 
977         case TYPE_HP_RADIO2_OMODE:
978             /* Radio2 Operating mode */
979             if (tree) {
980                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb,
981                                            offset, length, ett_cdp_tlv, NULL, "Radio 2 operating mode: %s",
982                                            tvb_format_text(pinfo->pool, tvb, offset + 4, length - 4));
983                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
984                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
985                 proto_tree_add_item(tlv_tree, hf_cdp_platform, tvb, offset + 4, length - 4, ENC_ASCII|ENC_NA);
986             }
987             offset += length;
988             break;
989 
990         case TYPE_HP_RADIO1_RMODE:
991             /* Radio1 Radio mode */
992             if (tree) {
993                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb,
994                                            offset, length, ett_cdp_tlv, NULL, "Radio 1 radio mode: %s",
995                                            tvb_format_text(pinfo->pool, tvb, offset + 4, length - 4));
996                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
997                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
998                 proto_tree_add_item(tlv_tree, hf_cdp_platform, tvb, offset + 4, length - 4, ENC_ASCII|ENC_NA);
999             }
1000             offset += length;
1001             break;
1002 
1003         case TYPE_HP_RADIO2_RMODE:
1004             /* Radio2 Radio mode */
1005             if (tree) {
1006                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb,
1007                                            offset, length, ett_cdp_tlv, NULL, "Radio 2 radio mode: %s",
1008                                            tvb_format_text(pinfo->pool, tvb, offset + 4, length - 4));
1009                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
1010                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
1011                 proto_tree_add_item(tlv_tree, hf_cdp_platform, tvb, offset + 4, length - 4, ENC_ASCII|ENC_NA);
1012             }
1013             offset += length;
1014             break;
1015 
1016         default:
1017             if (tree) {
1018                 tlv_tree = proto_tree_add_subtree_format(cdp_tree, tvb, offset,
1019                                            length, ett_cdp_tlv, NULL, "Type: %s, length: %u",
1020                                            val_to_str(type, type_vals, "Unknown (0x%04x)"),
1021                                            length);
1022                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, ENC_BIG_ENDIAN);
1023                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, ENC_BIG_ENDIAN);
1024                 if (length > 4) {
1025                     proto_tree_add_item(tlv_tree, hf_cdp_data, tvb, offset + 4, length - 4, ENC_NA);
1026                 } else {
1027                     return tvb_captured_length(tvb);
1028                 }
1029             }
1030             offset += length;
1031         }
1032     }
1033     call_data_dissector(tvb_new_subset_remaining(tvb, offset), pinfo, cdp_tree);
1034     return tvb_captured_length(tvb);
1035 }
1036 
1037 #define PROTO_TYPE_NLPID       1
1038 #define PROTO_TYPE_IEEE_802_2  2
1039 
1040 static const value_string proto_type_vals[] = {
1041     { PROTO_TYPE_NLPID,      "NLPID" },
1042     { PROTO_TYPE_IEEE_802_2, "802.2" },
1043     { 0,                     NULL }
1044 };
1045 
1046 static int
dissect_address_tlv(tvbuff_t * tvb,packet_info * pinfo,int offset,int length,proto_tree * tree)1047 dissect_address_tlv(tvbuff_t *tvb, packet_info* pinfo, int offset, int length, proto_tree *tree)
1048 {
1049     proto_item *ti;
1050     proto_tree *address_tree;
1051     guint8      protocol_type;
1052     guint8      protocol_length;
1053     int         nlpid = 0;
1054     guint16     address_length;
1055     guint16     etypeid = 0;
1056     int         hf_addr = -1;
1057 
1058     if (length < 1)
1059         return -1;
1060     address_tree = proto_tree_add_subtree(tree, tvb, offset, length, ett_cdp_address, &ti, "Truncated address");
1061     protocol_type = tvb_get_guint8(tvb, offset);
1062     proto_tree_add_item(address_tree, hf_cdp_protocol_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1063     offset += 1;
1064     length -= 1;
1065 
1066     if (length < 1)
1067         return -1;
1068     protocol_length = tvb_get_guint8(tvb, offset);
1069     proto_tree_add_item(address_tree, hf_cdp_protocol_length, tvb, offset, 1, ENC_BIG_ENDIAN);
1070     offset += 1;
1071     length -= 1;
1072 
1073     if (length < protocol_length) {
1074         if (length != 0) {
1075             ti = proto_tree_add_item(address_tree, hf_cdp_protocol, tvb, offset, length, ENC_NA);
1076             proto_item_append_text(ti, " (truncated)");
1077         }
1078         return -1;
1079     }
1080 
1081     if ((protocol_type == PROTO_TYPE_NLPID) && (protocol_length == 1)) {
1082         nlpid = tvb_get_guint8(tvb, offset);
1083         proto_tree_add_bytes_format_value(address_tree, hf_cdp_protocol, tvb, offset, protocol_length, NULL, "%s",
1084                             val_to_str(nlpid, nlpid_vals, "Unknown (0x%02x)"));
1085     } else if ((protocol_type == PROTO_TYPE_IEEE_802_2) && (protocol_length == 8) && (tvb_get_ntoh48(tvb, offset) == 0xAAAA03000000)) {
1086         etypeid = tvb_get_ntohs(tvb, offset + 6);
1087         proto_tree_add_bytes_format_value(address_tree, hf_cdp_protocol, tvb, offset, protocol_length, NULL, "%s",
1088                             val_to_str(etypeid, etype_vals, "Unknown (0x%04x)"));
1089     } else {
1090         nlpid = -1;
1091         proto_tree_add_item(address_tree, hf_cdp_protocol, tvb, offset, protocol_length, ENC_NA);
1092     }
1093     offset += protocol_length;
1094     length -= protocol_length;
1095 
1096     if (length < 2)
1097         return -1;
1098     address_length = tvb_get_ntohs(tvb, offset);
1099     proto_tree_add_item(address_tree, hf_cdp_address_length, tvb, offset, 2, ENC_BIG_ENDIAN);
1100     offset += 2;
1101     length -= 2;
1102 
1103     if (length < address_length) {
1104         if (length != 0) {
1105             ti = proto_tree_add_item(address_tree, hf_cdp_address, tvb, offset, length, ENC_NA);
1106             proto_item_append_text(ti, " (truncated)");
1107         }
1108         return -1;
1109     }
1110     /* XXX - the Cisco document seems to be saying that, for 802.2-format
1111        protocol types, 0xAAAA03 0x000000 0x0800 is IPv6, but 0x0800 is
1112        the Ethernet protocol type for IPv4. */
1113     if ((protocol_type == PROTO_TYPE_NLPID) && (protocol_length == 1)) {
1114         switch (nlpid) {
1115 
1116         /* XXX - dissect NLPID_ISO8473_CLNP as OSI CLNP address? */
1117 
1118         case NLPID_IP:
1119             if (address_length == 4) {
1120                 /* The address is an IP address. */
1121                 proto_item_set_text(ti, "IP address: %s", tvb_ip_to_str(pinfo->pool, tvb, offset));
1122                 hf_addr = hf_cdp_nrgyz_ip_address;
1123                 proto_tree_add_item(address_tree, hf_cdp_nrgyz_ip_address, tvb, offset, address_length, ENC_BIG_ENDIAN);
1124             }
1125             break;
1126         }
1127     }
1128     if ((protocol_type == PROTO_TYPE_IEEE_802_2) && (protocol_length == 8) && (etypeid > 0)) {
1129         /*
1130          * See also:
1131          *
1132          *    http://www.rhyshaden.com/cdp.htm
1133          *
1134          * where other Ethertypes are mentioned.
1135          */
1136         switch (etypeid) {
1137 
1138         case ETHERTYPE_IPv6:
1139             if (address_length == 16) {
1140                 /* The address is an IPv6 address. */
1141                 proto_item_set_text(ti, "IPv6 address: %s", tvb_ip6_to_str(pinfo->pool, tvb, offset));
1142                 hf_addr = hf_cdp_nrgyz_ip6_address;
1143                 proto_tree_add_item(address_tree, hf_cdp_nrgyz_ip6_address, tvb, offset, address_length, ENC_NA);
1144             }
1145             break;
1146         }
1147     }
1148 
1149     if (hf_addr == -1)
1150     {
1151         proto_tree_add_item(address_tree, hf_cdp_address, tvb, offset, address_length, ENC_NA);
1152         proto_item_set_text(ti, "Address: %s", tvb_bytes_to_str(pinfo->pool, tvb, offset, address_length));
1153     }
1154 
1155     return 2 + protocol_length + 2 + address_length;
1156 }
1157 
1158 static void
dissect_capabilities(tvbuff_t * tvb,int offset,int length,proto_tree * tree)1159 dissect_capabilities(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
1160 {
1161     proto_item *ti;
1162     proto_tree *capabilities_tree;
1163 
1164     if (length < 4)
1165         return;
1166     ti = proto_tree_add_item(tree, hf_cdp_capabilities, tvb, offset, 4, ENC_BIG_ENDIAN);
1167     capabilities_tree = proto_item_add_subtree(ti, ett_cdp_capabilities);
1168     proto_tree_add_item(capabilities_tree, hf_cdp_capabilities_router, tvb, offset, 4, ENC_BIG_ENDIAN);
1169     proto_tree_add_item(capabilities_tree, hf_cdp_capabilities_trans_bridge, tvb, offset, 4, ENC_BIG_ENDIAN);
1170     proto_tree_add_item(capabilities_tree, hf_cdp_capabilities_src_bridge, tvb, offset, 4, ENC_BIG_ENDIAN);
1171     proto_tree_add_item(capabilities_tree, hf_cdp_capabilities_switch, tvb, offset, 4, ENC_BIG_ENDIAN);
1172     proto_tree_add_item(capabilities_tree, hf_cdp_capabilities_host, tvb, offset, 4, ENC_BIG_ENDIAN);
1173     proto_tree_add_item(capabilities_tree, hf_cdp_capabilities_igmp_capable, tvb, offset, 4, ENC_BIG_ENDIAN);
1174     proto_tree_add_item(capabilities_tree, hf_cdp_capabilities_repeater, tvb, offset, 4, ENC_BIG_ENDIAN);
1175     proto_tree_add_item(capabilities_tree, hf_cdp_capabilities_voip_phone , tvb, offset, 4, ENC_BIG_ENDIAN);
1176     proto_tree_add_item(capabilities_tree, hf_cdp_capabilities_remote, tvb, offset, 4, ENC_BIG_ENDIAN);
1177     proto_tree_add_item(capabilities_tree, hf_cdp_capabilities_cvta, tvb, offset, 4, ENC_BIG_ENDIAN);
1178     proto_tree_add_item(capabilities_tree, hf_cdp_capabilities_mac_relay, tvb, offset, 4, ENC_BIG_ENDIAN);
1179 }
1180 
1181 static void
dissect_nrgyz_tlv(tvbuff_t * tvb,packet_info * pinfo,int offset,guint16 length,guint16 num,proto_tree * tree)1182 dissect_nrgyz_tlv(tvbuff_t *tvb, packet_info* pinfo, int offset, guint16 length, guint16 num,
1183                   proto_tree *tree)
1184 {
1185     guint32     tlvt, tlvl;
1186     proto_tree *etree = NULL;
1187     char const *ttext = NULL;
1188 
1189     while (num-- && (length >= 8)) {
1190         tlvt = tvb_get_ntohl(tvb, offset);
1191         tlvl = tvb_get_ntohl(tvb, offset + 4);
1192 
1193         if (length < tlvl)
1194             break;
1195         length -= tlvl;
1196 
1197         if (tlvl < 8) {
1198             proto_tree_add_expert_format(tree, pinfo, &ei_cdp_nrgyz_tlvlength, tvb, offset, 8, "TLV with invalid length %u (< 8)", tlvl);
1199             offset += 8;
1200             break;
1201         }
1202         else {
1203             ttext = val_to_str(tlvt, type_nrgyz_vals, "Unknown (0x%04x)");
1204             switch (tlvt) {
1205             case TYPE_NRGYZ_ROLE:
1206             case TYPE_NRGYZ_DOMAIN:
1207             case TYPE_NRGYZ_NAME:
1208                 etree  = proto_tree_add_subtree_format(tree, tvb, offset,
1209                                          tlvl, ett_cdp_nrgyz_tlv, NULL, "EnergyWise %s: %s", ttext,
1210                                          tvb_format_stringzpad(pinfo->pool, tvb, offset + 8, tlvl - 8)
1211                     );
1212                 break;
1213             case TYPE_NRGYZ_REPLYTO:
1214                 etree  = proto_tree_add_subtree_format(tree, tvb, offset,
1215                                          tlvl, ett_cdp_nrgyz_tlv, NULL, "EnergyWise %s: %s port %u",
1216                                          ttext,
1217                                          tvb_ip_to_str(pinfo->pool, tvb, offset + 12),
1218                                          tvb_get_ntohs(tvb, offset + 10)
1219                     );
1220                 break;
1221             default:
1222                 etree  = proto_tree_add_subtree_format(tree, tvb, offset,
1223                                          tlvl, ett_cdp_nrgyz_tlv, NULL, "EnergyWise %s TLV", ttext);
1224             }
1225             proto_tree_add_item(etree, hf_cdp_nrgyz_tlvtype, tvb, offset, 4, ENC_BIG_ENDIAN);
1226             proto_tree_add_item(etree, hf_cdp_nrgyz_tlvlength, tvb, offset + 4, 4, ENC_BIG_ENDIAN);
1227             switch (tlvt) {
1228             case TYPE_NRGYZ_ROLE:
1229                 proto_tree_add_item(etree, hf_cdp_nrgyz_reply_to_role, tvb, offset + 8, tlvl - 8, ENC_NA|ENC_ASCII);
1230                 break;
1231             case TYPE_NRGYZ_DOMAIN:
1232                 proto_tree_add_item(etree, hf_cdp_nrgyz_reply_to_domain, tvb, offset + 8, tlvl - 8, ENC_NA|ENC_ASCII);
1233                 break;
1234             case TYPE_NRGYZ_NAME:
1235                 proto_tree_add_item(etree, hf_cdp_nrgyz_reply_to_name, tvb, offset + 8, tlvl - 8, ENC_NA|ENC_ASCII);
1236                 break;
1237             case TYPE_NRGYZ_REPLYTO:
1238                 proto_tree_add_item(etree, hf_cdp_nrgyz_reply_to_unknown_field, tvb, offset + 8, 2, ENC_BIG_ENDIAN);
1239                 proto_tree_add_item(etree, hf_cdp_nrgyz_reply_to_port, tvb, offset + 10, 2, ENC_BIG_ENDIAN);
1240                 proto_tree_add_item(etree, hf_cdp_nrgyz_reply_to_ip_address, tvb, offset + 12, 4, ENC_BIG_ENDIAN);
1241                 proto_tree_add_item(etree, hf_cdp_nrgyz_reply_to_backup_server_port, tvb, offset + 16, 2, ENC_BIG_ENDIAN);
1242                 proto_tree_add_item(etree, hf_cdp_nrgyz_reply_to_backup_server_ip, tvb, offset + 18, 4, ENC_BIG_ENDIAN);
1243                 break;
1244             default:
1245                 if (tlvl > 8) {
1246                     proto_tree_add_item(etree, hf_cdp_data, tvb, offset + 8, tlvl - 8, ENC_NA);
1247                 }
1248             }
1249             offset += tlvl;
1250         }
1251     }
1252     if (length) {
1253         proto_tree_add_expert(tree, pinfo, &ei_cdp_invalid_data, tvb, offset, length);
1254     }
1255 }
1256 
1257 static void
dissect_spare_poe_tlv(tvbuff_t * tvb,int offset,int length,proto_tree * tree)1258 dissect_spare_poe_tlv(tvbuff_t *tvb, int offset, int length,
1259                       proto_tree *tree)
1260 {
1261     proto_item *ti;
1262     proto_tree *tlv_tree;
1263 
1264     if (length == 0) {
1265         return;
1266     }
1267 
1268     ti = proto_tree_add_item(tree, hf_cdp_spare_poe_tlv, tvb, offset, 1, ENC_BIG_ENDIAN);
1269     tlv_tree = proto_item_add_subtree(ti, ett_cdp_spare_poe_tlv);
1270     proto_tree_add_item(tlv_tree, hf_cdp_spare_poe_tlv_poe, tvb, offset, 1, ENC_BIG_ENDIAN);
1271     proto_tree_add_item(tlv_tree, hf_cdp_spare_poe_tlv_spare_pair_arch, tvb, offset, 1, ENC_BIG_ENDIAN);
1272     proto_tree_add_item(tlv_tree, hf_cdp_spare_poe_tlv_req_spare_pair_poe, tvb, offset, 1, ENC_BIG_ENDIAN);
1273     proto_tree_add_item(tlv_tree, hf_cdp_spare_poe_tlv_pse_spare_pair_poe, tvb, offset, 1, ENC_BIG_ENDIAN);
1274 }
1275 
1276 static void
add_multi_line_string_to_tree(proto_tree * tree,tvbuff_t * tvb,gint start,gint len,int hf)1277 add_multi_line_string_to_tree(proto_tree *tree, tvbuff_t *tvb, gint start,
1278   gint len, int hf)
1279 {
1280     gint next;
1281     int  line_len;
1282     int  data_len;
1283 
1284     while (len > 0) {
1285         line_len = tvb_find_line_end(tvb, start, len, &next, FALSE);
1286         data_len = next - start;
1287         proto_tree_add_string(tree, hf, tvb, start, data_len, tvb_format_stringzpad(wmem_packet_scope(), tvb, start, line_len));
1288         start += data_len;
1289         len   -= data_len;
1290     }
1291 }
1292 
1293 void
proto_register_cdp(void)1294 proto_register_cdp(void)
1295 {
1296     static hf_register_info hf[] = {
1297         { &hf_cdp_version,
1298         { "Version",            "cdp.version",  FT_UINT8, BASE_DEC, NULL, 0x0,
1299           NULL, HFILL }},
1300 
1301         { &hf_cdp_ttl,
1302         { "TTL",                "cdp.ttl", FT_UINT8, BASE_DEC|BASE_UNIT_STRING, &units_second_seconds, 0x0,
1303           NULL, HFILL }},
1304 
1305         { &hf_cdp_checksum,
1306         { "Checksum",           "cdp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
1307           NULL, HFILL }},
1308 
1309         { &hf_cdp_checksum_status,
1310           { "Checksum Status",       "cdp.checksum.status", FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0,
1311             NULL, HFILL }},
1312 
1313         { &hf_cdp_tlvtype,
1314         { "Type",               "cdp.tlv.type", FT_UINT16, BASE_HEX, VALS(type_vals), 0x0,
1315           NULL, HFILL }},
1316 
1317         { &hf_cdp_tlvlength,
1318         { "Length",             "cdp.tlv.len", FT_UINT16, BASE_DEC, NULL, 0x0,
1319           NULL, HFILL }},
1320 
1321         { &hf_cdp_nrgyz_tlvtype,
1322         { "TLV Type",               "cdp.nrgyz.tlv.type", FT_UINT32, BASE_HEX, VALS(type_nrgyz_vals), 0x0,
1323           NULL, HFILL }},
1324 
1325         { &hf_cdp_nrgyz_tlvlength,
1326         { "TLV Length",             "cdp.nrgyz.tlv.len", FT_UINT16, BASE_DEC, NULL, 0x0,
1327           NULL, HFILL }},
1328 
1329         { &hf_cdp_deviceid,
1330         {"Device ID", "cdp.deviceid", FT_STRING, BASE_NONE,
1331          NULL, 0, NULL, HFILL }},
1332 
1333         { &hf_cdp_platform,
1334         {"Platform", "cdp.platform", FT_STRING, BASE_NONE,
1335          NULL, 0, NULL, HFILL }},
1336 
1337         { &hf_cdp_portid,
1338         {"Sent through Interface", "cdp.portid", FT_STRING, BASE_NONE,
1339                 NULL, 0, NULL, HFILL }},
1340 
1341         { &hf_cdp_capabilities,
1342         {"Capabilities", "cdp.capabilities", FT_UINT32, BASE_HEX,
1343                 NULL, 0, NULL, HFILL }},
1344 
1345         { &hf_cdp_capabilities_router,
1346         {"Router", "cdp.capabilities.router", FT_BOOLEAN, 32,
1347                 TFS(&tfs_yes_no), 0x01, NULL, HFILL }},
1348 
1349         { &hf_cdp_capabilities_trans_bridge,
1350         {"Transparent Bridge", "cdp.capabilities.trans_bridge", FT_BOOLEAN, 32,
1351                 TFS(&tfs_yes_no), 0x02, NULL, HFILL }},
1352 
1353         { &hf_cdp_capabilities_src_bridge,
1354         {"Source Route Bridge", "cdp.capabilities.src_bridge", FT_BOOLEAN, 32,
1355                 TFS(&tfs_yes_no), 0x04, NULL, HFILL }},
1356 
1357         { &hf_cdp_capabilities_switch,
1358         {"Switch", "cdp.capabilities.switch", FT_BOOLEAN, 32,
1359                 TFS(&tfs_yes_no), 0x08, NULL, HFILL }},
1360 
1361         { &hf_cdp_capabilities_host,
1362         {"Host", "cdp.capabilities.host", FT_BOOLEAN, 32,
1363                 TFS(&tfs_yes_no), 0x10, NULL, HFILL }},
1364 
1365         { &hf_cdp_capabilities_igmp_capable,
1366         {"IGMP capable", "cdp.capabilities.igmp_capable", FT_BOOLEAN, 32,
1367                 TFS(&tfs_yes_no), 0x20, NULL, HFILL }},
1368 
1369         { &hf_cdp_capabilities_repeater,
1370         {"Repeater", "cdp.capabilities.repeater", FT_BOOLEAN, 32,
1371                 TFS(&tfs_yes_no), 0x40, NULL, HFILL }},
1372 
1373         { &hf_cdp_capabilities_voip_phone,
1374         {"VoIP Phone", "cdp.capabilities.voip_phone", FT_BOOLEAN, 32,
1375                 TFS(&tfs_yes_no), 0x80, NULL, HFILL }},
1376 
1377         { &hf_cdp_capabilities_remote,
1378         {"Remotely Managed Device", "cdp.capabilities.remote", FT_BOOLEAN, 32,
1379                 TFS(&tfs_yes_no), 0x0100, NULL, HFILL }},
1380 
1381         { &hf_cdp_capabilities_cvta,
1382         {"CVTA/STP Dispute Resolution/Cisco VT Camera", "cdp.capabilities.cvta", FT_BOOLEAN, 32,
1383                 TFS(&tfs_yes_no), 0x0200, NULL, HFILL }},
1384 
1385         { &hf_cdp_capabilities_mac_relay,
1386         {"Two Port Mac Relay", "cdp.capabilities.mac_relay", FT_BOOLEAN, 32,
1387                 TFS(&tfs_yes_no), 0x0400, NULL, HFILL }},
1388 
1389         { &hf_cdp_spare_poe_tlv,
1390         { "Spare Pair PoE", "cdp.spare_poe_tlv", FT_UINT8, BASE_HEX,
1391                 NULL, 0x0, NULL, HFILL }
1392         },
1393 
1394         { &hf_cdp_spare_poe_tlv_poe,
1395         { "PSE Four-Wire PoE", "cdp.spare_poe_tlv.poe", FT_BOOLEAN, 8,
1396                 TFS(&tfs_supported_not_supported), 0x01, NULL, HFILL }
1397         },
1398 
1399         { &hf_cdp_spare_poe_tlv_spare_pair_arch,
1400         { "PD Spare Pair Architecture", "cdp.spare_poe_tlv.spare_pair_arch", FT_BOOLEAN, 8,
1401                 TFS(&tfs_shared_independent), 0x02, NULL, HFILL }
1402         },
1403 
1404         { &hf_cdp_spare_poe_tlv_req_spare_pair_poe,
1405         { "PD Request Spare Pair PoE", "cdp.spare_poe_tlv.req_spare_pair_poe", FT_BOOLEAN, 8,
1406                 TFS(&tfs_on_off), 0x04, NULL, HFILL }
1407         },
1408 
1409         { &hf_cdp_spare_poe_tlv_pse_spare_pair_poe,
1410         { "PSE Spare Pair PoE", "cdp.spare_poe_tlv.pse_spare_pair_poe", FT_BOOLEAN, 8,
1411                 TFS(&tfs_on_off), 0x08, NULL, HFILL }
1412         },
1413 
1414       /* Generated from convert_proto_tree_add_text.pl */
1415       { &hf_cdp_number_of_addresses, { "Number of addresses", "cdp.number_of_addresses", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1416       { &hf_cdp_odr_default_gateway, { "ODR Default gateway", "cdp.odr_default_gateway", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1417       { &hf_cdp_ip_prefix, { "IP Prefix", "cdp.ip_prefix", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1418       { &hf_cdp_oui, { "OUI", "cdp.oui", FT_UINT24, BASE_OUI, NULL, 0x0, NULL, HFILL }},
1419       { &hf_cdp_protocol_id, { "Protocol ID", "cdp.protocol_id", FT_UINT16, BASE_HEX, VALS(type_hello_vals), 0x0, NULL, HFILL }},
1420       { &hf_cdp_cluster_master_ip, { "Cluster Master IP", "cdp.cluster.master_ip", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1421       { &hf_cdp_cluster_ip, { "IP?", "cdp.cluster.ip", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1422       { &hf_cdp_cluster_version, { "Version?", "cdp.cluster.version", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1423       { &hf_cdp_cluster_sub_version, { "Sub Version?", "cdp.cluster.sub_version", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1424       { &hf_cdp_cluster_status, { "Status?", "cdp.cluster.status", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1425       { &hf_cdp_cluster_unknown, { "UNKNOWN", "cdp.cluster.unknown", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1426       { &hf_cdp_cluster_commander_mac, { "Cluster Commander MAC", "cdp.cluster.commander_mac", FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1427       { &hf_cdp_cluster_switch_mac, { "Switch's MAC", "cdp.cluster.switch_mac", FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1428       { &hf_cdp_cluster_management_vlan, { "Management VLAN", "cdp.cluster.management_vlan", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1429       { &hf_cdp_hello_unknown, { "Unknown", "cdp.hello.unknown", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1430       { &hf_cdp_vtp_management_domain, { "VTP Management Domain", "cdp.vtp_management_domain", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1431       { &hf_cdp_native_vlan, { "Native VLAN", "cdp.native_vlan", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1432       { &hf_cdp_duplex, { "Duplex", "cdp.duplex", FT_BOOLEAN, BASE_NONE, TFS(&tfs_full_half), 0x0, NULL, HFILL }},
1433       { &hf_cdp_data, { "Data", "cdp.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1434       { &hf_cdp_voice_vlan, { "Voice VLAN", "cdp.voice_vlan", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1435       { &hf_cdp_power_consumption, { "Power Consumption", "cdp.power_consumption", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, &units_mw, 0x0, NULL, HFILL }},
1436       { &hf_cdp_mtu, { "MTU", "cdp.mtu", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1437       { &hf_cdp_trust_bitmap, { "Trust Bitmap", "cdp.trust_bitmap", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1438       { &hf_cdp_untrusted_port_cos, { "Untrusted port CoS", "cdp.untrusted_port_cos", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1439       { &hf_cdp_system_name, { "System Name", "cdp.system_name", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1440       { &hf_cdp_system_object_identifier, { "System Object Identifier", "cdp.system_object_identifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1441       { &hf_cdp_location_unknown, { "UNKNOWN", "cdp.location.unknown", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1442       { &hf_cdp_location, { "Location", "cdp.location", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1443       { &hf_cdp_request_id, { "Request-ID", "cdp.request_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1444       { &hf_cdp_management_id, { "Management-ID", "cdp.management_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1445       { &hf_cdp_power_requested, { "Power Requested", "cdp.power_requested", FT_UINT32, BASE_DEC|BASE_UNIT_STRING, &units_mw, 0x0, NULL, HFILL }},
1446       { &hf_cdp_power_available, { "Power Available", "cdp.power_available", FT_UINT32, BASE_DEC|BASE_UNIT_STRING, &units_mw, 0x0, NULL, HFILL }},
1447       { &hf_cdp_encrypted_data, { "Encrypted Data", "cdp.encrypted_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1448       { &hf_cdp_seen_sequence, { "Seen Sequence?", "cdp.seen_sequence", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1449       { &hf_cdp_sequence_number, { "Sequence Number", "cdp.sequence_number", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1450       { &hf_cdp_model_number, { "Model Number", "cdp.model_number", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1451       { &hf_cdp_unknown_pad, { "Unknown Pad", "cdp.unknown_pad", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1452       { &hf_cdp_hardware_version_id, { "Hardware Version ID", "cdp.hardware_version_id", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1453       { &hf_cdp_system_serial_number, { "System Serial Number", "cdp.system_serial_number", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1454       { &hf_cdp_nrgyz_unknown_values, { "Unknown Values", "cdp.nrgyz_unknown_values", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1455       { &hf_cdp_len_tlv_table, { "Length of TLV table", "cdp.len_tlv_table", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1456       { &hf_cdp_num_tlvs_table, { "Number of TLVs in table", "cdp.num_tlvs_table", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1457       { &hf_cdp_protocol, { "Protocol", "cdp.protocol", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1458       { &hf_cdp_protocol_type, { "Protocol type", "cdp.protocol_type", FT_UINT8, BASE_HEX, VALS(proto_type_vals), 0x0, NULL, HFILL }},
1459       { &hf_cdp_protocol_length, { "Protocol length", "cdp.protocol_length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1460       { &hf_cdp_address, { "Address", "cdp.address", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1461       { &hf_cdp_address_length, { "Address length", "cdp.address_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1462       { &hf_cdp_nrgyz_reply_to_unknown_field, { "Unknown Field", "cdp.nrgyz_reply_to.unknown_field", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1463       { &hf_cdp_nrgyz_reply_to_port, { "Port", "cdp.nrgyz_reply_to.port", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1464       { &hf_cdp_nrgyz_ip_address, { "IP Address", "cdp.nrgyz.ip_address", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1465       { &hf_cdp_nrgyz_ip6_address, { "IPv6 Address", "cdp.nrgyz.ipv6_address", FT_IPv6, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1466       { &hf_cdp_nrgyz_reply_to_ip_address, { "IP Address", "cdp.nrgyz_reply_to.ip_address", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1467       { &hf_cdp_nrgyz_reply_to_backup_server_port, { "Backup server Port?", "cdp.nrgyz_reply_to.backup_server_port", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1468       { &hf_cdp_nrgyz_reply_to_backup_server_ip, { "Backup Server IP?", "cdp.nrgyz_reply_to.backup_server_ip", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1469       { &hf_cdp_nrgyz_reply_to_name, { "Name", "cdp.nrgyz_reply_to.name", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1470       { &hf_cdp_nrgyz_reply_to_domain, { "Domain", "cdp.nrgyz_reply_to.domain", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1471       { &hf_cdp_nrgyz_reply_to_role, { "Role", "cdp.nrgyz_reply_to.role", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1472       { &hf_cdp_software_version, { "Software version", "cdp.software_version", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1473     };
1474 
1475     static gint *ett[] = {
1476         &ett_cdp,
1477         &ett_cdp_tlv,
1478         &ett_cdp_nrgyz_tlv,
1479         &ett_cdp_address,
1480         &ett_cdp_capabilities,
1481         &ett_cdp_checksum,
1482         &ett_cdp_spare_poe_tlv
1483     };
1484 
1485     static ei_register_info ei[] = {
1486         { &ei_cdp_invalid_data, { "cdp.invalid_data", PI_MALFORMED, PI_ERROR, "Invalid bytes at end", EXPFILL }},
1487         { &ei_cdp_nrgyz_tlvlength, { "cdp.nrgyz_tlv.length.invalid", PI_MALFORMED, PI_ERROR, "TLV with invalid length", EXPFILL }},
1488         { &ei_cdp_checksum, { "cdp.bad_checksum", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }},
1489     };
1490 
1491     expert_module_t* expert_cdp;
1492 
1493     proto_cdp = proto_register_protocol("Cisco Discovery Protocol", "CDP", "cdp");
1494 
1495     proto_register_field_array(proto_cdp, hf, array_length(hf));
1496     proto_register_subtree_array(ett, array_length(ett));
1497     expert_cdp = expert_register_protocol(proto_cdp);
1498     expert_register_field_array(expert_cdp, ei, array_length(ei));
1499 }
1500 
1501 void
proto_reg_handoff_cdp(void)1502 proto_reg_handoff_cdp(void)
1503 {
1504     dissector_handle_t cdp_handle;
1505 
1506     cdp_handle  = create_dissector_handle(dissect_cdp, proto_cdp);
1507     dissector_add_uint("llc.cisco_pid", CISCO_PID_CDP, cdp_handle);
1508     dissector_add_uint("chdlc.protocol", 0x2000, cdp_handle);
1509     dissector_add_uint("ppp.protocol", 0x0207, cdp_handle);
1510     dissector_add_uint("gre.proto", 0x2000, cdp_handle);
1511 }
1512 
1513 /*
1514  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1515  *
1516  * Local variables:
1517  * c-basic-offset: 4
1518  * tab-width: 8
1519  * indent-tabs-mode: nil
1520  * End:
1521  *
1522  * vi: set shiftwidth=4 tabstop=8 expandtab:
1523  * :indentSize=4:tabSize=8:noTabs=true:
1524  */
1525