summaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-eigrp.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/dissectors/packet-eigrp.c')
-rw-r--r--epan/dissectors/packet-eigrp.c3407
1 files changed, 3407 insertions, 0 deletions
diff --git a/epan/dissectors/packet-eigrp.c b/epan/dissectors/packet-eigrp.c
new file mode 100644
index 00000000..3c663455
--- /dev/null
+++ b/epan/dissectors/packet-eigrp.c
@@ -0,0 +1,3407 @@
+/* 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>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "config.h"
+
+#include <epan/packet.h>
+#include <epan/addr_resolv.h>
+#include <epan/addr_and_mask.h>
+#include <epan/ipproto.h>
+#include <epan/expert.h>
+
+#include "packet-eigrp.h"
+#include "packet-ipx.h"
+#include "packet-atalk.h"
+
+/*
+ * Originally Cisco proprietary; now the subject of RFC 7868.
+ */
+
+/**
+ * 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.. who's 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_CD 0x02 /*!< Candidate Default */
+#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 int * const 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 int * const 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_cd = -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;
+
+/* Generated from convert_proto_tree_add_text.pl */
+static int hf_eigrp_ipx_address = -1;
+static int hf_eigrp_release = -1;
+static int hf_eigrp_tlv_version = -1;
+static int hf_eigrp_ipv4_destination = -1;
+static int hf_eigrp_ipv6_destination = -1;
+static int hf_eigrp_appletalk_cable_range = -1;
+static int hf_eigrp_nexthop_address = -1;
+static int hf_eigrp_cable_range = -1;
+static int hf_eigrp_metric_delay = -1;
+static int hf_eigrp_metric_bandwidth = -1;
+static int hf_eigrp_checksum = -1;
+static int hf_eigrp_checksum_status = -1;
+static int hf_eigrp_metric_comm_type = -1;
+static int ett_metric_comm_type = -1;
+static int hf_eigrp_extcomm_eigrp_flag = -1;
+static int hf_eigrp_extcomm_eigrp_tag = -1;
+static int hf_eigrp_extcomm_eigrp_res = -1;
+static int hf_eigrp_extcomm_eigrp_rid = -1;
+static int hf_eigrp_extcomm_eigrp_as = -1;
+static int hf_eigrp_extcomm_eigrp_sdly = -1;
+static int hf_eigrp_extcomm_eigrp_rel = -1;
+static int hf_eigrp_extcomm_eigrp_hop = -1;
+static int hf_eigrp_extcomm_eigrp_sbw = -1;
+static int hf_eigrp_extcomm_eigrp_load = -1;
+static int hf_eigrp_extcomm_eigrp_mtu = -1;
+static int hf_eigrp_extcomm_eigrp_xas = -1;
+static int hf_eigrp_extcomm_eigrp_xrid = -1;
+static int hf_eigrp_extcomm_eigrp_xproto = -1;
+static int hf_eigrp_extcomm_eigrp_xmetric = -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;
+static expert_field ei_eigrp_tlv_trunc = 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}
+};
+
+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}
+};
+
+static const value_string eigrp_metric_comm_type_vals[] = {
+ { EIGRP_EXTCOMM_EIGRP, "EIGRP_EXTCOMM_EIGRP"},
+ { EIGRP_EXTCOMM_VRR, "EIGRP_EXTCOMM_VRR"},
+ { EIGRP_EXTCOMM_DAD, "EIGRP_EXTCOMM_DAD"},
+ { EIGRP_EXTCOMM_VRHB, "EIGRP_EXTCOMM_VRHB"},
+ { EIGRP_EXTCOMM_SRLM, "EIGRP_EXTCOMM_SRLM"},
+ { EIGRP_EXTCOMM_SAR, "EIGRP_EXTCOMM_SAR"},
+ { EIGRP_EXTCOMM_RPM, "EIGRP_EXTCOMM_RPM"},
+ { EIGRP_EXTCOMM_SOO_ASFMT, "EIGRP_EXTCOMM_SOO"},
+ { EIGRP_EXTCOMM_SOO_ADRFMT, "EIGRP_EXTCOMM_SOO"},
+ { 0, NULL}
+};
+
+
+/**
+ *@fn void dissect_eigrp_parameter (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 Parameter TLV, which is used to convey metric weights and the
+ * hold time.
+ *
+ * @brief
+ * 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, 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 Sequence TLV which consists of the addresses 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)
+{
+ proto_item *ti_addrlen;
+ int offset = 0;
+ guint8 addr_len;
+
+ while (tvb_reported_length_remaining(tvb, offset) > 0) {
+ addr_len = tvb_get_guint8(tvb, offset);
+ ti_addrlen = proto_tree_add_item(tree, hf_eigrp_seq_addrlen, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+
+ if (tvb_reported_length_remaining(tvb, offset) < addr_len) {
+ /* The remaining part of the TLV is shorter than the address it should contain */
+ expert_add_info(pinfo, ti, &ei_eigrp_tlv_trunc);
+ break;
+ }
+
+ 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_bytes_format_value(tree, hf_eigrp_ipx_address, tvb, offset, addr_len, NULL,
+ "IPX Address: %s", tvb_address_to_str(pinfo->pool, tvb, AT_IPX, 1));
+ 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);
+ }
+
+ offset += addr_len;
+ }
+}
+
+/**
+ *@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_item(tree, hf_eigrp_release, tvb, offset, 2, ENC_BIG_ENDIAN);
+ 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_item(tree, hf_eigrp_tlv_version, tvb, offset, 2, ENC_BIG_ENDIAN);
+ 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_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_tree = proto_tree_add_subtree_format(tree, tvb, offset, (size*2), ett_eigrp_tidlist, NULL, "%d TIDs", size);
+ 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_tree *sub_tree;
+ tvbuff_t *sub_tvb;
+
+ /* Decode the route flags field */
+ sub_tree = proto_tree_add_subtree(tree, tvb, offset, 1, ett_eigrp_extdata_flags, NULL, "External 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_tree *sub_tree;
+ tvbuff_t *sub_tvb;
+
+ /* Decode the route flags field */
+ sub_tree = proto_tree_add_subtree(tree, tvb, offset, limit, ett_eigrp_metric_flags, NULL, "Flags");
+ sub_tvb = tvb_new_subset_length_caplen(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_cd, 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 void dissect_eigrp_ipv4_addrs (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
+ *
+ * @par
+ * Dissect all IPv4 address from offset though the end of the packet
+ */
+static void
+dissect_eigrp_ipv4_addrs (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
+ packet_info *pinfo, int offset, int unreachable)
+{
+ guint8 length;
+ ws_in4_addr ip_addr;
+ int addr_len;
+ proto_item *ti_prefixlen, *ti_dst;
+ int first = TRUE;
+
+ for (; tvb_reported_length_remaining(tvb, offset) > 0; offset += (1 + addr_len)) {
+ length = tvb_get_guint8(tvb, offset);
+ addr_len = tvb_get_ipv4_addr_with_prefix_len(tvb, offset + 1, &ip_addr, length);
+
+ if (addr_len < 0) {
+ /* Invalid prefix length, more than 32 bits */
+ 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);
+ break; /* We don't know how long this address is */
+ } else {
+ address addr;
+
+ proto_tree_add_item(tree, hf_eigrp_ipv4_prefixlen, tvb, offset, 1,
+ ENC_BIG_ENDIAN);
+ offset += 1;
+ set_address(&addr, AT_IPv4, 4, &ip_addr);
+ ti_dst = proto_tree_add_ipv4(tree, hf_eigrp_ipv4_destination, tvb, offset, addr_len, ip_addr);
+
+ /* add it to the top level line */
+ proto_item_append_text(ti," %c %s/%u", first ? '=':',',
+ address_to_str(pinfo->pool, &addr), length);
+
+ if (unreachable) {
+ expert_add_info(pinfo, ti_dst, &ei_eigrp_unreachable);
+ }
+ }
+ first = FALSE;
+ }
+}
+
+/**
+ *@fn void dissect_eigrp_ipv6_addrs (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
+ *
+ * @par
+ * Dissect all IPv6 address from offset though the end of the packet
+ */
+static void
+dissect_eigrp_ipv6_addrs (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
+ packet_info *pinfo, int offset, int unreachable)
+{
+ guint8 length;
+ int addr_len;
+ ws_in6_addr addr;
+ address addr_str;
+ proto_item *ti_prefixlen, *ti_dst;
+ int first = TRUE;
+
+ for (; tvb_reported_length_remaining(tvb, offset) > 0; offset += (1 + addr_len)) {
+ length = tvb_get_guint8(tvb, offset);
+ addr_len = tvb_get_ipv6_addr_with_prefix_len(tvb, offset + 1, &addr, length);
+
+ if (addr_len < 0) {
+ /* Invalid prefix length, more than 128 bits */
+ 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);
+ break; /* We don't know how long this address is */
+ } 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++;
+ }
+
+ set_address(&addr_str, AT_IPv6, 16, addr.bytes);
+ ti_dst = proto_tree_add_ipv6(tree, hf_eigrp_ipv6_destination, tvb, offset, addr_len, &addr);
+
+ /* add it to the top level line */
+ proto_item_append_text(ti," %c %s/%u", first ? '=':',',
+ address_to_str(pinfo->pool, &addr_str), length);
+
+ if (unreachable) {
+ expert_add_info(pinfo, ti_dst, &ei_eigrp_unreachable);
+ }
+ }
+ first = FALSE;
+ }
+}
+
+/**
+ *@fn int dissect_eigrp_ipx_addrs (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_addrs (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_str_punct(pinfo->pool, tvb_get_ntohl(tvb, offset), ' '));
+
+ if (unreachable) {
+ expert_add_info(pinfo, ti_dst, &ei_eigrp_unreachable);
+ }
+
+ offset +=4;
+ return(offset);
+}
+
+/**
+ *@fn void dissect_eigrp_services (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
+ *
+ * @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 void
+dissect_eigrp_services (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;
+ proto_tree *sub_tree, *reach_tree;
+ tvbuff_t *sub_tvb, *reach_tvb;
+ guint16 service, sub_service;
+
+ remaining = tvb_captured_length_remaining(tvb, offset);
+ sub_tree = proto_tree_add_subtree(tree, tvb, offset, remaining, ett_eigrp_tlv_metric, &sub_ti, "SAF Service ");
+ sub_tvb = tvb_new_subset_length_caplen(tvb, offset, remaining, -1);
+ sub_offset = 0;
+
+ for (; tvb_reported_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_tree = proto_tree_add_subtree(sub_tree, sub_tvb, sub_offset, 22,
+ ett_eigrp_saf_reachability, NULL, "Reachability");
+ reach_tvb = tvb_new_subset_length_caplen(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_length(sub_tvb, sub_offset, length);
+ test_string = tvb_get_string_enc(pinfo->pool, xml_tvb, 0, (length < 32 ?
+ length : 32), ENC_ASCII);
+ 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;
+ }
+}
+
+/**
+ *@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_tree *sub_tree;
+ tvbuff_t *sub_tvb;
+
+ sub_tree = proto_tree_add_subtree(tree, tvb, offset, 16, ett_eigrp_tlv_metric, NULL, "Legacy Metric");
+ sub_tvb = tvb_new_subset_length_caplen(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_tree *sub_tree;
+ tvbuff_t *sub_tvb;
+ int sub_offset = 0;
+
+ sub_tree = proto_tree_add_subtree(tree, tvb, offset, 20, ett_eigrp_tlv_extdata, NULL, "External Data");
+ sub_tvb = tvb_new_subset_length_caplen(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_tree *sub_tree;
+ tvbuff_t *sub_tvb;
+ int sub_offset = 0;
+
+ sub_tree = proto_tree_add_subtree(tree, tvb, offset, 20, ett_eigrp_tlv_extdata, NULL, "External Data");
+ sub_tvb = tvb_new_subset_length_caplen(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, ti);
+ 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 void 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
+ *
+ * @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 void
+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 */
+ dissect_eigrp_ipv4_addrs(ti, tree, tvb, pinfo, offset, unreachable);
+}
+
+/**
+ *@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_item(tree, hf_eigrp_appletalk_cable_range, tvb, 0, 4, ENC_BIG_ENDIAN);
+ 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_item(tree, hf_eigrp_nexthop_address, 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 cable range */
+ proto_tree_add_item(tree, hf_eigrp_cable_range, tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_item_append_text(ti, ": %u-%u",
+ tvb_get_ntohs(tvb, 36), tvb_get_ntohs(tvb, 38));
+ }
+}
+
+/**
+ *@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_addrs(ti, tree, tvb, pinfo, offset, unreachable);
+}
+
+/**
+ *@fn void 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
+ *
+ * @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 void
+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 */
+ dissect_eigrp_ipx_addrs(ti, tree, tvb, pinfo, offset, unreachable);
+}
+
+/**
+ *@fn void dissect_eigrp_multi_topology_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
+ *
+ * @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 void
+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:
+ dissect_eigrp_ipv4_addrs(ti, tree, tvb, pinfo, offset, unreachable);
+ break;
+ case EIGRP_AF_IPv6:
+ dissect_eigrp_ipv6_addrs(ti, tree, tvb, pinfo, offset, unreachable);
+ break;
+ case EIGRP_AF_IPX:
+ dissect_eigrp_ipx_addrs(ti, tree, tvb, pinfo, offset, unreachable);
+ break;
+
+ case EIGRP_SF_COMMON:
+ case EIGRP_SF_IPv4:
+ case EIGRP_SF_IPv6:
+ dissect_eigrp_services(ti, tree, tvb, pinfo, offset);
+ break;
+
+ default:
+ proto_tree_add_expert(tree, pinfo, &ei_eigrp_afi, tvb, offset, -1);
+ }
+}
+
+/**
+ *@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;
+ proto_item* ti;
+ proto_tree* type_tree;
+
+ while (limit > 0) {
+ comm_type = tvb_get_ntohs(tvb, offset);
+ ti = proto_tree_add_uint(tree, hf_eigrp_metric_comm_type, tvb, offset, 2, comm_type);
+ type_tree = proto_item_add_subtree(ti, ett_metric_comm_type);
+
+ offset += 2;
+
+ 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_item(type_tree, hf_eigrp_extcomm_eigrp_flag, tvb, offset, 2, ENC_BIG_ENDIAN);
+ proto_tree_add_item(type_tree, hf_eigrp_extcomm_eigrp_tag, tvb, offset+2, 4, ENC_BIG_ENDIAN);
+ break;
+
+ case EIGRP_EXTCOMM_VRR:
+ proto_tree_add_item(type_tree, hf_eigrp_extcomm_eigrp_res, tvb, offset, 2, ENC_BIG_ENDIAN);
+ proto_tree_add_item(type_tree, hf_eigrp_extcomm_eigrp_rid, tvb, offset+2, 4, ENC_BIG_ENDIAN);
+ break;
+
+ /*
+ * Vecmetric information for given EIGRP VPNv4 route,
+ * applies to both internal and external
+ */
+ case EIGRP_EXTCOMM_DAD:
+ proto_tree_add_item(type_tree, hf_eigrp_extcomm_eigrp_as, tvb, offset, 2, ENC_BIG_ENDIAN);
+ proto_tree_add_item(type_tree, hf_eigrp_extcomm_eigrp_sdly, tvb, offset+2, 4, ENC_BIG_ENDIAN);
+ break;
+
+ case EIGRP_EXTCOMM_VRHB:
+ proto_tree_add_item(type_tree, hf_eigrp_extcomm_eigrp_rel, tvb, offset, 1, ENC_BIG_ENDIAN);
+ proto_tree_add_item(type_tree, hf_eigrp_extcomm_eigrp_hop, tvb, offset+1, 1, ENC_BIG_ENDIAN);
+ proto_tree_add_item(type_tree, hf_eigrp_extcomm_eigrp_sbw, tvb, offset+2, 4, ENC_BIG_ENDIAN);
+ break;
+
+ case EIGRP_EXTCOMM_SRLM:
+ proto_tree_add_item(type_tree, hf_eigrp_extcomm_eigrp_res, tvb, offset, 1, ENC_BIG_ENDIAN);
+ proto_tree_add_item(type_tree, hf_eigrp_extcomm_eigrp_load, tvb, offset+1, 1, ENC_BIG_ENDIAN);
+ proto_tree_add_item(type_tree, hf_eigrp_extcomm_eigrp_mtu, tvb, offset+2, 4, ENC_BIG_ENDIAN);
+ break;
+
+ /*
+ * External information for given EIGRP VPNv4 route,
+ * applies to only to external routes
+ */
+ case EIGRP_EXTCOMM_SAR:
+ proto_tree_add_item(type_tree, hf_eigrp_extcomm_eigrp_xas, tvb, offset, 2, ENC_BIG_ENDIAN);
+ proto_tree_add_item(type_tree, hf_eigrp_extcomm_eigrp_xrid, tvb, offset+2, 4, ENC_BIG_ENDIAN);
+ break;
+
+ case EIGRP_EXTCOMM_RPM:
+ proto_tree_add_item(type_tree, hf_eigrp_extcomm_eigrp_xproto, tvb, offset, 2, ENC_BIG_ENDIAN);
+ proto_tree_add_item(type_tree, hf_eigrp_extcomm_eigrp_xmetric, tvb, offset+2, 4, ENC_BIG_ENDIAN);
+ break;
+
+ case EIGRP_EXTCOMM_SOO_ASFMT:
+ case EIGRP_EXTCOMM_SOO_ADRFMT:
+ proto_tree_add_item(type_tree, hf_eigrp_extcomm_eigrp_as, tvb, offset, 2, ENC_BIG_ENDIAN);
+ proto_tree_add_item(type_tree, hf_eigrp_extcomm_eigrp_tag, tvb, offset+2, 4, ENC_BIG_ENDIAN);
+ break;
+ }
+
+ proto_item_set_len(ti, 8);
+
+ /*on to the next */
+ offset += 6;
+ 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_tree *sub_tree;
+ tvbuff_t *sub_tvb;
+ int sub_offset;
+
+ guint16 attr_offset = 0;
+ guint8 attr_opcode = 0;
+
+ limit *= 2; /* words to bytes */
+
+ sub_tree = proto_tree_add_subtree(tree, tvb, offset, limit, ett_eigrp_tlv_attr, NULL, "Attributes");
+ sub_tvb = tvb_new_subset_length_caplen(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:
+ /* TODO: if this corresponds to RFC 7868, 6.9.3.2, should be scaled bandwidth
+ followed by scaled delay (both 32 bits) ? */
+ 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_length_caplen(sub_tvb, sub_offset, 8, -1),
+ sub_offset, limit);
+ break;
+
+ case EIGRP_ATTR_JITTER:
+ /* TODO: RFC 7868 6.9.3.5 suggests this value should be 6 bytes */
+ proto_tree_add_item(sub_tree, hf_eigrp_attr_jitter, sub_tvb,
+ sub_offset, 4, ENC_BIG_ENDIAN);
+ break;
+
+ case EIGRP_ATTR_QENERGY:
+ /* TODO: RFC 7868 6.9.3.6 splits this into separate high and low 16-bit values */
+ proto_tree_add_item(sub_tree, hf_eigrp_attr_qenergy, sub_tvb,
+ sub_offset, 4, ENC_BIG_ENDIAN);
+ break;
+
+ case EIGRP_ATTR_ENERGY:
+ /* TODO: RFC 7868 6.9.3.7 splits this into separate high and low 16-bit values */
+ 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_tree *sub_tree;
+ tvbuff_t *sub_tvb;
+ gint8 attr_size = 0;
+ guint64 big_num;
+
+ sub_tree = proto_tree_add_subtree(tree, tvb, offset, 24, ett_eigrp_tlv_metric, NULL, "Wide Metric");
+ sub_tvb = tvb_new_subset_length_caplen(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_GUINT64_CONSTANT(0x0000ffffffffffff)) {
+ proto_tree_add_uint64_format_value(sub_tree, hf_eigrp_metric_delay, sub_tvb, 8, 6, big_num, "Infinity");
+ } else {
+ proto_tree_add_uint64(sub_tree, hf_eigrp_metric_delay, sub_tvb, 8, 6, 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_GUINT64_CONSTANT(0x0000ffffffffffff)) {
+ proto_tree_add_uint64_format_value(sub_tree, hf_eigrp_metric_bandwidth, sub_tvb, 14, 6, big_num, "Infinity");
+ } else {
+ proto_tree_add_uint64(sub_tree, hf_eigrp_metric_bandwidth, sub_tvb, 14, 6, 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 void 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
+ *
+ * @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 void
+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:
+ dissect_eigrp_ipv4_addrs(ti, tree, tvb, pinfo, offset, unreachable);
+ break;
+
+ case EIGRP_AF_IPv6:
+ dissect_eigrp_ipv6_addrs(ti, tree, tvb, pinfo, offset, unreachable);
+ break;
+
+ case EIGRP_AF_IPX:
+ dissect_eigrp_ipx_addrs(ti, tree, tvb, pinfo, offset, unreachable);
+ break;
+
+ case EIGRP_SF_COMMON:
+ case EIGRP_SF_IPv4:
+ case EIGRP_SF_IPv6:
+ dissect_eigrp_services(ti, tree, tvb, pinfo, offset);
+ break;
+
+ default:
+ proto_tree_add_expert(tree, pinfo, &ei_eigrp_afi, tvb, offset, -1);
+ }
+}
+
+/**
+ *@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 int
+dissect_eigrp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
+{
+ proto_item *ti;
+ proto_tree *eigrp_tree, *tlv_tree;
+ guint opcode, vrid;
+ guint16 tlv;
+ 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_captured_length(tvb);
+ proto_tree_add_checksum(eigrp_tree, tvb, 2, hf_eigrp_checksum, hf_eigrp_checksum_status, &ei_eigrp_checksum_bad,
+ pinfo, ip_checksum_tvb(tvb, 0, size), ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY|PROTO_CHECKSUM_IN_CKSUM);
+
+ /* 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 < 4) {
+ /*
+ * As the draft says, in section 6.6.2 "Length Field Encoding",
+ * "The value does includes[sic] the Type and Length fields".
+ *
+ * Therefore, it must be at least 4.
+ */
+ proto_tree_add_expert(eigrp_tree, pinfo, &ei_eigrp_tlv_len, tvb, offset, -1);
+ return(tvb_captured_length(tvb));
+ }
+
+ tlv_tree = proto_tree_add_subtree(eigrp_tree, tvb, offset, size, ett_eigrp_tlv, &ti,
+ val_to_str(tlv, eigrp_tlv2string, "Unknown TLV (0x%04x)"));
+
+ 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_length(tvb, (offset + 4), (size - 4)), pinfo, tlv);
+ break;
+
+ case EIGRP_TLV_IPv4:
+ dissect_eigrp_ipv4_tlv(ti, tlv_tree, tvb_new_subset_length(tvb, (offset + 4), (size - 4)), pinfo, tlv);
+ break;
+
+ case EIGRP_TLV_ATALK:
+ dissect_eigrp_atalk_tlv(ti, tlv_tree, tvb_new_subset_length(tvb, (offset + 4), (size - 4)), tlv);
+ break;
+
+ case EIGRP_TLV_IPX:
+ dissect_eigrp_ipx_tlv(ti, tlv_tree, tvb_new_subset_length(tvb, (offset + 4), (size - 4)), pinfo, tlv);
+ break;
+
+ case EIGRP_TLV_IPv6:
+ dissect_eigrp_ipv6_tlv(ti, tlv_tree, tvb_new_subset_length(tvb, (offset + 4), (size - 4)), pinfo, tlv);
+ break;
+
+ case EIGRP_TLV_MP:
+ dissect_eigrp_multi_protocol_tlv(ti, tlv_tree, tvb_new_subset_length(tvb, (offset + 4), (size - 4)),
+ pinfo, tlv);
+ break;
+
+ case EIGRP_TLV_MTR:
+ dissect_eigrp_multi_topology_tlv(ti, tlv_tree, tvb_new_subset_length(tvb, (offset + 4), (size - 4)),
+ 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_captured_length(tvb));
+}
+
+static void
+eigrp_fmt_cable_range(gchar *result, guint32 revision )
+{
+ snprintf( result, ITEM_LABEL_LENGTH, "%u-%u", (guint16)(( revision & 0xFFFF0000 ) >> 16), (guint16)(revision & 0xFFFF) );
+}
+
+static void
+eigrp_fmt_nexthop_address(gchar *result, guint32 revision )
+{
+ snprintf( result, ITEM_LABEL_LENGTH, "%u.%u", (guint16)(( revision & 0xFFFF0000 ) >> 16), (guint16)(revision & 0xFFFF) );
+}
+
+static void
+eigrp_fmt_version(gchar *result, guint32 revision )
+{
+ snprintf( result, ITEM_LABEL_LENGTH, "%d.%02d", (guint8)(( revision & 0xFF00 ) >> 8), (guint8)(revision & 0xFF) );
+}
+
+/**
+ *@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. Don't 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, NULL, EIGRP_OPAQUE_SRCWD,
+ "Route Source Withdraw", HFILL }
+ },
+ { &hf_eigrp_metric_flags_cd,
+ { "Candidate Default", "eigrp.metric.flags.cd",
+ FT_BOOLEAN, 8, NULL, EIGRP_OPAQUE_CD,
+ NULL, HFILL }
+ },
+ { &hf_eigrp_metric_flags_active,
+ { "Route is Active", "eigrp.metric.flags.active",
+ FT_BOOLEAN, 8, NULL, 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, NULL, 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, NULL, EIGRP_OPAQUE_EXT,
+ "External route", HFILL }
+ },
+ { &hf_eigrp_extdata_flag_cd,
+ { "Route is Candidate Default", "eigrp.opaque.flag.cd",
+ FT_BOOLEAN, 8, NULL, 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_UINT32, BASE_DEC, NULL, 0x0,
+ "Metric calculated from legacy TLVs", HFILL }
+ },
+ { &hf_eigrp_attr_tag,
+ { "Tag", "eigrp.attr.tag",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Tag assigned by admin for dest", HFILL }
+ },
+ { &hf_eigrp_attr_jitter,
+ { "Jitter", "eigrp.attr.jitter",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Variation in path delay", HFILL }
+ },
+ { &hf_eigrp_attr_qenergy,
+ { "Q-Energy", "eigrp.attr.qenergy",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Non-Active energy usage along path", HFILL }
+ },
+ { &hf_eigrp_attr_energy,
+ { "Energy", "eigrp.attr.energy",
+ FT_UINT32, 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 }
+ },
+
+ /* Generated from convert_proto_tree_add_text.pl */
+ { &hf_eigrp_ipx_address, { "IPX Address", "eigrp.ipx_address", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_eigrp_release, { "EIGRP Release", "eigrp.release_version", FT_UINT16, BASE_CUSTOM, CF_FUNC(eigrp_fmt_version), 0x0, NULL, HFILL }},
+ { &hf_eigrp_tlv_version, { "EIGRP TLV version", "eigrp.tlv_version", FT_UINT16, BASE_CUSTOM, CF_FUNC(eigrp_fmt_version), 0x0, NULL, HFILL }},
+ { &hf_eigrp_ipv4_destination, { "Destination", "eigrp.ipv4.destination", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_eigrp_ipv6_destination, { "Destination", "eigrp.ipv6.destination", FT_IPv6, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_eigrp_appletalk_cable_range, { "AppleTalk Cable Range", "eigrp.appletalk_cable_range", FT_UINT32, BASE_CUSTOM, CF_FUNC(eigrp_fmt_cable_range), 0x0, NULL, HFILL }},
+ { &hf_eigrp_nexthop_address, { "NextHop Address", "eigrp.nexthop_address", FT_UINT32, BASE_CUSTOM, CF_FUNC(eigrp_fmt_nexthop_address), 0x0, NULL, HFILL }},
+ { &hf_eigrp_cable_range, { "Cable range", "eigrp.cable_range", FT_UINT32, BASE_CUSTOM, CF_FUNC(eigrp_fmt_cable_range), 0x0, NULL, HFILL }},
+ { &hf_eigrp_metric_delay, { "Delay", "eigrp.metric.delay", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_eigrp_metric_bandwidth, { "Bandwidth", "eigrp.metric.bandwidth", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_eigrp_checksum, { "Checksum", "eigrp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_eigrp_checksum_status, { "Checksum Status", "eigrp.checksum.status", FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0, NULL, HFILL }},
+ { &hf_eigrp_metric_comm_type, { "Type", "eigrp.metric.comm_type", FT_UINT16, BASE_DEC, VALS(eigrp_metric_comm_type_vals), 0x0, NULL, HFILL }},
+ { &hf_eigrp_extcomm_eigrp_flag, { "FLAG", "eigrp.extcomm.flag", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_eigrp_extcomm_eigrp_tag, { "TAG", "eigrp.extcomm.tag", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_eigrp_extcomm_eigrp_res, { "RES", "eigrp.extcomm.res", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_eigrp_extcomm_eigrp_rid, { "RID", "eigrp.extcomm.rid", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_eigrp_extcomm_eigrp_as, { "AS", "eigrp.extcomm.as", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_eigrp_extcomm_eigrp_sdly, { "SDLY", "eigrp.extcomm.sdly", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_eigrp_extcomm_eigrp_rel, { "RID", "eigrp.extcomm.rel", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_eigrp_extcomm_eigrp_hop, { "AS", "eigrp.extcomm.hop", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_eigrp_extcomm_eigrp_sbw, { "SDLY", "eigrp.extcomm.sbw", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_eigrp_extcomm_eigrp_load, { "LOAD", "eigrp.extcomm.load", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_eigrp_extcomm_eigrp_mtu, { "MTU", "eigrp.extcomm.mtu", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_eigrp_extcomm_eigrp_xas, { "xAS", "eigrp.extcomm.xas", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_eigrp_extcomm_eigrp_xrid, { "xRID", "eigrp.extcomm.xrid", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_eigrp_extcomm_eigrp_xproto, { "xProto", "eigrp.extcomm.xproto", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_eigrp_extcomm_eigrp_xmetric, { "xMETRIC", "eigrp.extcomm.xmetric", FT_UINT32, BASE_DEC, 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,
+
+ &ett_metric_comm_type
+ };
+
+ 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 (Length field less than 4)", EXPFILL }},
+ { &ei_eigrp_tlv_trunc, { "eigrp.tlv.truncated", PI_MALFORMED, PI_ERROR, "Corrupt TLV (Truncated prematurely)", EXPFILL }},
+ };
+
+ expert_module_t* expert_eigrp;
+
+ /* Register the protocol name and description */
+ proto_eigrp = proto_register_protocol("Enhanced Interior Gateway Routing Protocol", "EIGRP", "eigrp");
+ register_dissector("eigrp", dissect_eigrp, proto_eigrp);
+
+ /* 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 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 = find_dissector("eigrp");
+
+ ipxsap_handle = find_dissector_add_dependency("ipxsap", proto_eigrp);
+ media_type_table = find_dissector_table("media_type");
+
+ 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);
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */