2 * Routines for the disassembly of the "Cisco Discovery Protocol"
3 * (c) Copyright Hannes R. Boehm <hannes@boehm.org>
5 * $Id: packet-cdp.c,v 1.52 2004/03/13 09:35:41 guy Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@ethereal.com>
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>
42 * http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm
44 * for some information on CDP.
48 * http://www.cisco.com/en/US/products/hw/switches/ps663/products_tech_note09186a0080094713.shtml
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 */
90 /* Somewhere in here there's a Power Draw TLV */
93 #define TYPE_VOIP_VLAN_REPLY 0x000e /* VoIP VLAN reply */
94 #define TYPE_VOIP_VLAN_QUERY 0x000f /* VoIP VLAN query */
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 (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" },
119 { TYPE_TRUST_BITMAP, "Trust Bitmap" },
120 { TYPE_UNTRUSTED_COS, "Untrusted Port CoS" },
121 { TYPE_SYSTEM_NAME, "System Name" },
122 { TYPE_SYSTEM_OID, "System Object ID" },
123 { TYPE_MANAGEMENT_ADDR, "Management Address" },
124 { TYPE_LOCATION, "Location" },
128 #define TYPE_HELLO_CLUSTER_MGMT 0x0112
130 static const value_string type_hello_vals[] = {
131 { TYPE_HELLO_CLUSTER_MGMT, "Cluster Management" },
136 dissect_cdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
139 proto_tree *cdp_tree = NULL;
144 proto_tree *tlv_tree;
150 if (check_col(pinfo->cinfo, COL_PROTOCOL))
151 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CDP");
152 if (check_col(pinfo->cinfo, COL_INFO))
153 col_set_str(pinfo->cinfo, COL_INFO, "Cisco Discovery Protocol");
156 ti = proto_tree_add_item(tree, proto_cdp, tvb, offset, -1, FALSE);
157 cdp_tree = proto_item_add_subtree(ti, ett_cdp);
160 proto_tree_add_item(cdp_tree, hf_cdp_version, tvb, offset, 1, FALSE);
162 proto_tree_add_uint_format(cdp_tree, hf_cdp_ttl, tvb, offset, 1,
163 tvb_get_guint8(tvb, offset),
165 tvb_get_guint8(tvb, offset));
167 proto_tree_add_item(cdp_tree, hf_cdp_checksum, tvb, offset, 2, FALSE);
170 while (tvb_reported_length_remaining(tvb, offset) != 0) {
171 type = tvb_get_ntohs(tvb, offset + TLV_TYPE);
172 length = tvb_get_ntohs(tvb, offset + TLV_LENGTH);
174 tlvi = proto_tree_add_text(cdp_tree, tvb, offset, 4,
175 "TLV with invalid length %u (< 4)",
177 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
178 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
179 offset + TLV_TYPE, 2, type);
180 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
181 offset + TLV_LENGTH, 2, length);
190 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
191 length, "Device ID: %.*s",
193 tvb_get_ptr(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",
202 tvb_get_ptr(tvb, offset + 4, length - 4));
208 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
209 length, "Addresses");
210 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
211 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
212 offset + TLV_TYPE, 2, type);
213 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
214 offset + TLV_LENGTH, 2, length);
217 naddresses = tvb_get_ntohl(tvb, offset);
218 proto_tree_add_text(tlv_tree, tvb, offset, 4,
219 "Number of addresses: %u", naddresses);
222 while (naddresses != 0) {
223 addr_length = dissect_address_tlv(tvb, offset, length,
227 offset += addr_length;
228 length -= addr_length;
236 real_length = length;
237 if (tvb_get_guint8(tvb, offset + real_length) != 0x00) {
238 /* The length in the TLV doesn't appear to be the
239 length of the TLV, as the byte just past it
240 isn't the first byte of a 2-byte big-endian
241 small integer; make the length of the TLV the length
242 in the TLV, plus 4 bytes for the TLV type and length,
243 minus 1 because that's what makes one capture work. */
244 real_length = length + 3;
246 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
247 real_length, "Port ID: %.*s",
249 tvb_get_ptr(tvb, offset + 4, real_length - 4));
250 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
251 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
252 offset + TLV_TYPE, 2, type);
253 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
254 offset + TLV_LENGTH, 2, length);
255 proto_tree_add_text(tlv_tree, tvb, offset + 4,
257 "Sent through Interface: %.*s",
259 tvb_get_ptr(tvb, offset + 4, real_length - 4));
260 offset += real_length;
263 case TYPE_CAPABILITIES:
264 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
265 length, "Capabilities");
266 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
267 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
268 offset + TLV_TYPE, 2, type);
269 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
270 offset + TLV_LENGTH, 2, length);
273 dissect_capabilities(tvb, offset, length, tlv_tree);
277 case TYPE_IOS_VERSION:
278 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
279 length, "Software Version");
280 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
281 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
282 offset + TLV_TYPE, 2, type);
283 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
284 offset + TLV_LENGTH, 2, length);
285 add_multi_line_string_to_tree(tlv_tree, tvb, offset + 4,
286 length - 4, "Software Version: ");
292 tlvi = proto_tree_add_text(cdp_tree, tvb,
293 offset, length, "Platform: %.*s",
295 tvb_get_ptr(tvb, offset + 4, length - 4));
296 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
297 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
298 offset + TLV_TYPE, 2, type);
299 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
300 offset + TLV_LENGTH, 2, length);
301 proto_tree_add_text(tlv_tree, tvb, offset + 4,
302 length - 4, "Platform: %.*s",
304 tvb_get_ptr(tvb, offset + 4, length - 4));
308 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
309 length, "IP Prefixes: %d",length/5);
311 /* the actual number of prefixes is (length-4)/5
312 but if the variable is not a "float" but "integer"
313 then length/5=(length-4)/5 :) */
315 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
316 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
317 offset + TLV_TYPE, 2, type);
318 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
319 offset + TLV_LENGTH, 2, length);
323 proto_tree_add_text(tlv_tree, tvb, offset, 5,
325 ip_to_str(tvb_get_ptr(tvb, offset, 4)),
326 tvb_get_guint8(tvb,offset+4));
331 case TYPE_PROTOCOL_HELLO:
332 tlvi = proto_tree_add_text(cdp_tree, tvb,
333 offset,length, "Protocol Hello: %s",
334 val_to_str(tvb_get_ntohs(tvb, offset+7), type_hello_vals, "Unknown (0x%04x)"));
335 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
336 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
337 offset + TLV_TYPE, 2, type);
338 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
339 offset + TLV_LENGTH, 2, length);
340 proto_tree_add_text(tlv_tree, tvb, offset+4, 3,
342 tvb_get_ntoh24(tvb,offset+4),
343 val_to_str(tvb_get_ntoh24(tvb,offset+4), oui_vals, "Unknown"));
344 proto_tree_add_text(tlv_tree, tvb, offset+7, 2,
345 "Protocol ID: 0x%04X (%s)",
346 tvb_get_ntohs(tvb, offset+7),
347 val_to_str(tvb_get_ntohs(tvb, offset+7), type_hello_vals, "Unknown"));
348 switch(tvb_get_ntohs(tvb, offset+7)) {
349 case TYPE_HELLO_CLUSTER_MGMT:
350 /* proto_tree_add_text(tlv_tree, tvb, offset+9,
351 length - 9, "Cluster Management");
353 tvb_memcpy(tvb, (guint8 *)&ip_addr, offset+9, 4);
354 proto_tree_add_text(tlv_tree, tvb, offset+9, 4,
355 "Cluster Master IP: %s",ip_to_str((guint8 *)&ip_addr));
356 tvb_memcpy(tvb, (guint8 *)&ip_addr, offset+13, 4);
357 proto_tree_add_text(tlv_tree, tvb, offset+13, 4,
358 "UNKNOWN (IP?): 0x%08X (%s)",
359 ip_addr, ip_to_str((guint8 *)&ip_addr));
360 proto_tree_add_text(tlv_tree, tvb, offset+17, 1,
362 tvb_get_guint8(tvb, offset+17));
363 proto_tree_add_text(tlv_tree, tvb, offset+18, 1,
364 "Sub Version?: 0x%02X",
365 tvb_get_guint8(tvb, offset+18));
366 proto_tree_add_text(tlv_tree, tvb, offset+19, 1,
368 tvb_get_guint8(tvb, offset+19));
369 proto_tree_add_text(tlv_tree, tvb, offset+20, 1,
371 tvb_get_guint8(tvb, offset+20));
372 proto_tree_add_text(tlv_tree, tvb, offset+21, 6,
373 "Cluster Commander MAC: %s",
374 ether_to_str(tvb_get_ptr(tvb, offset+21, 6)));
375 proto_tree_add_text(tlv_tree, tvb, offset+27, 6,
377 ether_to_str(tvb_get_ptr(tvb, offset+27, 6)));
378 proto_tree_add_text(tlv_tree, tvb, offset+33, 1,
380 tvb_get_guint8(tvb, offset+33));
381 proto_tree_add_text(tlv_tree, tvb, offset+34, 2,
382 "Management VLAN: %d",
383 tvb_get_ntohs(tvb, offset+34));
386 proto_tree_add_text(tlv_tree, tvb, offset + 9,
387 length - 9, "Unknown");
392 case TYPE_VTP_MGMT_DOMAIN:
393 tlvi = proto_tree_add_text(cdp_tree, tvb,
394 offset, length, "VTP Management Domain: %.*s",
396 tvb_get_ptr(tvb, offset + 4, length - 4));
397 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
398 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
399 offset + TLV_TYPE, 2, type);
400 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
401 offset + TLV_LENGTH, 2, length);
402 proto_tree_add_text(tlv_tree, tvb, offset + 4,
403 length - 4, "VTP Management Domain: %.*s",
405 tvb_get_ptr(tvb, offset + 4, length - 4));
408 case TYPE_NATIVE_VLAN:
409 tlvi = proto_tree_add_text(cdp_tree, tvb,
410 offset, length, "Native VLAN: %u",
411 tvb_get_ntohs(tvb, offset + 4));
412 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
413 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
414 offset + TLV_TYPE, 2, type);
415 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
416 offset + TLV_LENGTH, 2, length);
417 proto_tree_add_text(tlv_tree, tvb, offset + 4,
418 length - 4, "Native VLAN: %u",
419 tvb_get_ntohs(tvb, offset + 4));
423 tlvi = proto_tree_add_text(cdp_tree, tvb,
424 offset, length, "Duplex: %s",
425 tvb_get_guint8(tvb, offset + 4) ?
427 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
428 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
429 offset + TLV_TYPE, 2, type);
430 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
431 offset + TLV_LENGTH, 2, length);
432 proto_tree_add_text(tlv_tree, tvb, offset + 4,
433 length - 4, "Duplex: %s",
434 tvb_get_guint8(tvb, offset + 4) ?
438 case TYPE_VOIP_VLAN_REPLY:
439 tlvi = proto_tree_add_text(cdp_tree, tvb,
440 offset, length, "VoIP VLAN Reply");
441 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
442 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
443 offset + TLV_TYPE, 2, type);
444 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
445 offset + TLV_LENGTH, 2, length);
446 proto_tree_add_text(tlv_tree, tvb, offset + 4,
450 case TYPE_VOIP_VLAN_QUERY:
451 tlvi = proto_tree_add_text(cdp_tree, tvb,
452 offset, length, "VoIP VLAN Query");
453 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
454 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
455 offset + TLV_TYPE, 2, type);
456 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
457 offset + TLV_LENGTH, 2, length);
458 proto_tree_add_text(tlv_tree, tvb, offset + 4,
463 tlvi = proto_tree_add_text(cdp_tree, tvb,
464 offset, length, "MTU: %u",
465 tvb_get_ntohl(tvb,offset + 4));
466 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
467 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
468 offset + TLV_TYPE, 2, type);
469 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
470 offset + TLV_LENGTH, 2, length);
471 proto_tree_add_text(tlv_tree, tvb, offset + 4,
472 length - 4, "MTU: %u",
473 tvb_get_ntohl(tvb,offset + 4));
476 case TYPE_TRUST_BITMAP:
477 tlvi = proto_tree_add_text(cdp_tree, tvb,
478 offset, length, "Trust Bitmap: 0x%02X",
479 tvb_get_guint8(tvb, offset + 4));
480 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
481 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
482 offset + TLV_TYPE, 2, type);
483 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
484 offset + TLV_LENGTH, 2, length);
485 proto_tree_add_text(tlv_tree, tvb, offset + 4,
486 length - 4, "Trust Bitmap: %02x",
487 tvb_get_guint8(tvb, offset + 4));
490 case TYPE_UNTRUSTED_COS:
491 tlvi = proto_tree_add_text(cdp_tree, tvb,
492 offset, length, "Untrusted port CoS: 0x%02X",
493 tvb_get_guint8(tvb, offset + 4));
494 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
495 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
496 offset + TLV_TYPE, 2, type);
497 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
498 offset + TLV_LENGTH, 2, length);
499 proto_tree_add_text(tlv_tree, tvb, offset + 4,
500 length - 4, "Untrusted port CoS: %02x",
501 tvb_get_guint8(tvb, offset + 4));
504 case TYPE_SYSTEM_NAME:
505 tlvi = proto_tree_add_text(cdp_tree, tvb,
506 offset, length, "System Name: %.*s",
508 tvb_get_ptr(tvb, offset + 4, length - 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, "System Name: %.*s",
517 tvb_get_ptr(tvb, offset + 4, length - 4));
520 case TYPE_SYSTEM_OID:
521 tlvi = proto_tree_add_text(cdp_tree, tvb,
522 offset, length, "System Object Identifier");
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, "System Object Identifier: %s",
530 tvb_bytes_to_str(tvb, offset + 4, length - 4));
533 case TYPE_MANAGEMENT_ADDR:
534 tlvi = proto_tree_add_text(cdp_tree, tvb,
535 offset, length, "Management Addresses");
536 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
537 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
538 offset + TLV_TYPE, 2, type);
539 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
540 offset + TLV_LENGTH, 2, length);
543 naddresses = tvb_get_ntohl(tvb, offset);
544 proto_tree_add_text(tlv_tree, tvb, offset, 4,
545 "Number of addresses: %u", naddresses);
548 while (naddresses != 0) {
549 addr_length = dissect_address_tlv(tvb, offset, length,
553 offset += addr_length;
554 length -= addr_length;
561 tlvi = proto_tree_add_text(cdp_tree, tvb,
562 offset, length, "Location: %.*s",
564 tvb_get_ptr(tvb, offset + 5, length - 5));
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 1 , "UNKNOWN: 0x%02X",
572 tvb_get_guint8(tvb, offset + 4));
573 proto_tree_add_text(tlv_tree, tvb, offset + 5,
574 length - 5, "Location: %.*s",
576 tvb_get_ptr(tvb, offset + 5, length - 5));
580 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
581 length, "Type: %s, length: %u",
582 val_to_str(type, type_vals, "Unknown (0x%04x)"),
584 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
585 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
586 offset + TLV_TYPE, 2, type);
587 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
588 offset + TLV_LENGTH, 2, length);
590 proto_tree_add_text(tlv_tree, tvb, offset + 4,
597 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo,
602 #define PROTO_TYPE_NLPID 1
603 #define PROTO_TYPE_IEEE_802_2 2
605 static const value_string proto_type_vals[] = {
606 { PROTO_TYPE_NLPID, "NLPID" },
607 { PROTO_TYPE_IEEE_802_2, "802.2" },
612 dissect_address_tlv(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
615 proto_tree *address_tree;
616 guint8 protocol_type;
617 guint8 protocol_length;
620 guint16 address_length;
621 char *address_type_str;
626 ti = proto_tree_add_text(tree, tvb, offset, length, "Truncated address");
627 address_tree = proto_item_add_subtree(ti, ett_cdp_address);
628 protocol_type = tvb_get_guint8(tvb, offset);
629 proto_tree_add_text(address_tree, tvb, offset, 1, "Protocol type: %s",
630 val_to_str(protocol_type, proto_type_vals, "Unknown (0x%02x)"));
636 protocol_length = tvb_get_guint8(tvb, offset);
637 proto_tree_add_text(address_tree, tvb, offset, 1, "Protocol length: %u",
642 if (length < protocol_length) {
644 proto_tree_add_text(address_tree, tvb, offset, length,
645 "Protocol: %s (truncated)",
646 tvb_bytes_to_str(tvb, offset, length));
651 if (protocol_type == PROTO_TYPE_NLPID && protocol_length == 1) {
652 nlpid = tvb_get_guint8(tvb, offset);
653 protocol_str = val_to_str(nlpid, nlpid_vals, "Unknown (0x%02x)");
656 if (protocol_str == NULL)
657 protocol_str = tvb_bytes_to_str(tvb, offset, protocol_length);
658 proto_tree_add_text(address_tree, tvb, offset, protocol_length,
659 "Protocol: %s", protocol_str);
660 offset += protocol_length;
661 length -= protocol_length;
665 address_length = tvb_get_ntohs(tvb, offset);
666 proto_tree_add_text(address_tree, tvb, offset, 2, "Address length: %u",
671 if (length < address_length) {
673 proto_tree_add_text(address_tree, tvb, offset, length,
674 "Address: %s (truncated)",
675 tvb_bytes_to_str(tvb, offset, length));
679 /* XXX - the Cisco document seems to be saying that, for 802.2-format
680 protocol types, 0xAAAA03 0x000000 0x0800 is IPv6, but 0x0800 is
681 the Ethernet protocol type for IPv4. */
682 length = 2 + protocol_length + 2 + address_length;
683 address_type_str = NULL;
685 if (protocol_type == PROTO_TYPE_NLPID && protocol_length == 1) {
688 /* XXX - dissect NLPID_ISO8473_CLNP as OSI CLNP address? */
691 if (address_length == 4) {
692 /* The address is an IP address. */
693 address_type_str = "IP address";
694 address_str = ip_to_str(tvb_get_ptr(tvb, offset, 4));
699 if (address_type_str == NULL)
700 address_type_str = "Address";
701 if (address_str == NULL) {
702 address_str = tvb_bytes_to_str(tvb, offset, address_length);
704 proto_item_set_text(ti, "%s: %s", address_type_str, address_str);
705 proto_tree_add_text(address_tree, tvb, offset, address_length, "%s: %s",
706 address_type_str, address_str);
707 return 2 + protocol_length + 2 + address_length;
711 dissect_capabilities(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
714 proto_tree *capabilities_tree;
715 guint32 capabilities;
719 capabilities = tvb_get_ntohl(tvb, offset);
720 ti = proto_tree_add_text(tree, tvb, offset, length, "Capabilities: 0x%08x",
722 capabilities_tree = proto_item_add_subtree(ti, ett_cdp_capabilities);
723 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
724 decode_boolean_bitfield(capabilities, 0x01, 4*8,
727 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
728 decode_boolean_bitfield(capabilities, 0x02, 4*8,
729 "Is a Transparent Bridge",
730 "Not a Transparent Bridge"));
731 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
732 decode_boolean_bitfield(capabilities, 0x04, 4*8,
733 "Is a Source Route Bridge",
734 "Not a Source Route Bridge"));
735 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
736 decode_boolean_bitfield(capabilities, 0x08, 4*8,
739 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
740 decode_boolean_bitfield(capabilities, 0x10, 4*8,
743 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
744 decode_boolean_bitfield(capabilities, 0x20, 4*8,
746 "Not IGMP capable"));
747 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
748 decode_boolean_bitfield(capabilities, 0x40, 4*8,
754 add_multi_line_string_to_tree(proto_tree *tree, tvbuff_t *tvb, gint start,
755 gint len, const gchar *prefix)
764 prefix_len = strlen(prefix);
767 for (i = 0; i < prefix_len; i++)
771 line_len = tvb_find_line_end(tvb, start, len, &next, FALSE);
772 data_len = next - start;
773 proto_tree_add_text(tree, tvb, start, data_len, "%s%.*s", prefix,
774 line_len, tvb_get_ptr(tvb, start, line_len));
782 proto_register_cdp(void)
784 static hf_register_info hf[] = {
786 { "Version", "cdp.version", FT_UINT8, BASE_DEC, NULL, 0x0,
790 { "TTL", "cdp.ttl", FT_UINT16, BASE_DEC, NULL, 0x0,
794 { "Checksum", "cdp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
798 { "Type", "cdp.tlv.type", FT_UINT16, BASE_HEX, VALS(type_vals), 0x0,
802 { "Length", "cdp.tlv.len", FT_UINT16, BASE_DEC, NULL, 0x0,
805 static gint *ett[] = {
809 &ett_cdp_capabilities,
812 proto_cdp = proto_register_protocol("Cisco Discovery Protocol",
814 proto_register_field_array(proto_cdp, hf, array_length(hf));
815 proto_register_subtree_array(ett, array_length(ett));
819 proto_reg_handoff_cdp(void)
821 dissector_handle_t cdp_handle;
823 data_handle = find_dissector("data");
824 cdp_handle = create_dissector_handle(dissect_cdp, proto_cdp);
825 dissector_add("llc.cisco_pid", 0x2000, cdp_handle);
826 dissector_add("chdlctype", 0x2000, cdp_handle);
827 dissector_add("ppp.protocol", 0x0207, cdp_handle);