Remove all $Id$ from top of file
[metze/wireshark/wip.git] / epan / dissectors / packet-eigrp.c
1 /* packet-eigrp.c
2  * Routines for EIGRP dissection
3  * Copyright 2011, Donnie V Savage <dsavage@cisco.com>
4  *
5  * Complete re-write and replaces previous file of same name authored by:
6  *    Copyright 2009, Jochen Bartl <jochen.bartl@gmail.co
7  *    Copyright 2000, Paul Ionescu <paul@acorp.ro>
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 1998 Gerald Combs
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26  */
27 #include "config.h"
28
29 #include <glib.h>
30 #include <epan/packet.h>
31 #include <epan/guid-utils.h>
32 #include <epan/addr_resolv.h>
33 #include <epan/atalk-utils.h>
34 #include <epan/addr_and_mask.h>
35 #include <epan/ipproto.h>
36 #include <epan/tfs.h>
37 #include <epan/expert.h>
38 #include <epan/reassemble.h>
39
40 #include "packet-ipx.h"
41 #include "packet-osi.h"
42
43 /**
44  * EIGRP Header size in bytes
45  */
46 #define EIGRP_HEADER_LENGTH     20
47
48 /**
49  * EIGRP Packet Opcodes
50  */
51 #define EIGRP_OPC_UPDATE        1       /*!< packet containing routing information */
52 #define EIGRP_OPC_REQUEST       2       /*!< sent to request one or more routes */
53 #define EIGRP_OPC_QUERY         3       /*!< sent when a routing is in active start */
54 #define EIGRP_OPC_REPLY         4       /*!< sent in response to a query */
55 #define EIGRP_OPC_HELLO         5       /*!< sent to maintain a peering session */
56 #define EIGRP_OPC_IPXSAP        6       /*!< IPX SAP information */
57 #define EIGRP_OPC_PROBE         7       /*!< for test purposes   */
58 #define EIGRP_OPC_ACK           8       /*!< acknowledge         */
59 #define EIGRP_OPC_STUB          9       /*!< peering operating in restricted mode */
60 #define EIGRP_OPC_SIAQUERY      10      /*!< QUERY - with relaxed restrictions */
61 #define EIGRP_OPC_SIAREPLY      11      /*!< REPLY - may contain old routing information */
62
63 /**
64  * EIGRP TLV Range definitions
65  *      PDM             TLV Range
66  *      General         0x0000
67  *      IPv4            0x0100          ** TLVs for one and all
68  *      ATALK           0x0200          ** legacy
69  *      IPX             0x0300          ** discontinued
70  *      IPv6            0x0400          ** legacy
71  *      Multiprotocol   0x0600          ** wide metrics
72  *      MultiTopology   0x00f0          ** deprecated
73  */
74 #define EIGRP_TLV_RANGEMASK     0xfff0  /*!< should be 0xff00 - opps     */
75 #define EIGRP_TLV_GENERAL       0x0000
76
77 /**
78  * 1.2 TLV Definitions  ** legacy
79  * These have been deprecated and should not be used for future packets
80  */
81 #define EIGRP_TLV_IPv4          0x0100          /*!< Classic IPv4 TLV encoding */
82 #define EIGRP_TLV_ATALK         0x0200          /*!< Classic Appletalk TLV encoding*/
83 #define EIGRP_TLV_IPX           0x0300          /*!< Classic IPX TLV encoding */
84 #define EIGRP_TLV_IPv6          0x0400          /*!< Classic IPv6 TLV encoding */
85
86 /**
87  * 2.0 Multi-Protocol TLV Definitions
88  * These have been deprecated and should not be used for future packets
89  */
90 #define EIGRP_TLV_MP            0x0600  /*!< Non-PDM specific encoding */
91
92 /**
93  * 3.0 TLV Definitions  ** deprecated
94  * These have been deprecated and should not be used for future packets
95  */
96 #define EIGRP_TLV_MTR           0x00f0          /*!< MTR TLV encoding */
97
98 /**
99  * TLV type definitions.  Generic (protocol-independent) TLV types are
100  * defined here.  Protocol-specific ones are defined elsewhere.
101  */
102 #define EIGRP_TLV_PARAMETER             (EIGRP_TLV_GENERAL | 0x0001)    /*!< eigrp parameters */
103 #define EIGRP_TLV_AUTH                  (EIGRP_TLV_GENERAL | 0x0002)    /*!< authentication */
104 #define EIGRP_TLV_SEQ                   (EIGRP_TLV_GENERAL | 0x0003)    /*!< sequenced packet */
105 #define EIGRP_TLV_SW_VERSION            (EIGRP_TLV_GENERAL | 0x0004)    /*!< software version */
106 #define EIGRP_TLV_NEXT_MCAST_SEQ        (EIGRP_TLV_GENERAL | 0x0005)    /*!< */
107 #define EIGRP_TLV_PEER_STUBINFO         (EIGRP_TLV_GENERAL | 0x0006)    /*!< stub information */
108 #define EIGRP_TLV_PEER_TERMINATION      (EIGRP_TLV_GENERAL | 0x0007)    /*!< peer termination */
109 #define EIGRP_TLV_PEER_TIDLIST          (EIGRP_TLV_GENERAL | 0x0008)    /*!< peer sub-topology list */
110
111 /**
112  * Route Based TLVs
113  */
114 #define EIGRP_TLV_TYPEMASK      0x000f
115 #define EIGRP_TLV_REQUEST       0x0001
116 #define EIGRP_TLV_INTERNAL      0x0002
117 #define EIGRP_TLV_EXTERNAL      0x0003
118 #define EIGRP_TLV_COMMUNITY     0x0004
119
120 /* Legacy TLV formats */
121 #define EIGRP_TLV_IPv4_REQ      (EIGRP_TLV_IPv4 | EIGRP_TLV_REQUEST)
122 #define EIGRP_TLV_IPv4_INT      (EIGRP_TLV_IPv4 | EIGRP_TLV_INTERNAL)
123 #define EIGRP_TLV_IPv4_EXT      (EIGRP_TLV_IPv4 | EIGRP_TLV_EXTERNAL)
124 #define EIGRP_TLV_IPv4_COM      (EIGRP_TLV_IPv4 | EIGRP_TLV_COMMUNITY)
125 #define EIGRP_TLV_IPX_INT       (EIGRP_TLV_IPX | EIGRP_TLV_INTERNAL)
126 #define EIGRP_TLV_IPX_EXT       (EIGRP_TLV_IPX | EIGRP_TLV_EXTERNAL)
127 #define EIGRP_TLV_IPX_COM       (EIGRP_TLV_IPX | EIGRP_TLV_COMMUNITY)
128 #define EIGRP_TLV_IPv6_INT      (EIGRP_TLV_IPv6 | EIGRP_TLV_INTERNAL)
129 #define EIGRP_TLV_IPv6_EXT      (EIGRP_TLV_IPv6 | EIGRP_TLV_EXTERNAL)
130 #define EIGRP_TLV_IPv6_COM      (EIGRP_TLV_IPv6 | EIGRP_TLV_COMMUNITY)
131
132 /* Deprecated TLV formats */
133 #define EIGRP_TLV_AT_INT        (EIGRP_TLV_ATALK | EIGRP_TLV_INTERNAL)
134 #define EIGRP_TLV_AT_EXT        (EIGRP_TLV_ATALK | EIGRP_TLV_EXTERNAL)
135 #define EIGRP_TLV_AT_CBL        (EIGRP_TLV_ATALK | 0x04)
136 #define EIGRP_TLV_MTR_REQ       (EIGRP_TLV_MTR | EIGRP_TLV_REQUEST)
137 #define EIGRP_TLV_MTR_INT       (EIGRP_TLV_MTR | EIGRP_TLV_INTERNAL)
138 #define EIGRP_TLV_MTR_EXT       (EIGRP_TLV_MTR | EIGRP_TLV_EXTERNAL)
139 #define EIGRP_TLV_MTR_COM       (EIGRP_TLV_MTR | EIGRP_TLV_COMMUNITY)
140 #define EIGRP_TLV_MTR_TIDLIST   (EIGRP_TLV_MTR | 0x0005)
141
142 /* Current "Wide Metric" TLV formats */
143 #define EIGRP_TLV_MP_REQ        (EIGRP_TLV_MP | EIGRP_TLV_REQUEST)
144 #define EIGRP_TLV_MP_INT        (EIGRP_TLV_MP | EIGRP_TLV_INTERNAL)
145 #define EIGRP_TLV_MP_EXT        (EIGRP_TLV_MP | EIGRP_TLV_EXTERNAL)
146 #define EIGRP_TLV_MP_COM        (EIGRP_TLV_MP | EIGRP_TLV_COMMUNITY)
147
148 /**
149  * External routes originate from some other protocol - these are them
150  */
151 #define NULL_PROTID     0       /*!< unknown protocol */
152 #define IGRP1_PROTID    1       /*!< IGRP.. whos your daddy! */
153 #define IGRP2_PROTID    2       /*!< EIGRP - Just flat out the best */
154 #define STATIC_PROTID   3       /*!< Staticly configured source */
155 #define RIP_PROTID      4       /*!< Routing Information Protocol */
156 #define HELLO_PROTID    5       /*!< Hello? RFC-891 you there? */
157 #define OSPF_PROTID     6       /*!< OSPF - Open Shortest Path First */
158 #define ISIS_PROTID     7       /*!< Intermediate System To Intermediate System */
159 #define EGP_PROTID      8       /*!< Exterior Gateway Protocol */
160 #define BGP_PROTID      9       /*!< Border Gateway Protocol */
161 #define IDRP_PROTID     10      /*!< InterDomain Routing Protocol */
162 #define CONN_PROTID     11      /*!< Connected source */
163
164 /**
165  *
166  * extdata flag field definitions
167  */
168 #define EIGRP_OPAQUE_EXT      0x01   /*!< Route is external */
169 #define EIGRP_OPAQUE_CD       0x02   /*!< Candidate default route */
170
171 /**
172  * Address-Family types are taken from:
173  *       http://www.iana.org/assignments/address-family-numbers
174  * to provide a standards based exchange of AFI information between
175  * EIGRP routers.
176  */
177 #define EIGRP_AF_IPv4           1       /*!< IPv4 (IP version 4) */
178 #define EIGRP_AF_IPv6           2       /*!< IPv6 (IP version 6) */
179 #define EIGRP_AF_IPX            11      /*!< IPX */
180 #define EIGRP_AF_ATALK          12      /*!< Appletalk */
181 #define EIGRP_SF_COMMON         16384   /*!< Cisco Service Family */
182 #define EIGRP_SF_IPv4           16385   /*!< Cisco IPv4 Service Family */
183 #define EIGRP_SF_IPv6           16386   /*!< Cisco IPv6 Service Family */
184
185 /**
186  * Authentication types supported by EIGRP
187  */
188 #define EIGRP_AUTH_TYPE_NONE            0
189 #define EIGRP_AUTH_TYPE_TEXT            1
190 #define EIGRP_AUTH_TYPE_MD5             2
191 #define EIGRP_AUTH_TYPE_MD5_LEN         16
192 #define EIGRP_AUTH_TYPE_SHA256          3
193 #define EIGRP_AUTH_TYPE_SHA256_LEN      32
194
195 /**
196  * opaque flag field definitions
197  */
198 #define EIGRP_OPAQUE_SRCWD    0x01   /*!< Route Source Withdraw */
199 #define EIGRP_OPAQUE_ACTIVE   0x04   /*!< Route is currently in active state */
200 #define EIGRP_OPAQUE_REPL     0x08   /*!< Route is replicated from different tableid */
201
202 /**
203  * pak flag bit field definitions - 0 (none)-7 source priority
204  */
205 #define EIGRP_PRIV_DEFAULT      0x00   /* 0 (none)-7 source priority */
206 #define EIGRP_PRIV_LOW          0x01
207 #define EIGRP_PRIV_MEDIUM       0x04
208 #define EIGRP_PRIV_HIGH         0x07
209
210 /**
211  * stub bit definitions
212  */
213 #define EIGRP_PEER_ALLOWS_CONNECTED     0x0001
214 #define EIGRP_PEER_ALLOWS_STATIC        0x0002
215 #define EIGRP_PEER_ALLOWS_SUMMARY       0x0004
216 #define EIGRP_PEER_ALLOWS_REDIST        0x0008
217 #define EIGRP_PEER_ALLOWS_LEAKING       0x0010
218 #define EIGRP_PEER_ALLOWS_RCVONLY       0x0020
219
220 /*
221  * Init bit definition. First unicast transmitted Update has this
222  * bit set in the flags field of the fixed header. It tells the neighbor
223  * to down-load his topology table.
224  */
225 #define EIGRP_INIT_FLAG 0x01
226
227 /*
228  * CR bit (Conditionally Received) definition in flags field on header. Any
229  * packets with the CR-bit set can be accepted by an EIGRP speaker if and
230  * only if a previous Hello was received with the SEQUENCE_TYPE TLV present.
231  *
232  * This allows multicasts to be transmitted in order and reliably at the
233  * same time as unicasts are transmitted.
234  */
235 #define EIGRP_CR_FLAG 0x02
236
237 /*
238  * RS bit.  The Restart flag is set in the hello and the init
239  * update packets during the nsf signaling period.  A nsf-aware
240  * router looks at the RS flag to detect if a peer is restarting
241  * and maintain the adjacency. A restarting router looks at
242  * this flag to determine if the peer is helping out with the restart.
243  */
244 #define EIGRP_RS_FLAG 0x04
245
246 /*
247  * EOT bit.  The End-of-Table flag marks the end of the start-up updates
248  * sent to a new peer.  A nsf restarting router looks at this flag to
249  * determine if it has finished receiving the start-up updates from all
250  * peers.  A nsf-aware router waits for this flag before cleaning up
251  * the stale routes from the restarting peer.
252  */
253 #define EIGRP_EOT_FLAG 0x08
254
255 /**
256  * EIGRP Virtual Router ID
257  *
258  * Define values to deal with EIGRP virtual router ids.  Virtual
259  * router IDs are stored in the upper short of the EIGRP fixed packet
260  * header.  The lower short of the packet header continues to be used
261  * as asystem number.
262  *
263  * Virtual Router IDs are PDM-independent.  All PDMs will use
264  * VRID_BASE to indicate the 'base' or 'legacy' EIGRP instance.
265  * All PDMs need to initialize their vrid to VRID_BASE for compatibility
266  * with legacy routers.
267  * Once IPv6 supports 'MTR Multicast', it will use the same VRID as
268  * IPv4.  No current plans to support VRIDs on IPX. :)
269  * Initial usage of VRID is to signal usage of Multicast topology for
270  * MTR.
271  *
272  * VRID_MCAST is a well known constant, other VRIDs will be determined
273  * programmatic...
274  *
275  * With the addition of SAF the VRID space has been divided into two
276  * segments 0x0000-0x7fff is for EIGRP and vNets, 0x8000-0xffff is
277  * for saf and its associated vNets.
278  */
279 #define EIGRP_VRID_MASK         0x8001
280 #define EIGRP_VRID_AF_BASE      0x0000
281 #define EIGRP_VRID_MCAST_BASE   0x0001
282 #define EIGRP_VRID_SF_BASE      0x8000
283
284 /* Extended Attributes for a destination */
285 #define EIGRP_ATTR_HDRLEN (2)
286 #define EIGRP_ATTR_MAXDATA (512)
287
288 #define EIGRP_ATTR_NOOP         0       /*!< No-Op used as offset padding */
289 #define EIGRP_ATTR_SCALED       1       /*!< Scaled metric values */
290 #define EIGRP_ATTR_TAG          2       /*!< Tag assigned by Admin for dest */
291 #define EIGRP_ATTR_COMM         3       /*!< Community attribute for dest */
292 #define EIGRP_ATTR_JITTER       4       /*!< Variation in path delay */
293 #define EIGRP_ATTR_QENERGY      5       /*!< Non-Active energy usage along path */
294 #define EIGRP_ATTR_ENERGY       6       /*!< Active energy usage along path */
295
296 /*
297  * Begin EIGRP-BGP interoperability communities
298  */
299 #define EIGRP_EXTCOMM_SOO_ASFMT         0x0003 /* Site-of-Origin, BGP AS format */
300 #define EIGRP_EXTCOMM_SOO_ADRFMT        0x0103 /* Site-of-Origin, BGP/EIGRP addr format */
301
302 /*
303  * EIGRP Specific communities
304  */
305 #define EIGRP_EXTCOMM_EIGRP             0x8800 /* EIGRP route information appended*/
306 #define EIGRP_EXTCOMM_DAD               0x8801 /* EIGRP AS + Delay           */
307 #define EIGRP_EXTCOMM_VRHB              0x8802 /* EIGRP Vector: Reliability + Hop + BW */
308 #define EIGRP_EXTCOMM_SRLM              0x8803 /* EIGRP System: Reserve +Load + MTU   */
309 #define EIGRP_EXTCOMM_SAR               0x8804 /* EIGRP System: Remote AS + Remote ID  */
310 #define EIGRP_EXTCOMM_RPM               0x8805 /* EIGRP Remote: Protocol + Metric    */
311 #define EIGRP_EXTCOMM_VRR               0x8806 /* EIGRP Vecmet: Rsvd + (internal) Routerid */
312
313 /* SAF types */
314 #define EIGRP_SVCDATA_COMPLETE          0x01    /*!< Data is attached */
315 #define EIGRP_SVCDATA_TRIMMED           0x02    /*!< Data was trimmed from service */
316
317 /* SAF Defined Numbers */
318 #define SAF_SERVICE_ID_CAPMAN   100             /*!< Capabilities Manager */
319 #define SAF_SERVICE_ID_UC       101             /*!< Unified Communications */
320 #define SAF_SERVICE_ID_PFR      102             /*!< Performance Routing */
321
322 /* Forward declaration we need below (if using proto_reg_handoff...
323    as a prefs callback)       */
324 void proto_reg_handoff_eigrp(void);
325 void proto_register_eigrp(void);
326
327 /* Initialize the protocol and registered fields */
328 static int proto_eigrp = -1;
329
330 /* header */
331 static gint hf_eigrp_version = -1;
332 static gint hf_eigrp_opcode = -1;
333 static gint hf_eigrp_flags = -1;
334 static gint hf_eigrp_sequence = -1;
335 static gint hf_eigrp_acknowledge = -1;
336 static gint hf_eigrp_vrid = -1;
337 static gint hf_eigrp_as = -1;
338 static gint ett_eigrp = -1;
339
340 /* packet header flags */
341 static gint hf_eigrp_flags_init = -1;
342 static gint hf_eigrp_flags_restart = -1;
343 static gint hf_eigrp_flags_eot = -1;
344 static gint hf_eigrp_flags_condrecv = -1;
345
346 static gint ett_eigrp_flags = -1;
347 static const int *eigrp_flag_fields[] = {
348     &hf_eigrp_flags_init,
349     &hf_eigrp_flags_condrecv,
350     &hf_eigrp_flags_restart,
351     &hf_eigrp_flags_eot,
352     NULL
353 };
354
355 /* tlv */
356 static gint hf_eigrp_tlv_type = -1;
357 static gint hf_eigrp_tlv_len = -1;
358 static gint hf_eigrp_tid = -1;
359 static gint hf_eigrp_afi = -1;
360 static gint hf_eigrp_nullpad = -1;
361
362 static gint ett_eigrp_tlv = -1;
363 static gint ett_eigrp_tlv_metric = -1;
364 static gint ett_eigrp_tlv_attr = -1;
365 static gint ett_eigrp_tlv_extdata = -1;
366
367 /* param */
368 static gint hf_eigrp_par_k1 = -1;
369 static gint hf_eigrp_par_k2 = -1;
370 static gint hf_eigrp_par_k3 = -1;
371 static gint hf_eigrp_par_k4 = -1;
372 static gint hf_eigrp_par_k5 = -1;
373 static gint hf_eigrp_par_k6 = -1;
374 static gint hf_eigrp_par_holdtime = -1;
375
376 /* auth */
377 static gint hf_eigrp_auth_type = -1;
378 static gint hf_eigrp_auth_len = -1;
379 static gint hf_eigrp_auth_keyid = -1;
380 static gint hf_eigrp_auth_keyseq = -1;
381 static gint hf_eigrp_auth_digest = -1;
382
383 /* seq */
384 static gint hf_eigrp_seq_addrlen = -1;
385 static gint hf_eigrp_seq_ipv4addr = -1;
386 static gint hf_eigrp_seq_ipv6addr = -1;
387
388 /* multicast seq */
389 static gint hf_eigrp_next_mcast_seq = -1;
390
391 /* stub flags */
392 static gint hf_eigrp_stub_flags = -1;
393 static gint hf_eigrp_stub_flags_connected = -1;
394 static gint hf_eigrp_stub_flags_static = -1;
395 static gint hf_eigrp_stub_flags_summary = -1;
396 static gint hf_eigrp_stub_flags_recvonly = -1;
397 static gint hf_eigrp_stub_flags_redist = -1;
398 static gint hf_eigrp_stub_flags_leakmap = -1;
399
400 static gint ett_eigrp_stub_flags = -1;
401 static const int *eigrp_stub_flag_fields[] = {
402     &hf_eigrp_stub_flags_connected,
403     &hf_eigrp_stub_flags_static,
404     &hf_eigrp_stub_flags_summary,
405     &hf_eigrp_stub_flags_redist,
406     &hf_eigrp_stub_flags_leakmap,
407     &hf_eigrp_stub_flags_recvonly,
408     NULL
409 };
410
411 /* tid */
412 static gint hf_eigrp_tidlist_tid = -1;
413 static gint hf_eigrp_tidlist_flags = -1;
414 static gint hf_eigrp_tidlist_len = -1;
415 static gint ett_eigrp_tidlist = -1;
416
417 /* 1.2 and 3.0 metric */
418 static gint hf_eigrp_legacy_metric_delay = -1;
419 static gint hf_eigrp_legacy_metric_bw = -1;
420 static gint hf_eigrp_legacy_metric_mtu = -1;
421 static gint hf_eigrp_legacy_metric_hopcount = -1;
422 static gint hf_eigrp_legacy_metric_rel = -1;
423 static gint hf_eigrp_legacy_metric_load = -1;
424 static gint hf_eigrp_legacy_metric_intag = -1;
425
426 /* 3.0 metric */
427 static gint hf_eigrp_legacy_metric_tag = -1;
428
429 /* 2.0 metric */
430 static gint hf_eigrp_metric_offset = -1;
431 static gint hf_eigrp_metric_priority = -1;
432 static gint hf_eigrp_metric_rel = -1;
433 static gint hf_eigrp_metric_load = -1;
434 static gint hf_eigrp_metric_mtu = -1;
435 static gint hf_eigrp_metric_hopcount = -1;
436 static gint hf_eigrp_metric_reserved = -1;
437
438 /* router id*/
439 static gint hf_eigrp_routerid = -1;
440
441 /* protocol dependent module route flags */
442 static gint hf_eigrp_metric_flags_srcwd = -1;
443 static gint hf_eigrp_metric_flags_active = -1;
444 static gint hf_eigrp_metric_flags_repl = -1;
445 static gint ett_eigrp_metric_flags = -1;
446
447 /* extended metrics */
448 static gint hf_eigrp_attr_opcode = -1;
449 static gint hf_eigrp_attr_offset = -1;
450 static gint hf_eigrp_attr_scaled = -1;
451 static gint hf_eigrp_attr_tag = -1;
452 static gint hf_eigrp_attr_jitter = -1;
453 static gint hf_eigrp_attr_qenergy = -1;
454 static gint hf_eigrp_attr_energy = -1;
455
456 /* route external data */
457 static gint hf_eigrp_extdata_origrid = -1;
458 static gint hf_eigrp_extdata_as = -1;
459 static gint hf_eigrp_extdata_tag = -1;
460 static gint hf_eigrp_extdata_metric = -1;
461 static gint hf_eigrp_extdata_reserved = -1;
462 static gint hf_eigrp_extdata_proto = -1;
463
464 static gint hf_eigrp_extdata_flag_ext = -1;
465 static gint hf_eigrp_extdata_flag_cd = -1;
466 static gint ett_eigrp_extdata_flags = -1;
467
468 /* ipv4 address */
469 static gint hf_eigrp_ipv4_nexthop = -1;
470 static gint hf_eigrp_ipv4_prefixlen = -1;
471
472 /* ipv6 address */
473 static gint hf_eigrp_ipv6_nexthop = -1;
474 static gint hf_eigrp_ipv6_prefixlen = -1;
475
476 /* ipx address */
477 static gint hf_eigrp_ipx_nexthop_net = -1;
478 static gint hf_eigrp_ipx_nexthop_host = -1;
479 static gint hf_eigrp_ipx_extdata_routerid = -1;
480 static gint hf_eigrp_ipx_extdata_delay = -1;
481 static gint hf_eigrp_ipx_extdata_metric = -1;
482 static gint hf_eigrp_ipx_dest = -1;
483
484 /* appletalk address */
485 static gint hf_eigrp_atalk_routerid = -1;
486
487 /* SAF services */
488 static gint hf_eigrp_saf_service = -1;
489 static gint hf_eigrp_saf_subservice = -1;
490 static gint hf_eigrp_saf_guid = -1;
491
492 static gint hf_eigrp_saf_reachability_afi = -1;
493 static gint hf_eigrp_saf_reachability_port = -1;
494 static gint hf_eigrp_saf_reachability_protocol = -1;
495 static gint hf_eigrp_saf_reachability_addr_ipv4 = -1;
496 static gint hf_eigrp_saf_reachability_addr_ipv6 = -1;
497 static gint hf_eigrp_saf_reachability_addr_hex = -1;
498 static gint ett_eigrp_saf_reachability = -1;
499
500 static gint hf_eigrp_saf_data_length = -1;
501 static gint hf_eigrp_saf_data_sequence = -1;
502 static gint hf_eigrp_saf_data_type = -1;
503
504 static expert_field ei_eigrp_checksum_bad = EI_INIT;
505 static expert_field ei_eigrp_unreachable = EI_INIT;
506 static expert_field ei_eigrp_seq_addrlen = EI_INIT;
507 static expert_field ei_eigrp_peer_termination = EI_INIT;
508 static expert_field ei_eigrp_tlv_type = EI_INIT;
509 static expert_field ei_eigrp_auth_type = EI_INIT;
510 static expert_field ei_eigrp_peer_termination_graceful = EI_INIT;
511 static expert_field ei_eigrp_auth_len = EI_INIT;
512 static expert_field ei_eigrp_tlv_len = EI_INIT;
513 static expert_field ei_eigrp_afi = EI_INIT;
514 static expert_field ei_eigrp_prefixlen = EI_INIT;
515
516 /* some extra handle that might be needed */
517 static dissector_handle_t ipxsap_handle = NULL;
518 static dissector_table_t media_type_table = NULL;
519
520 static const value_string eigrp_opcode2string[] = {
521     { EIGRP_OPC_UPDATE,         "Update" },
522     { EIGRP_OPC_REQUEST,        "Request" },
523     { EIGRP_OPC_QUERY,          "Query" },
524     { EIGRP_OPC_REPLY,          "Reply" },
525     { EIGRP_OPC_HELLO,          "Hello" },
526     { EIGRP_OPC_IPXSAP,         "IPX/SAP Update" },
527     { EIGRP_OPC_PROBE,          "Route Probe" },
528     { EIGRP_OPC_ACK,            "Hello (Ack)" },
529     { EIGRP_OPC_STUB,           "Stub-Info" },
530     { EIGRP_OPC_SIAQUERY,       "SIA-Query" },
531     { EIGRP_OPC_SIAREPLY,       "SIA-Reply" },
532     { 0, NULL }
533 };
534
535 static const value_string eigrp_tlv2string[] = {
536     /* General TLV formats */
537     { EIGRP_TLV_PARAMETER,              "Parameters"},
538     { EIGRP_TLV_AUTH,                   "Authentication"},
539     { EIGRP_TLV_SEQ,                    "Sequence"},
540     { EIGRP_TLV_SW_VERSION,             "Software Version"},
541     { EIGRP_TLV_NEXT_MCAST_SEQ,         "Next multicast sequence"},
542     { EIGRP_TLV_PEER_STUBINFO,          "Peer Stub Information"},
543     { EIGRP_TLV_PEER_TERMINATION,       "Peer Termination"},
544     { EIGRP_TLV_PEER_TIDLIST,           "Peer Topology ID List"},
545
546     /* Legacy TLV formats */
547     { EIGRP_TLV_IPv4_INT,               "Internal Route(IPv4)"},
548     { EIGRP_TLV_IPv4_EXT,               "External Route(IPv4)"},
549     { EIGRP_TLV_IPv4_COM,               "Ext-Community(IPv4)"},
550     { EIGRP_TLV_IPv6_INT,               "Internal Route(IPv6)"},
551     { EIGRP_TLV_IPv6_EXT,               "External Route(IPv6)"},
552     { EIGRP_TLV_IPv6_COM,               "Ext-Community(IPv6)"},
553     { EIGRP_TLV_IPX_INT,                "IPX Internal Route(IPX)"},
554     { EIGRP_TLV_IPX_EXT,                "IPX External Route(IPX)"},
555
556     /* Deprecated TLV formats */
557     { EIGRP_TLV_AT_INT,                 "Internal Route(ATALK)"},
558     { EIGRP_TLV_AT_EXT,                 "External Route(ATALK)"},
559     { EIGRP_TLV_AT_CBL,                 "Cable Configuration(ATALK)"},
560     { EIGRP_TLV_MTR_REQ,                "Request(MTR)"},
561     { EIGRP_TLV_MTR_INT,                "Internal Route(MTR)"},
562     { EIGRP_TLV_MTR_EXT,                "External Route(MTR)"},
563     { EIGRP_TLV_MTR_COM,                "Ext-Community(MTR)"},
564     { EIGRP_TLV_MTR_TIDLIST,            "TopologyID List"},
565
566     /* Current "Wide Metric" TLV formats */
567     { EIGRP_TLV_MP_REQ,                 "Request"},
568     { EIGRP_TLV_MP_INT,                 "Internal Route"},
569     { EIGRP_TLV_MP_EXT,                 "External Route"},
570     { EIGRP_TLV_MP_COM,                 "Ext-Community"},
571
572     { 0, NULL}
573 };
574
575 static const value_string eigrp_proto2string[] = {
576     { IGRP1_PROTID,             "IGRP"},
577     { IGRP2_PROTID,             "EIGRP"},
578     { STATIC_PROTID,            "Static Route"},
579     { RIP_PROTID,               "RIP"},
580     { HELLO_PROTID,             "Hello"},
581     { OSPF_PROTID,              "OSPF"},
582     { ISIS_PROTID,              "IS-IS"},
583     { EGP_PROTID,               "EGP"},
584     { BGP_PROTID,               "BGP"},
585     { IDRP_PROTID,              "IDRP"},
586     { CONN_PROTID,              "Connected Route"},
587     { 0, NULL}
588 };
589
590 static const value_string eigrp_auth2string[] = {
591     { EIGRP_AUTH_TYPE_TEXT,     "TEXT"},
592     { EIGRP_AUTH_TYPE_MD5,      "MD5"},
593     { EIGRP_AUTH_TYPE_SHA256,   "SHA256"},
594     { 0, NULL},
595 };
596
597 static const value_string eigrp_vrid2string[] = {
598     { EIGRP_VRID_AF_BASE,       "(Address-Family)"},
599     { EIGRP_VRID_SF_BASE,       "(Service-Family)"},
600     { EIGRP_VRID_MCAST_BASE,    "(Multi-Cast)"},
601     { 0, NULL}
602 };
603
604 static const value_string eigrp_afi2string[] = {
605     { EIGRP_AF_IPv4,            "IPv4"},
606     { EIGRP_AF_IPv6,            "IPv6"},
607     { EIGRP_AF_IPX,             "IPX"},
608     { EIGRP_AF_ATALK,           "Appletalk"},
609     { EIGRP_SF_COMMON,          "Service Family"},
610     { EIGRP_SF_IPv4,            "IPv4 Service Family"},
611     { EIGRP_SF_IPv6,            "IPv6 Service Family"},
612     { 0, NULL}
613 };
614
615 static const value_string eigrp_attr_opcode2string[] = {
616     { EIGRP_ATTR_NOOP,          "NO-OP for padding"},
617     { EIGRP_ATTR_SCALED,        "Scaled Metric"},
618     { EIGRP_ATTR_TAG,           "Admin Tag"},
619     { EIGRP_ATTR_COMM,          "Community"},
620     { EIGRP_ATTR_JITTER,        "Jitter"},
621     { EIGRP_ATTR_QENERGY,       "Non-Active energy"},
622     { EIGRP_ATTR_ENERGY,        "Active energy"},
623     { 0, NULL}
624 };
625
626 static const value_string eigrp_saf_type2string[] = {
627     { EIGRP_SVCDATA_COMPLETE,   "Attached Service Data"},
628     { EIGRP_SVCDATA_TRIMMED,    "Trimmed Service Data"},
629     { 0, NULL}
630 };
631
632 static const value_string eigrp_saf_srv2string[] = {
633     { SAF_SERVICE_ID_CAPMAN,    "Capabilities Manager"},
634     { SAF_SERVICE_ID_UC,        "Unified Communications"},
635     { SAF_SERVICE_ID_PFR,       "Performance Routing"},
636     { 0, NULL}
637 };
638
639 /**
640  *@fn void dissect_eigrp_parameter (proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo,
641  *
642  *
643  * @param[in,out] tree  detail dissection result
644  * @param[in] tvb       packet data
645  * @param[in] pinfo     general data about the protocol
646  * @param[in] ti        protocol item
647  *
648  * @par
649  * Dissect the Parameter TLV, which is used to convey metric weights and the
650  * hold time.
651  *
652  * @usage
653  * Note the addition of K6 for the new extended metrics, and does not apply to
654  * older TLV packet formats.
655  */
656 static void
657 dissect_eigrp_parameter (proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo,
658                          proto_item *ti)
659 {
660     int    offset = 0;
661     guint8 k1, k2, k3, k4, k5;
662
663     k1 = tvb_get_guint8(tvb, offset);
664     proto_tree_add_item(tree, hf_eigrp_par_k1, tvb, offset, 1, ENC_BIG_ENDIAN);
665
666     offset += 1;
667     k2 = tvb_get_guint8(tvb, offset);
668     proto_tree_add_item(tree, hf_eigrp_par_k2, tvb, offset, 1, ENC_BIG_ENDIAN);
669
670     offset += 1;
671     k3 = tvb_get_guint8(tvb, offset);
672     proto_tree_add_item(tree, hf_eigrp_par_k3, tvb, offset, 1, ENC_BIG_ENDIAN);
673
674     offset += 1;
675     k4 = tvb_get_guint8(tvb, offset);
676     proto_tree_add_item(tree, hf_eigrp_par_k4, tvb, offset, 1, ENC_BIG_ENDIAN);
677
678     offset += 1;
679     k5 = tvb_get_guint8(tvb, offset);
680     proto_tree_add_item(tree, hf_eigrp_par_k5, tvb, offset, 1, ENC_BIG_ENDIAN);
681
682     offset += 1;
683     proto_tree_add_item(tree, hf_eigrp_par_k6, tvb, offset, 1, ENC_BIG_ENDIAN);
684
685     offset += 1;
686     proto_tree_add_item(tree, hf_eigrp_par_holdtime, tvb, offset, 2, ENC_BIG_ENDIAN);
687
688     if (k1 == 255 && k2 == 255 && k3 == 255 && k4 == 255 && k5 == 255) {
689         proto_item_append_text(ti, ": Peer Termination");
690         expert_add_info(pinfo, ti, &ei_eigrp_peer_termination);
691     }
692 }
693
694 /**
695  *@fn void dissect_eigrp_auth_tlv (proto_tree *tree, tvbuff_t *tvb,
696  *                                 packet_info *pinfo, proto_item *ti)
697  *
698  * @param[in,out] tree  detail dissection result
699  * @param[in] tvb       packet data
700  * @param[in] pinfo     general data about the protocol
701  * @param[in] ti        protocol item
702  *
703  * @par
704  * Dissect the Authentication TLV and display digest. Currently MD5 and SHA256
705  * HMAC is supported.  For SHA256, a "secret key" with the HMAC-SHA-256
706  * password, the source address from which the packet is sent. This combined
707  * string is used as the key for hash calculation.
708  */
709 static void
710 dissect_eigrp_auth_tlv (proto_tree *tree, tvbuff_t *tvb,
711                         packet_info *pinfo, proto_item *ti)
712 {
713     proto_item *ti_auth_type, *ti_auth_len;
714     int         offset = 0;
715     guint16     auth_type, auth_len;
716
717     /* print out what family we dealing with... */
718
719     auth_type = tvb_get_ntohs(tvb, 0);
720     auth_len = tvb_get_ntohs(tvb, 2);
721
722     proto_item_append_text(ti, " %s", val_to_str_const(auth_type, eigrp_auth2string, ""));
723
724     ti_auth_type = proto_tree_add_item(tree, hf_eigrp_auth_type, tvb, offset, 2, ENC_BIG_ENDIAN);
725     offset += 2;
726     ti_auth_len = proto_tree_add_item(tree, hf_eigrp_auth_len, tvb, offset, 2, ENC_BIG_ENDIAN);
727     offset += 2;
728     proto_tree_add_item(tree, hf_eigrp_auth_keyid, tvb, offset, 4, ENC_BIG_ENDIAN);
729     offset += 4;
730     proto_tree_add_item(tree, hf_eigrp_auth_keyseq, tvb, offset, 4, ENC_BIG_ENDIAN);
731     offset += 4;
732     proto_tree_add_item(tree, hf_eigrp_nullpad, tvb, offset, 8, ENC_NA);
733     offset += 8;
734
735     switch (auth_type) {
736     case EIGRP_AUTH_TYPE_MD5:
737         if (EIGRP_AUTH_TYPE_MD5_LEN != auth_len) {
738             expert_add_info_format(pinfo, ti_auth_len, &ei_eigrp_auth_len, "Invalid auth len %u", auth_len);
739         } else {
740             proto_tree_add_item(tree, hf_eigrp_auth_digest, tvb, offset,
741                                 EIGRP_AUTH_TYPE_MD5_LEN, ENC_NA);
742         }
743         break;
744
745     case EIGRP_AUTH_TYPE_SHA256:
746         if (EIGRP_AUTH_TYPE_SHA256_LEN != auth_len) {
747             expert_add_info_format(pinfo, ti_auth_len, &ei_eigrp_auth_len, "Invalid auth len %u", auth_len);
748
749         } else {
750             proto_tree_add_item(tree, hf_eigrp_auth_digest, tvb, offset,
751                                 EIGRP_AUTH_TYPE_SHA256_LEN, ENC_NA);
752         }
753         break;
754
755     case EIGRP_AUTH_TYPE_NONE:
756     case EIGRP_AUTH_TYPE_TEXT:
757     default:
758         expert_add_info_format(pinfo, ti_auth_type, &ei_eigrp_auth_type, "Invalid auth type %u", auth_type);
759         break;
760     }
761 }
762
763 /**
764  *@fn void dissect_eigrp_seq_tlv (proto_tree *tree, tvbuff_t *tvb,
765  *                                packet_info *pinfo)
766  *
767  * @param[in,out] tree  detail dissection result
768  * @param[in] tvb       packet data
769  * @param[in] pinfo     general data about the protocol
770  *
771  * @par
772  * Dissect the Sequence TLV which consist of the address of peers that must
773  * not receive the next multicast packet transmitted.
774  */
775 static void
776 dissect_eigrp_seq_tlv (proto_tree *tree, tvbuff_t *tvb,
777                        packet_info *pinfo)
778 {
779     proto_item *ti_addrlen;
780     int         offset = 0;
781     guint8      addr_len;
782
783     addr_len = tvb_get_guint8(tvb, 0);
784     ti_addrlen = proto_tree_add_item(tree, hf_eigrp_seq_addrlen, tvb, offset, 1, ENC_BIG_ENDIAN);
785     offset += 1;
786
787     switch (addr_len) {
788     case 4:
789         /* IPv4 */
790         proto_tree_add_item(tree, hf_eigrp_seq_ipv4addr, tvb, offset, addr_len, ENC_BIG_ENDIAN);
791         break;
792     case 10:
793         /* IPX */
794         proto_tree_add_text(tree, tvb, offset, addr_len,
795                             "IPX Address = %08x.%04x.%04x.%04x",
796                             tvb_get_ntohl(tvb, 1), tvb_get_ntohs(tvb, 5),
797                             tvb_get_ntohs(tvb, 7), tvb_get_ntohs(tvb, 9));
798         break;
799     case 16:
800         /* IPv6 */
801         proto_tree_add_item(tree, hf_eigrp_seq_ipv6addr, tvb, offset, addr_len,
802                             ENC_NA);
803         break;
804     default:
805         expert_add_info(pinfo, ti_addrlen, &ei_eigrp_seq_addrlen);
806     }
807 }
808
809 /**
810  *@fn void dissect_eigrp_sw_version (tvbuff_t *tvb, proto_tree *tree,
811  *                                   proto_item *ti)
812  *
813  * @param[in,out] tree  detail dissection result
814  * @param[in] tvb       packet data
815  * @param[in] ti        protocol item
816  *
817  * @par
818  * Dissect Software Version TLV.  The older versions of EIGRP sent the IOS
819  * version along with the TLV Version.   When EIGRP "plugins" were created,
820  * this as change to send the "Release" of EIGRP to better identify where fixes
821  * are present(missing)
822  */
823 static void
824 dissect_eigrp_sw_version (tvbuff_t *tvb, proto_tree *tree,
825                           proto_item *ti)
826 {
827     int    offset = 0;
828     guint8 ios_rel_major, ios_rel_minor;
829     guint8 eigrp_rel_major, eigrp_rel_minor;
830
831     ios_rel_major = tvb_get_guint8(tvb, 0);
832     ios_rel_minor = tvb_get_guint8(tvb, 1);
833     proto_tree_add_text(tree, tvb, offset, 2, "EIGRP Release: %u.%u",
834                         ios_rel_major, ios_rel_minor);
835     offset += 2;
836     proto_item_append_text(ti, ": EIGRP=%u.%u", ios_rel_major, ios_rel_minor);
837
838     eigrp_rel_major = tvb_get_guint8(tvb, 2);
839     eigrp_rel_minor = tvb_get_guint8(tvb, 3);
840     proto_tree_add_text(tree,tvb,offset, 2, "EIGRP TLV version: %u.%u",
841                         eigrp_rel_major, eigrp_rel_minor);
842     proto_item_append_text(ti, ", TLV=%u.%u",
843                            eigrp_rel_major, eigrp_rel_minor);
844 }
845
846 /**
847  *@fn void dissect_eigrp_next_mcast_seq (tvbuff_t *tvb, proto_tree *tree,
848  *                                      proto_item *ti)
849  *
850  * @param[in,out] tree  detail dissection result
851  * @param[in] tvb       packet data
852  * @param[in] ti        protocol item
853  *
854  * @par
855  * Dissect Next Multicast Sequence TLV, which is part of the Hello with a
856  * Sequence TLV;  this gives a two-way binding between the packets and plugs a
857  * hole where a multicast could be received  by the wrong peers (due to a
858  * string of lost packets).
859  */
860 static void
861 dissect_eigrp_next_mcast_seq (tvbuff_t *tvb, proto_tree *tree,
862                               proto_item *ti)
863 {
864     proto_tree_add_item(tree, hf_eigrp_next_mcast_seq, tvb, 0, 4,
865                         ENC_BIG_ENDIAN);
866     proto_item_append_text(ti, ": %u", tvb_get_ntohl(tvb, 0));
867 }
868
869 /**
870  *@fn void dissect_eigrp_peer_stubinfo (tvbuff_t *tvb, proto_tree *tree)
871  *
872  *
873  * @param[in,out] tree  detail dissection result
874  * @param[in] tvb       packet data
875  *
876  * @par
877  * Dissect the PEER STUB TLV which contains the route types which the Peer will
878  * advertise. This is used to suppress QUERYs from being sent to the Peer
879  */
880 static void
881 dissect_eigrp_peer_stubinfo (tvbuff_t *tvb, proto_tree *tree)
882 {
883     proto_tree_add_bitmask(tree, tvb, 0, hf_eigrp_stub_flags, ett_eigrp_stub_flags,
884                            eigrp_stub_flag_fields, ENC_BIG_ENDIAN);
885 }
886
887 /**
888  *@fn void dissect_eigrp_peer_termination (packet_info *pinfo, proto_item *ti)
889  *
890  * @param[in] pinfo     general data about the protocol
891  * @param[in] ti        protocol item
892  *
893  * @par
894  * Dissect Peer Termination TLV.  This TLV has no parameters and is used to
895  * signal an adjacency should be tore down
896  */
897 static void
898 dissect_eigrp_peer_termination (packet_info *pinfo, proto_item *ti)
899 {
900     expert_add_info(pinfo, ti, &ei_eigrp_peer_termination_graceful);
901 }
902
903 /**
904  *@fn void dissect_eigrp_peer_tidlist (proto_tree *tree, tvbuff_t *tvb)
905  *
906  * @param[in,out] tree  detail dissection result
907  * @param[in] tvb       packet data
908  *
909  * @par
910  *  Dissect the Topology Identifier List TLV.  This TLV was introduced as part
911  *  of the "MTR (Multi-Topology Routing) Project to support sub topologies
912  *  within a given Autonomous System. The following represents the format of
913  *  the TID list
914  *
915  *    0                   1                   2                   3
916  *    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
917  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
918  *   |            Flags             |         Length                 |
919  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
920  *   |        Variable Length TID (two bytes) list                   |
921  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
922  */
923 static void
924 dissect_eigrp_peer_tidlist (proto_tree *tree, tvbuff_t *tvb)
925 {
926     proto_item *sub_ti;
927     proto_tree *sub_tree;
928     int         offset = 0;
929     guint16     size;
930
931     proto_tree_add_item(tree, hf_eigrp_tidlist_flags, tvb, offset, 2,
932                         ENC_BIG_ENDIAN);
933     offset += 2;
934
935     size = tvb_get_ntohs(tvb, offset) / 2;
936     proto_tree_add_item(tree, hf_eigrp_tidlist_len, tvb, offset, 2,
937                         ENC_BIG_ENDIAN);
938     offset += 2;
939
940     sub_ti = proto_tree_add_text(tree, tvb, offset, (size*2), "%d TIDs", size);
941     sub_tree = proto_item_add_subtree(sub_ti, ett_eigrp_tidlist);
942     for (; size ; size--) {
943         proto_tree_add_item(sub_tree, hf_eigrp_tidlist_tid, tvb, offset, 2,
944                             ENC_BIG_ENDIAN);
945         offset += 2;
946     }
947 }
948
949 /**
950  *@fn int dissect_eigrp_extdata_flags (proto_tree *tree, tvbuff_t *tvb, int offset)
951  *
952  * @param[in,out] tree  detail dissection result
953  * @param[in] tvb       packet data
954  * @param[in] offset    current byte offset in packet being processed
955  *
956  * @return int          number of bytes process
957  *
958  * @par
959  * Dissect the Flags field in the external data section of an external
960  * route.The following represents the format of the bit field
961  *
962  *    7 6 5 4 3 2 1 0
963  *   +-+-+-+-+-+-+-+-+
964  *   |   Flags       |
965  *   +-+-+-+-+-+-+-+-+
966  *                | |
967  *                | +- Route is External *not used*
968  *                +--- Route is Candidate Default
969  */
970 static int
971 dissect_eigrp_extdata_flags (proto_tree *tree, tvbuff_t *tvb, int offset)
972 {
973     proto_item *sub_ti;
974     proto_tree *sub_tree;
975     tvbuff_t   *sub_tvb;
976
977     /* Decode the route flags field */
978     sub_ti = proto_tree_add_text(tree, tvb, offset, 1, "External Flags");
979     sub_tree = proto_item_add_subtree(sub_ti, ett_eigrp_extdata_flags);
980     sub_tvb = tvb_new_subset_remaining(tvb, offset);
981
982     proto_tree_add_item(sub_tree, hf_eigrp_extdata_flag_ext, sub_tvb, 0, 1,
983                         ENC_BIG_ENDIAN);
984     proto_tree_add_item(sub_tree, hf_eigrp_extdata_flag_cd, sub_tvb, 0, 1,
985                         ENC_BIG_ENDIAN);
986
987     offset += 1;
988     return(offset);
989 }
990
991 /**
992  *@fn int dissect_eigrp_metric_flags (proto_tree *tree, tvbuff_t *tvb, int offset, int limit)
993  *
994  * @param[in,out] tree  detail dissection result
995  * @param[in] tvb       packet data
996  * @param[in] offset    current byte offset in packet being processed
997  * @param[in] limit     maximum number of bytes which can be process
998  *
999  * @return int          number of bytes process
1000  *
1001  * @par
1002  * Dissect Protocol Dependent Module (PDM) Flags field in the route metric
1003  * section of an internal and external route. The following represents the
1004  * format of the bit field
1005  *
1006  *       MSB             LSB
1007  *    7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
1008  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1009  *   |   Flags       |    MP Flags   |
1010  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1011  *              | | |
1012  *              | | +- Route is Replicated
1013  *              | +--- Route is Active
1014  *              +----- Source Withdraw
1015  */
1016 static int
1017 dissect_eigrp_metric_flags (proto_tree *tree, tvbuff_t *tvb, int offset, int limit)
1018 {
1019     proto_item *sub_ti;
1020     proto_tree *sub_tree;
1021     tvbuff_t   *sub_tvb;
1022
1023     /* Decode the route flags field */
1024     sub_ti = proto_tree_add_text(tree, tvb, offset, limit, "Flags");
1025     sub_tree = proto_item_add_subtree(sub_ti, ett_eigrp_metric_flags);
1026     sub_tvb = tvb_new_subset(tvb, offset, limit, -1);
1027
1028     /* just care about 'flags' byte, there are no MP flags for now */
1029     proto_tree_add_item(sub_tree, hf_eigrp_metric_flags_srcwd, sub_tvb, 0, 1,
1030                         ENC_BIG_ENDIAN);
1031     proto_tree_add_item(sub_tree, hf_eigrp_metric_flags_active, sub_tvb, 0, 1,
1032                         ENC_BIG_ENDIAN);
1033     proto_tree_add_item(sub_tree, hf_eigrp_metric_flags_repl, sub_tvb, 0, 1,
1034                         ENC_BIG_ENDIAN);
1035
1036     offset += limit;
1037     return(offset);
1038 }
1039
1040 /**
1041  *@fn int dissect_eigrp_ipv4_addr (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
1042  *                                 packet_info *pinfo, int offset, int unreachable)
1043  *
1044  * @param[in,out] tree  detail dissection result
1045  * @param[in] tvb       packet data
1046  * @param[in] pinfo     general data about the protocol
1047  * @param[in] offset    current byte offset in packet being processed
1048  *
1049  * @return int          number of bytes process
1050  *
1051  * @par
1052  * Dissect all IPv4 address from offset though the end of the packet
1053  */
1054 static int
1055 dissect_eigrp_ipv4_addr (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
1056                          packet_info *pinfo, int offset, int unreachable)
1057 {
1058     guint8      ip_addr[4], length;
1059     int         addr_len;
1060     proto_item *ti_prefixlen, *ti_dst;
1061     int         first = TRUE;
1062
1063     for (; tvb_length_remaining(tvb, offset) > 0; offset += (1 + addr_len)) {
1064         length = tvb_get_guint8(tvb, offset);
1065         addr_len = ipv4_addr_and_mask(tvb, offset + 1, ip_addr, length);
1066
1067         if (addr_len < 0) {
1068             ti_prefixlen = proto_tree_add_item(tree, hf_eigrp_ipv4_prefixlen,
1069                                                tvb, offset, 1, ENC_BIG_ENDIAN);
1070             expert_add_info_format(pinfo, ti_prefixlen, &ei_eigrp_prefixlen, "Invalid prefix length %u, must be <= 32", length);
1071             addr_len = 4; /* assure we can exit the loop */
1072
1073         } else {
1074             proto_tree_add_item(tree, hf_eigrp_ipv4_prefixlen, tvb, offset, 1,
1075                                 ENC_BIG_ENDIAN);
1076             offset += 1;
1077             ti_dst = proto_tree_add_text(tree, tvb, offset, addr_len,
1078                                          "Destination: %s", ip_to_str(ip_addr));
1079
1080             /* add it to the top level line */
1081             proto_item_append_text(ti,"  %c   %s/%u", first ? '=':',',
1082                                    ip_to_str(ip_addr), length);
1083
1084             if (unreachable) {
1085                 expert_add_info(pinfo, ti_dst, &ei_eigrp_unreachable);
1086             }
1087         }
1088         first = FALSE;
1089     }
1090     return (offset);
1091 }
1092
1093 /**
1094  *@fn int dissect_eigrp_ipv6_addr (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
1095  *                                 packet_info *pinfo, int offset, int unreachable)
1096  *
1097  * @param[in,out] tree  detail dissection result
1098  * @param[in] tvb       packet data
1099  * @param[in] pinfo     general data about the protocol
1100  * @param[in] offset    current byte offset in packet being processed
1101  *
1102  * @return int          number of bytes process
1103  *
1104  * @par
1105  * Dissect all IPv6 address from offset though the end of the packet
1106  */
1107 static int
1108 dissect_eigrp_ipv6_addr (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
1109                          packet_info *pinfo, int offset, int unreachable)
1110 {
1111     guint8             length;
1112     int                addr_len;
1113     struct e_in6_addr  addr;
1114     proto_item        *ti_prefixlen, *ti_dst;
1115     int                first = TRUE;
1116
1117     for (; tvb_length_remaining(tvb, offset) > 0; offset += (1 + addr_len)) {
1118         length = tvb_get_guint8(tvb, offset);
1119         addr_len = ipv6_addr_and_mask(tvb, offset + 1, &addr, length);
1120
1121         if (addr_len < 0) {
1122             ti_prefixlen = proto_tree_add_item(tree, hf_eigrp_ipv6_prefixlen,
1123                                                tvb, offset, 1, ENC_BIG_ENDIAN);
1124             expert_add_info_format(pinfo, ti_prefixlen, &ei_eigrp_prefixlen, "Invalid prefix length %u, must be <= 128", length);
1125             addr_len = 16; /* assure we can exit the loop */
1126         } else {
1127             proto_tree_add_item(tree, hf_eigrp_ipv6_prefixlen, tvb, offset, 1,
1128                                 ENC_BIG_ENDIAN);
1129             offset += 1;
1130
1131             if ((length < 128) && (length % 8 == 0)) {
1132                 addr_len++;
1133             }
1134
1135             ti_dst = proto_tree_add_text(tree, tvb, offset, addr_len,
1136                                          "Destination: %s", ip6_to_str(&addr));
1137
1138             /* add it to the top level line */
1139             proto_item_append_text(ti,"  %c   %s/%u", first ? '=':',',
1140                                    ip6_to_str(&addr), length);
1141
1142             if (unreachable) {
1143                 expert_add_info(pinfo, ti_dst, &ei_eigrp_unreachable);
1144             }
1145         }
1146         first = FALSE;
1147     }
1148     return(offset);
1149 }
1150
1151 /**
1152  *@fn int dissect_eigrp_ipx_addr (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
1153  *                                packet_info *pinfo, int offset, int unreachable)
1154  *
1155  * @param[in,out] tree  detail dissection result
1156  * @param[in] tvb       packet data
1157  * @param[in] pinfo     general data about the protocol
1158  * @param[in] offset    current byte offset in packet being processed
1159  *
1160  * @return int          number of bytes process
1161  *
1162  * @par
1163  * Dissect all IPX address from offset though the end of the packet
1164  */
1165 static int
1166 dissect_eigrp_ipx_addr (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
1167                         packet_info *pinfo, int offset, int unreachable)
1168 {
1169     proto_item *ti_dst;
1170
1171     ti_dst = proto_tree_add_item(tree, hf_eigrp_ipx_dest, tvb, offset, 4,
1172                                  ENC_NA);
1173
1174     /* add it to the top level line */
1175     proto_item_append_text(ti,"  =   %s",
1176                            ipxnet_to_string(tvb_get_ptr(tvb, offset, 4)));
1177
1178     if (unreachable) {
1179         expert_add_info(pinfo, ti_dst, &ei_eigrp_unreachable);
1180     }
1181
1182     offset +=4;
1183     return(offset);
1184 }
1185
1186 /**
1187  *@fn int dissect_eigrp_service (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
1188  *                               packet_info *pinfo, int offset)
1189  *
1190  * @param[in,out] tree  detail dissection result
1191  * @param[in] tvb       packet data
1192  * @param[in] pinfo     general data about the protocol
1193  * @param[in] ti        protocol item
1194  * @param[in] offset    current byte offset in packet being processed
1195  *
1196  * @return int          number of bytes process
1197  *
1198  * @par
1199  * Dissect all SAF Services from offset though the end of the packet. The
1200  * following represents the format of  a SAF Service:
1201  *
1202  *    0                   1                   2                   3
1203  *    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
1204  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1205  *   |            Service            |         SubService            |
1206  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1207  *   |                             GUID                              |
1208  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1209  *   |                             GUID(cont)                        |
1210  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1211  *   |                             GUID(cont)                        |
1212  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1213  *   |                             GUID(cont)                        |
1214  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1215  *   |            Type               |           Length              |
1216  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1217  *   |        Reachability AFI       |    Reachability Port          |
1218  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1219  *   |     Reachability Protocol     |    Reachability Addr          |
1220  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1221  *   |                      Reachability Addr(cont)                  |
1222  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1223  *   |                      Reachability Addr(cont)                  |
1224  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1225  *   |                      Reachability Addr(cont)                  |
1226  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1227  *   |    Reachability Addr(cont)    |           Sequence            |
1228  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1229  *   |           Sequence(cont)      |\/\/\/    Service Data   \/\/\/|
1230  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1231  *
1232  */
1233 static int
1234 dissect_eigrp_service (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
1235                        packet_info *pinfo, int offset)
1236 {
1237     int         afi, length, remaining;
1238     int         sub_offset;
1239     proto_item *sub_ti, *reach_ti;
1240     proto_tree *sub_tree, *reach_tree;
1241     tvbuff_t   *sub_tvb, *reach_tvb;
1242     guint16     service, sub_service;
1243
1244     remaining = tvb_length_remaining(tvb, offset);
1245     sub_ti = proto_tree_add_text(tree, tvb, offset, remaining, "SAF Service ");
1246     sub_tree = proto_item_add_subtree(sub_ti, ett_eigrp_tlv_metric);
1247     sub_tvb = tvb_new_subset(tvb, offset, remaining, -1);
1248     sub_offset = 0;
1249
1250     for (; tvb_length_remaining(sub_tvb, sub_offset) > 0; ) {
1251         service = tvb_get_ntohs(sub_tvb, sub_offset);
1252         proto_item_append_text(sub_ti, "%c %s", (sub_offset == 0 ? '=':','),
1253                                val_to_str_const(service, eigrp_saf_srv2string, ""));
1254
1255         sub_service = tvb_get_ntohs(sub_tvb, sub_offset+2);
1256         proto_item_append_text(ti, "%c %u:%u", (sub_offset == 0 ? '=':','),
1257                                service, sub_service);
1258
1259         proto_tree_add_item(sub_tree, hf_eigrp_saf_service, sub_tvb,
1260                             sub_offset, 2, ENC_BIG_ENDIAN);
1261         sub_offset += 2;
1262         proto_tree_add_item(sub_tree, hf_eigrp_saf_subservice, sub_tvb,
1263                             sub_offset, 2, ENC_BIG_ENDIAN);
1264         sub_offset += 2;
1265         proto_tree_add_item(sub_tree, hf_eigrp_saf_guid, sub_tvb,
1266                             sub_offset, GUID_LEN, ENC_BIG_ENDIAN);
1267         sub_offset += GUID_LEN;
1268
1269         proto_tree_add_item(sub_tree, hf_eigrp_saf_data_type, sub_tvb,
1270                             sub_offset, 2, ENC_BIG_ENDIAN);
1271         sub_offset += 2;
1272         length = tvb_get_ntohs(sub_tvb, sub_offset);
1273         proto_tree_add_item(sub_tree, hf_eigrp_saf_data_length, sub_tvb,
1274                             sub_offset, 2, ENC_BIG_ENDIAN);
1275         sub_offset += 2;
1276
1277         /*
1278          * Reachability information
1279          */
1280         reach_ti = proto_tree_add_text(sub_tree, sub_tvb, sub_offset, 22,
1281                                        "Reachability");
1282         reach_tree = proto_item_add_subtree(reach_ti, ett_eigrp_saf_reachability);
1283         reach_tvb = tvb_new_subset(sub_tvb, sub_offset, 22, -1);
1284
1285         afi = tvb_get_ntohs(reach_tvb, 0);
1286         proto_tree_add_item(reach_tree, hf_eigrp_saf_reachability_afi,
1287                             reach_tvb, 0, 2, ENC_BIG_ENDIAN);
1288         proto_tree_add_item(reach_tree, hf_eigrp_saf_reachability_port,
1289                             reach_tvb, 2, 2, ENC_BIG_ENDIAN);
1290         proto_tree_add_item(reach_tree, hf_eigrp_saf_reachability_protocol,
1291                             reach_tvb, 4, 2, ENC_BIG_ENDIAN);
1292
1293         switch (afi) {
1294         case EIGRP_AF_IPv4:
1295             proto_tree_add_item(reach_tree, hf_eigrp_saf_reachability_addr_ipv4,
1296                                 reach_tvb, 6, 4, ENC_BIG_ENDIAN);
1297             proto_tree_add_item(reach_tree, hf_eigrp_nullpad, reach_tvb, 10, 12,
1298                                 ENC_NA);
1299             break;
1300
1301         case EIGRP_AF_IPv6:
1302             proto_tree_add_item(reach_tree, hf_eigrp_saf_reachability_addr_ipv6,
1303                                 reach_tvb, 6, 16, ENC_NA);
1304             break;
1305         default:
1306             /* just print zeros... */
1307             proto_tree_add_item(reach_tree, hf_eigrp_saf_reachability_addr_hex,
1308                                 reach_tvb, 6, 16, ENC_NA);
1309             break;
1310         }
1311         sub_offset += 22;
1312
1313         proto_tree_add_item(sub_tree, hf_eigrp_saf_data_sequence, sub_tvb,
1314                             sub_offset, 4, ENC_BIG_ENDIAN);
1315         sub_offset += 4;
1316
1317         if (length > 0) {
1318             tvbuff_t *xml_tvb;
1319             guint8 *test_string, *tok;
1320
1321             /*
1322              * Service-Data is usually (but not always) plain text, specifically
1323              * XML. If it "looks like" XML (begins with optional white-space
1324              * followed by a '<'), try XML. Otherwise, try plain-text.
1325              */
1326             xml_tvb = tvb_new_subset(sub_tvb, sub_offset, length, length);
1327             test_string = tvb_get_string(wmem_packet_scope(), xml_tvb, 0, (length < 32 ?
1328                                                                 length : 32));
1329             tok = strtok(test_string, " \t\r\n");
1330
1331             if (tok && tok[0] == '<') {
1332                 /* Looks like XML */
1333                 dissector_try_string(media_type_table, "application/xml",
1334                                      xml_tvb, pinfo, sub_tree, NULL);
1335             } else {
1336                 /* Try plain text */
1337                 dissector_try_string(media_type_table, "text/plain",
1338                                      xml_tvb, pinfo, sub_tree, NULL);
1339             }
1340         }
1341         sub_offset += length;
1342     }
1343
1344     offset += sub_offset;
1345     return(offset);
1346 }
1347
1348 /**
1349  *@fn int dissect_eigrp_legacy_metric (proto_tree *tree, tvbuff_t *tvb, int offset)
1350  *
1351  * @param[in,out] tree  detail dissection result
1352  * @param[in] tvb       packet data
1353  * @param[in] offset    current byte offset in packet being processed
1354  *
1355  * @return int          number of bytes process
1356  *
1357  * @par
1358  * Dissect the TLV Versions 1.2 (legacy) and 3.0 (deprecated) metric
1359  * sections. The following represents the format
1360  *
1361  *    0                   1                   2                   3
1362  *    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
1363  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1364  *   |                       Scaled Delay                            |
1365  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1366  *   |                    Scaled Bandwidth                           |
1367  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1368  *   |         MTU                                    |   Hopcount   |
1369  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1370  *   | Reliability  |      Load     |  Internal Tag   |    Flag      |
1371  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1372  *
1373  */
1374 static int
1375 dissect_eigrp_legacy_metric (proto_tree *tree, tvbuff_t *tvb, int offset)
1376 {
1377     proto_item *sub_ti;
1378     proto_tree *sub_tree;
1379     tvbuff_t   *sub_tvb;
1380
1381     sub_ti = proto_tree_add_text(tree, tvb, offset, 16, "Legacy Metric");
1382     sub_tree = proto_item_add_subtree(sub_ti, ett_eigrp_tlv_metric);
1383     sub_tvb = tvb_new_subset(tvb, offset, 16, -1);
1384
1385     proto_tree_add_item(sub_tree, hf_eigrp_legacy_metric_delay, sub_tvb,
1386                         0, 4, ENC_BIG_ENDIAN);
1387     proto_tree_add_item(sub_tree, hf_eigrp_legacy_metric_bw, sub_tvb,
1388                         4, 4, ENC_BIG_ENDIAN);
1389     proto_tree_add_item(sub_tree, hf_eigrp_legacy_metric_mtu, sub_tvb,
1390                         8, 3, ENC_BIG_ENDIAN);
1391     proto_tree_add_item(sub_tree, hf_eigrp_legacy_metric_hopcount, sub_tvb,
1392                         11, 1, ENC_BIG_ENDIAN);
1393     proto_tree_add_item(sub_tree, hf_eigrp_legacy_metric_rel, sub_tvb,
1394                         12, 1, ENC_BIG_ENDIAN);
1395     proto_tree_add_item(sub_tree, hf_eigrp_legacy_metric_load, sub_tvb,
1396                         13, 1, ENC_BIG_ENDIAN);
1397     proto_tree_add_item(sub_tree, hf_eigrp_legacy_metric_intag, sub_tvb,
1398                         14, 1, ENC_BIG_ENDIAN);
1399
1400     /* Decode the route flags field */
1401     dissect_eigrp_metric_flags(sub_tree, sub_tvb, 15, 1);
1402
1403     offset += 16;
1404     return(offset);
1405 }
1406
1407 /**
1408  *@fn int dissect_eigrp_ipx_extdata (proto_tree *tree, tvbuff_t *tvb, int offset)
1409  *
1410  * @param[in,out] tree  detail dissection result
1411  * @param[in] tvb       packet data
1412  * @param[in] offset    current byte offset in packet being processed
1413  *
1414  * @return int          number of bytes process
1415  *
1416  * @par
1417  * Dissect the IPX External data for the TLV versions 1.2 and 3.0.
1418  * The following represents the format
1419  *
1420  *    0                   1                   2                   3
1421  *    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
1422  *                                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1423  *                                   |          Ext RouterID         |
1424  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1425  *   |                       Ext Router ID                           |
1426  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1427  *   |                Ext Autonomous System Number                   |
1428  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1429  *   |                        Route Tag                              |
1430  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1431  *   |  Ext Protocol  | Ext Flags    |     External Metric           |
1432  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1433  *   |      External Delay           |
1434  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1435  */
1436 static int
1437 dissect_eigrp_ipx_extdata (proto_tree *tree, tvbuff_t *tvb, int offset)
1438 {
1439     proto_item *sub_ti;
1440     proto_tree *sub_tree;
1441     tvbuff_t   *sub_tvb;
1442     int         sub_offset = 0;
1443
1444     sub_ti = proto_tree_add_text(tree, tvb, offset, 20, "External Data");
1445     sub_tree = proto_item_add_subtree(sub_ti, ett_eigrp_tlv_extdata);
1446     sub_tvb = tvb_new_subset(tvb, offset, 20, -1);
1447
1448     /* Decode the external route source info */
1449     proto_tree_add_item(sub_tree, hf_eigrp_ipx_extdata_routerid, sub_tvb,
1450                         sub_offset, 6, ENC_NA);
1451     sub_offset += 6;
1452     proto_tree_add_item(sub_tree, hf_eigrp_extdata_as, sub_tvb,
1453                         sub_offset, 4, ENC_BIG_ENDIAN);
1454     sub_offset += 4;
1455     proto_tree_add_item(sub_tree, hf_eigrp_extdata_tag, sub_tvb,
1456                         sub_offset, 4, ENC_BIG_ENDIAN);
1457     sub_offset += 4;
1458     proto_tree_add_item(sub_tree, hf_eigrp_extdata_proto, sub_tvb,
1459                         sub_offset, 1, ENC_BIG_ENDIAN);
1460     sub_offset += 1;
1461
1462     /* Decode the external route flags */
1463     dissect_eigrp_extdata_flags(sub_tree, sub_tvb, sub_offset);
1464     sub_offset += 1;
1465
1466     /* and the rest of it... */
1467     proto_tree_add_item(sub_tree, hf_eigrp_ipx_extdata_metric,
1468                         sub_tvb, sub_offset, 2, ENC_BIG_ENDIAN);
1469     sub_offset += 2;
1470     proto_tree_add_item(sub_tree, hf_eigrp_ipx_extdata_delay,
1471                         sub_tvb, sub_offset, 2, ENC_BIG_ENDIAN);
1472     sub_offset += 2;
1473
1474     offset += sub_offset;
1475     return(offset);
1476 }
1477
1478 /**
1479  *@fn int dissect_eigrp_extdata (proto_tree *tree, tvbuff_t *tvb, int offset)
1480  *
1481  * @param[in,out] tree  detail dissection result
1482  * @param[in] tvb       packet data
1483  * @param[in] offset    current byte offset in packet being processed
1484  *
1485  * @return int          number of bytes process
1486  *
1487  * @par
1488  * Dissect the external route data for TLV versions 1.2 and 3.0 for all
1489  * protocols except IPX. The following represents the format
1490  *
1491  *    0                   1                   2                   3
1492  *    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
1493  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1494  *   |                       Ext Router ID                           |
1495  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1496  *   |                Ext Autonomous System Number                   |
1497  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1498  *   |                        Route Tag                              |
1499  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1500  *   |                    External Metric                            |
1501  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1502  *   |         Reserved             |   Ext Protocol  | Ext Flags    |
1503  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1504  */
1505 static int
1506 dissect_eigrp_extdata (proto_tree *tree, tvbuff_t *tvb, int offset)
1507 {
1508     proto_item *sub_ti;
1509     proto_tree *sub_tree;
1510     tvbuff_t   *sub_tvb;
1511     int         sub_offset = 0;
1512
1513     sub_ti = proto_tree_add_text(tree, tvb, offset, 20, "External Data");
1514     sub_tree = proto_item_add_subtree(sub_ti, ett_eigrp_tlv_extdata);
1515     sub_tvb = tvb_new_subset(tvb, offset, 20, -1);
1516
1517     /* Decode the external route source info */
1518     proto_tree_add_item(sub_tree, hf_eigrp_extdata_origrid, sub_tvb,
1519                         sub_offset, 4, ENC_BIG_ENDIAN);
1520     sub_offset += 4;
1521     proto_tree_add_item(sub_tree, hf_eigrp_extdata_as, sub_tvb,
1522                         sub_offset, 4, ENC_BIG_ENDIAN);
1523     sub_offset += 4;
1524     proto_tree_add_item(sub_tree, hf_eigrp_extdata_tag, sub_tvb,
1525                         sub_offset, 4, ENC_BIG_ENDIAN);
1526     sub_offset += 4;
1527     proto_tree_add_item(sub_tree, hf_eigrp_extdata_metric, sub_tvb,
1528                         sub_offset, 4, ENC_BIG_ENDIAN);
1529     sub_offset += 4;
1530     proto_tree_add_item(sub_tree, hf_eigrp_extdata_reserved, sub_tvb,
1531                         sub_offset, 2, ENC_BIG_ENDIAN);
1532     sub_offset += 2;
1533     proto_tree_add_item(sub_tree, hf_eigrp_extdata_proto, sub_tvb,
1534                         sub_offset, 1, ENC_BIG_ENDIAN);
1535     sub_offset += 1;
1536
1537     /* Decode the external route flags */
1538     dissect_eigrp_extdata_flags(sub_tree, sub_tvb, sub_offset);
1539     sub_offset += 1;
1540
1541     offset += sub_offset;
1542     return(offset);
1543 }
1544
1545 /**
1546  *@fn int dissect_eigrp_nexthop (proto_tree *tree, tvbuff_t *tvb, guint16 afi, int offset)
1547  *
1548  * @param[in,out] tree  detail dissection result
1549  * @param[in] tvb       packet data
1550  * @param[in] afi       IANA address family indicator
1551  * @param[in] offset    current byte offset in packet being processed
1552  *
1553  * @return int          number of bytes process
1554  *
1555  * @par
1556  * Dissect the next hop field which is in the "route TLVs".  This function will
1557  * handle all the various protocol AFIs and return the appropriate number of
1558  * bytes processed
1559  */
1560 static int
1561 dissect_eigrp_nexthop (proto_tree *tree, tvbuff_t *tvb, guint16 afi, int offset)
1562 {
1563     /* dissect dest information */
1564     switch (afi) {
1565     case EIGRP_SF_IPv4:
1566     case EIGRP_AF_IPv4:
1567         proto_tree_add_item(tree, hf_eigrp_ipv4_nexthop, tvb, offset, 4,
1568                             ENC_BIG_ENDIAN);
1569         offset += 4;
1570         break;
1571
1572     case EIGRP_SF_IPv6:
1573     case EIGRP_AF_IPv6:
1574         proto_tree_add_item(tree, hf_eigrp_ipv6_nexthop, tvb, offset, 16,
1575                             ENC_NA);
1576         offset += 16;
1577         break;
1578
1579     case EIGRP_AF_IPX:
1580         proto_tree_add_item(tree, hf_eigrp_ipx_nexthop_net, tvb, offset, 4,
1581                             ENC_NA);
1582         offset += 4;
1583         proto_tree_add_item(tree, hf_eigrp_ipx_nexthop_host, tvb, offset, 6,
1584                             ENC_NA);
1585         offset += 6;
1586         break;
1587
1588     case EIGRP_SF_COMMON:
1589         break;
1590
1591     default:
1592         break;
1593     }
1594
1595     return(offset);
1596 }
1597
1598 /**
1599  *@fn void dissect_eigrp_general_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
1600  *                                    packet_info *pinfo, guint16 tlv)
1601  *
1602  * @param[in,out] tree  detail dissection result
1603  * @param[in] tvb       packet data
1604  * @param[in] pinfo     general data about the protocol
1605  * @param[in] ti        protocol item
1606  * @param[in] tlv       Specific TLV in to be dissected
1607  *
1608  * @par
1609  * General EIGRP parameters carry EIGRP management information and are not
1610  * specific to any one routed protocol.
1611  *
1612  */
1613 static void
1614 dissect_eigrp_general_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
1615                            packet_info *pinfo, guint16 tlv)
1616 {
1617     switch (tlv) {
1618     case EIGRP_TLV_PARAMETER:
1619         dissect_eigrp_parameter(tree, tvb, pinfo, ti);
1620         break;
1621     case EIGRP_TLV_AUTH:
1622         dissect_eigrp_auth_tlv(tree, tvb, pinfo, ti);
1623         break;
1624     case EIGRP_TLV_SEQ:
1625         dissect_eigrp_seq_tlv(tree, tvb, pinfo);
1626         break;
1627     case EIGRP_TLV_SW_VERSION:
1628         dissect_eigrp_sw_version(tvb, tree, ti);
1629         break;
1630     case EIGRP_TLV_NEXT_MCAST_SEQ:
1631         dissect_eigrp_next_mcast_seq(tvb, tree, ti);
1632         break;
1633     case EIGRP_TLV_PEER_STUBINFO:
1634         dissect_eigrp_peer_stubinfo(tvb, tree);
1635         break;
1636     case EIGRP_TLV_PEER_TERMINATION:
1637         dissect_eigrp_peer_termination(pinfo, ti);
1638         break;
1639     case EIGRP_TLV_PEER_TIDLIST:
1640         dissect_eigrp_peer_tidlist(tree, tvb);
1641         break;
1642     default:
1643         expert_add_info_format(pinfo, ti, &ei_eigrp_tlv_type, "Unknown Generic TLV (0x%04x)", tlv);
1644         break;
1645     }
1646 }
1647
1648 /**
1649  *@fn int dissect_eigrp_ipv4_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
1650  *                                 packet_info *pinfo, guint16 tlv)
1651  *
1652  * @param[in,out] tree  detail dissection result
1653  * @param[in] tvb       packet data
1654  * @param[in] pinfo     general data about the protocol
1655  * @param[in] tlv       Specific TLV in to be dissected
1656  *
1657  * @return int          number of bytes process
1658  *
1659  * @par
1660  * Dissect the Legacy IPv4 route TLV; handles both the internal and external
1661  * TLV types; This packet format is being deprecated and replaced with the
1662  * Multi-Protocol packet formats as of EIGRP Release-8.  This TLV format is used
1663  * to maintain backward compatibility between older version so EIGRP, "MTR"
1664  * EIGRP, and current shipping code.
1665  *
1666  *    0                   1                   2                   3
1667  *    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
1668  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1669  *   |                      IPv4 Nexthop                             |
1670  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1671  *   |                       Scaled Delay                            |
1672  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1673  *   |                    Scaled Bandwidth                           |
1674  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1675  *   |         MTU                                    |   Hopcount   |
1676  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1677  *   | Reliability  |      Load     |  Internal Tag   |   Flag       |
1678  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1679  */
1680 static int
1681 dissect_eigrp_ipv4_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
1682                         packet_info *pinfo, guint16 tlv)
1683 {
1684     int offset      = 0;
1685     int unreachable = FALSE;
1686
1687     proto_tree_add_item(tree, hf_eigrp_ipv4_nexthop, tvb, offset, 4,
1688                         ENC_BIG_ENDIAN);
1689     offset += 4;
1690
1691     /* dissect external data if needed */
1692     if ((tlv & EIGRP_TLV_TYPEMASK) == EIGRP_TLV_EXTERNAL) {
1693         offset = dissect_eigrp_extdata(tree, tvb, offset);
1694     }
1695
1696     /* dissect the metric */
1697     offset = dissect_eigrp_legacy_metric(tree, tvb, offset);
1698
1699     /* dissect addresses */
1700     offset = dissect_eigrp_ipv4_addr(ti, tree, tvb, pinfo, offset, unreachable);
1701
1702     return offset;
1703 }
1704
1705 /**
1706  *@fn void dissect_eigrp_atalk_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
1707  *                                  proto_item *ti, guint16 tlv)
1708  *
1709  * @param[in,out] tree  detail dissection result
1710  * @param[in] tvb       packet data
1711  * @param[in] tlv       Specific TLV in to be dissected
1712  *
1713  * @par
1714  * Dissect the legacy AppleTalk route TLV; handles both the internal and external
1715  * TLV type.  The following represents the format
1716  */
1717 static void
1718 dissect_eigrp_atalk_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
1719                          guint16 tlv)
1720 {
1721     int offset = 0;
1722
1723     /* cable tlv? */
1724     if (EIGRP_TLV_AT_CBL == tlv) {
1725         proto_tree_add_text(tree, tvb, 0, 4, "AppleTalk Cable Range = %u-%u",
1726                             tvb_get_ntohs(tvb, 0), tvb_get_ntohs(tvb, 2));
1727         proto_tree_add_item(tree, hf_eigrp_atalk_routerid, tvb, 4, 4,
1728                             ENC_BIG_ENDIAN);
1729         proto_item_append_text(ti, ": Cable range= %u-%u, Router ID= %u",
1730                                tvb_get_ntohs(tvb, 0), tvb_get_ntohs(tvb, 2),
1731                                tvb_get_ntohl(tvb, 4));
1732
1733     } else {
1734         proto_tree_add_text(tree, tvb, offset, 4, "NextHop Address = %u.%u",
1735                             tvb_get_ntohs(tvb, 0), tvb_get_ntohs(tvb, 2));
1736         offset += 4;
1737
1738         /* dissect external data if needed */
1739         if ((tlv & EIGRP_TLV_TYPEMASK) == EIGRP_TLV_EXTERNAL) {
1740             offset = dissect_eigrp_extdata(tree, tvb,offset);
1741         }
1742
1743         /* dissect the metric */
1744         offset = dissect_eigrp_legacy_metric(tree, tvb, offset);
1745
1746         /* dissect cable range */
1747         proto_tree_add_text(tree, tvb, offset, 4, "Cable range = %u-%u",
1748                             tvb_get_ntohs(tvb, 36), tvb_get_ntohs(tvb, 38));
1749         proto_item_append_text(ti, ": %u-%u",
1750                                tvb_get_ntohs(tvb, 36), tvb_get_ntohs(tvb, 38));
1751     }
1752     return;
1753 }
1754
1755 /**
1756  *@fn void dissect_eigrp_ipv6_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
1757  *                                 packet_info *pinfo, guint16 tlv)
1758  *
1759  * @param[in,out] tree  detail dissection result
1760  * @param[in] tvb       packet data
1761  * @param[in] pinfo     general data about the protocol
1762  * @param[in] tlv       Specific TLV in to be dissected
1763  *
1764  * @par
1765  * Dissect the Legacy IPv6 route TLV; handles both the internal and external
1766  * TLV types; This packet format is being deprecated and replaced with the
1767  * Multi-Protocol packet formats as of EIGRP Release-8.  This TLV format is used
1768  * to maintain backward compatibility between older version so EIGRP, "MTR"
1769  * EIGRP, and current shipping code.
1770  */
1771 static void
1772 dissect_eigrp_ipv6_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
1773                         packet_info *pinfo, guint16 tlv)
1774 {
1775     int offset      = 0;
1776     int unreachable = FALSE;
1777
1778     proto_tree_add_item(tree, hf_eigrp_ipv6_nexthop, tvb, offset, 16,
1779                         ENC_NA);
1780     offset += 16;
1781
1782     /* dissect external data if needed */
1783     if ((tlv & EIGRP_TLV_TYPEMASK) == EIGRP_TLV_EXTERNAL) {
1784         offset = dissect_eigrp_extdata(tree, tvb, offset);
1785     }
1786
1787     /* dissect the metric */
1788     offset = dissect_eigrp_legacy_metric(tree, tvb, offset);
1789
1790     /* dissect addresses */
1791     dissect_eigrp_ipv6_addr(ti, tree, tvb, pinfo, offset, unreachable);
1792     return;
1793 }
1794
1795 /**
1796  *@fn int dissect_eigrp_ipx_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
1797  *                                packet_info *pinfo, guint16 tlv)
1798  *
1799  * @param[in,out] tree  detail dissection result
1800  * @param[in] tvb       packet data
1801  * @param[in] pinfo     general data about the protocol
1802  * @param[in] tlv       Specific TLV in to be dissected
1803  *
1804  * @return int          number of bytes process
1805  *
1806  * @par
1807  * Dissect the legacy IPX route TLV; handles both the internal and external
1808  * TLV type.  The following represents the format
1809  *
1810  *    0                   1                   2                   3
1811  *    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
1812  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1813  *   |                         Nexthop Net                           |
1814  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1815  *   |                        Nexthop Host                           |
1816  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1817  *   |  Nexthop Host(cont)           |
1818  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1819  *
1820  * Optional External Data:
1821  *                                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1822  *                                   |          Ext RouterID         |
1823  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1824  *   |                       Ext Router ID                           |
1825  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1826  *   |                Ext Autonomous System Number                   |
1827  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1828  *   |                        Route Tag                              |
1829  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1830  *   |  Ext Protocol  | Ext Flags    |    External Metric            |
1831  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1832  *   |     External Delay            |
1833  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1834  *
1835  *                                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1836  *                                   |           Scaled Delay        |
1837  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1838  *   |           Scaled Delay        |      Scaled Bandwidth         |
1839  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1840  *   |         Scaled Bandwidth      |             MTU               |
1841  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1842  *   |   MTU(cont)   |    Hopcount   | Reliability   |     Load      |
1843  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1844  *   | Internal Tag |      Flag      |
1845  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1846  *
1847  *
1848  */
1849 static int
1850 dissect_eigrp_ipx_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
1851                        packet_info *pinfo, guint16 tlv)
1852 {
1853     int offset      = 0;
1854     int unreachable = FALSE;
1855
1856     /* nexthop for route... */
1857     offset = dissect_eigrp_nexthop(tree, tvb, EIGRP_AF_IPX, offset);
1858
1859     /* dissect external data if needed */
1860     if ((tlv & EIGRP_TLV_TYPEMASK) == EIGRP_TLV_EXTERNAL) {
1861         offset = dissect_eigrp_ipx_extdata(tree, tvb, offset);
1862     }
1863
1864     /* dissect the metric */
1865     offset = dissect_eigrp_legacy_metric(tree, tvb, offset);
1866
1867     /* dissect addresses */
1868     offset = dissect_eigrp_ipx_addr(ti, tree, tvb, pinfo, offset, unreachable);
1869
1870     return offset;
1871 }
1872
1873 /**
1874  *@fn void dissect_eigrp_ipv4_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
1875  *                                 packet_info *pinfo, proto_item *ti, guint16 tlv)
1876  *
1877  * @param[in,out] tree  detail dissection result
1878  * @param[in] tvb       packet data
1879  * @param[in] pinfo     general data about the protocol
1880  * @param[in] ti        protocol item
1881  * @param[in] tlv       Specific TLV in to be dissected
1882  *
1883  * @return int          number of bytes process
1884  *
1885  * @par
1886  * Dissect the Multi-Topology route TLV; This packet format has been deprecated
1887  * and replaced with the Multi-Protocol packet formats as of EIGRP Release-8. Of
1888  * course this means it will be around for a long long while. The following
1889  * represents the format
1890  *
1891  *    1       2                   3   0                   1         1
1892  *    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
1893  *                                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1894  *                                   |           Reserved            |
1895  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1896  *   |   Topology Identifier         |       Family Identifier       |
1897  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1898  *   |                       Router ID                               |
1899  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1900  *   |                       Route Tag                               |
1901  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1902  *   |                       Scaled Delay                            |
1903  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1904  *   |                    Scaled Bandwidth                           |
1905  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1906  *   |         MTU                                    |   Hopcount   |
1907  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1908  *   | Reliability  |      Load      |  Internal Tag   |    Flag     |
1909  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1910  *   |\/\/\/         NextHop (Family Specific Length)          \/\/\/|
1911  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1912  *   |\/\/\/          External Route Data (Optional)           \/\/\/|
1913  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1914  *   |\/\/\/       Destination (Family Specific Length)        \/\/\/|
1915  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1916  *
1917  */
1918 static int
1919 dissect_eigrp_multi_topology_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
1920                                   packet_info *pinfo, guint16 tlv)
1921 {
1922     guint16     afi;
1923     int         offset      = 2;
1924     int         unreachable = FALSE;
1925
1926     /* tid for you */
1927     proto_tree_add_item(tree, hf_eigrp_tid, tvb, offset, 2, ENC_BIG_ENDIAN);
1928     offset += 2;
1929
1930     /* now it's all about the family */
1931     afi = tvb_get_ntohs(tvb, offset);
1932     proto_tree_add_item(tree, hf_eigrp_afi, tvb, offset, 2, ENC_BIG_ENDIAN);
1933     offset += 2;
1934
1935     /* gota have an id... */
1936     proto_tree_add_item(tree, hf_eigrp_routerid, tvb, offset, 4, ENC_BIG_ENDIAN);
1937     offset += 4;
1938
1939     /* tag.. your it! */
1940     proto_tree_add_item(tree, hf_eigrp_legacy_metric_tag, tvb, offset, 4, ENC_BIG_ENDIAN);
1941     offset += 4;
1942
1943     /* dissect the metric */
1944     offset = dissect_eigrp_legacy_metric(tree, tvb, offset);
1945
1946     /* dissect nexthop */
1947     offset = dissect_eigrp_nexthop(tree, tvb, afi, offset);
1948
1949     /* dissect external data if needed */
1950     if ((tlv & EIGRP_TLV_TYPEMASK) == EIGRP_TLV_EXTERNAL) {
1951         if (afi == EIGRP_AF_IPX) {
1952             offset = dissect_eigrp_ipx_extdata(tree, tvb, offset);
1953         } else {
1954             offset = dissect_eigrp_extdata(tree, tvb, offset);
1955         }
1956     }
1957
1958     /* dissect dest information */
1959     switch (afi) {
1960     case EIGRP_AF_IPv4:
1961         offset = dissect_eigrp_ipv4_addr(ti, tree, tvb, pinfo, offset, unreachable);
1962         break;
1963     case EIGRP_AF_IPv6:
1964         offset = dissect_eigrp_ipv6_addr(ti, tree, tvb, pinfo, offset, unreachable);
1965         break;
1966     case EIGRP_AF_IPX:
1967         offset = dissect_eigrp_ipx_addr(ti, tree, tvb, pinfo, offset, unreachable);
1968         break;
1969
1970     case EIGRP_SF_COMMON:
1971     case EIGRP_SF_IPv4:
1972     case EIGRP_SF_IPv6:
1973         offset = dissect_eigrp_service(ti, tree, tvb, pinfo, offset);
1974         break;
1975
1976     default:
1977         proto_tree_add_expert(tree, pinfo, &ei_eigrp_afi, tvb, offset, -1);
1978     }
1979
1980     return offset;
1981 }
1982
1983 /**
1984  *@fn int dissect_eigrp_metric_comm (proto_tree *tree, tvbuff_t *tvb, int offset, int limit)
1985  *
1986  * @param[in,out] tree  detail dissection result
1987  * @param[in] tvb       packet data
1988  * @param[in] offset    current byte offset in packet being processed
1989  * @param[in] limit     maximum number of bytes which can be process
1990  *
1991  * @return int          number of bytes process
1992  *
1993  * @par
1994  * Dissect extended community attached to metric TLVs to support VPNv4
1995  * deployments, The following represents the format
1996  *
1997  *   0                   1                   2                   3
1998  *   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
1999  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2000  *  |  Type high    |  Type low(*)  |                               |
2001  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+          Value                |
2002  *  |                                                               |
2003  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2004  */
2005 static int
2006 dissect_eigrp_metric_comm (proto_tree *tree, tvbuff_t *tvb, int offset, int limit)
2007 {
2008     int comm_type;
2009
2010     while (limit > 0) {
2011         comm_type = tvb_get_ntohs(tvb, offset);
2012         offset++;
2013
2014         switch (comm_type) {
2015             /*
2016              * Tag for this route. It is present for all EIGRP VPNv4
2017              * routes, internal and external
2018              */
2019         case EIGRP_EXTCOMM_EIGRP:
2020             proto_tree_add_text(tree, tvb, offset, 8,
2021                                 "Type(EIGRP_EXTCOMM_EIGRP): Flag(0x%02x) Tag(%u)",
2022                                 tvb_get_ntohs(tvb, 0),
2023                                 tvb_get_ntohl(tvb, 2));
2024             break;
2025         case EIGRP_EXTCOMM_VRR:
2026             proto_tree_add_text(tree, tvb, offset, 8,
2027                                 "Type(EIGRP_EXTCOMM_VRR)): RES(0x%02x) RID(0x%04x)",
2028                                 tvb_get_ntohs(tvb, 0),
2029                                 tvb_get_ntohl(tvb, 2));
2030             break;
2031
2032             /*
2033              * Vecmetric information for given EIGRP VPNv4 route,
2034              * applies to both internal and external
2035              */
2036         case EIGRP_EXTCOMM_DAD:
2037             proto_tree_add_text(tree, tvb, offset, 8,
2038                                 "Type(EIGRP_EXTCOMM_DAD): AS(%u):SDLY(%u)",
2039                                 tvb_get_ntohs(tvb, 0),
2040                                 tvb_get_ntohl(tvb, 2));
2041             break;
2042         case EIGRP_EXTCOMM_VRHB:
2043             proto_tree_add_text(tree, tvb, offset, 8,
2044                                 "Type(EIGRP_EXTCOMM_VRHB): REL(%u) HOP(%u) SBW(%u)",
2045                                 tvb_get_guint8(tvb, 0),
2046                                 tvb_get_guint8(tvb, 1),
2047                                 tvb_get_ntohl(tvb, 2));
2048             break;
2049         case EIGRP_EXTCOMM_SRLM:
2050             proto_tree_add_text(tree, tvb, offset, 8,
2051                                 "Type(EIGRP_EXTCOMM_SRLM): RES(%u) LOAD(%u) MTU(%u)",
2052                                 tvb_get_guint8(tvb, 0),
2053                                 tvb_get_guint8(tvb, 1),
2054                                 tvb_get_ntohl(tvb, 2));
2055             break;
2056
2057             /*
2058              * External information for given EIGRP VPNv4 route,
2059              * applies to only to external routes
2060              */
2061         case EIGRP_EXTCOMM_SAR:
2062             proto_tree_add_text(tree, tvb, offset, 8,
2063                                 "Type(EIGRP_EXTCOMM_SAR): xAS(%u) xRID(%u)",
2064                                 tvb_get_ntohs(tvb, 0),
2065                                 tvb_get_ntohl(tvb, 2));
2066             break;
2067         case EIGRP_EXTCOMM_RPM:
2068             proto_tree_add_text(tree, tvb, offset, 8,
2069                                 "Type(EIGRP_EXTCOMM_RPM): xProto(%u) xMETRIC(%u)",
2070                                 tvb_get_ntohs(tvb, 0),
2071                                 tvb_get_ntohl(tvb, 2));
2072             break;
2073
2074         case EIGRP_EXTCOMM_SOO_ASFMT:
2075         case EIGRP_EXTCOMM_SOO_ADRFMT:
2076             proto_tree_add_text(tree, tvb, offset, 8,
2077                                 "Type(EIGRP_EXTCOMM_SOO): AS(%u) TAG(%u)",
2078                                 tvb_get_ntohs(tvb, 0),
2079                                 tvb_get_ntohl(tvb, 2));
2080             break;
2081         }
2082
2083         /*on to the next */
2084         offset += 8;
2085         limit -= 8;
2086
2087         if (0 != limit%8) {
2088             break;
2089         }
2090
2091     }
2092
2093     return(offset);
2094 }
2095
2096 /**
2097  *@fn int dissect_eigrp_wide_metric_attr (proto_tree *tree, tvbuff_t *tvb,
2098  *                                        int offset, int limit)
2099  *
2100  * @param[in,out] tree  detail dissection result
2101  * @param[in] tvb       packet data
2102  * @param[in] offset    current byte offset in packet being processed
2103  * @param[in] limit     maximum number of words which should be process
2104  *
2105  * @return int          number of bytes process
2106  *
2107  * @par
2108  * Dissect the Metric Attributes which (optionally) are part of the wide-metric
2109  * route TLV.  Some of the attributes which effect the metric are controlled by
2110  * K6 which is now part of the Parameter TLV.  Also, eh extended community TLV is
2111  * no longer used, as it's now appended to the route
2112  */
2113 static int
2114 dissect_eigrp_wide_metric_attr (proto_tree *tree, tvbuff_t *tvb,
2115                                 int offset, int limit)
2116 {
2117     proto_item *sub_ti;
2118     proto_tree *sub_tree;
2119     tvbuff_t   *sub_tvb;
2120     int         sub_offset;
2121
2122     guint16 attr_offset = 0;
2123     guint8  attr_opcode = 0;
2124
2125     limit *= 2;   /* words to bytes */
2126
2127     sub_ti     = proto_tree_add_text(tree, tvb, offset, limit, "Attributes");
2128     sub_tree   = proto_item_add_subtree(sub_ti, ett_eigrp_tlv_attr);
2129     sub_tvb    = tvb_new_subset(tvb, offset, limit, -1);
2130     sub_offset = 0;
2131
2132     while (limit > 0) {
2133         attr_opcode = tvb_get_guint8(sub_tvb, sub_offset);
2134         proto_tree_add_item(sub_tree, hf_eigrp_attr_opcode, sub_tvb,
2135                             sub_offset, 1, ENC_BIG_ENDIAN);
2136         sub_offset += 1;
2137
2138         attr_offset = tvb_get_guint8(sub_tvb, sub_offset) * 2;
2139         proto_tree_add_item(sub_tree, hf_eigrp_attr_offset, sub_tvb,
2140                             sub_offset, 1, ENC_BIG_ENDIAN);
2141         sub_offset += 1;
2142
2143         switch (attr_opcode) {
2144         case EIGRP_ATTR_NOOP:
2145             break;
2146
2147         case EIGRP_ATTR_SCALED:
2148             proto_tree_add_item(sub_tree, hf_eigrp_attr_scaled, sub_tvb,
2149                                 sub_offset, 4, ENC_BIG_ENDIAN);
2150             break;
2151
2152         case EIGRP_ATTR_TAG:
2153             proto_tree_add_item(sub_tree, hf_eigrp_attr_tag, sub_tvb,
2154                                 sub_offset, 4, ENC_BIG_ENDIAN);
2155             break;
2156
2157         case EIGRP_ATTR_COMM:
2158             dissect_eigrp_metric_comm(sub_tree,
2159                                       tvb_new_subset(sub_tvb, sub_offset, 8, -1),
2160                                       sub_offset, limit);
2161             break;
2162
2163         case EIGRP_ATTR_JITTER:
2164             proto_tree_add_item(sub_tree, hf_eigrp_attr_jitter, sub_tvb,
2165                                 sub_offset, 4, ENC_BIG_ENDIAN);
2166             break;
2167
2168         case EIGRP_ATTR_QENERGY:
2169             proto_tree_add_item(sub_tree, hf_eigrp_attr_qenergy, sub_tvb,
2170                                 sub_offset, 4, ENC_BIG_ENDIAN);
2171             break;
2172
2173         case EIGRP_ATTR_ENERGY:
2174             proto_tree_add_item(sub_tree, hf_eigrp_attr_energy, sub_tvb,
2175                                 sub_offset, 4, ENC_BIG_ENDIAN);
2176             break;
2177
2178         default:
2179             break;
2180         }
2181         sub_offset += attr_offset;
2182         limit -= (EIGRP_ATTR_HDRLEN + attr_offset);
2183     }
2184
2185     offset += sub_offset;
2186     return(offset);
2187 }
2188
2189 /**
2190  *@fn int dissect_eigrp_wide_metric (proto_tree *tree, tvbuff_t *tvb, int offset)
2191  *
2192  * @param[in,out] tree  detail dissection result
2193  * @param[in] tvb       packet data
2194  * @param[in] offset    current byte offset in packet being processed
2195  *
2196  * @return int          number of bytes process
2197  *
2198  * @par
2199  * Dissect the latest-n-greatest "Wide"Metric" definition for EIGRP. This
2200  * definition was created to address the higher speed links and should handle
2201  * things until we break the speed of light *wink*
2202  *
2203  *    0                   1                   2                   3
2204  *    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
2205  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2206  *   |    Offset    |   Priority     |  Reliability  |     Load      |
2207  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2208  *   |         MTU                                    |   Hopcount   |
2209  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2210  *   |                            Delay                              |
2211  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2212  *   |         Delay                 |         Bandwidth             |
2213  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2214  *   |                        Bandwidth                              |
2215  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2216  *   |         Reserved              |           Flags               |
2217  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2218  *   |\/\/\/        Extended Metrics (Variable Length)         \/\/\/|
2219  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2220  *
2221  */
2222 static int
2223 dissect_eigrp_wide_metric (proto_tree *tree, tvbuff_t *tvb, int offset)
2224 {
2225     proto_item *sub_ti;
2226     proto_tree *sub_tree;
2227     tvbuff_t   *sub_tvb;
2228     gint8       attr_size = 0;
2229     guint64     big_num;
2230
2231     sub_ti = proto_tree_add_text(tree, tvb, offset, 24, "Wide Metric");
2232     sub_tree = proto_item_add_subtree(sub_ti, ett_eigrp_tlv_metric);
2233     sub_tvb = tvb_new_subset(tvb, offset, 24, -1);
2234
2235     attr_size = tvb_get_guint8(sub_tvb, 0);
2236
2237     proto_tree_add_item(sub_tree, hf_eigrp_metric_offset,
2238                         sub_tvb, 0,  1, ENC_BIG_ENDIAN);
2239     proto_tree_add_item(sub_tree, hf_eigrp_metric_priority,
2240                         sub_tvb, 1,  1, ENC_BIG_ENDIAN);
2241     proto_tree_add_item(sub_tree, hf_eigrp_metric_rel,
2242                         sub_tvb, 2,  1, ENC_BIG_ENDIAN);
2243     proto_tree_add_item(sub_tree, hf_eigrp_metric_load,
2244                         sub_tvb, 3,  1, ENC_BIG_ENDIAN);
2245     proto_tree_add_item(sub_tree, hf_eigrp_metric_mtu,
2246                         sub_tvb, 4,  3, ENC_BIG_ENDIAN);
2247     proto_tree_add_item(sub_tree, hf_eigrp_metric_hopcount,
2248                         sub_tvb, 7,  1, ENC_BIG_ENDIAN);
2249
2250     /* The one-way latency along an unloaded path to the destination
2251      * expressed in units of nanoseconds per kilobyte. This number is not
2252      * scaled, as is the case with scaled delay. A delay of 0xFFFFFFFFFFFF
2253      * indicates an unreachable route. */
2254     big_num = tvb_get_ntoh64(sub_tvb, 8);
2255     big_num >>= 16;
2256     if (big_num == G_GUINT64_CONSTANT(0x0000ffffffffffff)) {
2257         proto_tree_add_text(sub_tree, sub_tvb, 8, 6, "Delay: Infinity");
2258     } else {
2259         proto_tree_add_text(sub_tree, sub_tvb, 8, 6, "Delay: %" G_GINT64_MODIFIER "u", big_num);
2260     }
2261
2262     /* The path bandwidth measured in kilobyte per second as presented by
2263      * the interface.  This number is not scaled, as is the case with scaled
2264      * bandwidth. A bandwidth of 0xFFFFFFFFFFFF indicates an unreachable
2265      * route.
2266      */
2267     big_num = tvb_get_ntoh64(sub_tvb, 14);
2268     big_num >>= 16;
2269     if (big_num == G_GUINT64_CONSTANT(0x0000ffffffffffff)) {
2270         proto_tree_add_text(sub_tree, sub_tvb, 14, 6, "Bandwidth: Infinity");
2271     } else {
2272         proto_tree_add_text(sub_tree, sub_tvb, 14, 6, "Bandwidth: %" G_GINT64_MODIFIER "u", big_num);
2273     }
2274     proto_tree_add_item(sub_tree, hf_eigrp_metric_reserved, sub_tvb, 20, 2,
2275                         ENC_BIG_ENDIAN);
2276
2277     /* Decode the route flags field */
2278     dissect_eigrp_metric_flags(sub_tree, sub_tvb, 22, 2);
2279     offset += 24;
2280
2281     /* any extended metric attributes? */
2282     if (attr_size > 0) {
2283         offset = dissect_eigrp_wide_metric_attr(tree, tvb, offset, attr_size);
2284     }
2285
2286     return(offset);
2287 }
2288
2289 /**
2290  *@fn int dissect_eigrp_multi_protocol_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
2291  *                                           packet_info *pinfo, guint16 tlv)
2292
2293  *
2294  * @param[in,out] tree  detail dissection result
2295  * @param[in] tvb       packet data
2296  * @param[in] ti        protocol item
2297  * @param[in] pinfo     general data about the protocol
2298  *
2299  * @return int          number of bytes process
2300  *
2301  * @par
2302  * Dissect the Multi-Protocol (TLV Version 2.0) TLV format definition. The following
2303  * represents the format
2304  *
2305  *    0                   1                   2                   3
2306  *    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
2307  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2308  *   |   Topology Identifier         |         Family Identifier     |
2309  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2310  *   |                       Router ID                               |
2311  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2312  *   |                      Wide Metric                              |
2313  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2314  *   |\/\/\/        Extended Metrics (Variable Length)         \/\/\/|
2315  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2316  *   |\/\/\/         NextHop (Family Specific Length)          \/\/\/|
2317  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2318  *   |\/\/\/          External Route Data (Optional)           \/\/\/|
2319  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2320  *   |\/\/\/       Destination (Family Specific Length)        \/\/\/|
2321  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2322  */
2323 static int
2324 dissect_eigrp_multi_protocol_tlv (proto_item *ti, proto_tree *tree, tvbuff_t *tvb,
2325                                   packet_info *pinfo, guint16 tlv)
2326 {
2327     int         offset      = 0;
2328     guint16     afi;
2329     int         unreachable = FALSE;
2330
2331     /* tid for you */
2332     proto_tree_add_item(tree, hf_eigrp_tid, tvb, offset, 2, ENC_BIG_ENDIAN);
2333     offset += 2;
2334
2335     /* now it's all about the family */
2336     afi = tvb_get_ntohs(tvb, offset);
2337     proto_tree_add_item(tree, hf_eigrp_afi, tvb, offset, 2, ENC_BIG_ENDIAN);
2338     offset += 2;
2339
2340     /* gota have an id... */
2341     proto_tree_add_item(tree, hf_eigrp_routerid, tvb, offset, 4, ENC_BIG_ENDIAN);
2342     offset += 4;
2343
2344     /* decode the wide metric */
2345     offset = dissect_eigrp_wide_metric(tree, tvb, offset);
2346
2347     /* dissect nexthop */
2348     offset = dissect_eigrp_nexthop(tree, tvb, afi, offset);
2349
2350     /* dissect external data if needed */
2351     if ((tlv & EIGRP_TLV_TYPEMASK) == EIGRP_TLV_EXTERNAL) {
2352         if (afi == EIGRP_AF_IPX) {
2353             offset = dissect_eigrp_ipx_extdata(tree, tvb, offset);
2354         } else {
2355             offset = dissect_eigrp_extdata(tree, tvb, offset);
2356         }
2357     }
2358
2359     /* dissect dest information */
2360     switch (afi) {
2361     case EIGRP_AF_IPv4:
2362         offset = dissect_eigrp_ipv4_addr(ti, tree, tvb, pinfo, offset, unreachable);
2363         break;
2364
2365     case EIGRP_AF_IPv6:
2366         offset = dissect_eigrp_ipv6_addr(ti, tree, tvb, pinfo, offset, unreachable);
2367         break;
2368
2369     case EIGRP_AF_IPX:
2370         offset = dissect_eigrp_ipx_addr(ti, tree, tvb, pinfo, offset, unreachable);
2371         break;
2372
2373     case EIGRP_SF_COMMON:
2374     case EIGRP_SF_IPv4:
2375     case EIGRP_SF_IPv6:
2376         offset = dissect_eigrp_service(ti, tree, tvb, pinfo, offset);
2377         break;
2378
2379     default:
2380         proto_tree_add_expert(tree, pinfo, &ei_eigrp_afi, tvb, offset, -1);
2381     }
2382
2383     return offset;
2384 }
2385
2386 /**
2387  *@fn int dissect_eigrp (proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, void *data)
2388  *
2389  * @param[in] tvb       packet data
2390  * @param[in] pinfo     general data about the protocol
2391  * @param[in,out] tree  detail dissection result
2392  *
2393  * @return int          0 if packet is not for this decoder
2394  *
2395  * @par
2396  * This function is called to dissect the packets presented to it. The packet
2397  * data is held in a special buffer referenced here as tvb. The packet info
2398  * structure contains general data about the protocol, and can update
2399  * information here. The tree parameter is where the detail dissection takes
2400  * place.
2401  */
2402 #include <epan/in_cksum.h>
2403
2404 static guint16 ip_checksum(const guint8 *ptr, int len)
2405 {
2406     vec_t cksum_vec[1];
2407
2408     cksum_vec[0].ptr = ptr;
2409     cksum_vec[0].len = len;
2410     return in_cksum(&cksum_vec[0], 1);
2411 }
2412 static int
2413 dissect_eigrp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
2414 {
2415     proto_item *ti;
2416     proto_tree *eigrp_tree        = NULL, *tlv_tree;
2417     guint       opcode, vrid;
2418     guint16     tlv, checksum, cacl_checksum;
2419     guint32     ack, size, offset = EIGRP_HEADER_LENGTH;
2420
2421     /* Make entries in Protocol column and Info column on summary display */
2422     col_set_str(pinfo->cinfo, COL_PROTOCOL, "EIGRP");
2423
2424     /* This field shows up as the "Info" column in the display; you should use
2425      * it, if possible, to summarize what's in the packet, so that a user
2426      * looking at the list of packets can tell what type of packet it is. See
2427      * section 1.5 for more information.
2428      */
2429     col_clear(pinfo->cinfo, COL_INFO);
2430
2431     opcode = tvb_get_guint8(tvb, 1);
2432     ack    = tvb_get_ntohl(tvb, 12);
2433     if ((opcode == EIGRP_OPC_HELLO) && (0 != ack)) {
2434         opcode = EIGRP_OPC_ACK;
2435     }
2436
2437     col_add_str(pinfo->cinfo, COL_INFO,
2438                 val_to_str(opcode, eigrp_opcode2string, "Unknown OpCode (0x%04x)"));
2439
2440     /* A protocol dissector may be called in 2 different ways - with, or
2441      * without a non-null "tree" argument.
2442      * Note also that there is no guarantee, the first time the dissector is
2443      * called, whether "tree" will be null or not; your dissector must work
2444      * correctly, building or updating whatever state information is necessary,
2445      * in either case.
2446      */
2447     /* NOTE: The offset and length values in the call to
2448      * "proto_tree_add_item()" define what data bytes to highlight in the
2449      * hex display window when the line in the protocol tree display
2450      * corresponding to that item is selected.
2451      */
2452
2453     /* create display subtree for the protocol */
2454     ti = proto_tree_add_protocol_format(tree, proto_eigrp, tvb, 0, -1,
2455                                         "Cisco EIGRP");
2456     eigrp_tree = proto_item_add_subtree(ti, ett_eigrp);
2457     proto_tree_add_item(eigrp_tree, hf_eigrp_version, tvb, 0, 1,
2458                         ENC_BIG_ENDIAN);
2459     proto_tree_add_item(eigrp_tree, hf_eigrp_opcode, tvb, 1, 1,
2460                         ENC_BIG_ENDIAN);
2461
2462     size          = tvb_length(tvb);
2463     checksum      = tvb_get_ntohs(tvb, 2);
2464     cacl_checksum = ip_checksum(tvb_get_ptr(tvb, 0, size), size);
2465
2466     if (cacl_checksum == checksum) {
2467         proto_tree_add_text(eigrp_tree, tvb, 2, 2,
2468                             "Checksum: 0x%02x [incorrect]",
2469                             checksum);
2470         expert_add_info(pinfo, ti, &ei_eigrp_checksum_bad);
2471     } else {
2472         proto_tree_add_text(eigrp_tree, tvb, 2, 2,
2473                             "Checksum: 0x%02x [correct]", checksum);
2474     }
2475
2476     /* Decode the EIGRP Flags Field */
2477     proto_tree_add_bitmask(eigrp_tree, tvb, 4, hf_eigrp_flags, ett_eigrp_flags,
2478                            eigrp_flag_fields, ENC_BIG_ENDIAN);
2479
2480     proto_tree_add_item(eigrp_tree, hf_eigrp_sequence, tvb, 8, 4,
2481                         ENC_BIG_ENDIAN);
2482     proto_tree_add_item(eigrp_tree, hf_eigrp_acknowledge, tvb, 12, 4,
2483                         ENC_BIG_ENDIAN);
2484
2485     /* print out what family we dealing with... */
2486     ti = proto_tree_add_item(eigrp_tree, hf_eigrp_vrid, tvb, 16, 2,
2487                              ENC_BIG_ENDIAN);
2488     vrid = (tvb_get_ntohs(tvb, 16) & EIGRP_VRID_MASK);
2489     proto_item_append_text(ti, " %s", val_to_str_const(vrid, eigrp_vrid2string, ""));
2490
2491     /* print autonomous-system */
2492     proto_tree_add_item(eigrp_tree, hf_eigrp_as, tvb, 18, 2,
2493                         ENC_BIG_ENDIAN);
2494
2495     switch (opcode) {
2496     case EIGRP_OPC_IPXSAP:
2497         call_dissector(ipxsap_handle,
2498                        tvb_new_subset_remaining(tvb, EIGRP_HEADER_LENGTH), pinfo,
2499                        eigrp_tree);
2500         break;
2501
2502     default:
2503         while (tvb_reported_length_remaining(tvb, offset) > 0) {
2504             tlv = tvb_get_ntohs(tvb, offset);
2505
2506             /* it's a rose by the wrong name... */
2507             if (tlv == EIGRP_TLV_MTR_TIDLIST) {
2508                 tlv = EIGRP_TLV_PEER_TIDLIST;
2509             }
2510
2511             size =  tvb_get_ntohs(tvb, offset + 2);
2512             if (size == 0) {
2513                 proto_tree_add_expert(eigrp_tree, pinfo, &ei_eigrp_tlv_len, tvb, offset, -1);
2514                 return(tvb_length(tvb));
2515             }
2516
2517             ti = proto_tree_add_text(eigrp_tree, tvb, offset, size, "%s",
2518                                      val_to_str(tlv, eigrp_tlv2string, "Unknown TLV (0x%04x)"));
2519
2520             tlv_tree = proto_item_add_subtree(ti, ett_eigrp_tlv);
2521             proto_tree_add_item(tlv_tree, hf_eigrp_tlv_type, tvb,
2522                                 offset, 2, ENC_BIG_ENDIAN);
2523             proto_tree_add_item(tlv_tree, hf_eigrp_tlv_len, tvb,
2524                                 (offset + 2), 2, ENC_BIG_ENDIAN);
2525
2526             switch (tlv & EIGRP_TLV_RANGEMASK) {
2527             case EIGRP_TLV_GENERAL:
2528                 dissect_eigrp_general_tlv(ti, tlv_tree, tvb_new_subset(tvb, (offset + 4), (size - 4), -1), pinfo, tlv);
2529                 break;
2530
2531             case EIGRP_TLV_IPv4:
2532                 dissect_eigrp_ipv4_tlv(ti, tlv_tree, tvb_new_subset(tvb, (offset + 4), (size - 4), -1), pinfo, tlv);
2533                 break;
2534
2535             case EIGRP_TLV_ATALK:
2536                 dissect_eigrp_atalk_tlv(ti, tlv_tree, tvb_new_subset(tvb, (offset + 4), (size - 4), -1), tlv);
2537                 break;
2538
2539             case EIGRP_TLV_IPX:
2540                 dissect_eigrp_ipx_tlv(ti, tlv_tree, tvb_new_subset(tvb, (offset + 4), (size - 4), -1), pinfo, tlv);
2541                 break;
2542
2543             case EIGRP_TLV_IPv6:
2544                 dissect_eigrp_ipv6_tlv(ti, tlv_tree, tvb_new_subset(tvb, (offset + 4), (size - 4), -1), pinfo, tlv);
2545                 break;
2546
2547             case EIGRP_TLV_MP:
2548                 dissect_eigrp_multi_protocol_tlv(ti, tlv_tree, tvb_new_subset(tvb, (offset + 4), (size - 4), -1),
2549                                                  pinfo, tlv);
2550                 break;
2551
2552             case EIGRP_TLV_MTR:
2553                 dissect_eigrp_multi_topology_tlv(ti, tlv_tree, tvb_new_subset(tvb, (offset + 4), (size - 4), -1),
2554                                                  pinfo, tlv);
2555                 break;
2556
2557             default:
2558                 expert_add_info_format(pinfo, ti, &ei_eigrp_tlv_type, "Unknown TLV Group (0x%04x)", tlv);
2559             }
2560
2561             offset += size;
2562         }
2563         break;
2564     }
2565
2566     /* Return the amount of data this dissector was able to dissect */
2567     return(tvb_length(tvb));
2568 }
2569
2570 /**
2571  *@fn void proto _ register _ eigrp (void)
2572  *
2573  * @usage
2574  *      you can not have the function name inside a comment or else Wireshark
2575  *      will fail with "duplicate protocol" error.  Dont you hate it when tools
2576  *      try to be to smart :(
2577  *
2578  * @par
2579  *      Register the protocol with Wireshark
2580  *      this format is require because a script is used to build the C function
2581  *      that calls all the protocol registration.
2582  */
2583 void
2584 proto_register_eigrp(void)
2585 {
2586     /* Setup list of header fields  See Section 1.6.1 for details
2587      */
2588     static hf_register_info hf[] = {
2589         /*
2590          *
2591          * EIGRP Packet Header definitions
2592          *
2593          *    0                   1                   2                   3
2594          *    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
2595          *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2596          *   |Ver              |  Opcode       |          Checksum           |
2597          *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2598          *   |                          Flags                                |
2599          *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2600          *   |                      Sequence number                          |
2601          *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2602          *   |                    Acknowledgement number                     |
2603          *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2604          *   |  Virtual Router ID              | Autonomous system number    |
2605          *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2606          */
2607         { &hf_eigrp_version,
2608           { "Version", "eigrp.version",
2609             FT_UINT8, BASE_DEC, NULL, 0x0,
2610             "Version - Version of EIGRP packet format", HFILL }
2611         },
2612         { &hf_eigrp_opcode,
2613           { "Opcode", "eigrp.opcode",
2614             FT_UINT8, BASE_DEC, VALS(eigrp_opcode2string), 0x0,
2615             "Opcode - Operation code indicating the message type", HFILL }
2616         },
2617         { &hf_eigrp_flags,
2618           { "Flags", "eigrp.flags",
2619             FT_UINT32, BASE_HEX, NULL, 0x0,
2620             "Flag - Initialization bit and is used in establishing "
2621             "a new neighbor relationship", HFILL }
2622         },
2623         { &hf_eigrp_sequence,
2624           { "Sequence", "eigrp.seq",
2625             FT_UINT32, BASE_DEC, NULL, 0x0,
2626             "Sequence number -- used to send messages reliably", HFILL }
2627         },
2628         { &hf_eigrp_acknowledge,
2629           { "Acknowledge", "eigrp.ack",
2630             FT_UINT32, BASE_DEC, NULL, 0x0,
2631             "Acknowledge number -- used to send messages reliably", HFILL }
2632         },
2633         { &hf_eigrp_vrid,
2634           { "Virtual Router ID", "eigrp.vrid",
2635             FT_UINT16, BASE_DEC, NULL, 0,
2636             "Virtual Router ID - For each Virtual Router, there is a separate topology "
2637             "table and routing/service table; even for matching AS. "
2638             "This field allows the gateway to select which set router to use.", HFILL }
2639         },
2640         { &hf_eigrp_as,
2641           { "Autonomous System", "eigrp.as",
2642             FT_UINT16, BASE_DEC, NULL, 0x0,
2643             "Autonomous system number - Each AS has a separate topology table "
2644             "which for a give routing/service table. A gateway can participate "
2645             "in more than one AS. This field allows the gateway to"
2646             "select which set of topology tables to use.", HFILL }
2647         },
2648
2649         /*
2650          * Define eigrp_flags bits here
2651          *
2652          * Init bit definition. First unicast transmitted Update has this
2653          * bit set in the flags field of the fixed header. It tells the neighbor
2654          * to send its full topology table.
2655          */
2656         { &hf_eigrp_flags_init,
2657           { "Init", "eigrp.flags.init",
2658             FT_BOOLEAN, 32, TFS(&tfs_set_notset), EIGRP_INIT_FLAG,
2659             "Init - tells the neighbor to send its full topology table", HFILL }
2660         },
2661
2662         /*
2663          * Conditionally Received - Any packet with the CR-bit set can
2664          * be accepted by an EIGRP speaker if and only if a previous Hello was
2665          * received with the SEQUENCE_TYPE TLV present.
2666          * This allows multicasts to be transmitted in order and reliably at the
2667          * same time as unicasts are transmitted.
2668          */
2669         { &hf_eigrp_flags_condrecv,
2670           { "Conditional Receive", "eigrp.flags.condrecv",
2671             FT_BOOLEAN, 32, TFS(&tfs_set_notset), EIGRP_CR_FLAG,
2672             "Conditionally Received the next packet if address was in listed "
2673             "in the previous HELLO", HFILL }
2674         },
2675
2676         /*
2677          * Restart flag is set in the hello and the init update
2678          * packets during the nsf signaling period.  A nsf-aware
2679          * router looks at the RS flag to detect if a peer is restarting
2680          * and maintain the adjacency. A restarting router looks at
2681          * this flag to determine if the peer is helping out with the restart.
2682          */
2683         { &hf_eigrp_flags_restart,
2684           { "Restart", "eigrp.flags.restart",
2685             FT_BOOLEAN, 32, TFS(&tfs_set_notset), EIGRP_RS_FLAG,
2686             "Restart flag - Set in the HELLO and the initial "
2687             "UPDATE packets during the nsf signaling period.", HFILL },
2688         },
2689
2690         /*
2691          * EOT bit.  The End-of-Table flag marks the end of the start-up updates
2692          * sent to a new peer.  A nsf restarting router looks at this flag to
2693          * determine if it has finished receiving the start-up updates from all
2694          * peers.  A nsf-aware router waits for this flag before cleaning up
2695          * the stale routes from the restarting peer.
2696          */
2697         { &hf_eigrp_flags_eot,
2698           { "End Of Table", "eigrp.flags.eot",
2699             FT_BOOLEAN, 32, TFS(&tfs_set_notset), EIGRP_EOT_FLAG,
2700             "End-of-Table - Marks the end of the start-up UPDATES indicating the "
2701             "complete topology database has been sent to a new peer", HFILL }
2702         },
2703
2704         /**
2705          * TLV type definitions.  Generic (protocol-independent) TLV types are
2706          * defined here.  Protocol-specific ones are defined later
2707          *
2708          *     +-----+------------------+
2709          *     |     |     |            |
2710          *     | Type| Len |    Vector  |
2711          *     |     |     |            |
2712          *     +-----+------------------+
2713          *
2714          * TLV type definitions.  Generic (protocol-independent) TLV types are
2715          * defined here.  Protocol-specific ones are defined elsewhere.
2716          *
2717          * EIGRP_PARAMETER              0x0001          parameter
2718          * EIGRP_AUTH                   0x0002          authentication
2719          * EIGRP_SEQUENCE               0x0003          sequenced packet
2720          * EIGRP_SW_VERSION             0x0004          software version
2721          * EIGRP_NEXT_MCAST_SEQ         0x0005          multicast sequence
2722          * EIGRP_PEER_STUBINFO          0x0006          stub information
2723          * EIGRP_PEER_TERMINATION       0x0007          peer termination
2724          */
2725         { &hf_eigrp_tlv_type,
2726           { "Type", "eigrp.tlv_type",
2727             FT_UINT16, BASE_HEX, VALS(eigrp_tlv2string), 0x0,
2728             "TLV Type", HFILL }
2729         },
2730         { &hf_eigrp_tlv_len,
2731           { "Length", "eigrp.tlv.len",
2732             FT_UINT16, BASE_DEC, NULL, 0x0,
2733             "TLV Length", HFILL }
2734         },
2735
2736 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2737  * Parameters TLV
2738  */
2739         { &hf_eigrp_par_k1, { "K1", "eigrp.par.k1", FT_UINT8, BASE_DEC, NULL, 0x0,
2740                               "Bandwidth/Throughput Coefficient", HFILL }},
2741         { &hf_eigrp_par_k2, { "K2", "eigrp.par.k2", FT_UINT8, BASE_DEC, NULL, 0x0,
2742                               "Load Coefficient", HFILL }},
2743         { &hf_eigrp_par_k3, { "K3", "eigrp.par.k3", FT_UINT8, BASE_DEC, NULL, 0x0,
2744                               "Delay/Latency Coefficient", HFILL }},
2745         { &hf_eigrp_par_k4, { "K4", "eigrp.par.k4", FT_UINT8, BASE_DEC, NULL, 0x0,
2746                               "Reliability Coefficient", HFILL }},
2747         { &hf_eigrp_par_k5, { "K5", "eigrp.par.k5", FT_UINT8, BASE_DEC, NULL, 0x0,
2748                               "Reliability Coefficient", HFILL }},
2749         { &hf_eigrp_par_k6, { "K6", "eigrp.par.k6", FT_UINT8, BASE_DEC, NULL, 0x0,
2750                               "Extended Metric Coefficient", HFILL }},
2751         { &hf_eigrp_par_holdtime,
2752           { "Hold Time", "eigrp.par.holdtime", FT_UINT16, BASE_DEC, NULL, 0x0,
2753             "How long to ignore lost HELLO's", HFILL }
2754         },
2755
2756 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2757  * Authentication TLV
2758  */
2759         { &hf_eigrp_auth_type,
2760           { "Type", "eigrp.auth.type",
2761             FT_UINT16, BASE_DEC, VALS(eigrp_auth2string), 0x0,
2762             NULL, HFILL }
2763         },
2764         { &hf_eigrp_auth_len,
2765           { "Length", "eigrp.auth.length",
2766             FT_UINT16, BASE_DEC, NULL, 0x0,
2767             NULL, HFILL }
2768         },
2769         { &hf_eigrp_auth_keyid,
2770           { "Key ID", "eigrp.auth.keyid",
2771             FT_UINT32, BASE_DEC, NULL, 0x0,
2772             NULL, HFILL }
2773         },
2774         { &hf_eigrp_auth_keyseq,
2775           { "Key Sequence", "eigrp.auth.keyseq",
2776             FT_UINT32, BASE_DEC, NULL, 0x0,
2777             NULL, HFILL }
2778         },
2779         { &hf_eigrp_auth_digest,
2780           { "Digest", "eigrp.auth.digest",
2781             FT_BYTES, BASE_NONE, NULL, 0x0,
2782             NULL, HFILL }
2783         },
2784
2785 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2786  * Sequence TLV
2787  */
2788         { &hf_eigrp_seq_addrlen,
2789           { "Address length", "eigrp.seq.addrlen",
2790             FT_UINT8, BASE_DEC, NULL, 0x0,
2791             NULL, HFILL }
2792         },
2793         { &hf_eigrp_seq_ipv4addr,
2794           { "IP Address", "eigrp.seq.ipv4addr",
2795             FT_IPv4, BASE_NONE, NULL, 0x0,
2796             NULL, HFILL }
2797         },
2798         { &hf_eigrp_seq_ipv6addr,
2799           { "IPv6 Address", "eigrp.seq.ipv6addr",
2800             FT_IPv6, BASE_NONE, NULL, 0x0,
2801             NULL, HFILL }
2802         },
2803
2804 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2805  * Next Multicast Sequence
2806  */
2807         /*
2808          * This was added to the hello containing the sequence TLV so that the
2809          * hello packet could be more tightly bound to the multicast packet bearing
2810          * the CR bit that follows it.  The sequence number of the impending multicast
2811          * is carried herein.
2812          */
2813         { &hf_eigrp_next_mcast_seq,
2814           { "Multicast Sequence", "eigrp.next_mcast_seq",
2815             FT_UINT32, BASE_DEC, NULL, 0x0,
2816             NULL, HFILL }
2817         },
2818
2819 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2820  * Peer Stub Information TLV
2821  */
2822         { &hf_eigrp_stub_flags,
2823           { "Stub Options", "eigrp.stub_options",
2824             FT_UINT16, BASE_HEX, NULL, 0x0,
2825             NULL, HFILL }
2826         },
2827
2828         /*
2829          * Define eigrp_stub_flags bits here
2830          */
2831         { &hf_eigrp_stub_flags_connected,
2832           { "Connected", "eigrp.stub_options.connected",
2833             FT_BOOLEAN, 16, TFS(&tfs_set_notset), EIGRP_PEER_ALLOWS_CONNECTED,
2834             NULL, HFILL }
2835         },
2836         { &hf_eigrp_stub_flags_static,
2837           { "Static", "eigrp.stub_options.static",
2838             FT_BOOLEAN, 16, TFS(&tfs_set_notset), EIGRP_PEER_ALLOWS_STATIC,
2839             NULL, HFILL }
2840         },
2841         { &hf_eigrp_stub_flags_summary,
2842           { "Summary", "eigrp.stub_options.summary",
2843             FT_BOOLEAN, 16, TFS(&tfs_set_notset), EIGRP_PEER_ALLOWS_SUMMARY,
2844             NULL, HFILL }
2845         },
2846         { &hf_eigrp_stub_flags_redist,
2847           { "Redistributed", "eigrp.stub_options.redist",
2848             FT_BOOLEAN, 16, TFS(&tfs_set_notset), EIGRP_PEER_ALLOWS_REDIST,
2849             NULL, HFILL }
2850         },
2851         { &hf_eigrp_stub_flags_leakmap,
2852           { "Leak-Map", "eigrp.stub_options.leakmap",
2853             FT_BOOLEAN, 16, TFS(&tfs_set_notset), EIGRP_PEER_ALLOWS_LEAKING,
2854             NULL, HFILL }
2855         },
2856         { &hf_eigrp_stub_flags_recvonly,
2857           { "Receive-Only", "eigrp.stub_options.recvonly",
2858             FT_BOOLEAN, 16, TFS(&tfs_set_notset), EIGRP_PEER_ALLOWS_RCVONLY,
2859             NULL, HFILL }
2860         },
2861
2862 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2863  * Peer Termination TLV
2864  */
2865         /* Place holder - this TLV has no options */
2866
2867 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2868  * EIGRP 3.0 Vector Header  (deprecated)
2869  */
2870         /*
2871          * common header for all version 3 tlvs
2872          */
2873         { &hf_eigrp_tid,
2874           { "Topology", "eigrp.tid",
2875             FT_UINT16, BASE_DEC, NULL, 0x0,
2876             NULL, HFILL }
2877         },
2878         { &hf_eigrp_afi,
2879           { "AFI", "eigrp.afi",
2880             FT_UINT16, BASE_DEC, VALS(eigrp_afi2string), 0x0,
2881             NULL, HFILL }
2882         },
2883
2884 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2885  * EIGRP TLV 1.2 (legacy) and TLV 3.0 Metric (deprecated) definition
2886  */
2887         { &hf_eigrp_legacy_metric_delay,
2888           { "Scaled Delay", "eigrp.old_metric.delay",
2889             FT_UINT32, BASE_DEC, NULL, 0x0,
2890             "delay, in 39.1 nanosec interments", HFILL }
2891         },
2892         { &hf_eigrp_legacy_metric_bw,
2893           { "Scaled BW", "eigrp.old_metric.bw",
2894             FT_UINT32, BASE_DEC, NULL, 0x0,
2895             "bandwidth, in units of 1 Kbit/sec", HFILL }
2896         },
2897         { &hf_eigrp_legacy_metric_mtu,
2898           { "MTU", "eigrp.old_metric.mtu",
2899             FT_UINT24, BASE_DEC, NULL, 0x0,
2900             "MTU, in octets", HFILL }
2901         },
2902         { &hf_eigrp_legacy_metric_hopcount,
2903           { "Hop Count", "eigrp.old_metric.hopcount",
2904             FT_UINT8, BASE_DEC, NULL, 0x0,
2905             "Number of hops to destination", HFILL }
2906         },
2907         { &hf_eigrp_legacy_metric_rel,
2908           { "Reliability", "eigrp.old_metric.rel",
2909             FT_UINT8, BASE_DEC, NULL, 0x0,
2910             "percent packets successfully tx/rx", HFILL }
2911         },
2912         { &hf_eigrp_legacy_metric_load,
2913           { "Load", "eigrp.old_metric.load",
2914             FT_UINT8, BASE_DEC, NULL, 0x0,
2915             "percent of channel occupied", HFILL }
2916         },
2917         { &hf_eigrp_legacy_metric_intag,
2918           { "Route Tag", "eigrp.old_metric.intag",
2919             FT_UINT8, BASE_DEC, NULL, 0x0,
2920             "Internal Route Tag", HFILL }
2921         },
2922
2923 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2924  * EIGRP 3.0 TIDLIST TLV  (only survivor in MTR)
2925  */
2926         { &hf_eigrp_tidlist_tid,
2927           { "TID List", "eigrp.tidlist",
2928             FT_UINT16, BASE_DEC, NULL, 0x0,
2929             NULL, HFILL }
2930         },
2931         { &hf_eigrp_tidlist_flags,
2932           { "TID List Flags", "eigrp.tidlist.flags",
2933             FT_UINT16, BASE_HEX, NULL, 0x0,
2934             NULL, HFILL }
2935         },
2936         { &hf_eigrp_tidlist_len,
2937           { "TID List Size", "eigrp.tidlist.len",
2938             FT_UINT16, BASE_DEC, NULL, 0x0,
2939             NULL, HFILL }
2940         },
2941         { &hf_eigrp_routerid,
2942           { "RouterID", "eigrp.routerid",
2943             FT_IPv4, BASE_NONE, NULL, 0x0,
2944             "Router ID of injecting router", HFILL }
2945         },
2946         { &hf_eigrp_legacy_metric_tag,
2947           { "Tag", "eigrp.old_metric.tag",
2948             FT_UINT32, BASE_DEC, NULL, 0x0,
2949             "route tag", HFILL }
2950         },
2951
2952 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2953  *
2954  * PDM opaque flag field definitions
2955  */
2956         { &hf_eigrp_metric_flags_srcwd,
2957           { "Source Withdraw", "eigrp.metric.flags.srcwd",
2958             FT_BOOLEAN, 8, TFS(&tfs_true_false), EIGRP_OPAQUE_SRCWD,
2959             "Route Source Withdraw", HFILL }
2960         },
2961         { &hf_eigrp_metric_flags_active,
2962           { "Route is Active", "eigrp.metric.flags.active",
2963             FT_BOOLEAN, 8, TFS(&tfs_true_false), EIGRP_OPAQUE_ACTIVE,
2964             "Route is currently in active state", HFILL }
2965         },
2966         { &hf_eigrp_metric_flags_repl,
2967           { "Route is Replicated", "eigrp.metric.flags.repl",
2968             FT_BOOLEAN, 8, TFS(&tfs_true_false), EIGRP_OPAQUE_REPL,
2969             "Route is replicated from different tableid", HFILL }
2970         },
2971
2972 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2973  * EIGRP TLV 1.2/3.0 ExtData Definitions
2974  */
2975         { &hf_eigrp_extdata_origrid,
2976           { "Originating RouterID", "eigrp.extdata.origrid",
2977             FT_IPv4, BASE_NONE, NULL, 0x0,
2978             "Router ID of redistributing router", HFILL }
2979         },
2980
2981         { &hf_eigrp_extdata_as,
2982           { "Originating A.S.", "eigrp.extdata.as",
2983             FT_UINT32, BASE_DEC, NULL, 0x0,
2984             "Autonomous System of redistributing protocol", HFILL }
2985         },
2986
2987         { &hf_eigrp_extdata_tag,
2988           { "Administrative Tag", "eigrp.extdata.tag",
2989             FT_UINT32, BASE_DEC, NULL, 0x0,
2990             "Administrative Route Tag", HFILL }
2991         },
2992         { &hf_eigrp_extdata_metric,
2993           { "External Metric", "eigrp.extdata.metric",
2994             FT_UINT32, BASE_DEC, NULL, 0x0,
2995             "Metric reported by redistributing protocol", HFILL }
2996         },
2997         { &hf_eigrp_extdata_reserved,
2998           { "Reserved", "eigrp.extdata.reserved",
2999             FT_UINT16, BASE_DEC, NULL, 0x0,
3000             NULL, HFILL }
3001         },
3002
3003         /* IPX ExtData Definitions */
3004         { &hf_eigrp_ipx_extdata_delay,
3005           { "External Delay", "eigrp.extdata.ipx_delay",
3006             FT_UINT16, BASE_DEC, NULL, 0x0,
3007             "Delay reported by redistributing protocol", HFILL }
3008         },
3009         { &hf_eigrp_ipx_extdata_metric,
3010           { "External Metric", "eigrp.extdata.ipx_metric",
3011             FT_UINT16, BASE_DEC, NULL, 0x0,
3012             "Delay reported by redistributing protocol", HFILL }
3013         },
3014
3015         { &hf_eigrp_extdata_proto,
3016           { "External Protocol ID", "eigrp.extdata.proto",
3017             FT_UINT8, BASE_DEC, VALS(eigrp_proto2string), 0x0,
3018             NULL, HFILL }
3019         },
3020
3021         { &hf_eigrp_extdata_flag_ext,
3022           { "Route is External", "eigrp.opaque.flag.ext",
3023             FT_BOOLEAN, 8, TFS(&tfs_true_false), EIGRP_OPAQUE_EXT,
3024             "External route", HFILL }
3025         },
3026         { &hf_eigrp_extdata_flag_cd,
3027           { "Route is Candidate Default", "eigrp.opaque.flag.cd",
3028             FT_BOOLEAN, 8, TFS(&tfs_true_false), EIGRP_OPAQUE_CD,
3029             "Candidate-Default route", HFILL }
3030         },
3031
3032 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3033  * EIGRP TLV 2.0 "Wide" Metric format definition
3034  */
3035         /* Number of 16bit words in the metric section, used to determine the
3036          * start of the destination/attribute information.
3037          */
3038         { &hf_eigrp_metric_offset,
3039           { "Offset", "eigrp.metric.offset",
3040             FT_UINT8, BASE_DEC, NULL, 0x0,
3041             "Number of 16bit words to reach the start of the"
3042             "destination/attribute information", HFILL }
3043         },
3044
3045         /* Priority of the prefix when transmitting a group of destination
3046          * addresses to neighboring routers. A priority of zero indicates no
3047          * priority is set.
3048          */
3049         { &hf_eigrp_metric_priority,
3050           { "Priority", "eigrp.metric.priority",
3051             FT_UINT8, BASE_DEC, NULL, 0x0,
3052             "Priority of the prefix for ordering transmission", HFILL }
3053         },
3054
3055         /** The current error rate for the path. Measured as an error
3056          * percentage. A value of 255 indicates 100% reliability
3057          */
3058         { &hf_eigrp_metric_rel,
3059           { "Reliability", "eigrp.metric.reliability",
3060             FT_UINT8, BASE_DEC, NULL, 0x0,
3061             "percent packets successfully tx/rx", HFILL }
3062         },
3063
3064         /** The load utilization of the path to the destination. Measured as a
3065          * percentage of load. A value of 255 indicates 100% load.
3066          */
3067         { &hf_eigrp_metric_load,
3068           { "Load", "eigrp.metric.load",
3069             FT_UINT8, BASE_DEC, NULL, 0x0,
3070             "percent of channel occupied", HFILL }
3071         },
3072
3073         /** The minimum maximum transmission unit size for the path to the
3074          * destination. Not used in metric calculation, but available to
3075          * underlying protocols
3076          */
3077         { &hf_eigrp_metric_mtu,
3078           { "MTU", "eigrp.metric.mtu",
3079             FT_UINT24, BASE_DEC, NULL, 0x0,
3080             "MTU, in octets", HFILL }
3081         },
3082
3083         /** number of router traversals to the destination */
3084         { &hf_eigrp_metric_hopcount,
3085           { "Hop Count", "eigrp.metric.hopcount",
3086             FT_UINT8, BASE_DEC, NULL, 0x0,
3087             "Number of hops to destination", HFILL }
3088         },
3089
3090         /* Reserved - Transmitted as 0x0000 */
3091         { &hf_eigrp_metric_reserved,
3092           { "Reserved", "eigrp.metric.reserved",
3093             FT_UINT16, BASE_HEX, NULL, 0x0,
3094             NULL, HFILL }
3095         },
3096
3097 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3098  * EIGRP TLV 2.0 Extended Metric Attributes
3099  */
3100         { &hf_eigrp_attr_opcode,
3101           { "Opcode", "eigrp.attr.opcode",
3102             FT_UINT8, BASE_DEC, VALS(eigrp_attr_opcode2string), 0x0,
3103             "Opcode - Operation code indicating the attribute type", HFILL }
3104         },
3105         { &hf_eigrp_attr_offset,
3106           { "Offset", "eigrp.attr.offset",
3107             FT_UINT8, BASE_DEC, NULL, 0x0,
3108             "Number of 2 byte words of data", HFILL }
3109         },
3110         { &hf_eigrp_attr_scaled,
3111           { "Legacy Metric", "eigrp.attr.scaled",
3112             FT_UINT16, BASE_DEC, NULL, 0x0,
3113             "Metric calculated from legacy TLVs", HFILL }
3114         },
3115         { &hf_eigrp_attr_tag,
3116           { "Tag", "eigrp.attr.tag",
3117             FT_UINT16, BASE_DEC, NULL, 0x0,
3118             "Tag assigned by admin for dest", HFILL }
3119         },
3120         { &hf_eigrp_attr_jitter,
3121           { "Jitter", "eigrp.attr.jitter",
3122             FT_UINT16, BASE_DEC, NULL, 0x0,
3123             "Variation in path delay", HFILL }
3124         },
3125         { &hf_eigrp_attr_qenergy,
3126           { "Q-Energy", "eigrp.attr.qenergy",
3127             FT_UINT16, BASE_DEC, NULL, 0x0,
3128             "Non-Active energy usage along path", HFILL }
3129         },
3130         { &hf_eigrp_attr_energy,
3131           { "Energy", "eigrp.attr.energy",
3132             FT_UINT16, BASE_DEC, NULL, 0x0,
3133             "Active energy usage along path", HFILL }
3134         },
3135
3136 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3137  *
3138  * IPv4 specific address definitions
3139  */
3140         { &hf_eigrp_ipv4_nexthop,
3141           { "NextHop", "eigrp.ipv4.nexthop",
3142             FT_IPv4, BASE_NONE, NULL, 0x0,
3143             NULL, HFILL }
3144         },
3145         { &hf_eigrp_ipv4_prefixlen,
3146           { "Prefix Length", "eigrp.ipv4.prefixlen",
3147             FT_UINT8, BASE_DEC, NULL, 0x0,
3148             NULL, HFILL }
3149         },
3150
3151 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3152  *
3153  * IPv6 specific address definitions
3154  */
3155         { &hf_eigrp_ipv6_nexthop,
3156           { "NextHop", "eigrp.ipv6.nexthop",
3157             FT_IPv6, BASE_NONE, NULL, 0x0,
3158             NULL, HFILL }
3159         },
3160
3161         { &hf_eigrp_ipv6_prefixlen,
3162           { "Prefix Length", "eigrp.ipv6.prefixlen",
3163             FT_UINT8, BASE_DEC, NULL, 0x0,
3164             NULL, HFILL }
3165         },
3166
3167 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3168  *
3169  * IPX specific address definitions
3170  */
3171         { &hf_eigrp_ipx_nexthop_net,
3172           { "NextHop Net", "eigrp.ipx.nexthop_net",
3173             FT_IPXNET, BASE_NONE, NULL, 0x0,
3174             NULL, HFILL }
3175         },
3176         { &hf_eigrp_ipx_nexthop_host,
3177           { "NextHop Host", "eigrp.ipx.nexthop_host",
3178             FT_ETHER, BASE_NONE, NULL, 0x0,
3179             NULL, HFILL }
3180         },
3181         { &hf_eigrp_ipx_extdata_routerid,
3182           { "External RouterID", "eigrp.ipx.routerid",
3183             FT_ETHER, BASE_NONE, NULL, 0x0,
3184             "Router ID of redistributing router", HFILL }
3185         },
3186         { &hf_eigrp_ipx_dest,
3187           { "Destination", "eigrp.ipx.dest",
3188             FT_IPXNET, BASE_NONE, NULL, 0x0,
3189             NULL, HFILL }
3190         },
3191
3192 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3193  *
3194  * AppleTalk specific address definitions
3195  */
3196         { &hf_eigrp_atalk_routerid,
3197           { "AppleTalk Router ID", "eigrp.atalk.routerid",
3198             FT_UINT32, BASE_DEC, NULL, 0x0,
3199             NULL, HFILL }
3200         },
3201
3202 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3203  * Service Advertisement Framework definitions
3204  */
3205         { &hf_eigrp_saf_service,
3206           { "Service", "eigrp.saf.service",
3207             FT_UINT16, BASE_DEC, VALS(eigrp_saf_srv2string), 0x0,
3208             NULL, HFILL }
3209         },
3210         { &hf_eigrp_saf_subservice,
3211           { "Sub-Service", "eigrp.saf.subservice",
3212             FT_UINT16, BASE_DEC, NULL, 0x0,
3213             NULL, HFILL }
3214         },
3215         { &hf_eigrp_saf_guid,
3216           { "GUID", "eigrp.saf.guid",
3217             FT_GUID, BASE_NONE, NULL, 0x0,
3218             NULL, HFILL }
3219         },
3220         { &hf_eigrp_saf_data_type,
3221           { "Type", "eigrp.saf.data.type",
3222             FT_UINT16, BASE_HEX, VALS(eigrp_saf_type2string), 0x0,
3223             "SAF Message Data Type", HFILL }
3224         },
3225         { &hf_eigrp_saf_data_length,
3226           { "Length", "eigrp.saf.data.length",
3227             FT_UINT16, BASE_DEC, NULL, 0x0,
3228             NULL, HFILL }
3229         },
3230         { &hf_eigrp_saf_data_sequence,
3231           { "Sequence", "eigrp.saf.data.sequence",
3232             FT_UINT32, BASE_DEC, NULL, 0x0,
3233             NULL, HFILL }
3234         },
3235         { &hf_eigrp_saf_reachability_afi,
3236           { "AFI", "eigrp.saf.data.reachability.afi",
3237             FT_UINT16, BASE_DEC, VALS(eigrp_afi2string), 0x0,
3238             NULL, HFILL }
3239         },
3240         { &hf_eigrp_saf_reachability_port,
3241           { "Port", "eigrp.saf.data.reachability.port",
3242             FT_UINT16, BASE_DEC, NULL, 0x0,
3243             NULL, HFILL }
3244         },
3245         { &hf_eigrp_saf_reachability_protocol,
3246           { "Protocol", "eigrp.saf.data.reachability.protocol",
3247             FT_UINT16, BASE_DEC, NULL, 0x0,
3248             NULL, HFILL }
3249         },
3250         { &hf_eigrp_saf_reachability_addr_ipv4,
3251           { "IPv4 Addr", "eigrp.saf.data.reachability.addr_ipv4",
3252             FT_IPv4, BASE_NONE, NULL, 0x0,
3253             NULL, HFILL }
3254         },
3255         { &hf_eigrp_saf_reachability_addr_ipv6,
3256           { "IPv6 Addr", "eigrp.saf.data.reachability.addr_ipv6",
3257             FT_IPv6, BASE_NONE, NULL, 0x0,
3258             NULL, HFILL }
3259         },
3260         { &hf_eigrp_saf_reachability_addr_hex,
3261           { "Addr", "eigrp.saf.data.reachability.addr_hex",
3262             FT_BYTES, BASE_NONE, NULL, 0x0,
3263             NULL, HFILL }
3264         },
3265
3266         /* misc field used in a couple places */
3267         { &hf_eigrp_nullpad,
3268           { "Nullpad", "eigrp.nullpad",
3269             FT_BYTES, BASE_NONE, NULL, 0x0,
3270             NULL, HFILL }
3271         },
3272     };
3273
3274     /* Setup protocol subtree array */
3275     static gint *ett[] = {
3276         /* header flag */
3277         &ett_eigrp,
3278         &ett_eigrp_flags,
3279
3280         /* tlv specific */
3281         &ett_eigrp_tlv,
3282         &ett_eigrp_tlv_metric,
3283         &ett_eigrp_tlv_attr,
3284         &ett_eigrp_tlv_extdata,
3285
3286         &ett_eigrp_tidlist,
3287         &ett_eigrp_stub_flags,
3288         &ett_eigrp_saf_reachability,
3289
3290         /* metric tlv specific */
3291         &ett_eigrp_metric_flags,
3292         &ett_eigrp_extdata_flags,
3293     };
3294
3295     static ei_register_info ei[] = {
3296         { &ei_eigrp_peer_termination, { "eigrp.peer_termination", PI_RESPONSE_CODE, PI_NOTE, "Peer Termination", EXPFILL }},
3297         { &ei_eigrp_auth_len, { "eigrp.auth.length.invalid", PI_MALFORMED, PI_WARN, "Invalid auth len", EXPFILL }},
3298         { &ei_eigrp_auth_type, { "eigrp.auth.type.invalid", PI_PROTOCOL, PI_WARN, "Invalid auth type", EXPFILL }},
3299         { &ei_eigrp_seq_addrlen, { "eigrp.seq.addrlen.invalid", PI_MALFORMED, PI_ERROR, "Invalid address length", EXPFILL }},
3300         { &ei_eigrp_peer_termination_graceful, { "eigrp.peer_termination_graceful", PI_RESPONSE_CODE, PI_NOTE, "Peer Termination (Graceful Shutdown)", EXPFILL }},
3301         { &ei_eigrp_prefixlen, { "eigrp.prefixlen.invalid", PI_MALFORMED, PI_WARN, "Invalid prefix length", EXPFILL }},
3302         { &ei_eigrp_unreachable, { "eigrp.unreachable", PI_RESPONSE_CODE, PI_NOTE, "Unreachable", EXPFILL }},
3303         { &ei_eigrp_tlv_type, { "eigrp.tlv_type.unknown", PI_PROTOCOL, PI_WARN, "Unknown TLV", EXPFILL }},
3304         { &ei_eigrp_afi, { "eigrp.afi.unknown", PI_PROTOCOL, PI_WARN, "Unknown AFI", EXPFILL }},
3305         { &ei_eigrp_checksum_bad, { "eigrp.checksum.bad", PI_CHECKSUM, PI_WARN, "Bad Checksum", EXPFILL }},
3306         { &ei_eigrp_tlv_len, { "eigrp.tlv.len.invalid", PI_MALFORMED, PI_ERROR, "Corrupt TLV (Zero Size)", EXPFILL }},
3307     };
3308
3309     expert_module_t* expert_eigrp;
3310
3311     /* Register the protocol name and description */
3312     proto_eigrp = proto_register_protocol(
3313         "Enhanced Interior Gateway Routing Protocol",   /* name         */
3314         "EIGRP",                                        /* short name   */
3315         "eigrp"                                         /* abbrev       */
3316         );
3317
3318     /* Required function calls to register the header fields and subtrees used */
3319     proto_register_field_array(proto_eigrp, hf, array_length(hf));
3320     proto_register_subtree_array(ett, array_length(ett));
3321     expert_eigrp = expert_register_protocol(proto_eigrp);
3322     expert_register_field_array(expert_eigrp, ei, array_length(ei));
3323 }
3324
3325 /**
3326  *@fn void proto_reg_handoff_eigrp(void)
3327  *
3328  * @usage
3329  * This exact format is required because a script is used to find these
3330  * routines and create the code that calls these routines.
3331  *
3332  * @par
3333  * If this dissector uses sub-dissector registration add a registration routine.
3334  *
3335  * This form of the reg_handoff function is used if if you perform registration
3336  * functions which are dependent upon prefs.  If this function is registered as
3337  * a prefs callback (see prefs_register_protocol above) this function is also
3338  * called by preferences whenever "Apply" is pressed;
3339  *
3340  * In that case, it should accommodate being called more than once.
3341  */
3342 void
3343 proto_reg_handoff_eigrp(void)
3344 {
3345     dissector_handle_t eigrp_handle;
3346
3347     ipxsap_handle = find_dissector("ipxsap");
3348     media_type_table = find_dissector_table("media_type");
3349
3350     eigrp_handle = new_create_dissector_handle(dissect_eigrp, proto_eigrp);
3351
3352     dissector_add_uint("ip.proto", IP_PROTO_EIGRP, eigrp_handle);
3353     dissector_add_uint("ddp.type", DDP_EIGRP, eigrp_handle);
3354     dissector_add_uint("ipx.socket", IPX_SOCKET_EIGRP, eigrp_handle);
3355 }