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;
69 static gint ett_cdp = -1;
70 static gint ett_cdp_tlv = -1;
71 static gint ett_cdp_address = -1;
72 static gint ett_cdp_capabilities = -1;
73 static gint ett_cdp_checksum = -1;
75 static dissector_handle_t data_handle;
78 dissect_address_tlv(tvbuff_t *tvb, int offset, int length, proto_tree *tree);
80 dissect_capabilities(tvbuff_t *tvb, int offset, int length, proto_tree *tree);
82 add_multi_line_string_to_tree(proto_tree *tree, tvbuff_t *tvb, gint start,
83 gint len, const gchar *prefix);
85 #define TYPE_DEVICE_ID 0x0001
86 #define TYPE_ADDRESS 0x0002
87 #define TYPE_PORT_ID 0x0003
88 #define TYPE_CAPABILITIES 0x0004
89 #define TYPE_IOS_VERSION 0x0005
90 #define TYPE_PLATFORM 0x0006
91 #define TYPE_IP_PREFIX 0x0007
92 #define TYPE_PROTOCOL_HELLO 0x0008 /* Protocol Hello */
93 #define TYPE_VTP_MGMT_DOMAIN 0x0009 /* VTP Domain, CTPv2 - see second URL */
94 #define TYPE_NATIVE_VLAN 0x000a /* Native VLAN, CTPv2 - see second URL */
95 #define TYPE_DUPLEX 0x000b /* Full/Half Duplex - see second URL */
98 #define TYPE_VOIP_VLAN_REPLY 0x000e /* VoIP VLAN reply */
99 #define TYPE_VOIP_VLAN_QUERY 0x000f /* VoIP VLAN query */
100 #define TYPE_POWER 0x0010 /* Power consumption */
101 #define TYPE_MTU 0x0011 /* MTU */
102 #define TYPE_TRUST_BITMAP 0x0012 /* Trust bitmap */
103 #define TYPE_UNTRUSTED_COS 0x0013 /* Untrusted port CoS */
104 #define TYPE_SYSTEM_NAME 0x0014 /* System Name */
105 #define TYPE_SYSTEM_OID 0x0015 /* System OID */
106 #define TYPE_MANAGEMENT_ADDR 0x0016 /* Management Address(es) */
107 #define TYPE_LOCATION 0x0017 /* Location */
110 static const value_string type_vals[] = {
111 { TYPE_DEVICE_ID, "Device ID" },
112 { TYPE_ADDRESS, "Addresses" },
113 { TYPE_PORT_ID, "Port ID" },
114 { TYPE_CAPABILITIES, "Capabilities" },
115 { TYPE_IOS_VERSION, "Software version" },
116 { TYPE_PLATFORM, "Platform" },
117 { TYPE_IP_PREFIX, "IP Prefix/Gateway (used for ODR)" },
118 { TYPE_PROTOCOL_HELLO, "Protocol Hello" },
119 { TYPE_VTP_MGMT_DOMAIN, "VTP Management Domain" },
120 { TYPE_NATIVE_VLAN, "Native VLAN" },
121 { TYPE_DUPLEX, "Duplex" },
123 { TYPE_VOIP_VLAN_REPLY, "VoIP VLAN Reply" },
124 { TYPE_VOIP_VLAN_QUERY, "VoIP VLAN Query" },
125 { TYPE_POWER, "Power consumption" },
127 { TYPE_TRUST_BITMAP, "Trust Bitmap" },
128 { TYPE_UNTRUSTED_COS, "Untrusted Port CoS" },
129 { TYPE_SYSTEM_NAME, "System Name" },
130 { TYPE_SYSTEM_OID, "System Object ID" },
131 { TYPE_MANAGEMENT_ADDR, "Management Address" },
132 { TYPE_LOCATION, "Location" },
136 #define TYPE_HELLO_CLUSTER_MGMT 0x0112
138 static const value_string type_hello_vals[] = {
139 { TYPE_HELLO_CLUSTER_MGMT, "Cluster Management" },
144 dissect_cdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
146 proto_item *ti, *checksum_item;
147 proto_tree *cdp_tree = NULL, *checksum_tree;
150 guint16 length, packet_checksum, computed_checksum, data_length;
151 gboolean checksum_good, checksum_bad;
153 proto_tree *tlv_tree;
160 if (check_col(pinfo->cinfo, COL_PROTOCOL))
161 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CDP");
162 if (check_col(pinfo->cinfo, COL_INFO))
163 col_clear(pinfo->cinfo, COL_INFO);
166 ti = proto_tree_add_item(tree, proto_cdp, tvb, offset, -1, FALSE);
167 cdp_tree = proto_item_add_subtree(ti, ett_cdp);
170 proto_tree_add_item(cdp_tree, hf_cdp_version, tvb, offset, 1, FALSE);
173 proto_tree_add_uint_format_value(cdp_tree, hf_cdp_ttl, tvb, offset, 1,
174 tvb_get_guint8(tvb, offset),
176 tvb_get_guint8(tvb, offset));
179 offset += 2; /* The version/ttl fields from above */
182 /* Checksum display & verification code */
183 packet_checksum = tvb_get_ntohs(tvb, offset);
185 data_length = tvb_reported_length(tvb);
187 cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, data_length);
188 cksum_vec[0].len = data_length;
190 computed_checksum = in_cksum(cksum_vec, 1);
191 checksum_good = (computed_checksum == 0);
192 checksum_bad = !checksum_good;
194 checksum_item = proto_tree_add_uint_format(cdp_tree,
195 hf_cdp_checksum, tvb, offset, 2, packet_checksum,
196 "Checksum: 0x%04x [correct]", packet_checksum);
198 checksum_item = proto_tree_add_uint_format(cdp_tree,
199 hf_cdp_checksum, tvb, offset, 2, packet_checksum,
200 "Checksum: 0x%04x [incorrect, should be 0x%04x]",
202 in_cksum_shouldbe(packet_checksum, computed_checksum));
205 checksum_tree = proto_item_add_subtree(checksum_item, ett_cdp_checksum);
206 checksum_item = proto_tree_add_boolean(checksum_tree, hf_cdp_checksum_good,
207 tvb, offset, 2, checksum_good);
208 PROTO_ITEM_SET_GENERATED(checksum_item);
209 checksum_item = proto_tree_add_boolean(checksum_tree, hf_cdp_checksum_bad,
210 tvb, offset, 2, checksum_bad);
211 PROTO_ITEM_SET_GENERATED(checksum_item);
215 while (tvb_reported_length_remaining(tvb, offset) != 0) {
216 type = tvb_get_ntohs(tvb, offset + TLV_TYPE);
217 length = tvb_get_ntohs(tvb, offset + TLV_LENGTH);
220 tlvi = proto_tree_add_text(cdp_tree, tvb, offset, 4,
221 "TLV with invalid length %u (< 4)",
223 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
224 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
225 offset + TLV_TYPE, 2, type);
226 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
227 offset + TLV_LENGTH, 2, length);
238 if(check_col(pinfo->cinfo, COL_INFO))
239 col_append_fstr(pinfo->cinfo, COL_INFO,
241 tvb_format_stringzpad(tvb, offset + 4,
245 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
246 length, "Device ID: %s",
247 tvb_format_stringzpad(tvb, offset + 4, length - 4));
248 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
249 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
250 offset + TLV_TYPE, 2, type);
251 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
252 offset + TLV_LENGTH, 2, length);
253 proto_tree_add_text(tlv_tree, tvb, offset + 4,
254 length - 4, "Device ID: %s",
255 tvb_format_stringzpad(tvb, offset + 4, length - 4));
261 real_length = length;
262 if (tvb_get_guint8(tvb, offset + real_length) != 0x00) {
263 /* The length in the TLV doesn't appear to be the
264 length of the TLV, as the byte just past it
265 isn't the first byte of a 2-byte big-endian
266 small integer; make the length of the TLV the length
267 in the TLV, plus 4 bytes for the TLV type and length,
268 minus 1 because that's what makes one capture work. */
269 real_length = length + 3;
272 if(check_col(pinfo->cinfo, COL_INFO))
273 col_append_fstr(pinfo->cinfo, COL_INFO,
275 tvb_format_stringzpad(tvb, offset + 4,
279 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
280 real_length, "Port ID: %s",
281 tvb_format_text(tvb, offset + 4, real_length - 4));
282 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
283 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
284 offset + TLV_TYPE, 2, type);
285 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
286 offset + TLV_LENGTH, 2, length);
287 proto_tree_add_text(tlv_tree, tvb, offset + 4,
289 "Sent through Interface: %s",
290 tvb_format_text(tvb, offset + 4, real_length - 4));
292 offset += real_length;
298 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
299 length, "Addresses");
300 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
301 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
302 offset + TLV_TYPE, 2, type);
303 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
304 offset + TLV_LENGTH, 2, length);
307 naddresses = tvb_get_ntohl(tvb, offset);
308 proto_tree_add_text(tlv_tree, tvb, offset, 4,
309 "Number of addresses: %u", naddresses);
312 while (naddresses != 0) {
313 addr_length = dissect_address_tlv(tvb, offset, length,
317 offset += addr_length;
318 length -= addr_length;
325 case TYPE_CAPABILITIES:
326 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
327 length, "Capabilities");
328 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
329 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
330 offset + TLV_TYPE, 2, type);
331 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
332 offset + TLV_LENGTH, 2, length);
335 dissect_capabilities(tvb, offset, length, tlv_tree);
339 case TYPE_IOS_VERSION:
340 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
341 length, "Software Version");
342 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
343 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
344 offset + TLV_TYPE, 2, type);
345 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
346 offset + TLV_LENGTH, 2, length);
347 add_multi_line_string_to_tree(tlv_tree, tvb, offset + 4,
348 length - 4, "Software Version: ");
354 tlvi = proto_tree_add_text(cdp_tree, tvb,
355 offset, length, "Platform: %s",
356 tvb_format_text(tvb, offset + 4, length - 4));
357 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
358 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
359 offset + TLV_TYPE, 2, type);
360 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
361 offset + TLV_LENGTH, 2, length);
362 proto_tree_add_text(tlv_tree, tvb, offset + 4,
363 length - 4, "Platform: %s",
364 tvb_format_text(tvb, offset + 4, length - 4));
370 /* if length is 8 then this is default gw not prefix */
371 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
372 length, "ODR Default gateway: %s",
373 ip_to_str(tvb_get_ptr(tvb, offset+4, 4)));
374 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
375 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
376 offset + TLV_TYPE, 2, type);
377 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
378 offset + TLV_LENGTH, 2, length);
379 proto_tree_add_text(tlv_tree, tvb, offset+4, 4,
380 "ODR Default gateway = %s",
381 ip_to_str(tvb_get_ptr(tvb, offset+4, 4)));
384 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
385 length, "IP Prefixes: %d",length/5);
387 /* the actual number of prefixes is (length-4)/5
388 but if the variable is not a "float" but "integer"
389 then length/5=(length-4)/5 :) */
391 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
392 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
393 offset + TLV_TYPE, 2, type);
394 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
395 offset + TLV_LENGTH, 2, length);
399 proto_tree_add_text(tlv_tree, tvb, offset, 5,
401 ip_to_str(tvb_get_ptr(tvb, offset, 4)),
402 tvb_get_guint8(tvb,offset+4));
409 case TYPE_PROTOCOL_HELLO:
410 tlvi = proto_tree_add_text(cdp_tree, tvb,
411 offset,length, "Protocol Hello: %s",
412 val_to_str(tvb_get_ntohs(tvb, offset+7), type_hello_vals, "Unknown (0x%04x)"));
413 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
414 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
415 offset + TLV_TYPE, 2, type);
416 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
417 offset + TLV_LENGTH, 2, length);
418 proto_tree_add_text(tlv_tree, tvb, offset+4, 3,
420 tvb_get_ntoh24(tvb,offset+4),
421 val_to_str(tvb_get_ntoh24(tvb,offset+4), oui_vals, "Unknown"));
422 proto_tree_add_text(tlv_tree, tvb, offset+7, 2,
423 "Protocol ID: 0x%04X (%s)",
424 tvb_get_ntohs(tvb, offset+7),
425 val_to_str(tvb_get_ntohs(tvb, offset+7), type_hello_vals, "Unknown"));
426 switch(tvb_get_ntohs(tvb, offset+7)) {
428 case TYPE_HELLO_CLUSTER_MGMT:
429 /* proto_tree_add_text(tlv_tree, tvb, offset+9,
430 length - 9, "Cluster Management");
432 ip_addr = tvb_get_ipv4(tvb, offset+9);
433 proto_tree_add_text(tlv_tree, tvb, offset+9, 4,
434 "Cluster Master IP: %s",ip_to_str((guint8 *)&ip_addr));
435 ip_addr = tvb_get_ipv4(tvb, offset+13);
436 proto_tree_add_text(tlv_tree, tvb, offset+13, 4,
437 "UNKNOWN (IP?): 0x%08X (%s)",
438 ip_addr, ip_to_str((guint8 *)&ip_addr));
439 proto_tree_add_text(tlv_tree, tvb, offset+17, 1,
441 tvb_get_guint8(tvb, offset+17));
442 proto_tree_add_text(tlv_tree, tvb, offset+18, 1,
443 "Sub Version?: 0x%02X",
444 tvb_get_guint8(tvb, offset+18));
445 proto_tree_add_text(tlv_tree, tvb, offset+19, 1,
447 tvb_get_guint8(tvb, offset+19));
448 proto_tree_add_text(tlv_tree, tvb, offset+20, 1,
450 tvb_get_guint8(tvb, offset+20));
451 proto_tree_add_text(tlv_tree, tvb, offset+21, 6,
452 "Cluster Commander MAC: %s",
453 ether_to_str(tvb_get_ptr(tvb, offset+21, 6)));
454 proto_tree_add_text(tlv_tree, tvb, offset+27, 6,
456 ether_to_str(tvb_get_ptr(tvb, offset+27, 6)));
457 proto_tree_add_text(tlv_tree, tvb, offset+33, 1,
459 tvb_get_guint8(tvb, offset+33));
460 proto_tree_add_text(tlv_tree, tvb, offset+34, 2,
461 "Management VLAN: %d",
462 tvb_get_ntohs(tvb, offset+34));
465 proto_tree_add_text(tlv_tree, tvb, offset + 9,
466 length - 9, "Unknown");
472 case TYPE_VTP_MGMT_DOMAIN:
473 tlvi = proto_tree_add_text(cdp_tree, tvb,
474 offset, length, "VTP Management Domain: %s",
475 tvb_format_text(tvb, offset + 4, length - 4));
476 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
477 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
478 offset + TLV_TYPE, 2, type);
479 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
480 offset + TLV_LENGTH, 2, length);
481 proto_tree_add_text(tlv_tree, tvb, offset + 4,
482 length - 4, "VTP Management Domain: %s",
483 tvb_format_text(tvb, offset + 4, length - 4));
487 case TYPE_NATIVE_VLAN:
488 tlvi = proto_tree_add_text(cdp_tree, tvb,
489 offset, length, "Native VLAN: %u",
490 tvb_get_ntohs(tvb, offset + 4));
491 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
492 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
493 offset + TLV_TYPE, 2, type);
494 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
495 offset + TLV_LENGTH, 2, length);
496 proto_tree_add_text(tlv_tree, tvb, offset + 4,
497 length - 4, "Native VLAN: %u",
498 tvb_get_ntohs(tvb, offset + 4));
503 tlvi = proto_tree_add_text(cdp_tree, tvb,
504 offset, length, "Duplex: %s",
505 tvb_get_guint8(tvb, offset + 4) ?
507 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
508 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
509 offset + TLV_TYPE, 2, type);
510 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
511 offset + TLV_LENGTH, 2, length);
512 proto_tree_add_text(tlv_tree, tvb, offset + 4,
513 length - 4, "Duplex: %s",
514 tvb_get_guint8(tvb, offset + 4) ?
519 case TYPE_VOIP_VLAN_REPLY:
521 tlvi = proto_tree_add_text(cdp_tree, tvb,
522 offset, length, "VoIP VLAN Reply: %u", tvb_get_ntohs(tvb, offset + 5));
525 * XXX - what are these? I've seen them in some captures;
526 * they have a length of 6, and run up to the end of
527 * the packet, so if we try to dissect it the same way
528 * we dissect the 7-byte ones, we report a malformed
531 tlvi = proto_tree_add_text(cdp_tree, tvb,
532 offset, length, "VoIP VLAN Reply");
534 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
535 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
536 offset + TLV_TYPE, 2, type);
537 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
538 offset + TLV_LENGTH, 2, length);
539 proto_tree_add_text(tlv_tree, tvb, offset + 4,
542 proto_tree_add_text(tlv_tree, tvb, offset + 5,
544 tvb_get_ntohs(tvb, offset + 5));
549 case TYPE_VOIP_VLAN_QUERY:
551 tlvi = proto_tree_add_text(cdp_tree, tvb,
552 offset, length, "VoIP VLAN Query: %u", tvb_get_ntohs(tvb, offset + 5));
555 * XXX - what are these? I've seen them in some captures;
556 * they have a length of 6, and run up to the end of
557 * the packet, so if we try to dissect it the same way
558 * we dissect the 7-byte ones, we report a malformed
561 tlvi = proto_tree_add_text(cdp_tree, tvb,
562 offset, length, "VoIP VLAN Query");
564 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
565 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
566 offset + TLV_TYPE, 2, type);
567 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
568 offset + TLV_LENGTH, 2, length);
569 proto_tree_add_text(tlv_tree, tvb, offset + 4,
572 proto_tree_add_text(tlv_tree, tvb, offset + 5,
574 tvb_get_ntohs(tvb, offset + 5));
580 tlvi = proto_tree_add_text(cdp_tree, tvb,
581 offset, length, "Power consumption: %u mW",
582 tvb_get_ntohs(tvb, offset + 4));
583 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
584 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
585 offset + TLV_TYPE, 2, type);
586 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
587 offset + TLV_LENGTH, 2, length);
588 proto_tree_add_text(tlv_tree, tvb, offset + 4,
589 length - 4, "Power consumption: %u mW",
590 tvb_get_ntohs(tvb, offset + 4));
595 tlvi = proto_tree_add_text(cdp_tree, tvb,
596 offset, length, "MTU: %u",
597 tvb_get_ntohl(tvb,offset + 4));
598 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
599 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
600 offset + TLV_TYPE, 2, type);
601 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
602 offset + TLV_LENGTH, 2, length);
603 proto_tree_add_text(tlv_tree, tvb, offset + 4,
604 length - 4, "MTU: %u",
605 tvb_get_ntohl(tvb,offset + 4));
609 case TYPE_TRUST_BITMAP:
610 tlvi = proto_tree_add_text(cdp_tree, tvb,
611 offset, length, "Trust Bitmap: 0x%02X",
612 tvb_get_guint8(tvb, offset + 4));
613 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
614 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
615 offset + TLV_TYPE, 2, type);
616 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
617 offset + TLV_LENGTH, 2, length);
618 proto_tree_add_text(tlv_tree, tvb, offset + 4,
619 length - 4, "Trust Bitmap: %02x",
620 tvb_get_guint8(tvb, offset + 4));
624 case TYPE_UNTRUSTED_COS:
625 tlvi = proto_tree_add_text(cdp_tree, tvb,
626 offset, length, "Untrusted port CoS: 0x%02X",
627 tvb_get_guint8(tvb, offset + 4));
628 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
629 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
630 offset + TLV_TYPE, 2, type);
631 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
632 offset + TLV_LENGTH, 2, length);
633 proto_tree_add_text(tlv_tree, tvb, offset + 4,
634 length - 4, "Untrusted port CoS: %02x",
635 tvb_get_guint8(tvb, offset + 4));
639 case TYPE_SYSTEM_NAME:
640 tlvi = proto_tree_add_text(cdp_tree, tvb,
641 offset, length, "System Name: %s",
642 tvb_format_text(tvb, offset + 4, length - 4));
643 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
644 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
645 offset + TLV_TYPE, 2, type);
646 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
647 offset + TLV_LENGTH, 2, length);
648 proto_tree_add_text(tlv_tree, tvb, offset + 4,
649 length - 4, "System Name: %s",
650 tvb_format_text(tvb, offset + 4, length - 4));
654 case TYPE_SYSTEM_OID:
655 tlvi = proto_tree_add_text(cdp_tree, tvb,
656 offset, length, "System Object Identifier");
657 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
658 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
659 offset + TLV_TYPE, 2, type);
660 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
661 offset + TLV_LENGTH, 2, length);
662 proto_tree_add_text(tlv_tree, tvb, offset + 4,
663 length - 4, "System Object Identifier: %s",
664 tvb_bytes_to_str(tvb, offset + 4, length - 4));
668 case TYPE_MANAGEMENT_ADDR:
669 tlvi = proto_tree_add_text(cdp_tree, tvb,
670 offset, length, "Management Addresses");
671 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
672 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
673 offset + TLV_TYPE, 2, type);
674 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
675 offset + TLV_LENGTH, 2, length);
678 naddresses = tvb_get_ntohl(tvb, offset);
679 proto_tree_add_text(tlv_tree, tvb, offset, 4,
680 "Number of addresses: %u", naddresses);
683 while (naddresses != 0) {
684 addr_length = dissect_address_tlv(tvb, offset, length,
688 offset += addr_length;
689 length -= addr_length;
697 tlvi = proto_tree_add_text(cdp_tree, tvb,
698 offset, length, "Location: %s",
699 tvb_format_text(tvb, offset + 5, length - 5));
700 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
701 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
702 offset + TLV_TYPE, 2, type);
703 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
704 offset + TLV_LENGTH, 2, length);
705 proto_tree_add_text(tlv_tree, tvb, offset + 4,
706 1 , "UNKNOWN: 0x%02X",
707 tvb_get_guint8(tvb, offset + 4));
708 proto_tree_add_text(tlv_tree, tvb, offset + 5,
709 length - 5, "Location: %s",
710 tvb_format_text(tvb, offset + 5, length - 5));
716 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
717 length, "Type: %s, length: %u",
718 val_to_str(type, type_vals, "Unknown (0x%04x)"),
720 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
721 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
722 offset + TLV_TYPE, 2, type);
723 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
724 offset + TLV_LENGTH, 2, length);
726 proto_tree_add_text(tlv_tree, tvb, offset + 4,
733 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo,
737 #define PROTO_TYPE_NLPID 1
738 #define PROTO_TYPE_IEEE_802_2 2
740 static const value_string proto_type_vals[] = {
741 { PROTO_TYPE_NLPID, "NLPID" },
742 { PROTO_TYPE_IEEE_802_2, "802.2" },
747 dissect_address_tlv(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
750 proto_tree *address_tree;
751 guint8 protocol_type;
752 guint8 protocol_length;
754 const char *protocol_str;
755 guint16 address_length;
756 const char *address_type_str;
761 ti = proto_tree_add_text(tree, tvb, offset, length, "Truncated address");
762 address_tree = proto_item_add_subtree(ti, ett_cdp_address);
763 protocol_type = tvb_get_guint8(tvb, offset);
764 proto_tree_add_text(address_tree, tvb, offset, 1, "Protocol type: %s",
765 val_to_str(protocol_type, proto_type_vals, "Unknown (0x%02x)"));
771 protocol_length = tvb_get_guint8(tvb, offset);
772 proto_tree_add_text(address_tree, tvb, offset, 1, "Protocol length: %u",
777 if (length < protocol_length) {
779 proto_tree_add_text(address_tree, tvb, offset, length,
780 "Protocol: %s (truncated)",
781 tvb_bytes_to_str(tvb, offset, length));
786 if (protocol_type == PROTO_TYPE_NLPID && protocol_length == 1) {
787 nlpid = tvb_get_guint8(tvb, offset);
788 protocol_str = val_to_str(nlpid, nlpid_vals, "Unknown (0x%02x)");
791 if (protocol_str == NULL)
792 protocol_str = tvb_bytes_to_str(tvb, offset, protocol_length);
793 proto_tree_add_text(address_tree, tvb, offset, protocol_length,
794 "Protocol: %s", protocol_str);
795 offset += protocol_length;
796 length -= protocol_length;
800 address_length = tvb_get_ntohs(tvb, offset);
801 proto_tree_add_text(address_tree, tvb, offset, 2, "Address length: %u",
806 if (length < address_length) {
808 proto_tree_add_text(address_tree, tvb, offset, length,
809 "Address: %s (truncated)",
810 tvb_bytes_to_str(tvb, offset, length));
814 /* XXX - the Cisco document seems to be saying that, for 802.2-format
815 protocol types, 0xAAAA03 0x000000 0x0800 is IPv6, but 0x0800 is
816 the Ethernet protocol type for IPv4. */
817 length = 2 + protocol_length + 2 + address_length;
818 address_type_str = NULL;
820 if (protocol_type == PROTO_TYPE_NLPID && protocol_length == 1) {
823 /* XXX - dissect NLPID_ISO8473_CLNP as OSI CLNP address? */
826 if (address_length == 4) {
827 /* The address is an IP address. */
828 address_type_str = "IP address";
829 address_str = ip_to_str(tvb_get_ptr(tvb, offset, 4));
834 if (address_type_str == NULL)
835 address_type_str = "Address";
836 if (address_str == NULL) {
837 address_str = tvb_bytes_to_str(tvb, offset, address_length);
839 proto_item_set_text(ti, "%s: %s", address_type_str, address_str);
840 proto_tree_add_text(address_tree, tvb, offset, address_length, "%s: %s",
841 address_type_str, address_str);
842 return 2 + protocol_length + 2 + address_length;
846 dissect_capabilities(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
849 proto_tree *capabilities_tree;
850 guint32 capabilities;
854 capabilities = tvb_get_ntohl(tvb, offset);
855 ti = proto_tree_add_text(tree, tvb, offset, length, "Capabilities: 0x%08x",
857 capabilities_tree = proto_item_add_subtree(ti, ett_cdp_capabilities);
858 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
859 decode_boolean_bitfield(capabilities, 0x01, 4*8,
862 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
863 decode_boolean_bitfield(capabilities, 0x02, 4*8,
864 "Is a Transparent Bridge",
865 "Not a Transparent Bridge"));
866 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
867 decode_boolean_bitfield(capabilities, 0x04, 4*8,
868 "Is a Source Route Bridge",
869 "Not a Source Route Bridge"));
870 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
871 decode_boolean_bitfield(capabilities, 0x08, 4*8,
874 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
875 decode_boolean_bitfield(capabilities, 0x10, 4*8,
878 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
879 decode_boolean_bitfield(capabilities, 0x20, 4*8,
881 "Not IGMP capable"));
882 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
883 decode_boolean_bitfield(capabilities, 0x40, 4*8,
889 add_multi_line_string_to_tree(proto_tree *tree, tvbuff_t *tvb, gint start,
890 gint len, const gchar *prefix)
899 prefix_len = strlen(prefix);
902 for (i = 0; i < prefix_len; i++)
906 line_len = tvb_find_line_end(tvb, start, len, &next, FALSE);
907 data_len = next - start;
908 proto_tree_add_text(tree, tvb, start, data_len, "%s%s", prefix,
909 tvb_format_stringzpad(tvb, start, line_len));
917 proto_register_cdp(void)
919 static hf_register_info hf[] = {
921 { "Version", "cdp.version", FT_UINT8, BASE_DEC, NULL, 0x0,
925 { "TTL", "cdp.ttl", FT_UINT16, BASE_DEC, NULL, 0x0,
929 { "Checksum", "cdp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
932 { &hf_cdp_checksum_good,
933 { "Good", "cdp.checksum_good", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
934 "True: checksum matches packet content; False: doesn't match content or not checked", HFILL }},
936 { &hf_cdp_checksum_bad,
937 { "Bad ", "cdp.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
938 "True: checksum doesn't match packet content; False: matches content or not checked", HFILL }},
941 { "Type", "cdp.tlv.type", FT_UINT16, BASE_HEX, VALS(type_vals), 0x0,
945 { "Length", "cdp.tlv.len", FT_UINT16, BASE_DEC, NULL, 0x0,
948 static gint *ett[] = {
952 &ett_cdp_capabilities,
956 proto_cdp = proto_register_protocol("Cisco Discovery Protocol",
958 proto_register_field_array(proto_cdp, hf, array_length(hf));
959 proto_register_subtree_array(ett, array_length(ett));
963 proto_reg_handoff_cdp(void)
965 dissector_handle_t cdp_handle;
967 data_handle = find_dissector("data");
968 cdp_handle = create_dissector_handle(dissect_cdp, proto_cdp);
969 dissector_add("llc.cisco_pid", 0x2000, cdp_handle);
970 dissector_add("chdlctype", 0x2000, cdp_handle);
971 dissector_add("ppp.protocol", 0x0207, cdp_handle);