wireshark/epan/dissectors/packet-eigrp.c
Evan Huus a252026213 Fix minor issue introduced with conversion to new expert API in r51688.
Specifically, proto_tree_add_expert() must take an actual tree node (for example
from proto_item_add_subtree()) and cannot take just any old item node. The
original intent (before the conversion) appeared to be just to put it on the
tree, so do that.

Another assertion gone from
https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=9406

svn path=/trunk/; revision=53456
2013-11-20 22:51:14 +00:00

3358 lines
127 KiB
C

/* packet-eigrp.c
* Routines for EIGRP dissection
* Copyright 2011, Donnie V Savage <dsavage@cisco.com>
*
* Complete re-write and replaces previous file of same name authored by:
* Copyright 2009, Jochen Bartl <jochen.bartl@gmail.co
* Copyright 2000, Paul Ionescu <paul@acorp.ro>
*
* $Id$
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <glib.h>
#include <epan/packet.h>
#include <epan/guid-utils.h>
#include <epan/addr_resolv.h>
#include <epan/atalk-utils.h>
#include <epan/addr_and_mask.h>
#include <epan/ipproto.h>
#include <epan/tfs.h>
#include <epan/expert.h>
#include <epan/reassemble.h>
#include "packet-ipx.h"
#include "packet-osi.h"
/**
* EIGRP Header size in bytes
*/
#define EIGRP_HEADER_LENGTH 20
/**
* EIGRP Packet Opcodes
*/
#define EIGRP_OPC_UPDATE 1 /*!< packet containing routing information */
#define EIGRP_OPC_REQUEST 2 /*!< sent to request one or more routes */
#define EIGRP_OPC_QUERY 3 /*!< sent when a routing is in active start */
#define EIGRP_OPC_REPLY 4 /*!< sent in response to a query */
#define EIGRP_OPC_HELLO 5 /*!< sent to maintain a peering session */
#define EIGRP_OPC_IPXSAP 6 /*!< IPX SAP information */
#define EIGRP_OPC_PROBE 7 /*!< for test purposes */
#define EIGRP_OPC_ACK 8 /*!< acknowledge */
#define EIGRP_OPC_STUB 9 /*!< peering operating in restricted mode */
#define EIGRP_OPC_SIAQUERY 10 /*!< QUERY - with relaxed restrictions */
#define EIGRP_OPC_SIAREPLY 11 /*!< REPLY - may contain old routing information */
/**
* EIGRP TLV Range definitions
* PDM TLV Range
* General 0x0000
* IPv4 0x0100 ** TLVs for one and all
* ATALK 0x0200 ** legacy
* IPX 0x0300 ** discontinued
* IPv6 0x0400 ** legacy
* Multiprotocol 0x0600 ** wide metrics
* MultiTopology 0x00f0 ** deprecated
*/
#define EIGRP_TLV_RANGEMASK 0xfff0 /*!< should be 0xff00 - opps */
#define EIGRP_TLV_GENERAL 0x0000
/**
* 1.2 TLV Definitions ** legacy
* These have been deprecated and should not be used for future packets
*/
#define EIGRP_TLV_IPv4 0x0100 /*!< Classic IPv4 TLV encoding */
#define EIGRP_TLV_ATALK 0x0200 /*!< Classic Appletalk TLV encoding*/
#define EIGRP_TLV_IPX 0x0300 /*!< Classic IPX TLV encoding */
#define EIGRP_TLV_IPv6 0x0400 /*!< Classic IPv6 TLV encoding */
/**
* 2.0 Multi-Protocol TLV Definitions
* These have been deprecated and should not be used for future packets
*/
#define EIGRP_TLV_MP 0x0600 /*!< Non-PDM specific encoding */
/**
* 3.0 TLV Definitions ** deprecated
* These have been deprecated and should not be used for future packets
*/
#define EIGRP_TLV_MTR 0x00f0 /*!< MTR TLV encoding */
/**
* TLV type definitions. Generic (protocol-independent) TLV types are
* defined here. Protocol-specific ones are defined elsewhere.
*/
#define EIGRP_TLV_PARAMETER (EIGRP_TLV_GENERAL | 0x0001) /*!< eigrp parameters */
#define EIGRP_TLV_AUTH (EIGRP_TLV_GENERAL | 0x0002) /*!< authentication */
#define EIGRP_TLV_SEQ (EIGRP_TLV_GENERAL | 0x0003) /*!< sequenced packet */
#define EIGRP_TLV_SW_VERSION (EIGRP_TLV_GENERAL | 0x0004) /*!< software version */
#define EIGRP_TLV_NEXT_MCAST_SEQ (EIGRP_TLV_GENERAL | 0x0005) /*!< */
#define EIGRP_TLV_PEER_STUBINFO (EIGRP_TLV_GENERAL | 0x0006) /*!< stub information */
#define EIGRP_TLV_PEER_TERMINATION (EIGRP_TLV_GENERAL | 0x0007) /*!< peer termination */
#define EIGRP_TLV_PEER_TIDLIST (EIGRP_TLV_GENERAL | 0x0008) /*!< peer sub-topology list */
/**
* Route Based TLVs
*/
#define EIGRP_TLV_TYPEMASK 0x000f
#define EIGRP_TLV_REQUEST 0x0001
#define EIGRP_TLV_INTERNAL 0x0002
#define EIGRP_TLV_EXTERNAL 0x0003
#define EIGRP_TLV_COMMUNITY 0x0004
/* Legacy TLV formats */
#define EIGRP_TLV_IPv4_REQ (EIGRP_TLV_IPv4 | EIGRP_TLV_REQUEST)
#define EIGRP_TLV_IPv4_INT (EIGRP_TLV_IPv4 | EIGRP_TLV_INTERNAL)
#define EIGRP_TLV_IPv4_EXT (EIGRP_TLV_IPv4 | EIGRP_TLV_EXTERNAL)
#define EIGRP_TLV_IPv4_COM (EIGRP_TLV_IPv4 | EIGRP_TLV_COMMUNITY)
#define EIGRP_TLV_IPX_INT (EIGRP_TLV_IPX | EIGRP_TLV_INTERNAL)
#define EIGRP_TLV_IPX_EXT (EIGRP_TLV_IPX | EIGRP_TLV_EXTERNAL)
#define EIGRP_TLV_IPX_COM (EIGRP_TLV_IPX | EIGRP_TLV_COMMUNITY)
#define EIGRP_TLV_IPv6_INT (EIGRP_TLV_IPv6 | EIGRP_TLV_INTERNAL)
#define EIGRP_TLV_IPv6_EXT (EIGRP_TLV_IPv6 | EIGRP_TLV_EXTERNAL)
#define EIGRP_TLV_IPv6_COM (EIGRP_TLV_IPv6 | EIGRP_TLV_COMMUNITY)
/* Deprecated TLV formats */
#define EIGRP_TLV_AT_INT (EIGRP_TLV_ATALK | EIGRP_TLV_INTERNAL)
#define EIGRP_TLV_AT_EXT (EIGRP_TLV_ATALK | EIGRP_TLV_EXTERNAL)
#define EIGRP_TLV_AT_CBL (EIGRP_TLV_ATALK | 0x04)
#define EIGRP_TLV_MTR_REQ (EIGRP_TLV_MTR | EIGRP_TLV_REQUEST)
#define EIGRP_TLV_MTR_INT (EIGRP_TLV_MTR | EIGRP_TLV_INTERNAL)
#define EIGRP_TLV_MTR_EXT (EIGRP_TLV_MTR | EIGRP_TLV_EXTERNAL)
#define EIGRP_TLV_MTR_COM (EIGRP_TLV_MTR | EIGRP_TLV_COMMUNITY)
#define EIGRP_TLV_MTR_TIDLIST (EIGRP_TLV_MTR | 0x0005)
/* Current "Wide Metric" TLV formats */
#define EIGRP_TLV_MP_REQ (EIGRP_TLV_MP | EIGRP_TLV_REQUEST)
#define EIGRP_TLV_MP_INT (EIGRP_TLV_MP | EIGRP_TLV_INTERNAL)
#define EIGRP_TLV_MP_EXT (EIGRP_TLV_MP | EIGRP_TLV_EXTERNAL)
#define EIGRP_TLV_MP_COM (EIGRP_TLV_MP | EIGRP_TLV_COMMUNITY)
/**
* External routes originate from some other protocol - these are them
*/
#define NULL_PROTID 0 /*!< unknown protocol */
#define IGRP1_PROTID 1 /*!< IGRP.. whos your daddy! */
#define IGRP2_PROTID 2 /*!< EIGRP - Just flat out the best */
#define STATIC_PROTID 3 /*!< Staticly configured source */
#define RIP_PROTID 4 /*!< Routing Information Protocol */
#define HELLO_PROTID 5 /*!< Hello? RFC-891 you there? */
#define OSPF_PROTID 6 /*!< OSPF - Open Shortest Path First */
#define ISIS_PROTID 7 /*!< Intermediate System To Intermediate System */
#define EGP_PROTID 8 /*!< Exterior Gateway Protocol */
#define BGP_PROTID 9 /*!< Border Gateway Protocol */
#define IDRP_PROTID 10 /*!< InterDomain Routing Protocol */
#define CONN_PROTID 11 /*!< Connected source */
/**
*
* extdata flag field definitions
*/
#define EIGRP_OPAQUE_EXT 0x01 /*!< Route is external */
#define EIGRP_OPAQUE_CD 0x02 /*!< Candidate default route */
/**
* Address-Family types are taken from:
* http://www.iana.org/assignments/address-family-numbers
* to provide a standards based exchange of AFI information between
* EIGRP routers.
*/
#define EIGRP_AF_IPv4 1 /*!< IPv4 (IP version 4) */
#define EIGRP_AF_IPv6 2 /*!< IPv6 (IP version 6) */
#define EIGRP_AF_IPX 11 /*!< IPX */
#define EIGRP_AF_ATALK 12 /*!< Appletalk */
#define EIGRP_SF_COMMON 16384 /*!< Cisco Service Family */
#define EIGRP_SF_IPv4 16385 /*!< Cisco IPv4 Service Family */
#define EIGRP_SF_IPv6 16386 /*!< Cisco IPv6 Service Family */
/**
* Authentication types supported by EIGRP
*/
#define EIGRP_AUTH_TYPE_NONE 0
#define EIGRP_AUTH_TYPE_TEXT 1
#define EIGRP_AUTH_TYPE_MD5 2
#define EIGRP_AUTH_TYPE_MD5_LEN 16
#define EIGRP_AUTH_TYPE_SHA256 3
#define EIGRP_AUTH_TYPE_SHA256_LEN 32
/**
* opaque flag field definitions
*/
#define EIGRP_OPAQUE_SRCWD 0x01 /*!< Route Source Withdraw */
#define EIGRP_OPAQUE_ACTIVE 0x04 /*!< Route is currently in active state */
#define EIGRP_OPAQUE_REPL 0x08 /*!< Route is replicated from different tableid */
/**
* pak flag bit field definitions - 0 (none)-7 source priority
*/
#define EIGRP_PRIV_DEFAULT 0x00 /* 0 (none)-7 source priority */
#define EIGRP_PRIV_LOW 0x01
#define EIGRP_PRIV_MEDIUM 0x04
#define EIGRP_PRIV_HIGH 0x07
/**
* stub bit definitions
*/
#define EIGRP_PEER_ALLOWS_CONNECTED 0x0001
#define EIGRP_PEER_ALLOWS_STATIC 0x0002
#define EIGRP_PEER_ALLOWS_SUMMARY 0x0004
#define EIGRP_PEER_ALLOWS_REDIST 0x0008
#define EIGRP_PEER_ALLOWS_LEAKING 0x0010
#define EIGRP_PEER_ALLOWS_RCVONLY 0x0020
/*
* Init bit definition. First unicast transmitted Update has this
* bit set in the flags field of the fixed header. It tells the neighbor
* to down-load his topology table.
*/
#define EIGRP_INIT_FLAG 0x01
/*
* CR bit (Conditionally Received) definition in flags field on header. Any
* packets with the CR-bit set can be accepted by an EIGRP speaker if and
* only if a previous Hello was received with the SEQUENCE_TYPE TLV present.
*
* This allows multicasts to be transmitted in order and reliably at the
* same time as unicasts are transmitted.
*/
#define EIGRP_CR_FLAG 0x02
/*
* RS bit. The Restart flag is set in the hello and the init
* update packets during the nsf signaling period. A nsf-aware
* router looks at the RS flag to detect if a peer is restarting
* and maintain the adjacency. A restarting router looks at
* this flag to determine if the peer is helping out with the restart.
*/
#define EIGRP_RS_FLAG 0x04
/*
* EOT bit. The End-of-Table flag marks the end of the start-up updates
* sent to a new peer. A nsf restarting router looks at this flag to
* determine if it has finished receiving the start-up updates from all
* peers. A nsf-aware router waits for this flag before cleaning up
* the stale routes from the restarting peer.
*/
#define EIGRP_EOT_FLAG 0x08
/**
* EIGRP Virtual Router ID
*
* Define values to deal with EIGRP virtual router ids. Virtual
* router IDs are stored in the upper short of the EIGRP fixed packet
* header. The lower short of the packet header continues to be used
* as asystem number.
*
* Virtual Router IDs are PDM-independent. All PDMs will use
* VRID_BASE to indicate the 'base' or 'legacy' EIGRP instance.
* All PDMs need to initialize their vrid to VRID_BASE for compatibility
* with legacy routers.
* Once IPv6 supports 'MTR Multicast', it will use the same VRID as
* IPv4. No current plans to support VRIDs on IPX. :)
* Initial usage of VRID is to signal usage of Multicast topology for
* MTR.
*
* VRID_MCAST is a well known constant, other VRIDs will be determined
* programmatic...
*
* With the addition of SAF the VRID space has been divided into two
* segments 0x0000-0x7fff is for EIGRP and vNets, 0x8000-0xffff is
* for saf and its associated vNets.
*/
#define EIGRP_VRID_MASK 0x8001
#define EIGRP_VRID_AF_BASE 0x0000
#define EIGRP_VRID_MCAST_BASE 0x0001
#define EIGRP_VRID_SF_BASE 0x8000
/* Extended Attributes for a destination */
#define EIGRP_ATTR_HDRLEN (2)
#define EIGRP_ATTR_MAXDATA (512)
#define EIGRP_ATTR_NOOP 0 /*!< No-Op used as offset padding */
#define EIGRP_ATTR_SCALED 1 /*!< Scaled metric values */
#define EIGRP_ATTR_TAG 2 /*!< Tag assigned by Admin for dest */
#define EIGRP_ATTR_COMM 3 /*!< Community attribute for dest */
#define EIGRP_ATTR_JITTER 4 /*!< Variation in path delay */
#define EIGRP_ATTR_QENERGY 5 /*!< Non-Active energy usage along path */
#define EIGRP_ATTR_ENERGY 6 /*!< Active energy usage along path */
/*
* Begin EIGRP-BGP interoperability communities
*/
#define EIGRP_EXTCOMM_SOO_ASFMT 0x0003 /* Site-of-Origin, BGP AS format */
#define EIGRP_EXTCOMM_SOO_ADRFMT 0x0103 /* Site-of-Origin, BGP/EIGRP addr format */
/*
* EIGRP Specific communities
*/
#define EIGRP_EXTCOMM_EIGRP 0x8800 /* EIGRP route information appended*/
#define EIGRP_EXTCOMM_DAD 0x8801 /* EIGRP AS + Delay */
#define EIGRP_EXTCOMM_VRHB 0x8802 /* EIGRP Vector: Reliability + Hop + BW */
#define EIGRP_EXTCOMM_SRLM 0x8803 /* EIGRP System: Reserve +Load + MTU */
#define EIGRP_EXTCOMM_SAR 0x8804 /* EIGRP System: Remote AS + Remote ID */
#define EIGRP_EXTCOMM_RPM 0x8805 /* EIGRP Remote: Protocol + Metric */
#define EIGRP_EXTCOMM_VRR 0x8806 /* EIGRP Vecmet: Rsvd + (internal) Routerid */
/* SAF types */
#define EIGRP_SVCDATA_COMPLETE 0x01 /*!< Data is attached */
#define EIGRP_SVCDATA_TRIMMED 0x02 /*!< Data was trimmed from service */
/* SAF Defined Numbers */
#define SAF_SERVICE_ID_CAPMAN 100 /*!< Capabilities Manager */
#define SAF_SERVICE_ID_UC 101 /*!< Unified Communications */
#define SAF_SERVICE_ID_PFR 102 /*!< Performance Routing */
/* Forward declaration we need below (if using proto_reg_handoff...
as a prefs callback) */
void proto_reg_handoff_eigrp(void);
void proto_register_eigrp(void);
/* Initialize the protocol and registered fields */
static int proto_eigrp = -1;
/* header */
static gint hf_eigrp_version = -1;
static gint hf_eigrp_opcode = -1;
static gint hf_eigrp_flags = -1;
static gint hf_eigrp_sequence = -1;
static gint hf_eigrp_acknowledge = -1;
static gint hf_eigrp_vrid = -1;
static gint hf_eigrp_as = -1;
static gint ett_eigrp = -1;
/* packet header flags */
static gint hf_eigrp_flags_init = -1;
static gint hf_eigrp_flags_restart = -1;
static gint hf_eigrp_flags_eot = -1;
static gint hf_eigrp_flags_condrecv = -1;
static gint ett_eigrp_flags = -1;
static const int *eigrp_flag_fields[] = {
&hf_eigrp_flags_init,
&hf_eigrp_flags_condrecv,
&hf_eigrp_flags_restart,
&hf_eigrp_flags_eot,
NULL
};
/* tlv */
static gint hf_eigrp_tlv_type = -1;
static gint hf_eigrp_tlv_len = -1;
static gint hf_eigrp_tid = -1;
static gint hf_eigrp_afi = -1;
static gint hf_eigrp_nullpad = -1;
static gint ett_eigrp_tlv = -1;
static gint ett_eigrp_tlv_metric = -1;
static gint ett_eigrp_tlv_attr = -1;
static gint ett_eigrp_tlv_extdata = -1;
/* param */
static gint hf_eigrp_par_k1 = -1;
static gint hf_eigrp_par_k2 = -1;
static gint hf_eigrp_par_k3 = -1;
static gint hf_eigrp_par_k4 = -1;
static gint hf_eigrp_par_k5 = -1;
static gint hf_eigrp_par_k6 = -1;
static gint hf_eigrp_par_holdtime = -1;
/* auth */
static gint hf_eigrp_auth_type = -1;
static gint hf_eigrp_auth_len = -1;
static gint hf_eigrp_auth_keyid = -1;
static gint hf_eigrp_auth_keyseq = -1;
static gint hf_eigrp_auth_digest = -1;
/* seq */
static gint hf_eigrp_seq_addrlen = -1;
static gint hf_eigrp_seq_ipv4addr = -1;
static gint hf_eigrp_seq_ipv6addr = -1;
/* multicast seq */
static gint hf_eigrp_next_mcast_seq = -1;
/* stub flags */
static gint hf_eigrp_stub_flags = -1;
static gint hf_eigrp_stub_flags_connected = -1;
static gint hf_eigrp_stub_flags_static = -1;
static gint hf_eigrp_stub_flags_summary = -1;
static gint hf_eigrp_stub_flags_recvonly = -1;
static gint hf_eigrp_stub_flags_redist = -1;
static gint hf_eigrp_stub_flags_leakmap = -1;
static gint ett_eigrp_stub_flags = -1;
static const int *eigrp_stub_flag_fields[] = {
&hf_eigrp_stub_flags_connected,
&hf_eigrp_stub_flags_static,
&hf_eigrp_stub_flags_summary,
&hf_eigrp_stub_flags_redist,
&hf_eigrp_stub_flags_leakmap,
&hf_eigrp_stub_flags_recvonly,
NULL
};
/* tid */
static gint hf_eigrp_tidlist_tid = -1;
static gint hf_eigrp_tidlist_flags = -1;
static gint hf_eigrp_tidlist_len = -1;
static gint ett_eigrp_tidlist = -1;
/* 1.2 and 3.0 metric */
static gint hf_eigrp_legacy_metric_delay = -1;
static gint hf_eigrp_legacy_metric_bw = -1;
static gint hf_eigrp_legacy_metric_mtu = -1;
static gint hf_eigrp_legacy_metric_hopcount = -1;
static gint hf_eigrp_legacy_metric_rel = -1;
static gint hf_eigrp_legacy_metric_load = -1;
static gint hf_eigrp_legacy_metric_intag = -1;
/* 3.0 metric */
static gint hf_eigrp_legacy_metric_tag = -1;
/* 2.0 metric */
static gint hf_eigrp_metric_offset = -1;
static gint hf_eigrp_metric_priority = -1;
static gint hf_eigrp_metric_rel = -1;
static gint hf_eigrp_metric_load = -1;
static gint hf_eigrp_metric_mtu = -1;
static gint hf_eigrp_metric_hopcount = -1;
static gint hf_eigrp_metric_reserved = -1;
/* router id*/
static gint hf_eigrp_routerid = -1;
/* protocol dependent module route flags */
static gint hf_eigrp_metric_flags_srcwd = -1;
static gint hf_eigrp_metric_flags_active = -1;
static gint hf_eigrp_metric_flags_repl = -1;
static gint ett_eigrp_metric_flags = -1;
/* extended metrics */
static gint hf_eigrp_attr_opcode = -1;
static gint hf_eigrp_attr_offset = -1;
static gint hf_eigrp_attr_scaled = -1;
static gint hf_eigrp_attr_tag = -1;
static gint hf_eigrp_attr_jitter = -1;
static gint hf_eigrp_attr_qenergy = -1;
static gint hf_eigrp_attr_energy = -1;
/* route external data */
static gint hf_eigrp_extdata_origrid = -1;
static gint hf_eigrp_extdata_as = -1;
static gint hf_eigrp_extdata_tag = -1;
static gint hf_eigrp_extdata_metric = -1;
static gint hf_eigrp_extdata_reserved = -1;
static gint hf_eigrp_extdata_proto = -1;
static gint hf_eigrp_extdata_flag_ext = -1;
static gint hf_eigrp_extdata_flag_cd = -1;
static gint ett_eigrp_extdata_flags = -1;
/* ipv4 address */
static gint hf_eigrp_ipv4_nexthop = -1;
static gint hf_eigrp_ipv4_prefixlen = -1;
/* ipv6 address */
static gint hf_eigrp_ipv6_nexthop = -1;
static gint hf_eigrp_ipv6_prefixlen = -1;
/* ipx address */
static gint hf_eigrp_ipx_nexthop_net = -1;
static gint hf_eigrp_ipx_nexthop_host = -1;
static gint hf_eigrp_ipx_extdata_routerid = -1;
static gint hf_eigrp_ipx_extdata_delay = -1;
static gint hf_eigrp_ipx_extdata_metric = -1;
static gint hf_eigrp_ipx_dest = -1;
/* appletalk address */
static gint hf_eigrp_atalk_routerid = -1;
/* SAF services */
static gint hf_eigrp_saf_service = -1;
static gint hf_eigrp_saf_subservice = -1;
static gint hf_eigrp_saf_guid = -1;
static gint hf_eigrp_saf_reachability_afi = -1;
static gint hf_eigrp_saf_reachability_port = -1;
static gint hf_eigrp_saf_reachability_protocol = -1;
static gint hf_eigrp_saf_reachability_addr_ipv4 = -1;
static gint hf_eigrp_saf_reachability_addr_ipv6 = -1;
static gint hf_eigrp_saf_reachability_addr_hex = -1;
static gint ett_eigrp_saf_reachability = -1;
static gint hf_eigrp_saf_data_length = -1;
static gint hf_eigrp_saf_data_sequence = -1;
static gint hf_eigrp_saf_data_type = -1;
static expert_field ei_eigrp_checksum_bad = EI_INIT;
static expert_field ei_eigrp_unreachable = EI_INIT;
static expert_field ei_eigrp_seq_addrlen = EI_INIT;
static expert_field ei_eigrp_peer_termination = EI_INIT;
static expert_field ei_eigrp_tlv_type = EI_INIT;
static expert_field ei_eigrp_auth_type = EI_INIT;
static expert_field ei_eigrp_peer_termination_graceful = EI_INIT;
static expert_field ei_eigrp_auth_len = EI_INIT;
static expert_field ei_eigrp_tlv_len = EI_INIT;
static expert_field ei_eigrp_afi = EI_INIT;
static expert_field ei_eigrp_prefixlen = EI_INIT;
/* some extra handle that might be needed */
static dissector_handle_t ipxsap_handle = NULL;
static dissector_table_t media_type_table = NULL;
static const value_string eigrp_opcode2string[] = {
{ EIGRP_OPC_UPDATE, "Update" },
{ EIGRP_OPC_REQUEST, "Request" },
{ EIGRP_OPC_QUERY, "Query" },
{ EIGRP_OPC_REPLY, "Reply" },
{ EIGRP_OPC_HELLO, "Hello" },
{ EIGRP_OPC_IPXSAP, "IPX/SAP Update" },
{ EIGRP_OPC_PROBE, "Route Probe" },
{ EIGRP_OPC_ACK, "Hello (Ack)" },
{ EIGRP_OPC_STUB, "Stub-Info" },
{ EIGRP_OPC_SIAQUERY, "SIA-Query" },
{ EIGRP_OPC_SIAREPLY, "SIA-Reply" },
{ 0, NULL }
};
static const value_string eigrp_tlv2string[] = {
/* General TLV formats */
{ EIGRP_TLV_PARAMETER, "Parameters"},
{ EIGRP_TLV_AUTH, "Authentication"},
{ EIGRP_TLV_SEQ, "Sequence"},
{ EIGRP_TLV_SW_VERSION, "Software Version"},
{ EIGRP_TLV_NEXT_MCAST_SEQ, "Next multicast sequence"},
{ EIGRP_TLV_PEER_STUBINFO, "Peer Stub Information"},
{ EIGRP_TLV_PEER_TERMINATION, "Peer Termination"},
{ EIGRP_TLV_PEER_TIDLIST, "Peer Topology ID List"},
/* Legacy TLV formats */
{ EIGRP_TLV_IPv4_INT, "Internal Route(IPv4)"},
{ EIGRP_TLV_IPv4_EXT, "External Route(IPv4)"},
{ EIGRP_TLV_IPv4_COM, "Ext-Community(IPv4)"},
{ EIGRP_TLV_IPv6_INT, "Internal Route(IPv6)"},
{ EIGRP_TLV_IPv6_EXT, "External Route(IPv6)"},
{ EIGRP_TLV_IPv6_COM, "Ext-Community(IPv6)"},
{ EIGRP_TLV_IPX_INT, "IPX Internal Route(IPX)"},
{ EIGRP_TLV_IPX_EXT, "IPX External Route(IPX)"},
/* Deprecated TLV formats */
{ EIGRP_TLV_AT_INT, "Internal Route(ATALK)"},
{ EIGRP_TLV_AT_EXT, "External Route(ATALK)"},
{ EIGRP_TLV_AT_CBL, "Cable Configuration(ATALK)"},
{ EIGRP_TLV_MTR_REQ, "Request(MTR)"},
{ EIGRP_TLV_MTR_INT, "Internal Route(MTR)"},
{ EIGRP_TLV_MTR_EXT, "External Route(MTR)"},
{ EIGRP_TLV_MTR_COM, "Ext-Community(MTR)"},
{ EIGRP_TLV_MTR_TIDLIST, "TopologyID List"},
/* Current "Wide Metric" TLV formats */
{ EIGRP_TLV_MP_REQ, "Request"},
{ EIGRP_TLV_MP_INT, "Internal Route"},
{ EIGRP_TLV_MP_EXT, "External Route"},
{ EIGRP_TLV_MP_COM, "Ext-Community"},
{ 0, NULL}
};
static const value_string eigrp_proto2string[] = {
{ IGRP1_PROTID, "IGRP"},
{ IGRP2_PROTID, "EIGRP"},
{ STATIC_PROTID, "Static Route"},
{ RIP_PROTID, "RIP"},
{ HELLO_PROTID, "Hello"},
{ OSPF_PROTID, "OSPF"},
{ ISIS_PROTID, "IS-IS"},
{ EGP_PROTID, "EGP"},
{ BGP_PROTID, "BGP"},
{ IDRP_PROTID, "IDRP"},
{ CONN_PROTID, "Connected Route"},
{ 0, NULL}
};
static const value_string eigrp_auth2string[] = {
{ EIGRP_AUTH_TYPE_TEXT, "TEXT"},
{ EIGRP_AUTH_TYPE_MD5, "MD5"},
{ EIGRP_AUTH_TYPE_SHA256, "SHA256"},
{ 0, NULL},
};
static const value_string eigrp_vrid2string[] = {
{ EIGRP_VRID_AF_BASE, "(Address-Family)"},
{ EIGRP_VRID_SF_BASE, "(Service-Family)"},
{ EIGRP_VRID_MCAST_BASE, "(Multi-Cast)"},
{ 0, NULL}
};
static const value_string eigrp_afi2string[] = {
{ EIGRP_AF_IPv4, "IPv4"},
{ EIGRP_AF_IPv6, "IPv6"},
{ EIGRP_AF_IPX, "IPX"},
{ EIGRP_AF_ATALK, "Appletalk"},
{ EIGRP_SF_COMMON, "Service Family"},
{ EIGRP_SF_IPv4, "IPv4 Service Family"},
{ EIGRP_SF_IPv6, "IPv6 Service Family"},
{ 0, NULL}
};
static const value_string eigrp_attr_opcode2string[] = {
{ EIGRP_ATTR_NOOP, "NO-OP for padding"},
{ EIGRP_ATTR_SCALED, "Scaled Metric"},
{ EIGRP_ATTR_TAG, "Admin Tag"},
{ EIGRP_ATTR_COMM, "Community"},
{ EIGRP_ATTR_JITTER, "Jitter"},
{ EIGRP_ATTR_QENERGY, "Non-Active energy"},
{ EIGRP_ATTR_ENERGY, "Active energy"},
{ 0, NULL}
};
static const value_string eigrp_saf_type2string[] = {
{ EIGRP_SVCDATA_COMPLETE, "Attached Service Data"},
{ EIGRP_SVCDATA_TRIMMED, "Trimmed Service Data"},
{ 0, NULL}
};
static const value_string eigrp_saf_srv2string[] = {
{ SAF_SERVICE_ID_CAPMAN, "Capabilities Manager"},
{ SAF_SERVICE_ID_UC, "Unified Communications"},
{ SAF_SERVICE_ID_PFR, "Performance Routing"},
{ 0, NULL}
};
/**
*@fn void dissect_eigrp_parameter (proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo,
*
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] pinfo general data about the protocol
* @param[in] ti protocol item
*
* @par
* Dissect the Parameter TLV, which is used to convey metric weights and the
* hold time.
*
* @usage
* Note the addition of K6 for the new extended metrics, and does not apply to
* older TLV packet formats.
*/
static void
dissect_eigrp_parameter (proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo,
proto_item *ti)
{
int offset = 0;
guint8 k1, k2, k3, k4, k5;
k1 = tvb_get_guint8(tvb, offset);
proto_tree_add_item(tree, hf_eigrp_par_k1, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
k2 = tvb_get_guint8(tvb, offset);
proto_tree_add_item(tree, hf_eigrp_par_k2, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
k3 = tvb_get_guint8(tvb, offset);
proto_tree_add_item(tree, hf_eigrp_par_k3, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
k4 = tvb_get_guint8(tvb, offset);
proto_tree_add_item(tree, hf_eigrp_par_k4, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
k5 = tvb_get_guint8(tvb, offset);
proto_tree_add_item(tree, hf_eigrp_par_k5, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
proto_tree_add_item(tree, hf_eigrp_par_k6, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
proto_tree_add_item(tree, hf_eigrp_par_holdtime, tvb, offset, 2, ENC_BIG_ENDIAN);
if (k1 == 255 && k2 == 255 && k3 == 255 && k4 == 255 && k5 == 255) {
proto_item_append_text(ti, ": Peer Termination");
expert_add_info(pinfo, ti, &ei_eigrp_peer_termination);
}
}
/**
*@fn void dissect_eigrp_auth_tlv (proto_tree *tree, tvbuff_t *tvb,
* packet_info *pinfo, proto_item *ti)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] pinfo general data about the protocol
* @param[in] ti protocol item
*
* @par
* Dissect the Authentication TLV and display digest. Currently MD5 and SHA256
* HMAC is supported. For SHA256, a "secret key" with the HMAC-SHA-256
* password, the source address from which the packet is sent. This combined
* string is used as the key for hash calculation.
*/
static void
dissect_eigrp_auth_tlv (proto_tree *tree, tvbuff_t *tvb,
packet_info *pinfo, proto_item *ti)
{
proto_item *ti_auth_type, *ti_auth_len;
int offset = 0;
guint16 auth_type, auth_len;
/* print out what family we dealing with... */
auth_type = tvb_get_ntohs(tvb, 0);
auth_len = tvb_get_ntohs(tvb, 2);
proto_item_append_text(ti, " %s", val_to_str_const(auth_type, eigrp_auth2string, ""));
ti_auth_type = proto_tree_add_item(tree, hf_eigrp_auth_type, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
ti_auth_len = proto_tree_add_item(tree, hf_eigrp_auth_len, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
proto_tree_add_item(tree, hf_eigrp_auth_keyid, tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
proto_tree_add_item(tree, hf_eigrp_auth_keyseq, tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
proto_tree_add_item(tree, hf_eigrp_nullpad, tvb, offset, 8, ENC_NA);
offset += 8;
switch (auth_type) {
case EIGRP_AUTH_TYPE_MD5:
if (EIGRP_AUTH_TYPE_MD5_LEN != auth_len) {
expert_add_info_format(pinfo, ti_auth_len, &ei_eigrp_auth_len, "Invalid auth len %u", auth_len);
} else {
proto_tree_add_item(tree, hf_eigrp_auth_digest, tvb, offset,
EIGRP_AUTH_TYPE_MD5_LEN, ENC_NA);
}
break;
case EIGRP_AUTH_TYPE_SHA256:
if (EIGRP_AUTH_TYPE_SHA256_LEN != auth_len) {
expert_add_info_format(pinfo, ti_auth_len, &ei_eigrp_auth_len, "Invalid auth len %u", auth_len);
} else {
proto_tree_add_item(tree, hf_eigrp_auth_digest, tvb, offset,
EIGRP_AUTH_TYPE_SHA256_LEN, ENC_NA);
}
break;
case EIGRP_AUTH_TYPE_NONE:
case EIGRP_AUTH_TYPE_TEXT:
default:
expert_add_info_format(pinfo, ti_auth_type, &ei_eigrp_auth_type, "Invalid auth type %u", auth_type);
break;
}
}
/**
*@fn void dissect_eigrp_seq_tlv (proto_tree *tree, tvbuff_t *tvb,
* packet_info *pinfo)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] pinfo general data about the protocol
*
* @par
* Dissect the Sequence TLV which consist of the address of peers that must
* not receive the next multicast packet transmitted.
*/
static void
dissect_eigrp_seq_tlv (proto_tree *tree, tvbuff_t *tvb,
packet_info *pinfo)
{
proto_item *ti_addrlen;
int offset = 0;
guint8 addr_len;
addr_len = tvb_get_guint8(tvb, 0);
ti_addrlen = proto_tree_add_item(tree, hf_eigrp_seq_addrlen, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
switch (addr_len) {
case 4:
/* IPv4 */
proto_tree_add_item(tree, hf_eigrp_seq_ipv4addr, tvb, offset, addr_len, ENC_BIG_ENDIAN);
break;
case 10:
/* IPX */
proto_tree_add_text(tree, tvb, offset, addr_len,
"IPX Address = %08x.%04x.%04x.%04x",
tvb_get_ntohl(tvb, 1), tvb_get_ntohs(tvb, 5),
tvb_get_ntohs(tvb, 7), tvb_get_ntohs(tvb, 9));
break;
case 16:
/* IPv6 */
proto_tree_add_item(tree, hf_eigrp_seq_ipv6addr, tvb, offset, addr_len,
ENC_NA);
break;
default:
expert_add_info(pinfo, ti_addrlen, &ei_eigrp_seq_addrlen);
}
}
/**
*@fn void dissect_eigrp_sw_version (tvbuff_t *tvb, proto_tree *tree,
* proto_item *ti)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] ti protocol item
*
* @par
* Dissect Software Version TLV. The older versions of EIGRP sent the IOS
* version along with the TLV Version. When EIGRP "plugins" were created,
* this as change to send the "Release" of EIGRP to better identify where fixes
* are present(missing)
*/
static void
dissect_eigrp_sw_version (tvbuff_t *tvb, proto_tree *tree,
proto_item *ti)
{
int offset = 0;
guint8 ios_rel_major, ios_rel_minor;
guint8 eigrp_rel_major, eigrp_rel_minor;
ios_rel_major = tvb_get_guint8(tvb, 0);
ios_rel_minor = tvb_get_guint8(tvb, 1);
proto_tree_add_text(tree, tvb, offset, 2, "EIGRP Release: %u.%u",
ios_rel_major, ios_rel_minor);
offset += 2;
proto_item_append_text(ti, ": EIGRP=%u.%u", ios_rel_major, ios_rel_minor);
eigrp_rel_major = tvb_get_guint8(tvb, 2);
eigrp_rel_minor = tvb_get_guint8(tvb, 3);
proto_tree_add_text(tree,tvb,offset, 2, "EIGRP TLV version: %u.%u",
eigrp_rel_major, eigrp_rel_minor);
proto_item_append_text(ti, ", TLV=%u.%u",
eigrp_rel_major, eigrp_rel_minor);
}
/**
*@fn void dissect_eigrp_next_mcast_seq (tvbuff_t *tvb, proto_tree *tree,
* proto_item *ti)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] ti protocol item
*
* @par
* Dissect Next Multicast Sequence TLV, which is part of the Hello with a
* Sequence TLV; this gives a two-way binding between the packets and plugs a
* hole where a multicast could be received by the wrong peers (due to a
* string of lost packets).
*/
static void
dissect_eigrp_next_mcast_seq (tvbuff_t *tvb, proto_tree *tree,
proto_item *ti)
{
proto_tree_add_item(tree, hf_eigrp_next_mcast_seq, tvb, 0, 4,
ENC_BIG_ENDIAN);
proto_item_append_text(ti, ": %u", tvb_get_ntohl(tvb, 0));
}
/**
*@fn void dissect_eigrp_peer_stubinfo (tvbuff_t *tvb, proto_tree *tree)
*
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
*
* @par
* Dissect the PEER STUB TLV which contains the route types which the Peer will
* advertise. This is used to suppress QUERYs from being sent to the Peer
*/
static void
dissect_eigrp_peer_stubinfo (tvbuff_t *tvb, proto_tree *tree)
{
proto_tree_add_bitmask(tree, tvb, 0, hf_eigrp_stub_flags, ett_eigrp_stub_flags,
eigrp_stub_flag_fields, ENC_BIG_ENDIAN);
}
/**
*@fn void dissect_eigrp_peer_termination (packet_info *pinfo, proto_item *ti)
*
* @param[in] pinfo general data about the protocol
* @param[in] ti protocol item
*
* @par
* Dissect Peer Termination TLV. This TLV has no parameters and is used to
* signal an adjacency should be tore down
*/
static void
dissect_eigrp_peer_termination (packet_info *pinfo, proto_item *ti)
{
expert_add_info(pinfo, ti, &ei_eigrp_peer_termination_graceful);
}
/**
*@fn void dissect_eigrp_peer_tidlist (proto_tree *tree, tvbuff_t *tvb)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
*
* @par
* Dissect the Topology Identifier List TLV. This TLV was introduced as part
* of the "MTR (Multi-Topology Routing) Project to support sub topologies
* within a given Autonomous System. The following represents the format of
* the TID list
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Flags | Length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Variable Length TID (two bytes) list |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
static void
dissect_eigrp_peer_tidlist (proto_tree *tree, tvbuff_t *tvb)
{
proto_item *sub_ti;
proto_tree *sub_tree;
int offset = 0;
guint16 size;
proto_tree_add_item(tree, hf_eigrp_tidlist_flags, tvb, offset, 2,
ENC_BIG_ENDIAN);
offset += 2;
size = tvb_get_ntohs(tvb, offset) / 2;
proto_tree_add_item(tree, hf_eigrp_tidlist_len, tvb, offset, 2,
ENC_BIG_ENDIAN);
offset += 2;
sub_ti = proto_tree_add_text(tree, tvb, offset, (size*2), "%d TIDs", size);
sub_tree = proto_item_add_subtree(sub_ti, ett_eigrp_tidlist);
for (; size ; size--) {
proto_tree_add_item(sub_tree, hf_eigrp_tidlist_tid, tvb, offset, 2,
ENC_BIG_ENDIAN);
offset += 2;
}
}
/**
*@fn int dissect_eigrp_extdata_flags (proto_tree *tree, tvbuff_t *tvb, int offset)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] offset current byte offset in packet being processed
*
* @return int number of bytes process
*
* @par
* Dissect the Flags field in the external data section of an external
* route.The following represents the format of the bit field
*
* 7 6 5 4 3 2 1 0
* +-+-+-+-+-+-+-+-+
* | Flags |
* +-+-+-+-+-+-+-+-+
* | |
* | +- Route is External *not used*
* +--- Route is Candidate Default
*/
static int
dissect_eigrp_extdata_flags (proto_tree *tree, tvbuff_t *tvb, int offset)
{
proto_item *sub_ti;
proto_tree *sub_tree;
tvbuff_t *sub_tvb;
/* Decode the route flags field */
sub_ti = proto_tree_add_text(tree, tvb, offset, 1, "External Flags");
sub_tree = proto_item_add_subtree(sub_ti, ett_eigrp_extdata_flags);
sub_tvb = tvb_new_subset_remaining(tvb, offset);
proto_tree_add_item(sub_tree, hf_eigrp_extdata_flag_ext, sub_tvb, 0, 1,
ENC_BIG_ENDIAN);
proto_tree_add_item(sub_tree, hf_eigrp_extdata_flag_cd, sub_tvb, 0, 1,
ENC_BIG_ENDIAN);
offset += 1;
return(offset);
}
/**
*@fn int dissect_eigrp_metric_flags (proto_tree *tree, tvbuff_t *tvb, int offset, int limit)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] offset current byte offset in packet being processed
* @param[in] limit maximum number of bytes which can be process
*
* @return int number of bytes process
*
* @par
* Dissect Protocol Dependent Module (PDM) Flags field in the route metric
* section of an internal and external route. The following represents the
* format of the bit field
*
* MSB LSB
* 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Flags | MP Flags |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | | |
* | | +- Route is Replicated
* | +--- Route is Active
* +----- Source Withdraw
*/
static int
dissect_eigrp_metric_flags (proto_tree *tree, tvbuff_t *tvb, int offset, int limit)
{
proto_item *sub_ti;
proto_tree *sub_tree;
tvbuff_t *sub_tvb;
/* Decode the route flags field */
sub_ti = proto_tree_add_text(tree, tvb, offset, limit, "Flags");
sub_tree = proto_item_add_subtree(sub_ti, ett_eigrp_metric_flags);
sub_tvb = tvb_new_subset(tvb, offset, limit, -1);
/* just care about 'flags' byte, there are no MP flags for now */
proto_tree_add_item(sub_tree, hf_eigrp_metric_flags_srcwd, sub_tvb, 0, 1,
ENC_BIG_ENDIAN);
proto_tree_add_item(sub_tree, hf_eigrp_metric_flags_active, sub_tvb, 0, 1,
ENC_BIG_ENDIAN);
proto_tree_add_item(sub_tree, hf_eigrp_metric_flags_repl, sub_tvb, 0, 1,
ENC_BIG_ENDIAN);
offset += limit;
return(offset);
}
/**
*@fn int dissect_eigrp_ipv4_addr (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
* packet_info *pinfo, int offset, int unreachable)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] pinfo general data about the protocol
* @param[in] offset current byte offset in packet being processed
*
* @return int number of bytes process
*
* @par
* Dissect all IPv4 address from offset though the end of the packet
*/
static int
dissect_eigrp_ipv4_addr (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
packet_info *pinfo, int offset, int unreachable)
{
guint8 ip_addr[4], length;
int addr_len;
proto_item *ti_prefixlen, *ti_dst;
int first = TRUE;
for (; tvb_length_remaining(tvb, offset) > 0; offset += (1 + addr_len)) {
length = tvb_get_guint8(tvb, offset);
addr_len = ipv4_addr_and_mask(tvb, offset + 1, ip_addr, length);
if (addr_len < 0) {
ti_prefixlen = proto_tree_add_item(tree, hf_eigrp_ipv4_prefixlen,
tvb, offset, 1, ENC_BIG_ENDIAN);
expert_add_info_format(pinfo, ti_prefixlen, &ei_eigrp_prefixlen, "Invalid prefix length %u, must be <= 32", length);
addr_len = 4; /* assure we can exit the loop */
} else {
proto_tree_add_item(tree, hf_eigrp_ipv4_prefixlen, tvb, offset, 1,
ENC_BIG_ENDIAN);
offset += 1;
ti_dst = proto_tree_add_text(tree, tvb, offset, addr_len,
"Destination: %s", ip_to_str(ip_addr));
/* add it to the top level line */
proto_item_append_text(ti," %c %s/%u", first ? '=':',',
ip_to_str(ip_addr), length);
if (unreachable) {
expert_add_info(pinfo, ti_dst, &ei_eigrp_unreachable);
}
}
first = FALSE;
}
return (offset);
}
/**
*@fn int dissect_eigrp_ipv6_addr (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
* packet_info *pinfo, int offset, int unreachable)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] pinfo general data about the protocol
* @param[in] offset current byte offset in packet being processed
*
* @return int number of bytes process
*
* @par
* Dissect all IPv6 address from offset though the end of the packet
*/
static int
dissect_eigrp_ipv6_addr (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
packet_info *pinfo, int offset, int unreachable)
{
guint8 length;
int addr_len;
struct e_in6_addr addr;
proto_item *ti_prefixlen, *ti_dst;
int first = TRUE;
for (; tvb_length_remaining(tvb, offset) > 0; offset += (1 + addr_len)) {
length = tvb_get_guint8(tvb, offset);
addr_len = ipv6_addr_and_mask(tvb, offset + 1, &addr, length);
if (addr_len < 0) {
ti_prefixlen = proto_tree_add_item(tree, hf_eigrp_ipv6_prefixlen,
tvb, offset, 1, ENC_BIG_ENDIAN);
expert_add_info_format(pinfo, ti_prefixlen, &ei_eigrp_prefixlen, "Invalid prefix length %u, must be <= 128", length);
addr_len = 16; /* assure we can exit the loop */
} else {
proto_tree_add_item(tree, hf_eigrp_ipv6_prefixlen, tvb, offset, 1,
ENC_BIG_ENDIAN);
offset += 1;
if ((length < 128) && (length % 8 == 0)) {
addr_len++;
}
ti_dst = proto_tree_add_text(tree, tvb, offset, addr_len,
"Destination: %s", ip6_to_str(&addr));
/* add it to the top level line */
proto_item_append_text(ti," %c %s/%u", first ? '=':',',
ip6_to_str(&addr), length);
if (unreachable) {
expert_add_info(pinfo, ti_dst, &ei_eigrp_unreachable);
}
}
first = FALSE;
}
return(offset);
}
/**
*@fn int dissect_eigrp_ipx_addr (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
* packet_info *pinfo, int offset, int unreachable)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] pinfo general data about the protocol
* @param[in] offset current byte offset in packet being processed
*
* @return int number of bytes process
*
* @par
* Dissect all IPX address from offset though the end of the packet
*/
static int
dissect_eigrp_ipx_addr (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
packet_info *pinfo, int offset, int unreachable)
{
proto_item *ti_dst;
ti_dst = proto_tree_add_item(tree, hf_eigrp_ipx_dest, tvb, offset, 4,
ENC_NA);
/* add it to the top level line */
proto_item_append_text(ti," = %s",
ipxnet_to_string(tvb_get_ptr(tvb, offset, 4)));
if (unreachable) {
expert_add_info(pinfo, ti_dst, &ei_eigrp_unreachable);
}
offset +=4;
return(offset);
}
/**
*@fn int dissect_eigrp_service (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
* packet_info *pinfo, int offset)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] pinfo general data about the protocol
* @param[in] ti protocol item
* @param[in] offset current byte offset in packet being processed
*
* @return int number of bytes process
*
* @par
* Dissect all SAF Services from offset though the end of the packet. The
* following represents the format of a SAF Service:
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Service | SubService |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | GUID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | GUID(cont) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | GUID(cont) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | GUID(cont) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Type | Length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Reachability AFI | Reachability Port |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Reachability Protocol | Reachability Addr |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Reachability Addr(cont) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Reachability Addr(cont) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Reachability Addr(cont) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Reachability Addr(cont) | Sequence |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Sequence(cont) |\/\/\/ Service Data \/\/\/|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
static int
dissect_eigrp_service (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
packet_info *pinfo, int offset)
{
int afi, length, remaining;
int sub_offset;
proto_item *sub_ti, *reach_ti;
proto_tree *sub_tree, *reach_tree;
tvbuff_t *sub_tvb, *reach_tvb;
guint16 service, sub_service;
remaining = tvb_length_remaining(tvb, offset);
sub_ti = proto_tree_add_text(tree, tvb, offset, remaining, "SAF Service ");
sub_tree = proto_item_add_subtree(sub_ti, ett_eigrp_tlv_metric);
sub_tvb = tvb_new_subset(tvb, offset, remaining, -1);
sub_offset = 0;
for (; tvb_length_remaining(sub_tvb, sub_offset) > 0; ) {
service = tvb_get_ntohs(sub_tvb, sub_offset);
proto_item_append_text(sub_ti, "%c %s", (sub_offset == 0 ? '=':','),
val_to_str_const(service, eigrp_saf_srv2string, ""));
sub_service = tvb_get_ntohs(sub_tvb, sub_offset+2);
proto_item_append_text(ti, "%c %u:%u", (sub_offset == 0 ? '=':','),
service, sub_service);
proto_tree_add_item(sub_tree, hf_eigrp_saf_service, sub_tvb,
sub_offset, 2, ENC_BIG_ENDIAN);
sub_offset += 2;
proto_tree_add_item(sub_tree, hf_eigrp_saf_subservice, sub_tvb,
sub_offset, 2, ENC_BIG_ENDIAN);
sub_offset += 2;
proto_tree_add_item(sub_tree, hf_eigrp_saf_guid, sub_tvb,
sub_offset, GUID_LEN, ENC_BIG_ENDIAN);
sub_offset += GUID_LEN;
proto_tree_add_item(sub_tree, hf_eigrp_saf_data_type, sub_tvb,
sub_offset, 2, ENC_BIG_ENDIAN);
sub_offset += 2;
length = tvb_get_ntohs(sub_tvb, sub_offset);
proto_tree_add_item(sub_tree, hf_eigrp_saf_data_length, sub_tvb,
sub_offset, 2, ENC_BIG_ENDIAN);
sub_offset += 2;
/*
* Reachability information
*/
reach_ti = proto_tree_add_text(sub_tree, sub_tvb, sub_offset, 22,
"Reachability");
reach_tree = proto_item_add_subtree(reach_ti, ett_eigrp_saf_reachability);
reach_tvb = tvb_new_subset(sub_tvb, sub_offset, 22, -1);
afi = tvb_get_ntohs(reach_tvb, 0);
proto_tree_add_item(reach_tree, hf_eigrp_saf_reachability_afi,
reach_tvb, 0, 2, ENC_BIG_ENDIAN);
proto_tree_add_item(reach_tree, hf_eigrp_saf_reachability_port,
reach_tvb, 2, 2, ENC_BIG_ENDIAN);
proto_tree_add_item(reach_tree, hf_eigrp_saf_reachability_protocol,
reach_tvb, 4, 2, ENC_BIG_ENDIAN);
switch (afi) {
case EIGRP_AF_IPv4:
proto_tree_add_item(reach_tree, hf_eigrp_saf_reachability_addr_ipv4,
reach_tvb, 6, 4, ENC_BIG_ENDIAN);
proto_tree_add_item(reach_tree, hf_eigrp_nullpad, reach_tvb, 10, 12,
ENC_NA);
break;
case EIGRP_AF_IPv6:
proto_tree_add_item(reach_tree, hf_eigrp_saf_reachability_addr_ipv6,
reach_tvb, 6, 16, ENC_NA);
break;
default:
/* just print zeros... */
proto_tree_add_item(reach_tree, hf_eigrp_saf_reachability_addr_hex,
reach_tvb, 6, 16, ENC_NA);
break;
}
sub_offset += 22;
proto_tree_add_item(sub_tree, hf_eigrp_saf_data_sequence, sub_tvb,
sub_offset, 4, ENC_BIG_ENDIAN);
sub_offset += 4;
if (length > 0) {
tvbuff_t *xml_tvb;
guint8 *test_string, *tok;
/*
* Service-Data is usually (but not always) plain text, specifically
* XML. If it "looks like" XML (begins with optional white-space
* followed by a '<'), try XML. Otherwise, try plain-text.
*/
xml_tvb = tvb_new_subset(sub_tvb, sub_offset, length, length);
test_string = tvb_get_string(wmem_packet_scope(), xml_tvb, 0, (length < 32 ?
length : 32));
tok = strtok(test_string, " \t\r\n");
if (tok && tok[0] == '<') {
/* Looks like XML */
dissector_try_string(media_type_table, "application/xml",
xml_tvb, pinfo, sub_tree, NULL);
} else {
/* Try plain text */
dissector_try_string(media_type_table, "text/plain",
xml_tvb, pinfo, sub_tree, NULL);
}
}
sub_offset += length;
}
offset += sub_offset;
return(offset);
}
/**
*@fn int dissect_eigrp_legacy_metric (proto_tree *tree, tvbuff_t *tvb, int offset)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] offset current byte offset in packet being processed
*
* @return int number of bytes process
*
* @par
* Dissect the TLV Versions 1.2 (legacy) and 3.0 (deprecated) metric
* sections. The following represents the format
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Scaled Delay |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Scaled Bandwidth |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | MTU | Hopcount |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Reliability | Load | Internal Tag | Flag |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
static int
dissect_eigrp_legacy_metric (proto_tree *tree, tvbuff_t *tvb, int offset)
{
proto_item *sub_ti;
proto_tree *sub_tree;
tvbuff_t *sub_tvb;
sub_ti = proto_tree_add_text(tree, tvb, offset, 16, "Legacy Metric");
sub_tree = proto_item_add_subtree(sub_ti, ett_eigrp_tlv_metric);
sub_tvb = tvb_new_subset(tvb, offset, 16, -1);
proto_tree_add_item(sub_tree, hf_eigrp_legacy_metric_delay, sub_tvb,
0, 4, ENC_BIG_ENDIAN);
proto_tree_add_item(sub_tree, hf_eigrp_legacy_metric_bw, sub_tvb,
4, 4, ENC_BIG_ENDIAN);
proto_tree_add_item(sub_tree, hf_eigrp_legacy_metric_mtu, sub_tvb,
8, 3, ENC_BIG_ENDIAN);
proto_tree_add_item(sub_tree, hf_eigrp_legacy_metric_hopcount, sub_tvb,
11, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(sub_tree, hf_eigrp_legacy_metric_rel, sub_tvb,
12, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(sub_tree, hf_eigrp_legacy_metric_load, sub_tvb,
13, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(sub_tree, hf_eigrp_legacy_metric_intag, sub_tvb,
14, 1, ENC_BIG_ENDIAN);
/* Decode the route flags field */
dissect_eigrp_metric_flags(sub_tree, sub_tvb, 15, 1);
offset += 16;
return(offset);
}
/**
*@fn int dissect_eigrp_ipx_extdata (proto_tree *tree, tvbuff_t *tvb, int offset)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] offset current byte offset in packet being processed
*
* @return int number of bytes process
*
* @par
* Dissect the IPX External data for the TLV versions 1.2 and 3.0.
* The following represents the format
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Ext RouterID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Ext Router ID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Ext Autonomous System Number |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Route Tag |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Ext Protocol | Ext Flags | External Metric |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | External Delay |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
static int
dissect_eigrp_ipx_extdata (proto_tree *tree, tvbuff_t *tvb, int offset)
{
proto_item *sub_ti;
proto_tree *sub_tree;
tvbuff_t *sub_tvb;
int sub_offset = 0;
sub_ti = proto_tree_add_text(tree, tvb, offset, 20, "External Data");
sub_tree = proto_item_add_subtree(sub_ti, ett_eigrp_tlv_extdata);
sub_tvb = tvb_new_subset(tvb, offset, 20, -1);
/* Decode the external route source info */
proto_tree_add_item(sub_tree, hf_eigrp_ipx_extdata_routerid, sub_tvb,
sub_offset, 6, ENC_NA);
sub_offset += 6;
proto_tree_add_item(sub_tree, hf_eigrp_extdata_as, sub_tvb,
sub_offset, 4, ENC_BIG_ENDIAN);
sub_offset += 4;
proto_tree_add_item(sub_tree, hf_eigrp_extdata_tag, sub_tvb,
sub_offset, 4, ENC_BIG_ENDIAN);
sub_offset += 4;
proto_tree_add_item(sub_tree, hf_eigrp_extdata_proto, sub_tvb,
sub_offset, 1, ENC_BIG_ENDIAN);
sub_offset += 1;
/* Decode the external route flags */
dissect_eigrp_extdata_flags(sub_tree, sub_tvb, sub_offset);
sub_offset += 1;
/* and the rest of it... */
proto_tree_add_item(sub_tree, hf_eigrp_ipx_extdata_metric,
sub_tvb, sub_offset, 2, ENC_BIG_ENDIAN);
sub_offset += 2;
proto_tree_add_item(sub_tree, hf_eigrp_ipx_extdata_delay,
sub_tvb, sub_offset, 2, ENC_BIG_ENDIAN);
sub_offset += 2;
offset += sub_offset;
return(offset);
}
/**
*@fn int dissect_eigrp_extdata (proto_tree *tree, tvbuff_t *tvb, int offset)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] offset current byte offset in packet being processed
*
* @return int number of bytes process
*
* @par
* Dissect the external route data for TLV versions 1.2 and 3.0 for all
* protocols except IPX. The following represents the format
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Ext Router ID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Ext Autonomous System Number |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Route Tag |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | External Metric |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Reserved | Ext Protocol | Ext Flags |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
static int
dissect_eigrp_extdata (proto_tree *tree, tvbuff_t *tvb, int offset)
{
proto_item *sub_ti;
proto_tree *sub_tree;
tvbuff_t *sub_tvb;
int sub_offset = 0;
sub_ti = proto_tree_add_text(tree, tvb, offset, 20, "External Data");
sub_tree = proto_item_add_subtree(sub_ti, ett_eigrp_tlv_extdata);
sub_tvb = tvb_new_subset(tvb, offset, 20, -1);
/* Decode the external route source info */
proto_tree_add_item(sub_tree, hf_eigrp_extdata_origrid, sub_tvb,
sub_offset, 4, ENC_BIG_ENDIAN);
sub_offset += 4;
proto_tree_add_item(sub_tree, hf_eigrp_extdata_as, sub_tvb,
sub_offset, 4, ENC_BIG_ENDIAN);
sub_offset += 4;
proto_tree_add_item(sub_tree, hf_eigrp_extdata_tag, sub_tvb,
sub_offset, 4, ENC_BIG_ENDIAN);
sub_offset += 4;
proto_tree_add_item(sub_tree, hf_eigrp_extdata_metric, sub_tvb,
sub_offset, 4, ENC_BIG_ENDIAN);
sub_offset += 4;
proto_tree_add_item(sub_tree, hf_eigrp_extdata_reserved, sub_tvb,
sub_offset, 2, ENC_BIG_ENDIAN);
sub_offset += 2;
proto_tree_add_item(sub_tree, hf_eigrp_extdata_proto, sub_tvb,
sub_offset, 1, ENC_BIG_ENDIAN);
sub_offset += 1;
/* Decode the external route flags */
dissect_eigrp_extdata_flags(sub_tree, sub_tvb, sub_offset);
sub_offset += 1;
offset += sub_offset;
return(offset);
}
/**
*@fn int dissect_eigrp_nexthop (proto_tree *tree, tvbuff_t *tvb, guint16 afi, int offset)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] afi IANA address family indicator
* @param[in] offset current byte offset in packet being processed
*
* @return int number of bytes process
*
* @par
* Dissect the next hop field which is in the "route TLVs". This function will
* handle all the various protocol AFIs and return the appropriate number of
* bytes processed
*/
static int
dissect_eigrp_nexthop (proto_tree *tree, tvbuff_t *tvb, guint16 afi, int offset)
{
/* dissect dest information */
switch (afi) {
case EIGRP_SF_IPv4:
case EIGRP_AF_IPv4:
proto_tree_add_item(tree, hf_eigrp_ipv4_nexthop, tvb, offset, 4,
ENC_BIG_ENDIAN);
offset += 4;
break;
case EIGRP_SF_IPv6:
case EIGRP_AF_IPv6:
proto_tree_add_item(tree, hf_eigrp_ipv6_nexthop, tvb, offset, 16,
ENC_NA);
offset += 16;
break;
case EIGRP_AF_IPX:
proto_tree_add_item(tree, hf_eigrp_ipx_nexthop_net, tvb, offset, 4,
ENC_NA);
offset += 4;
proto_tree_add_item(tree, hf_eigrp_ipx_nexthop_host, tvb, offset, 6,
ENC_NA);
offset += 6;
break;
case EIGRP_SF_COMMON:
break;
default:
break;
}
return(offset);
}
/**
*@fn void dissect_eigrp_general_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
* packet_info *pinfo, guint16 tlv)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] pinfo general data about the protocol
* @param[in] ti protocol item
* @param[in] tlv Specific TLV in to be dissected
*
* @par
* General EIGRP parameters carry EIGRP management information and are not
* specific to any one routed protocol.
*
*/
static void
dissect_eigrp_general_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
packet_info *pinfo, guint16 tlv)
{
switch (tlv) {
case EIGRP_TLV_PARAMETER:
dissect_eigrp_parameter(tree, tvb, pinfo, ti);
break;
case EIGRP_TLV_AUTH:
dissect_eigrp_auth_tlv(tree, tvb, pinfo, ti);
break;
case EIGRP_TLV_SEQ:
dissect_eigrp_seq_tlv(tree, tvb, pinfo);
break;
case EIGRP_TLV_SW_VERSION:
dissect_eigrp_sw_version(tvb, tree, ti);
break;
case EIGRP_TLV_NEXT_MCAST_SEQ:
dissect_eigrp_next_mcast_seq(tvb, tree, ti);
break;
case EIGRP_TLV_PEER_STUBINFO:
dissect_eigrp_peer_stubinfo(tvb, tree);
break;
case EIGRP_TLV_PEER_TERMINATION:
dissect_eigrp_peer_termination(pinfo, ti);
break;
case EIGRP_TLV_PEER_TIDLIST:
dissect_eigrp_peer_tidlist(tree, tvb);
break;
default:
expert_add_info_format(pinfo, ti, &ei_eigrp_tlv_type, "Unknown Generic TLV (0x%04x)", tlv);
break;
}
}
/**
*@fn int dissect_eigrp_ipv4_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
* packet_info *pinfo, guint16 tlv)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] pinfo general data about the protocol
* @param[in] tlv Specific TLV in to be dissected
*
* @return int number of bytes process
*
* @par
* Dissect the Legacy IPv4 route TLV; handles both the internal and external
* TLV types; This packet format is being deprecated and replaced with the
* Multi-Protocol packet formats as of EIGRP Release-8. This TLV format is used
* to maintain backward compatibility between older version so EIGRP, "MTR"
* EIGRP, and current shipping code.
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | IPv4 Nexthop |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Scaled Delay |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Scaled Bandwidth |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | MTU | Hopcount |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Reliability | Load | Internal Tag | Flag |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
static int
dissect_eigrp_ipv4_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
packet_info *pinfo, guint16 tlv)
{
int offset = 0;
int unreachable = FALSE;
proto_tree_add_item(tree, hf_eigrp_ipv4_nexthop, tvb, offset, 4,
ENC_BIG_ENDIAN);
offset += 4;
/* dissect external data if needed */
if ((tlv & EIGRP_TLV_TYPEMASK) == EIGRP_TLV_EXTERNAL) {
offset = dissect_eigrp_extdata(tree, tvb, offset);
}
/* dissect the metric */
offset = dissect_eigrp_legacy_metric(tree, tvb, offset);
/* dissect addresses */
offset = dissect_eigrp_ipv4_addr(ti, tree, tvb, pinfo, offset, unreachable);
return offset;
}
/**
*@fn void dissect_eigrp_atalk_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
* proto_item *ti, guint16 tlv)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] tlv Specific TLV in to be dissected
*
* @par
* Dissect the legacy AppleTalk route TLV; handles both the internal and external
* TLV type. The following represents the format
*/
static void
dissect_eigrp_atalk_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
guint16 tlv)
{
int offset = 0;
/* cable tlv? */
if (EIGRP_TLV_AT_CBL == tlv) {
proto_tree_add_text(tree, tvb, 0, 4, "AppleTalk Cable Range = %u-%u",
tvb_get_ntohs(tvb, 0), tvb_get_ntohs(tvb, 2));
proto_tree_add_item(tree, hf_eigrp_atalk_routerid, tvb, 4, 4,
ENC_BIG_ENDIAN);
proto_item_append_text(ti, ": Cable range= %u-%u, Router ID= %u",
tvb_get_ntohs(tvb, 0), tvb_get_ntohs(tvb, 2),
tvb_get_ntohl(tvb, 4));
} else {
proto_tree_add_text(tree, tvb, offset, 4, "NextHop Address = %u.%u",
tvb_get_ntohs(tvb, 0), tvb_get_ntohs(tvb, 2));
offset += 4;
/* dissect external data if needed */
if ((tlv & EIGRP_TLV_TYPEMASK) == EIGRP_TLV_EXTERNAL) {
offset = dissect_eigrp_extdata(tree, tvb,offset);
}
/* dissect the metric */
offset = dissect_eigrp_legacy_metric(tree, tvb, offset);
/* dissect cable range */
proto_tree_add_text(tree, tvb, offset, 4, "Cable range = %u-%u",
tvb_get_ntohs(tvb, 36), tvb_get_ntohs(tvb, 38));
proto_item_append_text(ti, ": %u-%u",
tvb_get_ntohs(tvb, 36), tvb_get_ntohs(tvb, 38));
}
return;
}
/**
*@fn void dissect_eigrp_ipv6_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
* packet_info *pinfo, guint16 tlv)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] pinfo general data about the protocol
* @param[in] tlv Specific TLV in to be dissected
*
* @par
* Dissect the Legacy IPv6 route TLV; handles both the internal and external
* TLV types; This packet format is being deprecated and replaced with the
* Multi-Protocol packet formats as of EIGRP Release-8. This TLV format is used
* to maintain backward compatibility between older version so EIGRP, "MTR"
* EIGRP, and current shipping code.
*/
static void
dissect_eigrp_ipv6_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
packet_info *pinfo, guint16 tlv)
{
int offset = 0;
int unreachable = FALSE;
proto_tree_add_item(tree, hf_eigrp_ipv6_nexthop, tvb, offset, 16,
ENC_NA);
offset += 16;
/* dissect external data if needed */
if ((tlv & EIGRP_TLV_TYPEMASK) == EIGRP_TLV_EXTERNAL) {
offset = dissect_eigrp_extdata(tree, tvb, offset);
}
/* dissect the metric */
offset = dissect_eigrp_legacy_metric(tree, tvb, offset);
/* dissect addresses */
dissect_eigrp_ipv6_addr(ti, tree, tvb, pinfo, offset, unreachable);
return;
}
/**
*@fn int dissect_eigrp_ipx_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
* packet_info *pinfo, guint16 tlv)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] pinfo general data about the protocol
* @param[in] tlv Specific TLV in to be dissected
*
* @return int number of bytes process
*
* @par
* Dissect the legacy IPX route TLV; handles both the internal and external
* TLV type. The following represents the format
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Nexthop Net |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Nexthop Host |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Nexthop Host(cont) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* Optional External Data:
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Ext RouterID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Ext Router ID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Ext Autonomous System Number |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Route Tag |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Ext Protocol | Ext Flags | External Metric |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | External Delay |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Scaled Delay |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Scaled Delay | Scaled Bandwidth |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Scaled Bandwidth | MTU |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | MTU(cont) | Hopcount | Reliability | Load |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Internal Tag | Flag |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*
*/
static int
dissect_eigrp_ipx_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
packet_info *pinfo, guint16 tlv)
{
int offset = 0;
int unreachable = FALSE;
/* nexthop for route... */
offset = dissect_eigrp_nexthop(tree, tvb, EIGRP_AF_IPX, offset);
/* dissect external data if needed */
if ((tlv & EIGRP_TLV_TYPEMASK) == EIGRP_TLV_EXTERNAL) {
offset = dissect_eigrp_ipx_extdata(tree, tvb, offset);
}
/* dissect the metric */
offset = dissect_eigrp_legacy_metric(tree, tvb, offset);
/* dissect addresses */
offset = dissect_eigrp_ipx_addr(ti, tree, tvb, pinfo, offset, unreachable);
return offset;
}
/**
*@fn void dissect_eigrp_ipv4_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
* packet_info *pinfo, proto_item *ti, guint16 tlv)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] pinfo general data about the protocol
* @param[in] ti protocol item
* @param[in] tlv Specific TLV in to be dissected
*
* @return int number of bytes process
*
* @par
* Dissect the Multi-Topology route TLV; This packet format has been deprecated
* and replaced with the Multi-Protocol packet formats as of EIGRP Release-8. Of
* course this means it will be around for a long long while. The following
* represents the format
*
* 1 2 3 0 1 1
* 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Reserved |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Topology Identifier | Family Identifier |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Router ID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Route Tag |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Scaled Delay |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Scaled Bandwidth |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | MTU | Hopcount |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Reliability | Load | Internal Tag | Flag |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |\/\/\/ NextHop (Family Specific Length) \/\/\/|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |\/\/\/ External Route Data (Optional) \/\/\/|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |\/\/\/ Destination (Family Specific Length) \/\/\/|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
static int
dissect_eigrp_multi_topology_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
packet_info *pinfo, guint16 tlv)
{
guint16 afi;
int offset = 2;
int unreachable = FALSE;
/* tid for you */
proto_tree_add_item(tree, hf_eigrp_tid, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
/* now it's all about the family */
afi = tvb_get_ntohs(tvb, offset);
proto_tree_add_item(tree, hf_eigrp_afi, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
/* gota have an id... */
proto_tree_add_item(tree, hf_eigrp_routerid, tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
/* tag.. your it! */
proto_tree_add_item(tree, hf_eigrp_legacy_metric_tag, tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
/* dissect the metric */
offset = dissect_eigrp_legacy_metric(tree, tvb, offset);
/* dissect nexthop */
offset = dissect_eigrp_nexthop(tree, tvb, afi, offset);
/* dissect external data if needed */
if ((tlv & EIGRP_TLV_TYPEMASK) == EIGRP_TLV_EXTERNAL) {
if (afi == EIGRP_AF_IPX) {
offset = dissect_eigrp_ipx_extdata(tree, tvb, offset);
} else {
offset = dissect_eigrp_extdata(tree, tvb, offset);
}
}
/* dissect dest information */
switch (afi) {
case EIGRP_AF_IPv4:
offset = dissect_eigrp_ipv4_addr(ti, tree, tvb, pinfo, offset, unreachable);
break;
case EIGRP_AF_IPv6:
offset = dissect_eigrp_ipv6_addr(ti, tree, tvb, pinfo, offset, unreachable);
break;
case EIGRP_AF_IPX:
offset = dissect_eigrp_ipx_addr(ti, tree, tvb, pinfo, offset, unreachable);
break;
case EIGRP_SF_COMMON:
case EIGRP_SF_IPv4:
case EIGRP_SF_IPv6:
offset = dissect_eigrp_service(ti, tree, tvb, pinfo, offset);
break;
default:
proto_tree_add_expert(tree, pinfo, &ei_eigrp_afi, tvb, offset, -1);
}
return offset;
}
/**
*@fn int dissect_eigrp_metric_comm (proto_tree *tree, tvbuff_t *tvb, int offset, int limit)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] offset current byte offset in packet being processed
* @param[in] limit maximum number of bytes which can be process
*
* @return int number of bytes process
*
* @par
* Dissect extended community attached to metric TLVs to support VPNv4
* deployments, The following represents the format
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Type high | Type low(*) | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Value |
* | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
static int
dissect_eigrp_metric_comm (proto_tree *tree, tvbuff_t *tvb, int offset, int limit)
{
int comm_type;
while (limit > 0) {
comm_type = tvb_get_ntohs(tvb, offset);
offset++;
switch (comm_type) {
/*
* Tag for this route. It is present for all EIGRP VPNv4
* routes, internal and external
*/
case EIGRP_EXTCOMM_EIGRP:
proto_tree_add_text(tree, tvb, offset, 8,
"Type(EIGRP_EXTCOMM_EIGRP): Flag(0x%02x) Tag(%u)",
tvb_get_ntohs(tvb, 0),
tvb_get_ntohl(tvb, 2));
break;
case EIGRP_EXTCOMM_VRR:
proto_tree_add_text(tree, tvb, offset, 8,
"Type(EIGRP_EXTCOMM_VRR)): RES(0x%02x) RID(0x%04x)",
tvb_get_ntohs(tvb, 0),
tvb_get_ntohl(tvb, 2));
break;
/*
* Vecmetric information for given EIGRP VPNv4 route,
* applies to both internal and external
*/
case EIGRP_EXTCOMM_DAD:
proto_tree_add_text(tree, tvb, offset, 8,
"Type(EIGRP_EXTCOMM_DAD): AS(%u):SDLY(%u)",
tvb_get_ntohs(tvb, 0),
tvb_get_ntohl(tvb, 2));
break;
case EIGRP_EXTCOMM_VRHB:
proto_tree_add_text(tree, tvb, offset, 8,
"Type(EIGRP_EXTCOMM_VRHB): REL(%u) HOP(%u) SBW(%u)",
tvb_get_guint8(tvb, 0),
tvb_get_guint8(tvb, 1),
tvb_get_ntohl(tvb, 2));
break;
case EIGRP_EXTCOMM_SRLM:
proto_tree_add_text(tree, tvb, offset, 8,
"Type(EIGRP_EXTCOMM_SRLM): RES(%u) LOAD(%u) MTU(%u)",
tvb_get_guint8(tvb, 0),
tvb_get_guint8(tvb, 1),
tvb_get_ntohl(tvb, 2));
break;
/*
* External information for given EIGRP VPNv4 route,
* applies to only to external routes
*/
case EIGRP_EXTCOMM_SAR:
proto_tree_add_text(tree, tvb, offset, 8,
"Type(EIGRP_EXTCOMM_SAR): xAS(%u) xRID(%u)",
tvb_get_ntohs(tvb, 0),
tvb_get_ntohl(tvb, 2));
break;
case EIGRP_EXTCOMM_RPM:
proto_tree_add_text(tree, tvb, offset, 8,
"Type(EIGRP_EXTCOMM_RPM): xProto(%u) xMETRIC(%u)",
tvb_get_ntohs(tvb, 0),
tvb_get_ntohl(tvb, 2));
break;
case EIGRP_EXTCOMM_SOO_ASFMT:
case EIGRP_EXTCOMM_SOO_ADRFMT:
proto_tree_add_text(tree, tvb, offset, 8,
"Type(EIGRP_EXTCOMM_SOO): AS(%u) TAG(%u)",
tvb_get_ntohs(tvb, 0),
tvb_get_ntohl(tvb, 2));
break;
}
/*on to the next */
offset += 8;
limit -= 8;
if (0 != limit%8) {
break;
}
}
return(offset);
}
/**
*@fn int dissect_eigrp_wide_metric_attr (proto_tree *tree, tvbuff_t *tvb,
* int offset, int limit)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] offset current byte offset in packet being processed
* @param[in] limit maximum number of words which should be process
*
* @return int number of bytes process
*
* @par
* Dissect the Metric Attributes which (optionally) are part of the wide-metric
* route TLV. Some of the attributes which effect the metric are controlled by
* K6 which is now part of the Parameter TLV. Also, eh extended community TLV is
* no longer used, as it's now appended to the route
*/
static int
dissect_eigrp_wide_metric_attr (proto_tree *tree, tvbuff_t *tvb,
int offset, int limit)
{
proto_item *sub_ti;
proto_tree *sub_tree;
tvbuff_t *sub_tvb;
int sub_offset;
guint16 attr_offset = 0;
guint8 attr_opcode = 0;
limit *= 2; /* words to bytes */
sub_ti = proto_tree_add_text(tree, tvb, offset, limit, "Attributes");
sub_tree = proto_item_add_subtree(sub_ti, ett_eigrp_tlv_attr);
sub_tvb = tvb_new_subset(tvb, offset, limit, -1);
sub_offset = 0;
while (limit > 0) {
attr_opcode = tvb_get_guint8(sub_tvb, sub_offset);
proto_tree_add_item(sub_tree, hf_eigrp_attr_opcode, sub_tvb,
sub_offset, 1, ENC_BIG_ENDIAN);
sub_offset += 1;
attr_offset = tvb_get_guint8(sub_tvb, sub_offset) * 2;
proto_tree_add_item(sub_tree, hf_eigrp_attr_offset, sub_tvb,
sub_offset, 1, ENC_BIG_ENDIAN);
sub_offset += 1;
switch (attr_opcode) {
case EIGRP_ATTR_NOOP:
break;
case EIGRP_ATTR_SCALED:
proto_tree_add_item(sub_tree, hf_eigrp_attr_scaled, sub_tvb,
sub_offset, 4, ENC_BIG_ENDIAN);
break;
case EIGRP_ATTR_TAG:
proto_tree_add_item(sub_tree, hf_eigrp_attr_tag, sub_tvb,
sub_offset, 4, ENC_BIG_ENDIAN);
break;
case EIGRP_ATTR_COMM:
dissect_eigrp_metric_comm(sub_tree,
tvb_new_subset(sub_tvb, sub_offset, 8, -1),
sub_offset, limit);
break;
case EIGRP_ATTR_JITTER:
proto_tree_add_item(sub_tree, hf_eigrp_attr_jitter, sub_tvb,
sub_offset, 4, ENC_BIG_ENDIAN);
break;
case EIGRP_ATTR_QENERGY:
proto_tree_add_item(sub_tree, hf_eigrp_attr_qenergy, sub_tvb,
sub_offset, 4, ENC_BIG_ENDIAN);
break;
case EIGRP_ATTR_ENERGY:
proto_tree_add_item(sub_tree, hf_eigrp_attr_energy, sub_tvb,
sub_offset, 4, ENC_BIG_ENDIAN);
break;
default:
break;
}
sub_offset += attr_offset;
limit -= (EIGRP_ATTR_HDRLEN + attr_offset);
}
offset += sub_offset;
return(offset);
}
/**
*@fn int dissect_eigrp_wide_metric (proto_tree *tree, tvbuff_t *tvb, int offset)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] offset current byte offset in packet being processed
*
* @return int number of bytes process
*
* @par
* Dissect the latest-n-greatest "Wide"Metric" definition for EIGRP. This
* definition was created to address the higher speed links and should handle
* things until we break the speed of light *wink*
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Offset | Priority | Reliability | Load |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | MTU | Hopcount |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Delay |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Delay | Bandwidth |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Bandwidth |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Reserved | Flags |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |\/\/\/ Extended Metrics (Variable Length) \/\/\/|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
static int
dissect_eigrp_wide_metric (proto_tree *tree, tvbuff_t *tvb, int offset)
{
proto_item *sub_ti;
proto_tree *sub_tree;
tvbuff_t *sub_tvb;
gint8 attr_size = 0;
guint64 big_num;
sub_ti = proto_tree_add_text(tree, tvb, offset, 24, "Wide Metric");
sub_tree = proto_item_add_subtree(sub_ti, ett_eigrp_tlv_metric);
sub_tvb = tvb_new_subset(tvb, offset, 24, -1);
attr_size = tvb_get_guint8(sub_tvb, 0);
proto_tree_add_item(sub_tree, hf_eigrp_metric_offset,
sub_tvb, 0, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(sub_tree, hf_eigrp_metric_priority,
sub_tvb, 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(sub_tree, hf_eigrp_metric_rel,
sub_tvb, 2, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(sub_tree, hf_eigrp_metric_load,
sub_tvb, 3, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(sub_tree, hf_eigrp_metric_mtu,
sub_tvb, 4, 3, ENC_BIG_ENDIAN);
proto_tree_add_item(sub_tree, hf_eigrp_metric_hopcount,
sub_tvb, 7, 1, ENC_BIG_ENDIAN);
/* The one-way latency along an unloaded path to the destination
* expressed in units of nanoseconds per kilobyte. This number is not
* scaled, as is the case with scaled delay. A delay of 0xFFFFFFFFFFFF
* indicates an unreachable route. */
big_num = tvb_get_ntoh64(sub_tvb, 8);
big_num >>= 16;
if (big_num == G_GINT64_CONSTANT(0x0000ffffffffffffU)) {
proto_tree_add_text(sub_tree, sub_tvb, 8, 6, "Delay: Infinity");
} else {
proto_tree_add_text(sub_tree, sub_tvb, 8, 6, "Delay: %" G_GINT64_MODIFIER "u", big_num);
}
/* The path bandwidth measured in kilobyte per second as presented by
* the interface. This number is not scaled, as is the case with scaled
* bandwidth. A bandwidth of 0xFFFFFFFFFFFF indicates an unreachable
* route.
*/
big_num = tvb_get_ntoh64(sub_tvb, 14);
big_num >>= 16;
if (big_num == G_GINT64_CONSTANT(0x0000ffffffffffffU)) {
proto_tree_add_text(sub_tree, sub_tvb, 14, 6, "Bandwidth: Infinity");
} else {
proto_tree_add_text(sub_tree, sub_tvb, 14, 6, "Bandwidth: %" G_GINT64_MODIFIER "u", big_num);
}
proto_tree_add_item(sub_tree, hf_eigrp_metric_reserved, sub_tvb, 20, 2,
ENC_BIG_ENDIAN);
/* Decode the route flags field */
dissect_eigrp_metric_flags(sub_tree, sub_tvb, 22, 2);
offset += 24;
/* any extended metric attributes? */
if (attr_size > 0) {
offset = dissect_eigrp_wide_metric_attr(tree, tvb, offset, attr_size);
}
return(offset);
}
/**
*@fn int dissect_eigrp_multi_protocol_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
* packet_info *pinfo, guint16 tlv)
*
* @param[in,out] tree detail dissection result
* @param[in] tvb packet data
* @param[in] ti protocol item
* @param[in] pinfo general data about the protocol
*
* @return int number of bytes process
*
* @par
* Dissect the Multi-Protocol (TLV Version 2.0) TLV format definition. The following
* represents the format
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Topology Identifier | Family Identifier |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Router ID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Wide Metric |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |\/\/\/ Extended Metrics (Variable Length) \/\/\/|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |\/\/\/ NextHop (Family Specific Length) \/\/\/|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |\/\/\/ External Route Data (Optional) \/\/\/|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |\/\/\/ Destination (Family Specific Length) \/\/\/|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
static int
dissect_eigrp_multi_protocol_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
packet_info *pinfo, guint16 tlv)
{
int offset = 0;
guint16 afi;
int unreachable = FALSE;
/* tid for you */
proto_tree_add_item(tree, hf_eigrp_tid, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
/* now it's all about the family */
afi = tvb_get_ntohs(tvb, offset);
proto_tree_add_item(tree, hf_eigrp_afi, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
/* gota have an id... */
proto_tree_add_item(tree, hf_eigrp_routerid, tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
/* decode the wide metric */
offset = dissect_eigrp_wide_metric(tree, tvb, offset);
/* dissect nexthop */
offset = dissect_eigrp_nexthop(tree, tvb, afi, offset);
/* dissect external data if needed */
if ((tlv & EIGRP_TLV_TYPEMASK) == EIGRP_TLV_EXTERNAL) {
if (afi == EIGRP_AF_IPX) {
offset = dissect_eigrp_ipx_extdata(tree, tvb, offset);
} else {
offset = dissect_eigrp_extdata(tree, tvb, offset);
}
}
/* dissect dest information */
switch (afi) {
case EIGRP_AF_IPv4:
offset = dissect_eigrp_ipv4_addr(ti, tree, tvb, pinfo, offset, unreachable);
break;
case EIGRP_AF_IPv6:
offset = dissect_eigrp_ipv6_addr(ti, tree, tvb, pinfo, offset, unreachable);
break;
case EIGRP_AF_IPX:
offset = dissect_eigrp_ipx_addr(ti, tree, tvb, pinfo, offset, unreachable);
break;
case EIGRP_SF_COMMON:
case EIGRP_SF_IPv4:
case EIGRP_SF_IPv6:
offset = dissect_eigrp_service(ti, tree, tvb, pinfo, offset);
break;
default:
proto_tree_add_expert(tree, pinfo, &ei_eigrp_afi, tvb, offset, -1);
}
return offset;
}
/**
*@fn int dissect_eigrp (proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, void *data)
*
* @param[in] tvb packet data
* @param[in] pinfo general data about the protocol
* @param[in,out] tree detail dissection result
*
* @return int 0 if packet is not for this decoder
*
* @par
* This function is called to dissect the packets presented to it. The packet
* data is held in a special buffer referenced here as tvb. The packet info
* structure contains general data about the protocol, and can update
* information here. The tree parameter is where the detail dissection takes
* place.
*/
#include <epan/in_cksum.h>
static guint16 ip_checksum(const guint8 *ptr, int len)
{
vec_t cksum_vec[1];
cksum_vec[0].ptr = ptr;
cksum_vec[0].len = len;
return in_cksum(&cksum_vec[0], 1);
}
static int
dissect_eigrp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{
proto_item *ti;
proto_tree *eigrp_tree = NULL, *tlv_tree;
guint opcode, vrid;
guint16 tlv, checksum, cacl_checksum;
guint32 ack, size, offset = EIGRP_HEADER_LENGTH;
/* Make entries in Protocol column and Info column on summary display */
col_set_str(pinfo->cinfo, COL_PROTOCOL, "EIGRP");
/* This field shows up as the "Info" column in the display; you should use
* it, if possible, to summarize what's in the packet, so that a user
* looking at the list of packets can tell what type of packet it is. See
* section 1.5 for more information.
*/
col_clear(pinfo->cinfo, COL_INFO);
opcode = tvb_get_guint8(tvb, 1);
ack = tvb_get_ntohl(tvb, 12);
if ((opcode == EIGRP_OPC_HELLO) && (0 != ack)) {
opcode = EIGRP_OPC_ACK;
}
col_add_str(pinfo->cinfo, COL_INFO,
val_to_str(opcode, eigrp_opcode2string, "Unknown OpCode (0x%04x)"));
/* A protocol dissector may be called in 2 different ways - with, or
* without a non-null "tree" argument.
* Note also that there is no guarantee, the first time the dissector is
* called, whether "tree" will be null or not; your dissector must work
* correctly, building or updating whatever state information is necessary,
* in either case.
*/
/* NOTE: The offset and length values in the call to
* "proto_tree_add_item()" define what data bytes to highlight in the
* hex display window when the line in the protocol tree display
* corresponding to that item is selected.
*/
/* create display subtree for the protocol */
ti = proto_tree_add_protocol_format(tree, proto_eigrp, tvb, 0, -1,
"Cisco EIGRP");
eigrp_tree = proto_item_add_subtree(ti, ett_eigrp);
proto_tree_add_item(eigrp_tree, hf_eigrp_version, tvb, 0, 1,
ENC_BIG_ENDIAN);
proto_tree_add_item(eigrp_tree, hf_eigrp_opcode, tvb, 1, 1,
ENC_BIG_ENDIAN);
size = tvb_length(tvb);
checksum = tvb_get_ntohs(tvb, 2);
cacl_checksum = ip_checksum(tvb_get_ptr(tvb, 0, size), size);
if (cacl_checksum == checksum) {
proto_tree_add_text(eigrp_tree, tvb, 2, 2,
"Checksum: 0x%02x [incorrect]",
checksum);
expert_add_info(pinfo, ti, &ei_eigrp_checksum_bad);
} else {
proto_tree_add_text(eigrp_tree, tvb, 2, 2,
"Checksum: 0x%02x [correct]", checksum);
}
/* Decode the EIGRP Flags Field */
proto_tree_add_bitmask(eigrp_tree, tvb, 4, hf_eigrp_flags, ett_eigrp_flags,
eigrp_flag_fields, ENC_BIG_ENDIAN);
proto_tree_add_item(eigrp_tree, hf_eigrp_sequence, tvb, 8, 4,
ENC_BIG_ENDIAN);
proto_tree_add_item(eigrp_tree, hf_eigrp_acknowledge, tvb, 12, 4,
ENC_BIG_ENDIAN);
/* print out what family we dealing with... */
ti = proto_tree_add_item(eigrp_tree, hf_eigrp_vrid, tvb, 16, 2,
ENC_BIG_ENDIAN);
vrid = (tvb_get_ntohs(tvb, 16) & EIGRP_VRID_MASK);
proto_item_append_text(ti, " %s", val_to_str_const(vrid, eigrp_vrid2string, ""));
/* print autonomous-system */
proto_tree_add_item(eigrp_tree, hf_eigrp_as, tvb, 18, 2,
ENC_BIG_ENDIAN);
switch (opcode) {
case EIGRP_OPC_IPXSAP:
call_dissector(ipxsap_handle,
tvb_new_subset_remaining(tvb, EIGRP_HEADER_LENGTH), pinfo,
eigrp_tree);
break;
default:
while (tvb_reported_length_remaining(tvb, offset) > 0) {
tlv = tvb_get_ntohs(tvb, offset);
/* it's a rose by the wrong name... */
if (tlv == EIGRP_TLV_MTR_TIDLIST) {
tlv = EIGRP_TLV_PEER_TIDLIST;
}
size = tvb_get_ntohs(tvb, offset + 2);
if (size == 0) {
proto_tree_add_expert(eigrp_tree, pinfo, &ei_eigrp_tlv_len, tvb, offset, -1);
return(tvb_length(tvb));
}
ti = proto_tree_add_text(eigrp_tree, tvb, offset, size, "%s",
val_to_str(tlv, eigrp_tlv2string, "Unknown TLV (0x%04x)"));
tlv_tree = proto_item_add_subtree(ti, ett_eigrp_tlv);
proto_tree_add_item(tlv_tree, hf_eigrp_tlv_type, tvb,
offset, 2, ENC_BIG_ENDIAN);
proto_tree_add_item(tlv_tree, hf_eigrp_tlv_len, tvb,
(offset + 2), 2, ENC_BIG_ENDIAN);
switch (tlv & EIGRP_TLV_RANGEMASK) {
case EIGRP_TLV_GENERAL:
dissect_eigrp_general_tlv(ti, tlv_tree, tvb_new_subset(tvb, (offset + 4), (size - 4), -1), pinfo, tlv);
break;
case EIGRP_TLV_IPv4:
dissect_eigrp_ipv4_tlv(ti, tlv_tree, tvb_new_subset(tvb, (offset + 4), (size - 4), -1), pinfo, tlv);
break;
case EIGRP_TLV_ATALK:
dissect_eigrp_atalk_tlv(ti, tlv_tree, tvb_new_subset(tvb, (offset + 4), (size - 4), -1), tlv);
break;
case EIGRP_TLV_IPX:
dissect_eigrp_ipx_tlv(ti, tlv_tree, tvb_new_subset(tvb, (offset + 4), (size - 4), -1), pinfo, tlv);
break;
case EIGRP_TLV_IPv6:
dissect_eigrp_ipv6_tlv(ti, tlv_tree, tvb_new_subset(tvb, (offset + 4), (size - 4), -1), pinfo, tlv);
break;
case EIGRP_TLV_MP:
dissect_eigrp_multi_protocol_tlv(ti, tlv_tree, tvb_new_subset(tvb, (offset + 4), (size - 4), -1),
pinfo, tlv);
break;
case EIGRP_TLV_MTR:
dissect_eigrp_multi_topology_tlv(ti, tlv_tree, tvb_new_subset(tvb, (offset + 4), (size - 4), -1),
pinfo, tlv);
break;
default:
expert_add_info_format(pinfo, ti, &ei_eigrp_tlv_type, "Unknown TLV Group (0x%04x)", tlv);
}
offset += size;
}
break;
}
/* Return the amount of data this dissector was able to dissect */
return(tvb_length(tvb));
}
/**
*@fn void proto _ register _ eigrp (void)
*
* @usage
* you can not have the function name inside a comment or else Wireshark
* will fail with "duplicate protocol" error. Dont you hate it when tools
* try to be to smart :(
*
* @par
* Register the protocol with Wireshark
* this format is require because a script is used to build the C function
* that calls all the protocol registration.
*/
void
proto_register_eigrp(void)
{
/* Setup list of header fields See Section 1.6.1 for details
*/
static hf_register_info hf[] = {
/*
*
* EIGRP Packet Header definitions
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |Ver | Opcode | Checksum |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Flags |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Sequence number |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Acknowledgement number |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Virtual Router ID | Autonomous system number |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
{ &hf_eigrp_version,
{ "Version", "eigrp.version",
FT_UINT8, BASE_DEC, NULL, 0x0,
"Version - Version of EIGRP packet format", HFILL }
},
{ &hf_eigrp_opcode,
{ "Opcode", "eigrp.opcode",
FT_UINT8, BASE_DEC, VALS(eigrp_opcode2string), 0x0,
"Opcode - Operation code indicating the message type", HFILL }
},
{ &hf_eigrp_flags,
{ "Flags", "eigrp.flags",
FT_UINT32, BASE_HEX, NULL, 0x0,
"Flag - Initialization bit and is used in establishing "
"a new neighbor relationship", HFILL }
},
{ &hf_eigrp_sequence,
{ "Sequence", "eigrp.seq",
FT_UINT32, BASE_DEC, NULL, 0x0,
"Sequence number -- used to send messages reliably", HFILL }
},
{ &hf_eigrp_acknowledge,
{ "Acknowledge", "eigrp.ack",
FT_UINT32, BASE_DEC, NULL, 0x0,
"Acknowledge number -- used to send messages reliably", HFILL }
},
{ &hf_eigrp_vrid,
{ "Virtual Router ID", "eigrp.vrid",
FT_UINT16, BASE_DEC, NULL, 0,
"Virtual Router ID - For each Virtual Router, there is a separate topology "
"table and routing/service table; even for matching AS. "
"This field allows the gateway to select which set router to use.", HFILL }
},
{ &hf_eigrp_as,
{ "Autonomous System", "eigrp.as",
FT_UINT16, BASE_DEC, NULL, 0x0,
"Autonomous system number - Each AS has a separate topology table "
"which for a give routing/service table. A gateway can participate "
"in more than one AS. This field allows the gateway to"
"select which set of topology tables to use.", HFILL }
},
/*
* Define eigrp_flags bits here
*
* Init bit definition. First unicast transmitted Update has this
* bit set in the flags field of the fixed header. It tells the neighbor
* to send its full topology table.
*/
{ &hf_eigrp_flags_init,
{ "Init", "eigrp.flags.init",
FT_BOOLEAN, 32, TFS(&tfs_set_notset), EIGRP_INIT_FLAG,
"Init - tells the neighbor to send its full topology table", HFILL }
},
/*
* Conditionally Received - Any packet with the CR-bit set can
* be accepted by an EIGRP speaker if and only if a previous Hello was
* received with the SEQUENCE_TYPE TLV present.
* This allows multicasts to be transmitted in order and reliably at the
* same time as unicasts are transmitted.
*/
{ &hf_eigrp_flags_condrecv,
{ "Conditional Receive", "eigrp.flags.condrecv",
FT_BOOLEAN, 32, TFS(&tfs_set_notset), EIGRP_CR_FLAG,
"Conditionally Received the next packet if address was in listed "
"in the previous HELLO", HFILL }
},
/*
* Restart flag is set in the hello and the init update
* packets during the nsf signaling period. A nsf-aware
* router looks at the RS flag to detect if a peer is restarting
* and maintain the adjacency. A restarting router looks at
* this flag to determine if the peer is helping out with the restart.
*/
{ &hf_eigrp_flags_restart,
{ "Restart", "eigrp.flags.restart",
FT_BOOLEAN, 32, TFS(&tfs_set_notset), EIGRP_RS_FLAG,
"Restart flag - Set in the HELLO and the initial "
"UPDATE packets during the nsf signaling period.", HFILL },
},
/*
* EOT bit. The End-of-Table flag marks the end of the start-up updates
* sent to a new peer. A nsf restarting router looks at this flag to
* determine if it has finished receiving the start-up updates from all
* peers. A nsf-aware router waits for this flag before cleaning up
* the stale routes from the restarting peer.
*/
{ &hf_eigrp_flags_eot,
{ "End Of Table", "eigrp.flags.eot",
FT_BOOLEAN, 32, TFS(&tfs_set_notset), EIGRP_EOT_FLAG,
"End-of-Table - Marks the end of the start-up UPDATES indicating the "
"complete topology database has been sent to a new peer", HFILL }
},
/**
* TLV type definitions. Generic (protocol-independent) TLV types are
* defined here. Protocol-specific ones are defined later
*
* +-----+------------------+
* | | | |
* | Type| Len | Vector |
* | | | |
* +-----+------------------+
*
* TLV type definitions. Generic (protocol-independent) TLV types are
* defined here. Protocol-specific ones are defined elsewhere.
*
* EIGRP_PARAMETER 0x0001 parameter
* EIGRP_AUTH 0x0002 authentication
* EIGRP_SEQUENCE 0x0003 sequenced packet
* EIGRP_SW_VERSION 0x0004 software version
* EIGRP_NEXT_MCAST_SEQ 0x0005 multicast sequence
* EIGRP_PEER_STUBINFO 0x0006 stub information
* EIGRP_PEER_TERMINATION 0x0007 peer termination
*/
{ &hf_eigrp_tlv_type,
{ "Type", "eigrp.tlv_type",
FT_UINT16, BASE_HEX, VALS(eigrp_tlv2string), 0x0,
"TLV Type", HFILL }
},
{ &hf_eigrp_tlv_len,
{ "Length", "eigrp.tlv.len",
FT_UINT16, BASE_DEC, NULL, 0x0,
"TLV Length", HFILL }
},
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Parameters TLV
*/
{ &hf_eigrp_par_k1, { "K1", "eigrp.par.k1", FT_UINT8, BASE_DEC, NULL, 0x0,
"Bandwidth/Throughput Coefficient", HFILL }},
{ &hf_eigrp_par_k2, { "K2", "eigrp.par.k2", FT_UINT8, BASE_DEC, NULL, 0x0,
"Load Coefficient", HFILL }},
{ &hf_eigrp_par_k3, { "K3", "eigrp.par.k3", FT_UINT8, BASE_DEC, NULL, 0x0,
"Delay/Latency Coefficient", HFILL }},
{ &hf_eigrp_par_k4, { "K4", "eigrp.par.k4", FT_UINT8, BASE_DEC, NULL, 0x0,
"Reliability Coefficient", HFILL }},
{ &hf_eigrp_par_k5, { "K5", "eigrp.par.k5", FT_UINT8, BASE_DEC, NULL, 0x0,
"Reliability Coefficient", HFILL }},
{ &hf_eigrp_par_k6, { "K6", "eigrp.par.k6", FT_UINT8, BASE_DEC, NULL, 0x0,
"Extended Metric Coefficient", HFILL }},
{ &hf_eigrp_par_holdtime,
{ "Hold Time", "eigrp.par.holdtime", FT_UINT16, BASE_DEC, NULL, 0x0,
"How long to ignore lost HELLO's", HFILL }
},
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Authentication TLV
*/
{ &hf_eigrp_auth_type,
{ "Type", "eigrp.auth.type",
FT_UINT16, BASE_DEC, VALS(eigrp_auth2string), 0x0,
NULL, HFILL }
},
{ &hf_eigrp_auth_len,
{ "Length", "eigrp.auth.length",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_eigrp_auth_keyid,
{ "Key ID", "eigrp.auth.keyid",
FT_UINT32, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_eigrp_auth_keyseq,
{ "Key Sequence", "eigrp.auth.keyseq",
FT_UINT32, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_eigrp_auth_digest,
{ "Digest", "eigrp.auth.digest",
FT_BYTES, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Sequence TLV
*/
{ &hf_eigrp_seq_addrlen,
{ "Address length", "eigrp.seq.addrlen",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_eigrp_seq_ipv4addr,
{ "IP Address", "eigrp.seq.ipv4addr",
FT_IPv4, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_eigrp_seq_ipv6addr,
{ "IPv6 Address", "eigrp.seq.ipv6addr",
FT_IPv6, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Next Multicast Sequence
*/
/*
* This was added to the hello containing the sequence TLV so that the
* hello packet could be more tightly bound to the multicast packet bearing
* the CR bit that follows it. The sequence number of the impending multicast
* is carried herein.
*/
{ &hf_eigrp_next_mcast_seq,
{ "Multicast Sequence", "eigrp.next_mcast_seq",
FT_UINT32, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Peer Stub Information TLV
*/
{ &hf_eigrp_stub_flags,
{ "Stub Options", "eigrp.stub_options",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL }
},
/*
* Define eigrp_stub_flags bits here
*/
{ &hf_eigrp_stub_flags_connected,
{ "Connected", "eigrp.stub_options.connected",
FT_BOOLEAN, 16, TFS(&tfs_set_notset), EIGRP_PEER_ALLOWS_CONNECTED,
NULL, HFILL }
},
{ &hf_eigrp_stub_flags_static,
{ "Static", "eigrp.stub_options.static",
FT_BOOLEAN, 16, TFS(&tfs_set_notset), EIGRP_PEER_ALLOWS_STATIC,
NULL, HFILL }
},
{ &hf_eigrp_stub_flags_summary,
{ "Summary", "eigrp.stub_options.summary",
FT_BOOLEAN, 16, TFS(&tfs_set_notset), EIGRP_PEER_ALLOWS_SUMMARY,
NULL, HFILL }
},
{ &hf_eigrp_stub_flags_redist,
{ "Redistributed", "eigrp.stub_options.redist",
FT_BOOLEAN, 16, TFS(&tfs_set_notset), EIGRP_PEER_ALLOWS_REDIST,
NULL, HFILL }
},
{ &hf_eigrp_stub_flags_leakmap,
{ "Leak-Map", "eigrp.stub_options.leakmap",
FT_BOOLEAN, 16, TFS(&tfs_set_notset), EIGRP_PEER_ALLOWS_LEAKING,
NULL, HFILL }
},
{ &hf_eigrp_stub_flags_recvonly,
{ "Receive-Only", "eigrp.stub_options.recvonly",
FT_BOOLEAN, 16, TFS(&tfs_set_notset), EIGRP_PEER_ALLOWS_RCVONLY,
NULL, HFILL }
},
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Peer Termination TLV
*/
/* Place holder - this TLV has no options */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* EIGRP 3.0 Vector Header (deprecated)
*/
/*
* common header for all version 3 tlvs
*/
{ &hf_eigrp_tid,
{ "Topology", "eigrp.tid",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_eigrp_afi,
{ "AFI", "eigrp.afi",
FT_UINT16, BASE_DEC, VALS(eigrp_afi2string), 0x0,
NULL, HFILL }
},
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* EIGRP TLV 1.2 (legacy) and TLV 3.0 Metric (deprecated) definition
*/
{ &hf_eigrp_legacy_metric_delay,
{ "Scaled Delay", "eigrp.old_metric.delay",
FT_UINT32, BASE_DEC, NULL, 0x0,
"delay, in 39.1 nanosec interments", HFILL }
},
{ &hf_eigrp_legacy_metric_bw,
{ "Scaled BW", "eigrp.old_metric.bw",
FT_UINT32, BASE_DEC, NULL, 0x0,
"bandwidth, in units of 1 Kbit/sec", HFILL }
},
{ &hf_eigrp_legacy_metric_mtu,
{ "MTU", "eigrp.old_metric.mtu",
FT_UINT24, BASE_DEC, NULL, 0x0,
"MTU, in octets", HFILL }
},
{ &hf_eigrp_legacy_metric_hopcount,
{ "Hop Count", "eigrp.old_metric.hopcount",
FT_UINT8, BASE_DEC, NULL, 0x0,
"Number of hops to destination", HFILL }
},
{ &hf_eigrp_legacy_metric_rel,
{ "Reliability", "eigrp.old_metric.rel",
FT_UINT8, BASE_DEC, NULL, 0x0,
"percent packets successfully tx/rx", HFILL }
},
{ &hf_eigrp_legacy_metric_load,
{ "Load", "eigrp.old_metric.load",
FT_UINT8, BASE_DEC, NULL, 0x0,
"percent of channel occupied", HFILL }
},
{ &hf_eigrp_legacy_metric_intag,
{ "Route Tag", "eigrp.old_metric.intag",
FT_UINT8, BASE_DEC, NULL, 0x0,
"Internal Route Tag", HFILL }
},
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* EIGRP 3.0 TIDLIST TLV (only survivor in MTR)
*/
{ &hf_eigrp_tidlist_tid,
{ "TID List", "eigrp.tidlist",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_eigrp_tidlist_flags,
{ "TID List Flags", "eigrp.tidlist.flags",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL }
},
{ &hf_eigrp_tidlist_len,
{ "TID List Size", "eigrp.tidlist.len",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_eigrp_routerid,
{ "RouterID", "eigrp.routerid",
FT_IPv4, BASE_NONE, NULL, 0x0,
"Router ID of injecting router", HFILL }
},
{ &hf_eigrp_legacy_metric_tag,
{ "Tag", "eigrp.old_metric.tag",
FT_UINT32, BASE_DEC, NULL, 0x0,
"route tag", HFILL }
},
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* PDM opaque flag field definitions
*/
{ &hf_eigrp_metric_flags_srcwd,
{ "Source Withdraw", "eigrp.metric.flags.srcwd",
FT_BOOLEAN, 8, TFS(&tfs_true_false), EIGRP_OPAQUE_SRCWD,
"Route Source Withdraw", HFILL }
},
{ &hf_eigrp_metric_flags_active,
{ "Route is Active", "eigrp.metric.flags.active",
FT_BOOLEAN, 8, TFS(&tfs_true_false), EIGRP_OPAQUE_ACTIVE,
"Route is currently in active state", HFILL }
},
{ &hf_eigrp_metric_flags_repl,
{ "Route is Replicated", "eigrp.metric.flags.repl",
FT_BOOLEAN, 8, TFS(&tfs_true_false), EIGRP_OPAQUE_REPL,
"Route is replicated from different tableid", HFILL }
},
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* EIGRP TLV 1.2/3.0 ExtData Definitions
*/
{ &hf_eigrp_extdata_origrid,
{ "Originating RouterID", "eigrp.extdata.origrid",
FT_IPv4, BASE_NONE, NULL, 0x0,
"Router ID of redistributing router", HFILL }
},
{ &hf_eigrp_extdata_as,
{ "Originating A.S.", "eigrp.extdata.as",
FT_UINT32, BASE_DEC, NULL, 0x0,
"Autonomous System of redistributing protocol", HFILL }
},
{ &hf_eigrp_extdata_tag,
{ "Administrative Tag", "eigrp.extdata.tag",
FT_UINT32, BASE_DEC, NULL, 0x0,
"Administrative Route Tag", HFILL }
},
{ &hf_eigrp_extdata_metric,
{ "External Metric", "eigrp.extdata.metric",
FT_UINT32, BASE_DEC, NULL, 0x0,
"Metric reported by redistributing protocol", HFILL }
},
{ &hf_eigrp_extdata_reserved,
{ "Reserved", "eigrp.extdata.reserved",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
/* IPX ExtData Definitions */
{ &hf_eigrp_ipx_extdata_delay,
{ "External Delay", "eigrp.extdata.ipx_delay",
FT_UINT16, BASE_DEC, NULL, 0x0,
"Delay reported by redistributing protocol", HFILL }
},
{ &hf_eigrp_ipx_extdata_metric,
{ "External Metric", "eigrp.extdata.ipx_metric",
FT_UINT16, BASE_DEC, NULL, 0x0,
"Delay reported by redistributing protocol", HFILL }
},
{ &hf_eigrp_extdata_proto,
{ "External Protocol ID", "eigrp.extdata.proto",
FT_UINT8, BASE_DEC, VALS(eigrp_proto2string), 0x0,
NULL, HFILL }
},
{ &hf_eigrp_extdata_flag_ext,
{ "Route is External", "eigrp.opaque.flag.ext",
FT_BOOLEAN, 8, TFS(&tfs_true_false), EIGRP_OPAQUE_EXT,
"External route", HFILL }
},
{ &hf_eigrp_extdata_flag_cd,
{ "Route is Candidate Default", "eigrp.opaque.flag.cd",
FT_BOOLEAN, 8, TFS(&tfs_true_false), EIGRP_OPAQUE_CD,
"Candidate-Default route", HFILL }
},
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* EIGRP TLV 2.0 "Wide" Metric format definition
*/
/* Number of 16bit words in the metric section, used to determine the
* start of the destination/attribute information.
*/
{ &hf_eigrp_metric_offset,
{ "Offset", "eigrp.metric.offset",
FT_UINT8, BASE_DEC, NULL, 0x0,
"Number of 16bit words to reach the start of the"
"destination/attribute information", HFILL }
},
/* Priority of the prefix when transmitting a group of destination
* addresses to neighboring routers. A priority of zero indicates no
* priority is set.
*/
{ &hf_eigrp_metric_priority,
{ "Priority", "eigrp.metric.priority",
FT_UINT8, BASE_DEC, NULL, 0x0,
"Priority of the prefix for ordering transmission", HFILL }
},
/** The current error rate for the path. Measured as an error
* percentage. A value of 255 indicates 100% reliability
*/
{ &hf_eigrp_metric_rel,
{ "Reliability", "eigrp.metric.reliability",
FT_UINT8, BASE_DEC, NULL, 0x0,
"percent packets successfully tx/rx", HFILL }
},
/** The load utilization of the path to the destination. Measured as a
* percentage of load. A value of 255 indicates 100% load.
*/
{ &hf_eigrp_metric_load,
{ "Load", "eigrp.metric.load",
FT_UINT8, BASE_DEC, NULL, 0x0,
"percent of channel occupied", HFILL }
},
/** The minimum maximum transmission unit size for the path to the
* destination. Not used in metric calculation, but available to
* underlying protocols
*/
{ &hf_eigrp_metric_mtu,
{ "MTU", "eigrp.metric.mtu",
FT_UINT24, BASE_DEC, NULL, 0x0,
"MTU, in octets", HFILL }
},
/** number of router traversals to the destination */
{ &hf_eigrp_metric_hopcount,
{ "Hop Count", "eigrp.metric.hopcount",
FT_UINT8, BASE_DEC, NULL, 0x0,
"Number of hops to destination", HFILL }
},
/* Reserved - Transmitted as 0x0000 */
{ &hf_eigrp_metric_reserved,
{ "Reserved", "eigrp.metric.reserved",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL }
},
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* EIGRP TLV 2.0 Extended Metric Attributes
*/
{ &hf_eigrp_attr_opcode,
{ "Opcode", "eigrp.attr.opcode",
FT_UINT8, BASE_DEC, VALS(eigrp_attr_opcode2string), 0x0,
"Opcode - Operation code indicating the attribute type", HFILL }
},
{ &hf_eigrp_attr_offset,
{ "Offset", "eigrp.attr.offset",
FT_UINT8, BASE_DEC, NULL, 0x0,
"Number of 2 byte words of data", HFILL }
},
{ &hf_eigrp_attr_scaled,
{ "Legacy Metric", "eigrp.attr.scaled",
FT_UINT16, BASE_DEC, NULL, 0x0,
"Metric calculated from legacy TLVs", HFILL }
},
{ &hf_eigrp_attr_tag,
{ "Tag", "eigrp.attr.tag",
FT_UINT16, BASE_DEC, NULL, 0x0,
"Tag assigned by admin for dest", HFILL }
},
{ &hf_eigrp_attr_jitter,
{ "Jitter", "eigrp.attr.jitter",
FT_UINT16, BASE_DEC, NULL, 0x0,
"Variation in path delay", HFILL }
},
{ &hf_eigrp_attr_qenergy,
{ "Q-Energy", "eigrp.attr.qenergy",
FT_UINT16, BASE_DEC, NULL, 0x0,
"Non-Active energy usage along path", HFILL }
},
{ &hf_eigrp_attr_energy,
{ "Energy", "eigrp.attr.energy",
FT_UINT16, BASE_DEC, NULL, 0x0,
"Active energy usage along path", HFILL }
},
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* IPv4 specific address definitions
*/
{ &hf_eigrp_ipv4_nexthop,
{ "NextHop", "eigrp.ipv4.nexthop",
FT_IPv4, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_eigrp_ipv4_prefixlen,
{ "Prefix Length", "eigrp.ipv4.prefixlen",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* IPv6 specific address definitions
*/
{ &hf_eigrp_ipv6_nexthop,
{ "NextHop", "eigrp.ipv6.nexthop",
FT_IPv6, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_eigrp_ipv6_prefixlen,
{ "Prefix Length", "eigrp.ipv6.prefixlen",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* IPX specific address definitions
*/
{ &hf_eigrp_ipx_nexthop_net,
{ "NextHop Net", "eigrp.ipx.nexthop_net",
FT_IPXNET, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_eigrp_ipx_nexthop_host,
{ "NextHop Host", "eigrp.ipx.nexthop_host",
FT_ETHER, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_eigrp_ipx_extdata_routerid,
{ "External RouterID", "eigrp.ipx.routerid",
FT_ETHER, BASE_NONE, NULL, 0x0,
"Router ID of redistributing router", HFILL }
},
{ &hf_eigrp_ipx_dest,
{ "Destination", "eigrp.ipx.dest",
FT_IPXNET, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* AppleTalk specific address definitions
*/
{ &hf_eigrp_atalk_routerid,
{ "AppleTalk Router ID", "eigrp.atalk.routerid",
FT_UINT32, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Service Advertisement Framework definitions
*/
{ &hf_eigrp_saf_service,
{ "Service", "eigrp.saf.service",
FT_UINT16, BASE_DEC, VALS(eigrp_saf_srv2string), 0x0,
NULL, HFILL }
},
{ &hf_eigrp_saf_subservice,
{ "Sub-Service", "eigrp.saf.subservice",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_eigrp_saf_guid,
{ "GUID", "eigrp.saf.guid",
FT_GUID, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_eigrp_saf_data_type,
{ "Type", "eigrp.saf.data.type",
FT_UINT16, BASE_HEX, VALS(eigrp_saf_type2string), 0x0,
"SAF Message Data Type", HFILL }
},
{ &hf_eigrp_saf_data_length,
{ "Length", "eigrp.saf.data.length",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_eigrp_saf_data_sequence,
{ "Sequence", "eigrp.saf.data.sequence",
FT_UINT32, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_eigrp_saf_reachability_afi,
{ "AFI", "eigrp.saf.data.reachability.afi",
FT_UINT16, BASE_DEC, VALS(eigrp_afi2string), 0x0,
NULL, HFILL }
},
{ &hf_eigrp_saf_reachability_port,
{ "Port", "eigrp.saf.data.reachability.port",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_eigrp_saf_reachability_protocol,
{ "Protocol", "eigrp.saf.data.reachability.protocol",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_eigrp_saf_reachability_addr_ipv4,
{ "IPv4 Addr", "eigrp.saf.data.reachability.addr_ipv4",
FT_IPv4, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_eigrp_saf_reachability_addr_ipv6,
{ "IPv6 Addr", "eigrp.saf.data.reachability.addr_ipv6",
FT_IPv6, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_eigrp_saf_reachability_addr_hex,
{ "Addr", "eigrp.saf.data.reachability.addr_hex",
FT_BYTES, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
/* misc field used in a couple places */
{ &hf_eigrp_nullpad,
{ "Nullpad", "eigrp.nullpad",
FT_BYTES, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
};
/* Setup protocol subtree array */
static gint *ett[] = {
/* header flag */
&ett_eigrp,
&ett_eigrp_flags,
/* tlv specific */
&ett_eigrp_tlv,
&ett_eigrp_tlv_metric,
&ett_eigrp_tlv_attr,
&ett_eigrp_tlv_extdata,
&ett_eigrp_tidlist,
&ett_eigrp_stub_flags,
&ett_eigrp_saf_reachability,
/* metric tlv specific */
&ett_eigrp_metric_flags,
&ett_eigrp_extdata_flags,
};
static ei_register_info ei[] = {
{ &ei_eigrp_peer_termination, { "eigrp.peer_termination", PI_RESPONSE_CODE, PI_NOTE, "Peer Termination", EXPFILL }},
{ &ei_eigrp_auth_len, { "eigrp.auth.length.invalid", PI_MALFORMED, PI_WARN, "Invalid auth len", EXPFILL }},
{ &ei_eigrp_auth_type, { "eigrp.auth.type.invalid", PI_PROTOCOL, PI_WARN, "Invalid auth type", EXPFILL }},
{ &ei_eigrp_seq_addrlen, { "eigrp.seq.addrlen.invalid", PI_MALFORMED, PI_ERROR, "Invalid address length", EXPFILL }},
{ &ei_eigrp_peer_termination_graceful, { "eigrp.peer_termination_graceful", PI_RESPONSE_CODE, PI_NOTE, "Peer Termination (Graceful Shutdown)", EXPFILL }},
{ &ei_eigrp_prefixlen, { "eigrp.prefixlen.invalid", PI_MALFORMED, PI_WARN, "Invalid prefix length", EXPFILL }},
{ &ei_eigrp_unreachable, { "eigrp.unreachable", PI_RESPONSE_CODE, PI_NOTE, "Unreachable", EXPFILL }},
{ &ei_eigrp_tlv_type, { "eigrp.tlv_type.unknown", PI_PROTOCOL, PI_WARN, "Unknown TLV", EXPFILL }},
{ &ei_eigrp_afi, { "eigrp.afi.unknown", PI_PROTOCOL, PI_WARN, "Unknown AFI", EXPFILL }},
{ &ei_eigrp_checksum_bad, { "eigrp.checksum.bad", PI_CHECKSUM, PI_WARN, "Bad Checksum", EXPFILL }},
{ &ei_eigrp_tlv_len, { "eigrp.tlv.len.invalid", PI_MALFORMED, PI_ERROR, "Corrupt TLV (Zero Size)", EXPFILL }},
};
expert_module_t* expert_eigrp;
/* Register the protocol name and description */
proto_eigrp = proto_register_protocol(
"Enhanced Interior Gateway Routing Protocol", /* name */
"EIGRP", /* short name */
"eigrp" /* abbrev */
);
/* Required function calls to register the header fields and subtrees used */
proto_register_field_array(proto_eigrp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
expert_eigrp = expert_register_protocol(proto_eigrp);
expert_register_field_array(expert_eigrp, ei, array_length(ei));
}
/**
*@fn void proto_reg_handoff_eigrp(void)
*
* @usage
* This exact format is required because a script is used to find these
* routines and create the code that calls these routines.
*
* @par
* If this dissector uses sub-dissector registration add a registration routine.
*
* This form of the reg_handoff function is used if if you perform registration
* functions which are dependent upon prefs. If this function is registered as
* a prefs callback (see prefs_register_protocol above) this function is also
* called by preferences whenever "Apply" is pressed;
*
* In that case, it should accommodate being called more than once.
*/
void
proto_reg_handoff_eigrp(void)
{
dissector_handle_t eigrp_handle;
ipxsap_handle = find_dissector("ipxsap");
media_type_table = find_dissector_table("media_type");
eigrp_handle = new_create_dissector_handle(dissect_eigrp, proto_eigrp);
dissector_add_uint("ip.proto", IP_PROTO_EIGRP, eigrp_handle);
dissector_add_uint("ddp.type", DDP_EIGRP, eigrp_handle);
dissector_add_uint("ipx.socket", IPX_SOCKET_EIGRP, eigrp_handle);
}