2 * Routines for the disassembly of the "Cisco Discovery Protocol"
3 * (c) Copyright Hannes R. Boehm <hannes@boehm.org>
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/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" },
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",
192 tvb_format_stringzpad(tvb, offset + 4, length - 4));
193 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
194 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
195 offset + TLV_TYPE, 2, type);
196 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
197 offset + TLV_LENGTH, 2, length);
198 proto_tree_add_text(tlv_tree, tvb, offset + 4,
199 length - 4, "Device ID: %s",
200 tvb_format_stringzpad(tvb, offset + 4, length - 4));
206 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
207 length, "Addresses");
208 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
209 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
210 offset + TLV_TYPE, 2, type);
211 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
212 offset + TLV_LENGTH, 2, length);
215 naddresses = tvb_get_ntohl(tvb, offset);
216 proto_tree_add_text(tlv_tree, tvb, offset, 4,
217 "Number of addresses: %u", naddresses);
220 while (naddresses != 0) {
221 addr_length = dissect_address_tlv(tvb, offset, length,
225 offset += addr_length;
226 length -= addr_length;
234 real_length = length;
235 if (tvb_get_guint8(tvb, offset + real_length) != 0x00) {
236 /* The length in the TLV doesn't appear to be the
237 length of the TLV, as the byte just past it
238 isn't the first byte of a 2-byte big-endian
239 small integer; make the length of the TLV the length
240 in the TLV, plus 4 bytes for the TLV type and length,
241 minus 1 because that's what makes one capture work. */
242 real_length = length + 3;
244 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
245 real_length, "Port ID: %s",
246 tvb_format_text(tvb, offset + 4, real_length - 4));
247 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
248 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
249 offset + TLV_TYPE, 2, type);
250 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
251 offset + TLV_LENGTH, 2, length);
252 proto_tree_add_text(tlv_tree, tvb, offset + 4,
254 "Sent through Interface: %s",
255 tvb_format_text(tvb, offset + 4, real_length - 4));
256 offset += real_length;
259 case TYPE_CAPABILITIES:
260 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
261 length, "Capabilities");
262 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
263 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
264 offset + TLV_TYPE, 2, type);
265 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
266 offset + TLV_LENGTH, 2, length);
269 dissect_capabilities(tvb, offset, length, tlv_tree);
273 case TYPE_IOS_VERSION:
274 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
275 length, "Software Version");
276 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
277 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
278 offset + TLV_TYPE, 2, type);
279 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
280 offset + TLV_LENGTH, 2, length);
281 add_multi_line_string_to_tree(tlv_tree, tvb, offset + 4,
282 length - 4, "Software Version: ");
288 tlvi = proto_tree_add_text(cdp_tree, tvb,
289 offset, length, "Platform: %s",
290 tvb_format_text(tvb, offset + 4, length - 4));
291 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
292 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
293 offset + TLV_TYPE, 2, type);
294 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
295 offset + TLV_LENGTH, 2, length);
296 proto_tree_add_text(tlv_tree, tvb, offset + 4,
297 length - 4, "Platform: %s",
298 tvb_format_text(tvb, offset + 4, length - 4));
303 /* if length is 8 then this is default gw not prefix */
304 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
305 length, "ODR Default gateway: %s",
306 ip_to_str(tvb_get_ptr(tvb, offset+4, 4)));
307 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
308 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
309 offset + TLV_TYPE, 2, type);
310 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
311 offset + TLV_LENGTH, 2, length);
312 proto_tree_add_text(tlv_tree, tvb, offset+4, 4,
313 "ODR Default gateway = %s",
314 ip_to_str(tvb_get_ptr(tvb, offset+4, 4)));
317 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
318 length, "IP Prefixes: %d",length/5);
320 /* the actual number of prefixes is (length-4)/5
321 but if the variable is not a "float" but "integer"
322 then length/5=(length-4)/5 :) */
324 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
325 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
326 offset + TLV_TYPE, 2, type);
327 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
328 offset + TLV_LENGTH, 2, length);
332 proto_tree_add_text(tlv_tree, tvb, offset, 5,
334 ip_to_str(tvb_get_ptr(tvb, offset, 4)),
335 tvb_get_guint8(tvb,offset+4));
341 case TYPE_PROTOCOL_HELLO:
342 tlvi = proto_tree_add_text(cdp_tree, tvb,
343 offset,length, "Protocol Hello: %s",
344 val_to_str(tvb_get_ntohs(tvb, offset+7), type_hello_vals, "Unknown (0x%04x)"));
345 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
346 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
347 offset + TLV_TYPE, 2, type);
348 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
349 offset + TLV_LENGTH, 2, length);
350 proto_tree_add_text(tlv_tree, tvb, offset+4, 3,
352 tvb_get_ntoh24(tvb,offset+4),
353 val_to_str(tvb_get_ntoh24(tvb,offset+4), oui_vals, "Unknown"));
354 proto_tree_add_text(tlv_tree, tvb, offset+7, 2,
355 "Protocol ID: 0x%04X (%s)",
356 tvb_get_ntohs(tvb, offset+7),
357 val_to_str(tvb_get_ntohs(tvb, offset+7), type_hello_vals, "Unknown"));
358 switch(tvb_get_ntohs(tvb, offset+7)) {
359 case TYPE_HELLO_CLUSTER_MGMT:
360 /* proto_tree_add_text(tlv_tree, tvb, offset+9,
361 length - 9, "Cluster Management");
363 tvb_memcpy(tvb, (guint8 *)&ip_addr, offset+9, 4);
364 proto_tree_add_text(tlv_tree, tvb, offset+9, 4,
365 "Cluster Master IP: %s",ip_to_str((guint8 *)&ip_addr));
366 tvb_memcpy(tvb, (guint8 *)&ip_addr, offset+13, 4);
367 proto_tree_add_text(tlv_tree, tvb, offset+13, 4,
368 "UNKNOWN (IP?): 0x%08X (%s)",
369 ip_addr, ip_to_str((guint8 *)&ip_addr));
370 proto_tree_add_text(tlv_tree, tvb, offset+17, 1,
372 tvb_get_guint8(tvb, offset+17));
373 proto_tree_add_text(tlv_tree, tvb, offset+18, 1,
374 "Sub Version?: 0x%02X",
375 tvb_get_guint8(tvb, offset+18));
376 proto_tree_add_text(tlv_tree, tvb, offset+19, 1,
378 tvb_get_guint8(tvb, offset+19));
379 proto_tree_add_text(tlv_tree, tvb, offset+20, 1,
381 tvb_get_guint8(tvb, offset+20));
382 proto_tree_add_text(tlv_tree, tvb, offset+21, 6,
383 "Cluster Commander MAC: %s",
384 ether_to_str(tvb_get_ptr(tvb, offset+21, 6)));
385 proto_tree_add_text(tlv_tree, tvb, offset+27, 6,
387 ether_to_str(tvb_get_ptr(tvb, offset+27, 6)));
388 proto_tree_add_text(tlv_tree, tvb, offset+33, 1,
390 tvb_get_guint8(tvb, offset+33));
391 proto_tree_add_text(tlv_tree, tvb, offset+34, 2,
392 "Management VLAN: %d",
393 tvb_get_ntohs(tvb, offset+34));
396 proto_tree_add_text(tlv_tree, tvb, offset + 9,
397 length - 9, "Unknown");
402 case TYPE_VTP_MGMT_DOMAIN:
403 tlvi = proto_tree_add_text(cdp_tree, tvb,
404 offset, length, "VTP Management Domain: %s",
405 tvb_format_text(tvb, offset + 4, length - 4));
406 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
407 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
408 offset + TLV_TYPE, 2, type);
409 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
410 offset + TLV_LENGTH, 2, length);
411 proto_tree_add_text(tlv_tree, tvb, offset + 4,
412 length - 4, "VTP Management Domain: %s",
413 tvb_format_text(tvb, offset + 4, length - 4));
416 case TYPE_NATIVE_VLAN:
417 tlvi = proto_tree_add_text(cdp_tree, tvb,
418 offset, length, "Native VLAN: %u",
419 tvb_get_ntohs(tvb, offset + 4));
420 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
421 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
422 offset + TLV_TYPE, 2, type);
423 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
424 offset + TLV_LENGTH, 2, length);
425 proto_tree_add_text(tlv_tree, tvb, offset + 4,
426 length - 4, "Native VLAN: %u",
427 tvb_get_ntohs(tvb, offset + 4));
431 tlvi = proto_tree_add_text(cdp_tree, tvb,
432 offset, length, "Duplex: %s",
433 tvb_get_guint8(tvb, offset + 4) ?
435 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
436 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
437 offset + TLV_TYPE, 2, type);
438 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
439 offset + TLV_LENGTH, 2, length);
440 proto_tree_add_text(tlv_tree, tvb, offset + 4,
441 length - 4, "Duplex: %s",
442 tvb_get_guint8(tvb, offset + 4) ?
446 case TYPE_VOIP_VLAN_REPLY:
447 tlvi = proto_tree_add_text(cdp_tree, tvb,
448 offset, length, "VoIP VLAN Reply");
449 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
450 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
451 offset + TLV_TYPE, 2, type);
452 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
453 offset + TLV_LENGTH, 2, length);
454 proto_tree_add_text(tlv_tree, tvb, offset + 4,
458 case TYPE_VOIP_VLAN_QUERY:
459 tlvi = proto_tree_add_text(cdp_tree, tvb,
460 offset, length, "VoIP VLAN Query");
461 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
462 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
463 offset + TLV_TYPE, 2, type);
464 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
465 offset + TLV_LENGTH, 2, length);
466 proto_tree_add_text(tlv_tree, tvb, offset + 4,
471 tlvi = proto_tree_add_text(cdp_tree, tvb,
472 offset, length, "MTU: %u",
473 tvb_get_ntohl(tvb,offset + 4));
474 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
475 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
476 offset + TLV_TYPE, 2, type);
477 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
478 offset + TLV_LENGTH, 2, length);
479 proto_tree_add_text(tlv_tree, tvb, offset + 4,
480 length - 4, "MTU: %u",
481 tvb_get_ntohl(tvb,offset + 4));
484 case TYPE_TRUST_BITMAP:
485 tlvi = proto_tree_add_text(cdp_tree, tvb,
486 offset, length, "Trust Bitmap: 0x%02X",
487 tvb_get_guint8(tvb, offset + 4));
488 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
489 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
490 offset + TLV_TYPE, 2, type);
491 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
492 offset + TLV_LENGTH, 2, length);
493 proto_tree_add_text(tlv_tree, tvb, offset + 4,
494 length - 4, "Trust Bitmap: %02x",
495 tvb_get_guint8(tvb, offset + 4));
498 case TYPE_UNTRUSTED_COS:
499 tlvi = proto_tree_add_text(cdp_tree, tvb,
500 offset, length, "Untrusted port CoS: 0x%02X",
501 tvb_get_guint8(tvb, offset + 4));
502 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
503 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
504 offset + TLV_TYPE, 2, type);
505 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
506 offset + TLV_LENGTH, 2, length);
507 proto_tree_add_text(tlv_tree, tvb, offset + 4,
508 length - 4, "Untrusted port CoS: %02x",
509 tvb_get_guint8(tvb, offset + 4));
512 case TYPE_SYSTEM_NAME:
513 tlvi = proto_tree_add_text(cdp_tree, tvb,
514 offset, length, "System Name: %s",
515 tvb_format_text(tvb, offset + 4, length - 4));
516 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
517 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
518 offset + TLV_TYPE, 2, type);
519 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
520 offset + TLV_LENGTH, 2, length);
521 proto_tree_add_text(tlv_tree, tvb, offset + 4,
522 length - 4, "System Name: %s",
523 tvb_format_text(tvb, offset + 4, length - 4));
526 case TYPE_SYSTEM_OID:
527 tlvi = proto_tree_add_text(cdp_tree, tvb,
528 offset, length, "System Object Identifier");
529 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
530 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
531 offset + TLV_TYPE, 2, type);
532 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
533 offset + TLV_LENGTH, 2, length);
534 proto_tree_add_text(tlv_tree, tvb, offset + 4,
535 length - 4, "System Object Identifier: %s",
536 tvb_bytes_to_str(tvb, offset + 4, length - 4));
539 case TYPE_MANAGEMENT_ADDR:
540 tlvi = proto_tree_add_text(cdp_tree, tvb,
541 offset, length, "Management Addresses");
542 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
543 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
544 offset + TLV_TYPE, 2, type);
545 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
546 offset + TLV_LENGTH, 2, length);
549 naddresses = tvb_get_ntohl(tvb, offset);
550 proto_tree_add_text(tlv_tree, tvb, offset, 4,
551 "Number of addresses: %u", naddresses);
554 while (naddresses != 0) {
555 addr_length = dissect_address_tlv(tvb, offset, length,
559 offset += addr_length;
560 length -= addr_length;
567 tlvi = proto_tree_add_text(cdp_tree, tvb,
568 offset, length, "Location: %s",
569 tvb_format_text(tvb, offset + 5, length - 5));
570 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
571 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
572 offset + TLV_TYPE, 2, type);
573 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
574 offset + TLV_LENGTH, 2, length);
575 proto_tree_add_text(tlv_tree, tvb, offset + 4,
576 1 , "UNKNOWN: 0x%02X",
577 tvb_get_guint8(tvb, offset + 4));
578 proto_tree_add_text(tlv_tree, tvb, offset + 5,
579 length - 5, "Location: %s",
580 tvb_format_text(tvb, offset + 5, length - 5));
584 tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
585 length, "Type: %s, length: %u",
586 val_to_str(type, type_vals, "Unknown (0x%04x)"),
588 tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
589 proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
590 offset + TLV_TYPE, 2, type);
591 proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
592 offset + TLV_LENGTH, 2, length);
594 proto_tree_add_text(tlv_tree, tvb, offset + 4,
601 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo,
606 #define PROTO_TYPE_NLPID 1
607 #define PROTO_TYPE_IEEE_802_2 2
609 static const value_string proto_type_vals[] = {
610 { PROTO_TYPE_NLPID, "NLPID" },
611 { PROTO_TYPE_IEEE_802_2, "802.2" },
616 dissect_address_tlv(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
619 proto_tree *address_tree;
620 guint8 protocol_type;
621 guint8 protocol_length;
624 guint16 address_length;
625 char *address_type_str;
630 ti = proto_tree_add_text(tree, tvb, offset, length, "Truncated address");
631 address_tree = proto_item_add_subtree(ti, ett_cdp_address);
632 protocol_type = tvb_get_guint8(tvb, offset);
633 proto_tree_add_text(address_tree, tvb, offset, 1, "Protocol type: %s",
634 val_to_str(protocol_type, proto_type_vals, "Unknown (0x%02x)"));
640 protocol_length = tvb_get_guint8(tvb, offset);
641 proto_tree_add_text(address_tree, tvb, offset, 1, "Protocol length: %u",
646 if (length < protocol_length) {
648 proto_tree_add_text(address_tree, tvb, offset, length,
649 "Protocol: %s (truncated)",
650 tvb_bytes_to_str(tvb, offset, length));
655 if (protocol_type == PROTO_TYPE_NLPID && protocol_length == 1) {
656 nlpid = tvb_get_guint8(tvb, offset);
657 protocol_str = val_to_str(nlpid, nlpid_vals, "Unknown (0x%02x)");
660 if (protocol_str == NULL)
661 protocol_str = tvb_bytes_to_str(tvb, offset, protocol_length);
662 proto_tree_add_text(address_tree, tvb, offset, protocol_length,
663 "Protocol: %s", protocol_str);
664 offset += protocol_length;
665 length -= protocol_length;
669 address_length = tvb_get_ntohs(tvb, offset);
670 proto_tree_add_text(address_tree, tvb, offset, 2, "Address length: %u",
675 if (length < address_length) {
677 proto_tree_add_text(address_tree, tvb, offset, length,
678 "Address: %s (truncated)",
679 tvb_bytes_to_str(tvb, offset, length));
683 /* XXX - the Cisco document seems to be saying that, for 802.2-format
684 protocol types, 0xAAAA03 0x000000 0x0800 is IPv6, but 0x0800 is
685 the Ethernet protocol type for IPv4. */
686 length = 2 + protocol_length + 2 + address_length;
687 address_type_str = NULL;
689 if (protocol_type == PROTO_TYPE_NLPID && protocol_length == 1) {
692 /* XXX - dissect NLPID_ISO8473_CLNP as OSI CLNP address? */
695 if (address_length == 4) {
696 /* The address is an IP address. */
697 address_type_str = "IP address";
698 address_str = ip_to_str(tvb_get_ptr(tvb, offset, 4));
703 if (address_type_str == NULL)
704 address_type_str = "Address";
705 if (address_str == NULL) {
706 address_str = tvb_bytes_to_str(tvb, offset, address_length);
708 proto_item_set_text(ti, "%s: %s", address_type_str, address_str);
709 proto_tree_add_text(address_tree, tvb, offset, address_length, "%s: %s",
710 address_type_str, address_str);
711 return 2 + protocol_length + 2 + address_length;
715 dissect_capabilities(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
718 proto_tree *capabilities_tree;
719 guint32 capabilities;
723 capabilities = tvb_get_ntohl(tvb, offset);
724 ti = proto_tree_add_text(tree, tvb, offset, length, "Capabilities: 0x%08x",
726 capabilities_tree = proto_item_add_subtree(ti, ett_cdp_capabilities);
727 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
728 decode_boolean_bitfield(capabilities, 0x01, 4*8,
731 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
732 decode_boolean_bitfield(capabilities, 0x02, 4*8,
733 "Is a Transparent Bridge",
734 "Not a Transparent Bridge"));
735 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
736 decode_boolean_bitfield(capabilities, 0x04, 4*8,
737 "Is a Source Route Bridge",
738 "Not a Source Route Bridge"));
739 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
740 decode_boolean_bitfield(capabilities, 0x08, 4*8,
743 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
744 decode_boolean_bitfield(capabilities, 0x10, 4*8,
747 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
748 decode_boolean_bitfield(capabilities, 0x20, 4*8,
750 "Not IGMP capable"));
751 proto_tree_add_text(capabilities_tree, tvb, offset, 4,
752 decode_boolean_bitfield(capabilities, 0x40, 4*8,
758 add_multi_line_string_to_tree(proto_tree *tree, tvbuff_t *tvb, gint start,
759 gint len, const gchar *prefix)
768 prefix_len = strlen(prefix);
771 for (i = 0; i < prefix_len; i++)
775 line_len = tvb_find_line_end(tvb, start, len, &next, FALSE);
776 data_len = next - start;
777 proto_tree_add_text(tree, tvb, start, data_len, "%s%s", prefix,
778 tvb_format_stringzpad(tvb, start, line_len));
786 proto_register_cdp(void)
788 static hf_register_info hf[] = {
790 { "Version", "cdp.version", FT_UINT8, BASE_DEC, NULL, 0x0,
794 { "TTL", "cdp.ttl", FT_UINT16, BASE_DEC, NULL, 0x0,
798 { "Checksum", "cdp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
802 { "Type", "cdp.tlv.type", FT_UINT16, BASE_HEX, VALS(type_vals), 0x0,
806 { "Length", "cdp.tlv.len", FT_UINT16, BASE_DEC, NULL, 0x0,
809 static gint *ett[] = {
813 &ett_cdp_capabilities,
816 proto_cdp = proto_register_protocol("Cisco Discovery Protocol",
818 proto_register_field_array(proto_cdp, hf, array_length(hf));
819 proto_register_subtree_array(ett, array_length(ett));
823 proto_reg_handoff_cdp(void)
825 dissector_handle_t cdp_handle;
827 data_handle = find_dissector("data");
828 cdp_handle = create_dissector_handle(dissect_cdp, proto_cdp);
829 dissector_add("llc.cisco_pid", 0x2000, cdp_handle);
830 dissector_add("chdlctype", 0x2000, cdp_handle);
831 dissector_add("ppp.protocol", 0x0207, cdp_handle);