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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #include <epan/packet.h>
33 #include <epan/strutil.h>
36 #include <epan/nlpid.h>
42 * http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm#xtocid12
44 * for some information on CDP.
48 * http://www.cisco.com/en/US/products/hw/switches/ps663/products_tech_note09186a0080094713.shtml#cdp
50 * for some more information on CDP version 2.
53 /* Offsets in TLV structure. */
57 static int proto_cdp = -1;
58 static int hf_cdp_version = -1;
59 static int hf_cdp_checksum = -1;
60 static int hf_cdp_ttl = -1;
61 static int hf_cdp_tlvtype = -1;
62 static int hf_cdp_tlvlength = -1;
64 static gint ett_cdp = -1;
65 static gint ett_cdp_tlv = -1;
66 static gint ett_cdp_address = -1;
67 static gint ett_cdp_capabilities = -1;
69 static dissector_handle_t data_handle;
72 dissect_address_tlv(tvbuff_t *tvb, int offset, int length, proto_tree *tree);
74 dissect_capabilities(tvbuff_t *tvb, int offset, int length, proto_tree *tree);
76 add_multi_line_string_to_tree(proto_tree *tree, tvbuff_t *tvb, gint start,
77 gint len, const gchar *prefix);
79 #define TYPE_DEVICE_ID 0x0001
80 #define TYPE_ADDRESS 0x0002
81 #define TYPE_PORT_ID 0x0003
82 #define TYPE_CAPABILITIES 0x0004
83 #define TYPE_IOS_VERSION 0x0005
84 #define TYPE_PLATFORM 0x0006
85 #define TYPE_IP_PREFIX 0x0007
86 #define TYPE_PROTOCOL_HELLO 0x0008 /* Protocol Hello */
87 #define TYPE_VTP_MGMT_DOMAIN 0x0009 /* VTP Domain, CTPv2 - see second URL */
88 #define TYPE_NATIVE_VLAN 0x000a /* Native VLAN, CTPv2 - see second URL */
89 #define TYPE_DUPLEX 0x000b /* Full/Half Duplex - see second URL */
92 #define TYPE_VOIP_VLAN_REPLY 0x000e /* VoIP VLAN reply */
93 #define TYPE_VOIP_VLAN_QUERY 0x000f /* VoIP VLAN query */
94 #define TYPE_POWER 0x0010 /* Power consumption */
95 #define TYPE_MTU 0x0011 /* MTU */
96 #define TYPE_TRUST_BITMAP 0x0012 /* Trust bitmap */
97 #define TYPE_UNTRUSTED_COS 0x0013 /* Untrusted port CoS */
98 #define TYPE_SYSTEM_NAME 0x0014 /* System Name */
99 #define TYPE_SYSTEM_OID 0x0015 /* System OID */
100 #define TYPE_MANAGEMENT_ADDR 0x0016 /* Management Address(es) */
101 #define TYPE_LOCATION 0x0017 /* Location */
104 static const value_string type_vals[] = {
105 { TYPE_DEVICE_ID, "Device ID" },
106 { TYPE_ADDRESS, "Addresses" },
107 { TYPE_PORT_ID, "Port ID" },
108 { TYPE_CAPABILITIES, "Capabilities" },
109 { TYPE_IOS_VERSION, "Software version" },
110 { TYPE_PLATFORM, "Platform" },
111 { TYPE_IP_PREFIX, "IP Prefix/Gateway (used for ODR)" },
112 { TYPE_PROTOCOL_HELLO, "Protocol Hello" },
113 { TYPE_VTP_MGMT_DOMAIN, "VTP Management Domain" },
114 { TYPE_NATIVE_VLAN, "Native VLAN" },
115 { TYPE_DUPLEX, "Duplex" },
116 { TYPE_VOIP_VLAN_REPLY, "VoIP VLAN Reply" },
117 { TYPE_VOIP_VLAN_QUERY, "VoIP VLAN Query" },
118 { TYPE_POWER, "Power consumption" },
120 { TYPE_TRUST_BITMAP, "Trust Bitmap" },
121 { TYPE_UNTRUSTED_COS, "Untrusted Port CoS" },
122 { TYPE_SYSTEM_NAME, "System Name" },
123 { TYPE_SYSTEM_OID, "System Object ID" },
124 { TYPE_MANAGEMENT_ADDR, "Management Address" },
125 { TYPE_LOCATION, "Location" },
129 #define TYPE_HELLO_CLUSTER_MGMT 0x0112
131 static const value_string type_hello_vals[] = {
132 { TYPE_HELLO_CLUSTER_MGMT, "Cluster Management" },
137 dissect_cdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
140 proto_tree *cdp_tree = NULL;
145 proto_tree *tlv_tree;
151 if (check_col(pinfo->cinfo, COL_PROTOCOL))
152 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CDP");
153 if (check_col(pinfo->cinfo, COL_INFO))
154 col_set_str(pinfo->cinfo, COL_INFO, "Cisco Discovery Protocol");
157 ti = proto_tree_add_item(tree, proto_cdp, tvb, offset, -1, FALSE);
158 cdp_tree = proto_item_add_subtree(ti, ett_cdp);
161 proto_tree_add_item(cdp_tree, hf_cdp_version, tvb, offset, 1, FALSE);
163 proto_tree_add_uint_format_value(cdp_tree, hf_cdp_ttl, tvb, offset, 1,
164 tvb_get_guint8(tvb, offset),
166 tvb_get_guint8(tvb, offset));
168 proto_tree_add_item(cdp_tree, hf_cdp_checksum, tvb, offset, 2, FALSE);
171 while (tvb_reported_length_remaining(tvb, offset) != 0) {
172 type = tvb_get_ntohs(tvb, offset + TLV_TYPE);
173 length = tvb_get_ntohs(tvb, offset + TLV_LENGTH);
175 tlvi = proto_tree_add_text(cdp_tree, tvb, offset, 4,
176 "TLV with invalid length %u (< 4)",
178 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
179 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
180 offset + TLV_TYPE, 2, type);
181 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
182 offset + TLV_LENGTH, 2, length);
191 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
192 length, "Device ID: %s",
193 tvb_format_stringzpad(tvb, offset + 4, length - 4));
194 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
195 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
196 offset + TLV_TYPE, 2, type);
197 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
198 offset + TLV_LENGTH, 2, length);
199 proto_tree_add_text(tlv_tree, tvb, offset + 4,
200 length - 4, "Device ID: %s",
201 tvb_format_stringzpad(tvb, offset + 4, length - 4));
207 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
208 length, "Addresses");
209 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
210 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
211 offset + TLV_TYPE, 2, type);
212 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
213 offset + TLV_LENGTH, 2, length);
216 naddresses = tvb_get_ntohl(tvb, offset);
217 proto_tree_add_text(tlv_tree, tvb, offset, 4,
218 "Number of addresses: %u", naddresses);
221 while (naddresses != 0) {
222 addr_length = dissect_address_tlv(tvb, offset, length,
226 offset += addr_length;
227 length -= addr_length;
235 real_length = length;
236 if (tvb_get_guint8(tvb, offset + real_length) != 0x00) {
237 /* The length in the TLV doesn't appear to be the
238 length of the TLV, as the byte just past it
239 isn't the first byte of a 2-byte big-endian
240 small integer; make the length of the TLV the length
241 in the TLV, plus 4 bytes for the TLV type and length,
242 minus 1 because that's what makes one capture work. */
243 real_length = length + 3;
245 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
246 real_length, "Port ID: %s",
247 tvb_format_text(tvb, offset + 4, real_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,
255 "Sent through Interface: %s",
256 tvb_format_text(tvb, offset + 4, real_length - 4));
257 offset += real_length;
260 case TYPE_CAPABILITIES:
261 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
262 length, "Capabilities");
263 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
264 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
265 offset + TLV_TYPE, 2, type);
266 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
267 offset + TLV_LENGTH, 2, length);
270 dissect_capabilities(tvb, offset, length, tlv_tree);
274 case TYPE_IOS_VERSION:
275 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
276 length, "Software Version");
277 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
278 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
279 offset + TLV_TYPE, 2, type);
280 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
281 offset + TLV_LENGTH, 2, length);
282 add_multi_line_string_to_tree(tlv_tree, tvb, offset + 4,
283 length - 4, "Software Version: ");
289 tlvi = proto_tree_add_text(cdp_tree, tvb,
290 offset, length, "Platform: %s",
291 tvb_format_text(tvb, offset + 4, length - 4));
292 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
293 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
294 offset + TLV_TYPE, 2, type);
295 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
296 offset + TLV_LENGTH, 2, length);
297 proto_tree_add_text(tlv_tree, tvb, offset + 4,
298 length - 4, "Platform: %s",
299 tvb_format_text(tvb, offset + 4, length - 4));
304 /* if length is 8 then this is default gw not prefix */
305 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
306 length, "ODR Default gateway: %s",
307 ip_to_str(tvb_get_ptr(tvb, offset+4, 4)));
308 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
309 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
310 offset + TLV_TYPE, 2, type);
311 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
312 offset + TLV_LENGTH, 2, length);
313 proto_tree_add_text(tlv_tree, tvb, offset+4, 4,
314 "ODR Default gateway = %s",
315 ip_to_str(tvb_get_ptr(tvb, offset+4, 4)));
318 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
319 length, "IP Prefixes: %d",length/5);
321 /* the actual number of prefixes is (length-4)/5
322 but if the variable is not a "float" but "integer"
323 then length/5=(length-4)/5 :) */
325 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
326 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
327 offset + TLV_TYPE, 2, type);
328 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
329 offset + TLV_LENGTH, 2, length);
333 proto_tree_add_text(tlv_tree, tvb, offset, 5,
335 ip_to_str(tvb_get_ptr(tvb, offset, 4)),
336 tvb_get_guint8(tvb,offset+4));
342 case TYPE_PROTOCOL_HELLO:
343 tlvi = proto_tree_add_text(cdp_tree, tvb,
344 offset,length, "Protocol Hello: %s",
345 val_to_str(tvb_get_ntohs(tvb, offset+7), type_hello_vals, "Unknown (0x%04x)"));
346 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
347 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
348 offset + TLV_TYPE, 2, type);
349 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
350 offset + TLV_LENGTH, 2, length);
351 proto_tree_add_text(tlv_tree, tvb, offset+4, 3,
353 tvb_get_ntoh24(tvb,offset+4),
354 val_to_str(tvb_get_ntoh24(tvb,offset+4), oui_vals, "Unknown"));
355 proto_tree_add_text(tlv_tree, tvb, offset+7, 2,
356 "Protocol ID: 0x%04X (%s)",
357 tvb_get_ntohs(tvb, offset+7),
358 val_to_str(tvb_get_ntohs(tvb, offset+7), type_hello_vals, "Unknown"));
359 switch(tvb_get_ntohs(tvb, offset+7)) {
360 case TYPE_HELLO_CLUSTER_MGMT:
361 /* proto_tree_add_text(tlv_tree, tvb, offset+9,
362 length - 9, "Cluster Management");
364 ip_addr = tvb_get_ipv4(tvb, offset+9);
365 proto_tree_add_text(tlv_tree, tvb, offset+9, 4,
366 "Cluster Master IP: %s",ip_to_str((guint8 *)&ip_addr));
367 ip_addr = tvb_get_ipv4(tvb, offset+13);
368 proto_tree_add_text(tlv_tree, tvb, offset+13, 4,
369 "UNKNOWN (IP?): 0x%08X (%s)",
370 ip_addr, ip_to_str((guint8 *)&ip_addr));
371 proto_tree_add_text(tlv_tree, tvb, offset+17, 1,
373 tvb_get_guint8(tvb, offset+17));
374 proto_tree_add_text(tlv_tree, tvb, offset+18, 1,
375 "Sub Version?: 0x%02X",
376 tvb_get_guint8(tvb, offset+18));
377 proto_tree_add_text(tlv_tree, tvb, offset+19, 1,
379 tvb_get_guint8(tvb, offset+19));
380 proto_tree_add_text(tlv_tree, tvb, offset+20, 1,
382 tvb_get_guint8(tvb, offset+20));
383 proto_tree_add_text(tlv_tree, tvb, offset+21, 6,
384 "Cluster Commander MAC: %s",
385 ether_to_str(tvb_get_ptr(tvb, offset+21, 6)));
386 proto_tree_add_text(tlv_tree, tvb, offset+27, 6,
388 ether_to_str(tvb_get_ptr(tvb, offset+27, 6)));
389 proto_tree_add_text(tlv_tree, tvb, offset+33, 1,
391 tvb_get_guint8(tvb, offset+33));
392 proto_tree_add_text(tlv_tree, tvb, offset+34, 2,
393 "Management VLAN: %d",
394 tvb_get_ntohs(tvb, offset+34));
397 proto_tree_add_text(tlv_tree, tvb, offset + 9,
398 length - 9, "Unknown");
403 case TYPE_VTP_MGMT_DOMAIN:
404 tlvi = proto_tree_add_text(cdp_tree, tvb,
405 offset, length, "VTP Management Domain: %s",
406 tvb_format_text(tvb, offset + 4, length - 4));
407 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
408 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
409 offset + TLV_TYPE, 2, type);
410 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
411 offset + TLV_LENGTH, 2, length);
412 proto_tree_add_text(tlv_tree, tvb, offset + 4,
413 length - 4, "VTP Management Domain: %s",
414 tvb_format_text(tvb, offset + 4, length - 4));
417 case TYPE_NATIVE_VLAN:
418 tlvi = proto_tree_add_text(cdp_tree, tvb,
419 offset, length, "Native VLAN: %u",
420 tvb_get_ntohs(tvb, offset + 4));
421 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
422 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
423 offset + TLV_TYPE, 2, type);
424 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
425 offset + TLV_LENGTH, 2, length);
426 proto_tree_add_text(tlv_tree, tvb, offset + 4,
427 length - 4, "Native VLAN: %u",
428 tvb_get_ntohs(tvb, offset + 4));
432 tlvi = proto_tree_add_text(cdp_tree, tvb,
433 offset, length, "Duplex: %s",
434 tvb_get_guint8(tvb, offset + 4) ?
436 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
437 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
438 offset + TLV_TYPE, 2, type);
439 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
440 offset + TLV_LENGTH, 2, length);
441 proto_tree_add_text(tlv_tree, tvb, offset + 4,
442 length - 4, "Duplex: %s",
443 tvb_get_guint8(tvb, offset + 4) ?
447 case TYPE_VOIP_VLAN_REPLY:
449 tlvi = proto_tree_add_text(cdp_tree, tvb,
450 offset, length, "VoIP VLAN Reply: %u", tvb_get_ntohs(tvb, offset + 5));
453 * XXX - what are these? I've seen them in some captures;
454 * they have a length of 6, and run up to the end of
455 * the packet, so if we try to dissect it the same way
456 * we dissect the 7-byte ones, we report a malformed
459 tlvi = proto_tree_add_text(cdp_tree, tvb,
460 offset, length, "VoIP VLAN Reply");
462 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
463 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
464 offset + TLV_TYPE, 2, type);
465 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
466 offset + TLV_LENGTH, 2, length);
467 proto_tree_add_text(tlv_tree, tvb, offset + 4,
470 proto_tree_add_text(tlv_tree, tvb, offset + 5,
472 tvb_get_ntohs(tvb, offset + 5));
476 case TYPE_VOIP_VLAN_QUERY:
478 tlvi = proto_tree_add_text(cdp_tree, tvb,
479 offset, length, "VoIP VLAN Query: %u", tvb_get_ntohs(tvb, offset + 5));
482 * XXX - what are these? I've seen them in some captures;
483 * they have a length of 6, and run up to the end of
484 * the packet, so if we try to dissect it the same way
485 * we dissect the 7-byte ones, we report a malformed
488 tlvi = proto_tree_add_text(cdp_tree, tvb,
489 offset, length, "VoIP VLAN Query");
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,
499 proto_tree_add_text(tlv_tree, tvb, offset + 5,
501 tvb_get_ntohs(tvb, offset + 5));
506 tlvi = proto_tree_add_text(cdp_tree, tvb,
507 offset, length, "Power consumption: %u mW",
508 tvb_get_ntohs(tvb, offset + 4));
509 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
510 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
511 offset + TLV_TYPE, 2, type);
512 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
513 offset + TLV_LENGTH, 2, length);
514 proto_tree_add_text(tlv_tree, tvb, offset + 4,
515 length - 4, "Power consumption: %u mW",
516 tvb_get_ntohs(tvb, offset + 4));
520 tlvi = proto_tree_add_text(cdp_tree, tvb,
521 offset, length, "MTU: %u",
522 tvb_get_ntohl(tvb,offset + 4));
523 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
524 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
525 offset + TLV_TYPE, 2, type);
526 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
527 offset + TLV_LENGTH, 2, length);
528 proto_tree_add_text(tlv_tree, tvb, offset + 4,
529 length - 4, "MTU: %u",
530 tvb_get_ntohl(tvb,offset + 4));
533 case TYPE_TRUST_BITMAP:
534 tlvi = proto_tree_add_text(cdp_tree, tvb,
535 offset, length, "Trust Bitmap: 0x%02X",
536 tvb_get_guint8(tvb, offset + 4));
537 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
538 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
539 offset + TLV_TYPE, 2, type);
540 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
541 offset + TLV_LENGTH, 2, length);
542 proto_tree_add_text(tlv_tree, tvb, offset + 4,
543 length - 4, "Trust Bitmap: %02x",
544 tvb_get_guint8(tvb, offset + 4));
547 case TYPE_UNTRUSTED_COS:
548 tlvi = proto_tree_add_text(cdp_tree, tvb,
549 offset, length, "Untrusted port CoS: 0x%02X",
550 tvb_get_guint8(tvb, offset + 4));
551 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
552 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
553 offset + TLV_TYPE, 2, type);
554 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
555 offset + TLV_LENGTH, 2, length);
556 proto_tree_add_text(tlv_tree, tvb, offset + 4,
557 length - 4, "Untrusted port CoS: %02x",
558 tvb_get_guint8(tvb, offset + 4));
561 case TYPE_SYSTEM_NAME:
562 tlvi = proto_tree_add_text(cdp_tree, tvb,
563 offset, length, "System Name: %s",
564 tvb_format_text(tvb, offset + 4, length - 4));
565 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
566 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
567 offset + TLV_TYPE, 2, type);
568 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
569 offset + TLV_LENGTH, 2, length);
570 proto_tree_add_text(tlv_tree, tvb, offset + 4,
571 length - 4, "System Name: %s",
572 tvb_format_text(tvb, offset + 4, length - 4));
575 case TYPE_SYSTEM_OID:
576 tlvi = proto_tree_add_text(cdp_tree, tvb,
577 offset, length, "System Object Identifier");
578 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
579 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
580 offset + TLV_TYPE, 2, type);
581 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
582 offset + TLV_LENGTH, 2, length);
583 proto_tree_add_text(tlv_tree, tvb, offset + 4,
584 length - 4, "System Object Identifier: %s",
585 tvb_bytes_to_str(tvb, offset + 4, length - 4));
588 case TYPE_MANAGEMENT_ADDR:
589 tlvi = proto_tree_add_text(cdp_tree, tvb,
590 offset, length, "Management Addresses");
591 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
592 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
593 offset + TLV_TYPE, 2, type);
594 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
595 offset + TLV_LENGTH, 2, length);
598 naddresses = tvb_get_ntohl(tvb, offset);
599 proto_tree_add_text(tlv_tree, tvb, offset, 4,
600 "Number of addresses: %u", naddresses);
603 while (naddresses != 0) {
604 addr_length = dissect_address_tlv(tvb, offset, length,
608 offset += addr_length;
609 length -= addr_length;
616 tlvi = proto_tree_add_text(cdp_tree, tvb,
617 offset, length, "Location: %s",
618 tvb_format_text(tvb, offset + 5, length - 5));
619 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
620 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
621 offset + TLV_TYPE, 2, type);
622 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
623 offset + TLV_LENGTH, 2, length);
624 proto_tree_add_text(tlv_tree, tvb, offset + 4,
625 1 , "UNKNOWN: 0x%02X",
626 tvb_get_guint8(tvb, offset + 4));
627 proto_tree_add_text(tlv_tree, tvb, offset + 5,
628 length - 5, "Location: %s",
629 tvb_format_text(tvb, offset + 5, length - 5));
633 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
634 length, "Type: %s, length: %u",
635 val_to_str(type, type_vals, "Unknown (0x%04x)"),
637 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
638 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
639 offset + TLV_TYPE, 2, type);
640 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
641 offset + TLV_LENGTH, 2, length);
643 proto_tree_add_text(tlv_tree, tvb, offset + 4,
650 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo,
655 #define PROTO_TYPE_NLPID 1
656 #define PROTO_TYPE_IEEE_802_2 2
658 static const value_string proto_type_vals[] = {
659 { PROTO_TYPE_NLPID, "NLPID" },
660 { PROTO_TYPE_IEEE_802_2, "802.2" },
665 dissect_address_tlv(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
668 proto_tree *address_tree;
669 guint8 protocol_type;
670 guint8 protocol_length;
672 const char *protocol_str;
673 guint16 address_length;
674 const char *address_type_str;
679 ti = proto_tree_add_text(tree, tvb, offset, length, "Truncated address");
680 address_tree = proto_item_add_subtree(ti, ett_cdp_address);
681 protocol_type = tvb_get_guint8(tvb, offset);
682 proto_tree_add_text(address_tree, tvb, offset, 1, "Protocol type: %s",
683 val_to_str(protocol_type, proto_type_vals, "Unknown (0x%02x)"));
689 protocol_length = tvb_get_guint8(tvb, offset);
690 proto_tree_add_text(address_tree, tvb, offset, 1, "Protocol length: %u",
695 if (length < protocol_length) {
697 proto_tree_add_text(address_tree, tvb, offset, length,
698 "Protocol: %s (truncated)",
699 tvb_bytes_to_str(tvb, offset, length));
704 if (protocol_type == PROTO_TYPE_NLPID && protocol_length == 1) {
705 nlpid = tvb_get_guint8(tvb, offset);
706 protocol_str = val_to_str(nlpid, nlpid_vals, "Unknown (0x%02x)");
709 if (protocol_str == NULL)
710 protocol_str = tvb_bytes_to_str(tvb, offset, protocol_length);
711 proto_tree_add_text(address_tree, tvb, offset, protocol_length,
712 "Protocol: %s", protocol_str);
713 offset += protocol_length;
714 length -= protocol_length;
718 address_length = tvb_get_ntohs(tvb, offset);
719 proto_tree_add_text(address_tree, tvb, offset, 2, "Address length: %u",
724 if (length < address_length) {
726 proto_tree_add_text(address_tree, tvb, offset, length,
727 "Address: %s (truncated)",
728 tvb_bytes_to_str(tvb, offset, length));
732 /* XXX - the Cisco document seems to be saying that, for 802.2-format
733 protocol types, 0xAAAA03 0x000000 0x0800 is IPv6, but 0x0800 is
734 the Ethernet protocol type for IPv4. */
735 length = 2 + protocol_length + 2 + address_length;
736 address_type_str = NULL;
738 if (protocol_type == PROTO_TYPE_NLPID && protocol_length == 1) {
741 /* XXX - dissect NLPID_ISO8473_CLNP as OSI CLNP address? */
744 if (address_length == 4) {
745 /* The address is an IP address. */
746 address_type_str = "IP address";
747 address_str = ip_to_str(tvb_get_ptr(tvb, offset, 4));
752 if (address_type_str == NULL)
753 address_type_str = "Address";
754 if (address_str == NULL) {
755 address_str = tvb_bytes_to_str(tvb, offset, address_length);
757 proto_item_set_text(ti, "%s: %s", address_type_str, address_str);
758 proto_tree_add_text(address_tree, tvb, offset, address_length, "%s: %s",
759 address_type_str, address_str);
760 return 2 + protocol_length + 2 + address_length;
764 dissect_capabilities(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
767 proto_tree *capabilities_tree;
768 guint32 capabilities;
772 capabilities = tvb_get_ntohl(tvb, offset);
773 ti = proto_tree_add_text(tree, tvb, offset, length, "Capabilities: 0x%08x",
775 capabilities_tree = proto_item_add_subtree(ti, ett_cdp_capabilities);
776 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
777 decode_boolean_bitfield(capabilities, 0x01, 4*8,
780 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
781 decode_boolean_bitfield(capabilities, 0x02, 4*8,
782 "Is a Transparent Bridge",
783 "Not a Transparent Bridge"));
784 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
785 decode_boolean_bitfield(capabilities, 0x04, 4*8,
786 "Is a Source Route Bridge",
787 "Not a Source Route Bridge"));
788 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
789 decode_boolean_bitfield(capabilities, 0x08, 4*8,
792 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
793 decode_boolean_bitfield(capabilities, 0x10, 4*8,
796 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
797 decode_boolean_bitfield(capabilities, 0x20, 4*8,
799 "Not IGMP capable"));
800 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
801 decode_boolean_bitfield(capabilities, 0x40, 4*8,
807 add_multi_line_string_to_tree(proto_tree *tree, tvbuff_t *tvb, gint start,
808 gint len, const gchar *prefix)
817 prefix_len = strlen(prefix);
820 for (i = 0; i < prefix_len; i++)
824 line_len = tvb_find_line_end(tvb, start, len, &next, FALSE);
825 data_len = next - start;
826 proto_tree_add_text(tree, tvb, start, data_len, "%s%s", prefix,
827 tvb_format_stringzpad(tvb, start, line_len));
835 proto_register_cdp(void)
837 static hf_register_info hf[] = {
839 { "Version", "cdp.version", FT_UINT8, BASE_DEC, NULL, 0x0,
843 { "TTL", "cdp.ttl", FT_UINT16, BASE_DEC, NULL, 0x0,
847 { "Checksum", "cdp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
851 { "Type", "cdp.tlv.type", FT_UINT16, BASE_HEX, VALS(type_vals), 0x0,
855 { "Length", "cdp.tlv.len", FT_UINT16, BASE_DEC, NULL, 0x0,
858 static gint *ett[] = {
862 &ett_cdp_capabilities,
865 proto_cdp = proto_register_protocol("Cisco Discovery Protocol",
867 proto_register_field_array(proto_cdp, hf, array_length(hf));
868 proto_register_subtree_array(ett, array_length(ett));
872 proto_reg_handoff_cdp(void)
874 dissector_handle_t cdp_handle;
876 data_handle = find_dissector("data");
877 cdp_handle = create_dissector_handle(dissect_cdp, proto_cdp);
878 dissector_add("llc.cisco_pid", 0x2000, cdp_handle);
879 dissector_add("chdlctype", 0x2000, cdp_handle);
880 dissector_add("ppp.protocol", 0x0207, cdp_handle);