2 * Routines for the disassembly of the "Cisco Discovery Protocol"
3 * (c) Copyright Hannes R. Boehm <hannes@boehm.org>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
34 #include <epan/packet.h>
35 #include <epan/strutil.h>
36 #include <epan/in_cksum.h>
39 #include <epan/nlpid.h>
45 * http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm#xtocid12
47 * for some information on CDP.
51 * http://www.cisco.com/en/US/products/hw/switches/ps663/products_tech_note09186a0080094713.shtml#cdp
53 * for some more information on CDP version 2.
56 /* Offsets in TLV structure. */
60 static int proto_cdp = -1;
61 static int hf_cdp_version = -1;
62 static int hf_cdp_checksum = -1;
63 static int hf_cdp_checksum_good = -1;
64 static int hf_cdp_checksum_bad = -1;
65 static int hf_cdp_ttl = -1;
66 static int hf_cdp_tlvtype = -1;
67 static int hf_cdp_tlvlength = -1;
68 static int hf_cdp_deviceid = -1;
69 static int hf_cdp_platform = -1;
70 static int hf_cdp_portid = -1;
72 static gint ett_cdp = -1;
73 static gint ett_cdp_tlv = -1;
74 static gint ett_cdp_nrgyz_tlv = -1;
75 static gint ett_cdp_address = -1;
76 static gint ett_cdp_capabilities = -1;
77 static gint ett_cdp_checksum = -1;
79 static dissector_handle_t data_handle;
82 dissect_address_tlv(tvbuff_t *tvb, int offset, int length, proto_tree *tree);
84 dissect_capabilities(tvbuff_t *tvb, int offset, int length, proto_tree *tree);
86 dissect_nrgyz_tlv(tvbuff_t *tvb, int offset, guint16 length, guint16 num,
89 add_multi_line_string_to_tree(proto_tree *tree, tvbuff_t *tvb, gint start,
90 gint len, const gchar *prefix);
92 #define TYPE_DEVICE_ID 0x0001
93 #define TYPE_ADDRESS 0x0002
94 #define TYPE_PORT_ID 0x0003
95 #define TYPE_CAPABILITIES 0x0004
96 #define TYPE_IOS_VERSION 0x0005
97 #define TYPE_PLATFORM 0x0006
98 #define TYPE_IP_PREFIX 0x0007
99 #define TYPE_PROTOCOL_HELLO 0x0008 /* Protocol Hello */
100 #define TYPE_VTP_MGMT_DOMAIN 0x0009 /* VTP Domain, CTPv2 - see second URL */
101 #define TYPE_NATIVE_VLAN 0x000a /* Native VLAN, CTPv2 - see second URL */
102 #define TYPE_DUPLEX 0x000b /* Full/Half Duplex - see second URL */
105 #define TYPE_VOIP_VLAN_REPLY 0x000e /* VoIP VLAN reply */
106 #define TYPE_VOIP_VLAN_QUERY 0x000f /* VoIP VLAN query */
107 #define TYPE_POWER 0x0010 /* Power consumption */
108 #define TYPE_MTU 0x0011 /* MTU */
109 #define TYPE_TRUST_BITMAP 0x0012 /* Trust bitmap */
110 #define TYPE_UNTRUSTED_COS 0x0013 /* Untrusted port CoS */
111 #define TYPE_SYSTEM_NAME 0x0014 /* System Name */
112 #define TYPE_SYSTEM_OID 0x0015 /* System OID */
113 #define TYPE_MANAGEMENT_ADDR 0x0016 /* Management Address(es) */
114 #define TYPE_LOCATION 0x0017 /* Location */
115 #define TYPE_EXT_PORT_ID 0x0018 /* External Port-ID */
116 #define TYPE_POWER_REQUESTED 0x0019 /* Power Requested */
117 #define TYPE_POWER_AVAILABLE 0x001a /* Power Available */
118 #define TYPE_PORT_UNIDIR 0x001b /* Port Unidirectional */
119 #define TYPE_NRGYZ 0x001d /* EnergyWise over CDP */
121 static const value_string type_vals[] = {
122 { TYPE_DEVICE_ID, "Device ID" },
123 { TYPE_ADDRESS, "Addresses" },
124 { TYPE_PORT_ID, "Port ID" },
125 { TYPE_CAPABILITIES, "Capabilities" },
126 { TYPE_IOS_VERSION, "Software version" },
127 { TYPE_PLATFORM, "Platform" },
128 { TYPE_IP_PREFIX, "IP Prefix/Gateway (used for ODR)" },
129 { TYPE_PROTOCOL_HELLO, "Protocol Hello" },
130 { TYPE_VTP_MGMT_DOMAIN, "VTP Management Domain" },
131 { TYPE_NATIVE_VLAN, "Native VLAN" },
132 { TYPE_DUPLEX, "Duplex" },
133 { TYPE_VOIP_VLAN_REPLY, "VoIP VLAN Reply" },
134 { TYPE_VOIP_VLAN_QUERY, "VoIP VLAN Query" },
135 { TYPE_POWER, "Power consumption" },
137 { TYPE_TRUST_BITMAP, "Trust Bitmap" },
138 { TYPE_UNTRUSTED_COS, "Untrusted Port CoS" },
139 { TYPE_SYSTEM_NAME, "System Name" },
140 { TYPE_SYSTEM_OID, "System Object ID" },
141 { TYPE_MANAGEMENT_ADDR, "Management Address" },
142 { TYPE_LOCATION, "Location" },
143 { TYPE_EXT_PORT_ID, "External Port-ID" },
144 { TYPE_POWER_REQUESTED, "Power Requested" },
145 { TYPE_POWER_AVAILABLE, "Power Available" },
146 { TYPE_PORT_UNIDIR, "Port Unidirectional" },
147 { TYPE_NRGYZ, "EnergyWise" },
151 #define TYPE_HELLO_CLUSTER_MGMT 0x0112
153 static const value_string type_hello_vals[] = {
154 { TYPE_HELLO_CLUSTER_MGMT, "Cluster Management" },
158 #define TYPE_NRGYZ_ROLE 0x00000007
159 #define TYPE_NRGYZ_DOMAIN 0x00000008
160 #define TYPE_NRGYZ_NAME 0x00000009
161 #define TYPE_NRGYZ_REPLYTO 0x00000017
163 static const value_string type_nrgyz_vals[] = {
164 { TYPE_NRGYZ_ROLE, "Role" },
165 { TYPE_NRGYZ_DOMAIN, "Domain" },
166 { TYPE_NRGYZ_NAME, "Name" },
167 { TYPE_NRGYZ_REPLYTO, "Reply To" },
172 dissect_cdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
174 proto_item *ti, *checksum_item;
175 proto_tree *cdp_tree = NULL, *checksum_tree;
178 guint16 length, packet_checksum, computed_checksum, data_length;
179 gboolean checksum_good, checksum_bad;
180 proto_item *tlvi = NULL;
181 proto_tree *tlv_tree = NULL;
184 guint32 power_avail_len, power_avail;
185 guint32 power_req_len, power_req;
190 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CDP");
191 col_clear(pinfo->cinfo, COL_INFO);
194 ti = proto_tree_add_item(tree, proto_cdp, tvb, offset, -1, FALSE);
195 cdp_tree = proto_item_add_subtree(ti, ett_cdp);
198 proto_tree_add_item(cdp_tree, hf_cdp_version, tvb, offset, 1, FALSE);
201 proto_tree_add_uint_format_value(cdp_tree, hf_cdp_ttl, tvb, offset, 1,
202 tvb_get_guint8(tvb, offset),
204 tvb_get_guint8(tvb, offset));
207 offset += 2; /* The version/ttl fields from above */
210 /* Checksum display & verification code */
211 packet_checksum = tvb_get_ntohs(tvb, offset);
213 data_length = tvb_reported_length(tvb);
215 /* CDP doesn't adhere to RFC 1071 section 2. (B). It incorrectly assumes
216 * checksums are calculated on a big endian platform, therefore i.s.o.
217 * padding odd sized data with a zero byte _at the end_ it sets the last
218 * big endian _word_ to contain the last network _octet_. This byteswap
219 * has to be done on the last octet of network data before feeding it to
220 * the Internet checksum routine.
221 * CDP checksumming code has a bug in the addition of this last _word_
222 * as a signed number into the long word intermediate checksum. When
223 * reducing this long to word size checksum an off-by-one error can be
224 * made. This off-by-one error is compensated for in the last _word_ of
227 if (data_length & 1) {
228 guint8 *padded_buffer;
229 /* Allocate new buffer */
230 padded_buffer = ep_alloc(data_length+1);
231 tvb_memcpy(tvb, padded_buffer, 0, data_length);
232 /* Swap bytes in last word */
233 padded_buffer[data_length] = padded_buffer[data_length-1];
234 padded_buffer[data_length-1] = 0;
235 /* Compensate off-by-one error */
236 if (padded_buffer[data_length] & 0x80) {
237 padded_buffer[data_length]--;
238 padded_buffer[data_length-1]--;
240 /* Setup checksum routine data buffer */
241 cksum_vec[0].ptr = padded_buffer;
242 cksum_vec[0].len = data_length+1;
244 /* Setup checksum routine data buffer */
245 cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, data_length);
246 cksum_vec[0].len = data_length;
249 computed_checksum = in_cksum(cksum_vec, 1);
250 checksum_good = (computed_checksum == 0);
251 checksum_bad = !checksum_good;
253 checksum_item = proto_tree_add_uint_format(cdp_tree,
254 hf_cdp_checksum, tvb, offset, 2, packet_checksum,
255 "Checksum: 0x%04x [correct]", packet_checksum);
257 checksum_item = proto_tree_add_uint_format(cdp_tree,
258 hf_cdp_checksum, tvb, offset, 2, packet_checksum,
259 "Checksum: 0x%04x [incorrect, should be 0x%04x]",
261 in_cksum_shouldbe(packet_checksum, computed_checksum));
264 checksum_tree = proto_item_add_subtree(checksum_item, ett_cdp_checksum);
265 checksum_item = proto_tree_add_boolean(checksum_tree, hf_cdp_checksum_good,
266 tvb, offset, 2, checksum_good);
267 PROTO_ITEM_SET_GENERATED(checksum_item);
268 checksum_item = proto_tree_add_boolean(checksum_tree, hf_cdp_checksum_bad,
269 tvb, offset, 2, checksum_bad);
270 PROTO_ITEM_SET_GENERATED(checksum_item);
274 while (tvb_reported_length_remaining(tvb, offset) != 0) {
275 type = tvb_get_ntohs(tvb, offset + TLV_TYPE);
276 length = tvb_get_ntohs(tvb, offset + TLV_LENGTH);
279 tlvi = proto_tree_add_text(cdp_tree, tvb, offset, 4,
280 "TLV with invalid length %u (< 4)",
282 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
283 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
284 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
295 col_append_fstr(pinfo->cinfo, COL_INFO,
297 tvb_format_stringzpad(tvb, offset + 4, length - 4));
300 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
301 length, "Device ID: %s",
302 tvb_format_stringzpad(tvb, offset + 4, length - 4));
303 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
304 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
305 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
306 proto_tree_add_item(tlv_tree, hf_cdp_deviceid, tvb, offset + 4, length - 4, FALSE);
312 real_length = length;
313 if (tvb_get_guint8(tvb, offset + real_length) != 0x00) {
314 /* The length in the TLV doesn't appear to be the
315 length of the TLV, as the byte just past it
316 isn't the first byte of a 2-byte big-endian
317 small integer; make the length of the TLV the length
318 in the TLV, plus 4 bytes for the TLV type and length,
319 minus 1 because that's what makes one capture work. */
320 real_length = length + 3;
323 col_append_fstr(pinfo->cinfo, COL_INFO,
325 tvb_format_stringzpad(tvb, offset + 4,
329 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
330 real_length, "Port ID: %s",
331 tvb_format_text(tvb, offset + 4, real_length - 4));
332 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
333 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
334 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
335 proto_tree_add_item(tlv_tree, hf_cdp_portid, tvb, offset + 4, real_length - 4, FALSE);
337 offset += real_length;
343 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
344 length, "Addresses");
345 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
346 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
347 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
351 naddresses = tvb_get_ntohl(tvb, offset);
353 proto_tree_add_text(tlv_tree, tvb, offset, 4,
354 "Number of addresses: %u", naddresses);
358 while (naddresses != 0) {
359 addr_length = dissect_address_tlv(tvb, offset, length,
363 offset += addr_length;
364 length -= addr_length;
371 case TYPE_CAPABILITIES:
373 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
374 length, "Capabilities");
375 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
376 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
377 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
381 dissect_capabilities(tvb, offset, length, tlv_tree);
385 case TYPE_IOS_VERSION:
387 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
388 length, "Software Version");
389 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
390 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
391 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
392 add_multi_line_string_to_tree(tlv_tree, tvb, offset + 4,
393 length - 4, "Software Version: ");
401 tlvi = proto_tree_add_text(cdp_tree, tvb,
402 offset, length, "Platform: %s",
403 tvb_format_text(tvb, offset + 4, length - 4));
404 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
405 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
406 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
407 proto_tree_add_item(tlv_tree, hf_cdp_platform, tvb, offset + 4, length - 4, FALSE);
414 /* if length is 8 then this is default gw not prefix */
416 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
417 length, "ODR Default gateway: %s",
418 ip_to_str(tvb_get_ptr(tvb, offset+4, 4)));
419 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
420 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
421 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
422 proto_tree_add_text(tlv_tree, tvb, offset+4, 4,
423 "ODR Default gateway = %s",
424 ip_to_str(tvb_get_ptr(tvb, offset+4, 4)));
429 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
430 length, "IP Prefixes: %d",length/5);
432 /* the actual number of prefixes is (length-4)/5
433 but if the variable is not a "float" but "integer"
434 then length/5=(length-4)/5 :) */
436 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
437 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
438 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
444 proto_tree_add_text(tlv_tree, tvb, offset, 5,
446 ip_to_str(tvb_get_ptr(tvb, offset, 4)),
447 tvb_get_guint8(tvb,offset+4));
455 case TYPE_PROTOCOL_HELLO:
457 tlvi = proto_tree_add_text(cdp_tree, tvb,
458 offset,length, "Protocol Hello: %s",
459 val_to_str(tvb_get_ntohs(tvb, offset+7), type_hello_vals, "Unknown (0x%04x)"));
460 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
461 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
462 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
463 proto_tree_add_text(tlv_tree, tvb, offset+4, 3,
465 tvb_get_ntoh24(tvb,offset+4),
466 val_to_str(tvb_get_ntoh24(tvb,offset+4), oui_vals, "Unknown"));
467 proto_tree_add_text(tlv_tree, tvb, offset+7, 2,
468 "Protocol ID: 0x%04X (%s)",
469 tvb_get_ntohs(tvb, offset+7),
470 val_to_str(tvb_get_ntohs(tvb, offset+7), type_hello_vals, "Unknown"));
472 switch(tvb_get_ntohs(tvb, offset+7)) {
474 case TYPE_HELLO_CLUSTER_MGMT:
475 /* proto_tree_add_text(tlv_tree, tvb, offset+9,
476 length - 9, "Cluster Management");
478 ip_addr = tvb_get_ipv4(tvb, offset+9);
479 proto_tree_add_text(tlv_tree, tvb, offset+9, 4,
480 "Cluster Master IP: %s",ip_to_str((guint8 *)&ip_addr));
481 ip_addr = tvb_get_ipv4(tvb, offset+13);
482 proto_tree_add_text(tlv_tree, tvb, offset+13, 4,
483 "UNKNOWN (IP?): 0x%08X (%s)",
484 ip_addr, ip_to_str((guint8 *)&ip_addr));
485 proto_tree_add_text(tlv_tree, tvb, offset+17, 1,
487 tvb_get_guint8(tvb, offset+17));
488 proto_tree_add_text(tlv_tree, tvb, offset+18, 1,
489 "Sub Version?: 0x%02X",
490 tvb_get_guint8(tvb, offset+18));
491 proto_tree_add_text(tlv_tree, tvb, offset+19, 1,
493 tvb_get_guint8(tvb, offset+19));
494 proto_tree_add_text(tlv_tree, tvb, offset+20, 1,
496 tvb_get_guint8(tvb, offset+20));
497 proto_tree_add_text(tlv_tree, tvb, offset+21, 6,
498 "Cluster Commander MAC: %s",
499 ether_to_str(tvb_get_ptr(tvb, offset+21, 6)));
500 proto_tree_add_text(tlv_tree, tvb, offset+27, 6,
502 ether_to_str(tvb_get_ptr(tvb, offset+27, 6)));
503 proto_tree_add_text(tlv_tree, tvb, offset+33, 1,
505 tvb_get_guint8(tvb, offset+33));
506 proto_tree_add_text(tlv_tree, tvb, offset+34, 2,
507 "Management VLAN: %d",
508 tvb_get_ntohs(tvb, offset+34));
511 proto_tree_add_text(tlv_tree, tvb, offset + 9,
512 length - 9, "Unknown");
519 case TYPE_VTP_MGMT_DOMAIN:
521 tlvi = proto_tree_add_text(cdp_tree, tvb,
522 offset, length, "VTP Management Domain: %s",
523 tvb_format_text(tvb, offset + 4, length - 4));
524 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
525 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
526 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
527 proto_tree_add_text(tlv_tree, tvb, offset + 4,
528 length - 4, "VTP Management Domain: %s",
529 tvb_format_text(tvb, offset + 4, length - 4));
534 case TYPE_NATIVE_VLAN:
536 tlvi = proto_tree_add_text(cdp_tree, tvb,
537 offset, length, "Native VLAN: %u",
538 tvb_get_ntohs(tvb, offset + 4));
539 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
540 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
541 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
542 proto_tree_add_text(tlv_tree, tvb, offset + 4,
543 length - 4, "Native VLAN: %u",
544 tvb_get_ntohs(tvb, offset + 4));
551 tlvi = proto_tree_add_text(cdp_tree, tvb,
552 offset, length, "Duplex: %s",
553 tvb_get_guint8(tvb, offset + 4) ?
555 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
556 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
557 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
558 proto_tree_add_text(tlv_tree, tvb, offset + 4,
559 length - 4, "Duplex: %s",
560 tvb_get_guint8(tvb, offset + 4) ?
566 case TYPE_VOIP_VLAN_REPLY:
569 tlvi = proto_tree_add_text(cdp_tree, tvb, offset, length,
570 "VoIP VLAN Reply: %u", tvb_get_ntohs(tvb, offset + 5));
573 * XXX - what are these? I've seen them in some captures;
574 * they have a length of 6, and run up to the end of
575 * the packet, so if we try to dissect it the same way
576 * we dissect the 7-byte ones, we report a malformed
579 tlvi = proto_tree_add_text(cdp_tree, tvb,
580 offset, length, "VoIP VLAN Reply");
582 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
583 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
584 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
585 proto_tree_add_text(tlv_tree, tvb, offset + 4,
588 proto_tree_add_text(tlv_tree, tvb, offset + 5,
590 tvb_get_ntohs(tvb, offset + 5));
596 case TYPE_VOIP_VLAN_QUERY:
599 tlvi = proto_tree_add_text(cdp_tree, tvb,
600 offset, length, "VoIP VLAN Query: %u", tvb_get_ntohs(tvb, offset + 5));
603 * XXX - what are these? I've seen them in some captures;
604 * they have a length of 6, and run up to the end of
605 * the packet, so if we try to dissect it the same way
606 * we dissect the 7-byte ones, we report a malformed
609 tlvi = proto_tree_add_text(cdp_tree, tvb,
610 offset, length, "VoIP VLAN Query");
612 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
613 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
614 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
615 proto_tree_add_text(tlv_tree, tvb, offset + 4,
618 proto_tree_add_text(tlv_tree, tvb, offset + 5,
620 tvb_get_ntohs(tvb, offset + 5));
628 tlvi = proto_tree_add_text(cdp_tree, tvb,
629 offset, length, "Power Consumption: %u mW",
630 tvb_get_ntohs(tvb, offset + 4));
631 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
632 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
633 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
634 proto_tree_add_text(tlv_tree, tvb, offset + 4,
635 length - 4, "Power Consumption: %u mW",
636 tvb_get_ntohs(tvb, offset + 4));
643 tlvi = proto_tree_add_text(cdp_tree, tvb,
644 offset, length, "MTU: %u",
645 tvb_get_ntohl(tvb,offset + 4));
646 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
647 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
648 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
649 proto_tree_add_text(tlv_tree, tvb, offset + 4,
650 length - 4, "MTU: %u",
651 tvb_get_ntohl(tvb,offset + 4));
656 case TYPE_TRUST_BITMAP:
658 tlvi = proto_tree_add_text(cdp_tree, tvb,
659 offset, length, "Trust Bitmap: 0x%02X",
660 tvb_get_guint8(tvb, offset + 4));
661 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
662 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
663 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
664 proto_tree_add_text(tlv_tree, tvb, offset + 4,
665 length - 4, "Trust Bitmap: %02x",
666 tvb_get_guint8(tvb, offset + 4));
671 case TYPE_UNTRUSTED_COS:
673 tlvi = proto_tree_add_text(cdp_tree, tvb,
674 offset, length, "Untrusted port CoS: 0x%02X",
675 tvb_get_guint8(tvb, offset + 4));
676 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
677 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
678 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
679 proto_tree_add_text(tlv_tree, tvb, offset + 4,
680 length - 4, "Untrusted port CoS: %02x",
681 tvb_get_guint8(tvb, offset + 4));
686 case TYPE_SYSTEM_NAME:
688 tlvi = proto_tree_add_text(cdp_tree, tvb,
689 offset, length, "System Name: %s",
690 tvb_format_text(tvb, offset + 4, length - 4));
691 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
692 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
693 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
694 proto_tree_add_text(tlv_tree, tvb, offset + 4,
695 length - 4, "System Name: %s",
696 tvb_format_text(tvb, offset + 4, length - 4));
701 case TYPE_SYSTEM_OID:
703 tlvi = proto_tree_add_text(cdp_tree, tvb,
704 offset, length, "System Object Identifier");
705 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
706 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
707 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
708 proto_tree_add_text(tlv_tree, tvb, offset + 4,
709 length - 4, "System Object Identifier: %s",
710 tvb_bytes_to_str(tvb, offset + 4, length - 4));
715 case TYPE_MANAGEMENT_ADDR:
717 tlvi = proto_tree_add_text(cdp_tree, tvb,
718 offset, length, "Management Addresses");
719 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
720 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
721 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
725 naddresses = tvb_get_ntohl(tvb, offset);
727 proto_tree_add_text(tlv_tree, tvb, offset, 4,
728 "Number of addresses: %u", naddresses);
732 while (naddresses != 0) {
733 addr_length = dissect_address_tlv(tvb, offset, length,
737 offset += addr_length;
738 length -= addr_length;
747 tlvi = proto_tree_add_text(cdp_tree, tvb,
748 offset, length, "Location: %s",
749 tvb_format_text(tvb, offset + 5, length - 5));
750 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
751 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
752 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
753 proto_tree_add_text(tlv_tree, tvb, offset + 4,
754 1 , "UNKNOWN: 0x%02X",
755 tvb_get_guint8(tvb, offset + 4));
756 proto_tree_add_text(tlv_tree, tvb, offset + 5,
757 length - 5, "Location: %s",
758 tvb_format_text(tvb, offset + 5, length - 5));
763 case TYPE_POWER_REQUESTED:
765 tlvi = proto_tree_add_text(cdp_tree, tvb,
766 offset, length, "Power Request: ");
767 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
768 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
769 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
770 proto_tree_add_text(tlv_tree, tvb, offset + 4,
772 tvb_get_ntohs(tvb, offset + 4));
773 proto_tree_add_text(tlv_tree, tvb, offset + 6,
774 2, "Management-ID: %u",
775 tvb_get_ntohs(tvb, offset + 6));
777 power_req_len = (tvb_get_ntohs(tvb, offset + TLV_LENGTH)) - 8;
778 /* Move offset to where the list of Power Request Values Exist */
780 while(power_req_len) {
781 if (power_req_len > 4) {
782 power_req = tvb_get_ntohl(tvb, offset);
784 proto_tree_add_text(tlv_tree, tvb, offset,
785 4, "Power Requested: %u mW", power_req);
786 proto_item_append_text(tlvi, "%u mW, ", power_req);
791 if (power_req_len == 4) {
792 power_req = tvb_get_ntohl(tvb, offset);
794 proto_tree_add_text(tlv_tree, tvb, offset,
795 4, "Power Requested: %u mW", power_req);
796 proto_item_append_text(tlvi, "%u mW", power_req);
799 offset += power_req_len;
805 case TYPE_POWER_AVAILABLE:
807 tlvi = proto_tree_add_text(cdp_tree, tvb,
808 offset, length, "Power Available: ");
809 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
810 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
811 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
812 proto_tree_add_text(tlv_tree, tvb, offset + 4,
814 tvb_get_ntohs(tvb, offset + 4));
815 proto_tree_add_text(tlv_tree, tvb, offset + 6,
816 2, "Management-ID: %u",
817 tvb_get_ntohs(tvb, offset + 6));
819 power_avail_len = (tvb_get_ntohs(tvb, offset + TLV_LENGTH)) - 8;
820 /* Move offset to where the list of Power Available Values Exist */
822 while(power_avail_len) {
823 if (power_avail_len >= 4) {
824 power_avail = tvb_get_ntohl(tvb, offset);
826 proto_tree_add_text(tlv_tree, tvb, offset,
827 4, "Power Available: %u mW", power_avail);
828 proto_item_append_text(tlvi, "%u mW, ", power_avail);
830 power_avail_len -= 4;
833 offset += power_avail_len;
841 tlvi = proto_tree_add_text(cdp_tree, tvb,
842 offset, length, "EnergyWise");
843 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
844 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
845 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
846 proto_tree_add_text(tlv_tree, tvb, offset + 4,
847 20, "Encrypted Data");
848 proto_tree_add_text(tlv_tree, tvb, offset + 24,
849 4, "Unknown (Seen Sequence?): %u",
850 tvb_get_ntohl(tvb, offset + 24));
851 proto_tree_add_text(tlv_tree, tvb, offset + 28,
852 4, "Sequence Number: %u",
853 tvb_get_ntohl(tvb, offset + 28));
854 proto_tree_add_text(tlv_tree, tvb, offset + 32,
855 16, "Model Number: %s",
856 tvb_format_stringzpad(tvb, offset + 32, 16));
857 proto_tree_add_text(tlv_tree, tvb, offset + 48,
858 2, "Unknown Pad: %x",
859 tvb_get_ntohs(tvb, offset + 48));
860 proto_tree_add_text(tlv_tree, tvb, offset + 50,
861 3, "Hardware Version ID: %s",
862 tvb_format_stringzpad(tvb, offset + 50, 3));
863 proto_tree_add_text(tlv_tree, tvb, offset + 53,
864 11, "System Serial Number: %s",
865 tvb_format_stringzpad(tvb, offset + 53, 11));
866 proto_tree_add_text(tlv_tree, tvb, offset + 64,
867 8, "Unknown Values");
868 proto_tree_add_text(tlv_tree, tvb, offset + 72,
869 2, "Length of TLV table: %u",
870 tvb_get_ntohs(tvb, offset + 72));
871 proto_tree_add_text(tlv_tree, tvb, offset + 74,
872 2, "Number of TLVs in table: %u",
873 tvb_get_ntohs(tvb, offset + 74));
875 proto_tree_add_text(tlv_tree, tvb,
876 offset + 76, length - 76,
877 "EnergyWise TLV Table");
879 dissect_nrgyz_tlv(tvb, offset + 76,
880 tvb_get_ntohs(tvb, offset + 72),
881 tvb_get_ntohs(tvb, offset + 74),
891 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
892 length, "Type: %s, length: %u",
893 val_to_str(type, type_vals, "Unknown (0x%04x)"),
895 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
896 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype, tvb, offset + TLV_TYPE, 2, FALSE);
897 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength, tvb, offset + TLV_LENGTH, 2, FALSE);
899 proto_tree_add_text(tlv_tree, tvb, offset + 4,
908 call_dissector(data_handle, tvb_new_subset_remaining(tvb, offset), pinfo,
912 #define PROTO_TYPE_NLPID 1
913 #define PROTO_TYPE_IEEE_802_2 2
915 static const value_string proto_type_vals[] = {
916 { PROTO_TYPE_NLPID, "NLPID" },
917 { PROTO_TYPE_IEEE_802_2, "802.2" },
922 dissect_address_tlv(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
925 proto_tree *address_tree;
926 guint8 protocol_type;
927 guint8 protocol_length;
929 const char *protocol_str;
930 guint16 address_length;
931 const char *address_type_str;
932 const char *address_str;
936 ti = proto_tree_add_text(tree, tvb, offset, length, "Truncated address");
937 address_tree = proto_item_add_subtree(ti, ett_cdp_address);
938 protocol_type = tvb_get_guint8(tvb, offset);
939 proto_tree_add_text(address_tree, tvb, offset, 1, "Protocol type: %s",
940 val_to_str(protocol_type, proto_type_vals, "Unknown (0x%02x)"));
946 protocol_length = tvb_get_guint8(tvb, offset);
947 proto_tree_add_text(address_tree, tvb, offset, 1, "Protocol length: %u",
952 if (length < protocol_length) {
954 proto_tree_add_text(address_tree, tvb, offset, length,
955 "Protocol: %s (truncated)",
956 tvb_bytes_to_str(tvb, offset, length));
961 if (protocol_type == PROTO_TYPE_NLPID && protocol_length == 1) {
962 nlpid = tvb_get_guint8(tvb, offset);
963 protocol_str = val_to_str(nlpid, nlpid_vals, "Unknown (0x%02x)");
966 if (protocol_str == NULL)
967 protocol_str = tvb_bytes_to_str(tvb, offset, protocol_length);
968 proto_tree_add_text(address_tree, tvb, offset, protocol_length,
969 "Protocol: %s", protocol_str);
970 offset += protocol_length;
971 length -= protocol_length;
975 address_length = tvb_get_ntohs(tvb, offset);
976 proto_tree_add_text(address_tree, tvb, offset, 2, "Address length: %u",
981 if (length < address_length) {
983 proto_tree_add_text(address_tree, tvb, offset, length,
984 "Address: %s (truncated)",
985 tvb_bytes_to_str(tvb, offset, length));
989 /* XXX - the Cisco document seems to be saying that, for 802.2-format
990 protocol types, 0xAAAA03 0x000000 0x0800 is IPv6, but 0x0800 is
991 the Ethernet protocol type for IPv4. */
992 length = 2 + protocol_length + 2 + address_length;
993 address_type_str = NULL;
995 if (protocol_type == PROTO_TYPE_NLPID && protocol_length == 1) {
998 /* XXX - dissect NLPID_ISO8473_CLNP as OSI CLNP address? */
1001 if (address_length == 4) {
1002 /* The address is an IP address. */
1003 address_type_str = "IP address";
1004 address_str = ip_to_str(tvb_get_ptr(tvb, offset, 4));
1009 if (address_type_str == NULL)
1010 address_type_str = "Address";
1011 if (address_str == NULL) {
1012 address_str = tvb_bytes_to_str(tvb, offset, address_length);
1014 proto_item_set_text(ti, "%s: %s", address_type_str, address_str);
1015 proto_tree_add_text(address_tree, tvb, offset, address_length, "%s: %s",
1016 address_type_str, address_str);
1017 return 2 + protocol_length + 2 + address_length;
1021 dissect_capabilities(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
1024 proto_tree *capabilities_tree;
1025 guint32 capabilities;
1029 capabilities = tvb_get_ntohl(tvb, offset);
1030 ti = proto_tree_add_text(tree, tvb, offset, length, "Capabilities: 0x%08x",
1032 capabilities_tree = proto_item_add_subtree(ti, ett_cdp_capabilities);
1033 proto_tree_add_text(capabilities_tree, tvb, offset, 4, "%s",
1034 decode_boolean_bitfield(capabilities, 0x01, 4*8,
1037 proto_tree_add_text(capabilities_tree, tvb, offset, 4, "%s",
1038 decode_boolean_bitfield(capabilities, 0x02, 4*8,
1039 "Is a Transparent Bridge",
1040 "Not a Transparent Bridge"));
1041 proto_tree_add_text(capabilities_tree, tvb, offset, 4, "%s",
1042 decode_boolean_bitfield(capabilities, 0x04, 4*8,
1043 "Is a Source Route Bridge",
1044 "Not a Source Route Bridge"));
1045 proto_tree_add_text(capabilities_tree, tvb, offset, 4, "%s",
1046 decode_boolean_bitfield(capabilities, 0x08, 4*8,
1049 proto_tree_add_text(capabilities_tree, tvb, offset, 4, "%s",
1050 decode_boolean_bitfield(capabilities, 0x10, 4*8,
1053 proto_tree_add_text(capabilities_tree, tvb, offset, 4, "%s",
1054 decode_boolean_bitfield(capabilities, 0x20, 4*8,
1056 "Not IGMP capable"));
1057 proto_tree_add_text(capabilities_tree, tvb, offset, 4, "%s",
1058 decode_boolean_bitfield(capabilities, 0x40, 4*8,
1064 dissect_nrgyz_tlv(tvbuff_t *tvb, int offset, guint16 length, guint16 num,
1067 guint32 tlvt, tlvl, ip_addr;
1068 proto_item *it = NULL;
1069 proto_tree *etree = NULL;
1070 char const *ttext = NULL;
1072 while (num-- && length >= 8) {
1073 tlvt = tvb_get_ntohl(tvb, offset);
1074 tlvl = tvb_get_ntohl(tvb, offset + 4);
1076 if (length < tlvl) break;
1080 proto_tree_add_text(tree, tvb, offset, 8,
1081 "TLV with invalid length %u (< 8)",
1087 ttext = val_to_str(tlvt, type_nrgyz_vals, "Unknown (0x%04x)");
1089 case TYPE_NRGYZ_ROLE:
1090 case TYPE_NRGYZ_DOMAIN:
1091 case TYPE_NRGYZ_NAME:
1092 it = proto_tree_add_text(tree, tvb, offset,
1093 tlvl, "EnergyWise %s: %s", ttext,
1094 tvb_format_stringzpad(tvb,
1095 offset + 8, tlvl - 8)
1098 case TYPE_NRGYZ_REPLYTO:
1099 ip_addr = tvb_get_ipv4(tvb, offset + 12);
1100 it = proto_tree_add_text(tree, tvb, offset,
1101 tlvl, "EnergyWise %s: %s port %u",
1103 ip_to_str((guint8 *)&ip_addr),
1104 tvb_get_ntohs(tvb, offset + 10)
1108 it = proto_tree_add_text(tree, tvb, offset,
1109 tlvl, "EnergyWise %s TLV", ttext);
1111 etree = proto_item_add_subtree(it, ett_cdp_nrgyz_tlv);
1112 proto_tree_add_text(etree, tvb, offset, 4,
1113 "TLV Type: %x (%s)", tlvt, ttext);
1114 proto_tree_add_text(etree, tvb, offset + 4, 4,
1115 "TLV Length: %u", tlvl);
1117 case TYPE_NRGYZ_ROLE:
1118 case TYPE_NRGYZ_DOMAIN:
1119 case TYPE_NRGYZ_NAME:
1120 proto_tree_add_text(etree, tvb, offset + 8,
1121 tlvl - 8, "%s %s", ttext,
1122 tvb_format_stringzpad(tvb,
1123 offset + 8, tlvl - 8)
1126 case TYPE_NRGYZ_REPLYTO:
1127 ip_addr = tvb_get_ipv4(tvb, offset + 12);
1128 proto_tree_add_text(etree, tvb, offset + 8, 2,
1130 proto_tree_add_text(etree, tvb, offset + 10, 2,
1132 tvb_get_ntohs(tvb, offset + 10)
1134 proto_tree_add_text(etree, tvb, offset + 12, 4,
1136 ip_to_str((guint8 *)&ip_addr)
1138 proto_tree_add_text(etree, tvb, offset + 16, 2,
1139 "Unknown Field (Backup server Port?)");
1140 proto_tree_add_text(etree, tvb, offset + 18, 4,
1141 "Unknown Field (Backup Server IP?)");
1145 proto_tree_add_text(etree, tvb, offset + 8,
1153 proto_tree_add_text(tree, tvb, offset, length,
1154 "Invalid garbage at end");
1159 add_multi_line_string_to_tree(proto_tree *tree, tvbuff_t *tvb, gint start,
1160 gint len, const gchar *prefix)
1169 prefix_len = (int)strlen(prefix);
1170 if (prefix_len > 64)
1172 for (i = 0; i < prefix_len; i++)
1176 line_len = tvb_find_line_end(tvb, start, len, &next, FALSE);
1177 data_len = next - start;
1178 proto_tree_add_text(tree, tvb, start, data_len, "%s%s", prefix,
1179 tvb_format_stringzpad(tvb, start, line_len));
1187 proto_register_cdp(void)
1189 static hf_register_info hf[] = {
1191 { "Version", "cdp.version", FT_UINT8, BASE_DEC, NULL, 0x0,
1195 { "TTL", "cdp.ttl", FT_UINT16, BASE_DEC, NULL, 0x0,
1199 { "Checksum", "cdp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
1202 { &hf_cdp_checksum_good,
1203 { "Good", "cdp.checksum_good", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1204 "True: checksum matches packet content; False: doesn't match content or not checked", HFILL }},
1206 { &hf_cdp_checksum_bad,
1207 { "Bad", "cdp.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1208 "True: checksum doesn't match packet content; False: matches content or not checked", HFILL }},
1211 { "Type", "cdp.tlv.type", FT_UINT16, BASE_HEX, VALS(type_vals), 0x0,
1214 { &hf_cdp_tlvlength,
1215 { "Length", "cdp.tlv.len", FT_UINT16, BASE_DEC, NULL, 0x0,
1219 {"Device ID", "cdp.deviceid", FT_STRING, BASE_NONE,
1220 NULL, 0, NULL, HFILL }},
1223 {"Platform", "cdp.platform", FT_STRING, BASE_NONE,
1224 NULL, 0, NULL, HFILL }},
1227 {"Sent through Interface", "cdp.portid", FT_STRING, BASE_NONE,
1228 NULL, 0, NULL, HFILL }}
1230 static gint *ett[] = {
1235 &ett_cdp_capabilities,
1239 proto_cdp = proto_register_protocol("Cisco Discovery Protocol",
1241 proto_register_field_array(proto_cdp, hf, array_length(hf));
1242 proto_register_subtree_array(ett, array_length(ett));
1246 proto_reg_handoff_cdp(void)
1248 dissector_handle_t cdp_handle;
1250 data_handle = find_dissector("data");
1251 cdp_handle = create_dissector_handle(dissect_cdp, proto_cdp);
1252 dissector_add("llc.cisco_pid", 0x2000, cdp_handle);
1253 dissector_add("chdlctype", 0x2000, cdp_handle);
1254 dissector_add("ppp.protocol", 0x0207, cdp_handle);