* Routines for the disassembly of the "Cisco Discovery Protocol"
* (c) Copyright Hannes R. Boehm <hannes@boehm.org>
*
- * $Id: packet-cdp.c,v 1.28 2000/12/28 09:49:09 guy Exp $
+ * $Id: packet-cdp.c,v 1.50 2003/10/25 06:07:36 guy Exp $
*
* Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
+ * By Gerald Combs <gerald@ethereal.com>
* Copyright 1998 Gerald Combs
- *
- *
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-
-#include "config.h"
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
+#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <glib.h>
-#include "packet.h"
-#include "strutil.h"
+#include <epan/packet.h>
+#include <epan/strutil.h>
#include "nlpid.h"
/*
* http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm
*
* for some information on CDP.
+ *
+ * See
+ *
+ * http://www.cisco.com/en/US/products/hw/switches/ps663/products_tech_note09186a0080094713.shtml
+ *
+ * for some more information on CDP version 2.
*/
/* Offsets in TLV structure. */
static gint ett_cdp_address = -1;
static gint ett_cdp_capabilities = -1;
+static dissector_handle_t data_handle;
+
static int
dissect_address_tlv(tvbuff_t *tvb, int offset, int length, proto_tree *tree);
static void
#define TYPE_CAPABILITIES 0x0004
#define TYPE_IOS_VERSION 0x0005
#define TYPE_PLATFORM 0x0006
+#define TYPE_IP_PREFIX 0x0007
+
+#define TYPE_VTP_MGMT_DOMAIN 0x0009 /* VTP Domain, CTPv2 - see second URL */
+#define TYPE_NATIVE_VLAN 0x000a /* Native VLAN, CTPv2 - see second URL */
+#define TYPE_DUPLEX 0x000b /* Full/Half Duplex - see second URL */
static const value_string type_vals[] = {
- { TYPE_DEVICE_ID, "Device ID" },
- { TYPE_ADDRESS, "Addresses" },
- { TYPE_PORT_ID, "Port ID" },
- { TYPE_CAPABILITIES, "Capabilities" },
- { TYPE_IOS_VERSION, "Software version" },
- { TYPE_PLATFORM, "Platform" },
- { 0, NULL },
+ { TYPE_DEVICE_ID, "Device ID" },
+ { TYPE_ADDRESS, "Addresses" },
+ { TYPE_PORT_ID, "Port ID" },
+ { TYPE_CAPABILITIES, "Capabilities" },
+ { TYPE_IOS_VERSION, "Software version" },
+ { TYPE_PLATFORM, "Platform" },
+ { TYPE_IP_PREFIX, "IP Prefix (used for ODR)" },
+ { TYPE_VTP_MGMT_DOMAIN, "VTP Management Domain" },
+ { TYPE_NATIVE_VLAN, "Native VLAN" },
+ { TYPE_DUPLEX, "Duplex" },
+ { 0, NULL },
};
-
-static void
+
+static void
dissect_cdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
- proto_item *ti;
+ proto_item *ti;
proto_tree *cdp_tree = NULL;
int offset = 0;
guint16 type;
guint32 naddresses;
int addr_length;
- CHECK_DISPLAY_AS_DATA(proto_cdp, tvb, pinfo, tree);
-
- pinfo->current_proto = "CDP";
-
- if (check_col(pinfo->fd, COL_PROTOCOL))
- col_set_str(pinfo->fd, COL_PROTOCOL, "CDP");
- if (check_col(pinfo->fd, COL_INFO))
- col_set_str(pinfo->fd, COL_INFO, "Cisco Discovery Protocol");
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "CDP");
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "Cisco Discovery Protocol");
if (tree){
- ti = proto_tree_add_item(tree, proto_cdp, tvb, offset,
- tvb_length_remaining(tvb, offset), FALSE);
+ ti = proto_tree_add_item(tree, proto_cdp, tvb, offset, -1, FALSE);
cdp_tree = proto_item_add_subtree(ti, ett_cdp);
-
+
/* CDP header */
proto_tree_add_item(cdp_tree, hf_cdp_version, tvb, offset, 1, FALSE);
offset += 1;
while (tvb_reported_length_remaining(tvb, offset) != 0) {
type = tvb_get_ntohs(tvb, offset + TLV_TYPE);
length = tvb_get_ntohs(tvb, offset + TLV_LENGTH);
+ if (length < 4) {
+ tlvi = proto_tree_add_text(cdp_tree, tvb, offset, 4,
+ "TLV with invalid length %u (< 4)",
+ length);
+ tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
+ proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
+ offset + TLV_TYPE, 2, type);
+ proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
+ offset + TLV_LENGTH, 2, length);
+ offset += 4;
+ break;
+ }
switch (type) {
tvb_get_ptr(tvb, offset + 4, length - 4));
offset += length;
break;
+ case TYPE_IP_PREFIX:
+ tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
+ length, "IP Prefixes: %d",length/5);
+
+ /* the actual number of prefixes is (length-4)/5
+ but if the variable is not a "float" but "integer"
+ then length/5=(length-4)/5 :) */
+ tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
+ proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
+ offset + TLV_TYPE, 2, type);
+ proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
+ offset + TLV_LENGTH, 2, length);
+ offset += 4;
+ length -= 4;
+ while (length > 0) {
+ proto_tree_add_text(tlv_tree, tvb, offset, 5,
+ "IP Prefix = %s/%u",
+ ip_to_str(tvb_get_ptr(tvb, offset, 4)),
+ tvb_get_guint8(tvb,offset+4));
+ offset += 5;
+ length -= 5;
+ }
+ break;
+ case TYPE_VTP_MGMT_DOMAIN:
+ tlvi = proto_tree_add_text(cdp_tree, tvb,
+ offset, length, "VTP Management Domain: %.*s",
+ length - 4,
+ tvb_get_ptr(tvb, offset + 4, length - 4));
+ tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
+ proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
+ offset + TLV_TYPE, 2, type);
+ proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
+ offset + TLV_LENGTH, 2, length);
+ proto_tree_add_text(tlv_tree, tvb, offset + 4,
+ length - 4, "VTP Management Domain: %.*s",
+ length - 4,
+ tvb_get_ptr(tvb, offset + 4, length - 4));
+ offset += length;
+ break;
+ case TYPE_NATIVE_VLAN:
+ tlvi = proto_tree_add_text(cdp_tree, tvb,
+ offset, length, "Native VLAN: %u",
+ tvb_get_ntohs(tvb, offset + 4));
+ tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
+ proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
+ offset + TLV_TYPE, 2, type);
+ proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
+ offset + TLV_LENGTH, 2, length);
+ proto_tree_add_text(tlv_tree, tvb, offset + 4,
+ length - 4, "Native VLAN: %u",
+ tvb_get_ntohs(tvb, offset + 4));
+ offset += length;
+ break;
+ case TYPE_DUPLEX:
+ tlvi = proto_tree_add_text(cdp_tree, tvb,
+ offset, length, "Duplex: %s",
+ tvb_get_guint8(tvb, offset + 4) ?
+ "Full" : "Half" );
+ tlv_tree = proto_item_add_subtree(tlvi, ett_cdp_tlv);
+ proto_tree_add_uint(tlv_tree, hf_cdp_tlvtype, tvb,
+ offset + TLV_TYPE, 2, type);
+ proto_tree_add_uint(tlv_tree, hf_cdp_tlvlength, tvb,
+ offset + TLV_LENGTH, 2, length);
+ proto_tree_add_text(tlv_tree, tvb, offset + 4,
+ length - 4, "Duplex: %s",
+ tvb_get_guint8(tvb, offset + 4) ?
+ "Full" : "Half" );
+ offset += length;
+ break;
default:
tlvi = proto_tree_add_text(cdp_tree, tvb, offset,
length, "Type: %s, length: %u",
offset += length;
}
}
- dissect_data(tvb, offset, pinfo, cdp_tree);
+ call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo,
+ cdp_tree);
}
}
if (length < 1)
return -1;
- ti = proto_tree_add_notext(tree, tvb, offset, length);
+ ti = proto_tree_add_text(tree, tvb, offset, length, "Truncated address");
address_tree = proto_item_add_subtree(ti, ett_cdp_address);
protocol_type = tvb_get_guint8(tvb, offset);
proto_tree_add_text(address_tree, tvb, offset, 1, "Protocol type: %s",
offset += 1;
length -= 1;
- if (length < 1) {
- proto_item_set_text(ti, "Truncated address");
+ if (length < 1)
return -1;
- }
protocol_length = tvb_get_guint8(tvb, offset);
proto_tree_add_text(address_tree, tvb, offset, 1, "Protocol length: %u",
protocol_length);
length -= 1;
if (length < protocol_length) {
- proto_item_set_text(ti, "Truncated address");
if (length != 0) {
proto_tree_add_text(address_tree, tvb, offset, length,
"Protocol: %s (truncated)",
offset += protocol_length;
length -= protocol_length;
- if (length < 2) {
- proto_item_set_text(ti, "Truncated address");
+ if (length < 2)
return -1;
- }
address_length = tvb_get_ntohs(tvb, offset);
proto_tree_add_text(address_tree, tvb, offset, 2, "Address length: %u",
address_length);
length -= 2;
if (length < address_length) {
- proto_item_set_text(ti, "Truncated address");
if (length != 0) {
proto_tree_add_text(address_tree, tvb, offset, length,
"Address: %s (truncated)",
blanks[i] = ' ';
blanks[i] = '\0';
while (len > 0) {
- line_len = tvb_find_line_end(tvb, start, len, &next);
+ line_len = tvb_find_line_end(tvb, start, len, &next, FALSE);
data_len = next - start;
proto_tree_add_text(tree, tvb, start, data_len, "%s%.*s", prefix,
line_len, tvb_get_ptr(tvb, start, line_len));
static hf_register_info hf[] = {
{ &hf_cdp_version,
{ "Version", "cdp.version", FT_UINT8, BASE_DEC, NULL, 0x0,
- "" }},
+ "", HFILL }},
{ &hf_cdp_ttl,
{ "TTL", "cdp.ttl", FT_UINT16, BASE_DEC, NULL, 0x0,
- "" }},
+ "", HFILL }},
{ &hf_cdp_checksum,
{ "Checksum", "cdp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
- "" }},
+ "", HFILL }},
{ &hf_cdp_tlvtype,
{ "Type", "cdp.tlv.type", FT_UINT16, BASE_HEX, VALS(type_vals), 0x0,
- "" }},
+ "", HFILL }},
{ &hf_cdp_tlvlength,
{ "Length", "cdp.tlv.len", FT_UINT16, BASE_DEC, NULL, 0x0,
- "" }},
+ "", HFILL }},
};
static gint *ett[] = {
&ett_cdp,
&ett_cdp_capabilities,
};
- proto_cdp = proto_register_protocol("Cisco Discovery Protocol", "cdp");
+ proto_cdp = proto_register_protocol("Cisco Discovery Protocol",
+ "CDP", "cdp");
proto_register_field_array(proto_cdp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
}
void
proto_reg_handoff_cdp(void)
{
- dissector_add("llc.cisco_pid", 0x2000, dissect_cdp);
+ dissector_handle_t cdp_handle;
+
+ data_handle = find_dissector("data");
+ cdp_handle = create_dissector_handle(dissect_cdp, proto_cdp);
+ dissector_add("llc.cisco_pid", 0x2000, cdp_handle);
+ dissector_add("chdlctype", 0x2000, cdp_handle);
+ dissector_add("ppp.protocol", 0x0207, cdp_handle);
}