Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2  * Copyright (c) 1998-2004  Hannes Gredler <hannes (at) gredler.at>
      3  *      The TCPDUMP project
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that: (1) source code
      7  * distributions retain the above copyright notice and this paragraph
      8  * in its entirety, and (2) distributions including binary code include
      9  * the above copyright notice and this paragraph in its entirety in
     10  * the documentation or other materials provided with the distribution.
     11  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
     12  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
     13  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     14  * FOR A PARTICULAR PURPOSE.
     15  */
     16 
     17 #include <sys/cdefs.h>
     18 #ifndef lint
     19 __RCSID("$NetBSD: print-eigrp.c,v 1.12 2024/09/02 16:15:31 christos Exp $");
     20 #endif
     21 
     22 /* \summary: Enhanced Interior Gateway Routing Protocol (EIGRP) printer */
     23 
     24 /*
     25  * specification:
     26  *
     27  * https://web.archive.org/web/20190722221712/https://www.rhyshaden.com/eigrp.htm
     28  * RFC 7868
     29  */
     30 
     31 #include <config.h>
     32 
     33 #include "netdissect-stdinc.h"
     34 
     35 #include <string.h>
     36 
     37 #include "netdissect.h"
     38 #include "extract.h"
     39 #include "addrtoname.h"
     40 
     41 
     42 struct eigrp_common_header {
     43     nd_uint8_t  version;
     44     nd_uint8_t  opcode;
     45     nd_uint16_t checksum;
     46     nd_uint32_t flags;
     47     nd_uint32_t seq;
     48     nd_uint32_t ack;
     49     nd_uint16_t vrid;
     50     nd_uint16_t asn;
     51 };
     52 
     53 #define	EIGRP_VERSION                        2
     54 
     55 #define	EIGRP_OPCODE_UPDATE                  1
     56 #define	EIGRP_OPCODE_QUERY                   3
     57 #define	EIGRP_OPCODE_REPLY                   4
     58 #define	EIGRP_OPCODE_HELLO                   5
     59 #define	EIGRP_OPCODE_IPXSAP                  6
     60 #define	EIGRP_OPCODE_PROBE                   7
     61 
     62 static const struct tok eigrp_opcode_values[] = {
     63     { EIGRP_OPCODE_UPDATE, "Update" },
     64     { EIGRP_OPCODE_QUERY, "Query" },
     65     { EIGRP_OPCODE_REPLY, "Reply" },
     66     { EIGRP_OPCODE_HELLO, "Hello" },
     67     { EIGRP_OPCODE_IPXSAP, "IPX SAP" },
     68     { EIGRP_OPCODE_PROBE, "Probe" },
     69     { 0, NULL}
     70 };
     71 
     72 static const struct tok eigrp_common_header_flag_values[] = {
     73     { 0x01, "Init" },
     74     { 0x02, "Conditionally Received" },
     75     { 0x04, "Restart" },
     76     { 0x08, "End-of-Table" },
     77     { 0, NULL}
     78 };
     79 
     80 struct eigrp_tlv_header {
     81     nd_uint16_t type;
     82     nd_uint16_t length;
     83 };
     84 
     85 #define EIGRP_TLV_GENERAL_PARM   0x0001
     86 #define EIGRP_TLV_AUTH           0x0002
     87 #define EIGRP_TLV_SEQ            0x0003
     88 #define EIGRP_TLV_SW_VERSION     0x0004
     89 #define EIGRP_TLV_MCAST_SEQ      0x0005
     90 #define EIGRP_TLV_IP_INT         0x0102
     91 #define EIGRP_TLV_IP_EXT         0x0103
     92 #define EIGRP_TLV_AT_INT         0x0202
     93 #define EIGRP_TLV_AT_EXT         0x0203
     94 #define EIGRP_TLV_AT_CABLE_SETUP 0x0204
     95 #define EIGRP_TLV_IPX_INT        0x0302
     96 #define EIGRP_TLV_IPX_EXT        0x0303
     97 
     98 static const struct tok eigrp_tlv_values[] = {
     99     { EIGRP_TLV_GENERAL_PARM, "General Parameters"},
    100     { EIGRP_TLV_AUTH, "Authentication"},
    101     { EIGRP_TLV_SEQ, "Sequence"},
    102     { EIGRP_TLV_SW_VERSION, "Software Version"},
    103     { EIGRP_TLV_MCAST_SEQ, "Next Multicast Sequence"},
    104     { EIGRP_TLV_IP_INT, "IP Internal routes"},
    105     { EIGRP_TLV_IP_EXT, "IP External routes"},
    106     { EIGRP_TLV_AT_INT, "AppleTalk Internal routes"},
    107     { EIGRP_TLV_AT_EXT, "AppleTalk External routes"},
    108     { EIGRP_TLV_AT_CABLE_SETUP, "AppleTalk Cable setup"},
    109     { EIGRP_TLV_IPX_INT, "IPX Internal routes"},
    110     { EIGRP_TLV_IPX_EXT, "IPX External routes"},
    111     { 0, NULL}
    112 };
    113 
    114 struct eigrp_tlv_general_parm_t {
    115     nd_uint8_t  k1;
    116     nd_uint8_t  k2;
    117     nd_uint8_t  k3;
    118     nd_uint8_t  k4;
    119     nd_uint8_t  k5;
    120     nd_uint8_t  res;
    121     nd_uint16_t holdtime;
    122 };
    123 
    124 struct eigrp_tlv_sw_version_t {
    125     nd_uint8_t ios_major;
    126     nd_uint8_t ios_minor;
    127     nd_uint8_t eigrp_major;
    128     nd_uint8_t eigrp_minor;
    129 };
    130 
    131 struct eigrp_tlv_ip_int_t {
    132     nd_ipv4     nexthop;
    133     nd_uint32_t delay;
    134     nd_uint32_t bandwidth;
    135     nd_uint24_t mtu;
    136     nd_uint8_t  hopcount;
    137     nd_uint8_t  reliability;
    138     nd_uint8_t  load;
    139     nd_byte     reserved[2];
    140     nd_uint8_t  plen;
    141     nd_uint8_t  destination; /* variable length [1-4] bytes encoding */
    142 };
    143 
    144 struct eigrp_tlv_ip_ext_t {
    145     nd_ipv4     nexthop;
    146     nd_ipv4     origin_router;
    147     nd_uint32_t origin_as;
    148     nd_uint32_t tag;
    149     nd_uint32_t metric;
    150     nd_byte     reserved[2];
    151     nd_uint8_t  proto_id;
    152     nd_uint8_t  flags;
    153     nd_uint32_t delay;
    154     nd_uint32_t bandwidth;
    155     nd_uint24_t mtu;
    156     nd_uint8_t  hopcount;
    157     nd_uint8_t  reliability;
    158     nd_uint8_t  load;
    159     nd_byte     reserved2[2];
    160     nd_uint8_t  plen;
    161     nd_uint8_t  destination; /* variable length [1-4] bytes encoding */
    162 };
    163 
    164 struct eigrp_tlv_at_cable_setup_t {
    165     nd_uint16_t cable_start;
    166     nd_uint16_t cable_end;
    167     nd_uint32_t router_id;
    168 };
    169 
    170 struct eigrp_tlv_at_int_t {
    171     nd_byte     nexthop[4];
    172     nd_uint32_t delay;
    173     nd_uint32_t bandwidth;
    174     nd_uint24_t mtu;
    175     nd_uint8_t  hopcount;
    176     nd_uint8_t  reliability;
    177     nd_uint8_t  load;
    178     nd_byte     reserved[2];
    179     nd_uint16_t cable_start;
    180     nd_uint16_t cable_end;
    181 };
    182 
    183 struct eigrp_tlv_at_ext_t {
    184     nd_byte     nexthop[4];
    185     nd_uint32_t origin_router;
    186     nd_uint32_t origin_as;
    187     nd_uint32_t tag;
    188     nd_uint8_t  proto_id;
    189     nd_uint8_t  flags;
    190     nd_uint16_t metric;
    191     nd_uint32_t delay;
    192     nd_uint32_t bandwidth;
    193     nd_uint24_t mtu;
    194     nd_uint8_t  hopcount;
    195     nd_uint8_t  reliability;
    196     nd_uint8_t  load;
    197     nd_byte     reserved2[2];
    198     nd_uint16_t cable_start;
    199     nd_uint16_t cable_end;
    200 };
    201 
    202 static const struct tok eigrp_ext_proto_id_values[] = {
    203     { 0x01, "IGRP" },
    204     { 0x02, "EIGRP" },
    205     { 0x03, "Static" },
    206     { 0x04, "RIP" },
    207     { 0x05, "Hello" },
    208     { 0x06, "OSPF" },
    209     { 0x07, "IS-IS" },
    210     { 0x08, "EGP" },
    211     { 0x09, "BGP" },
    212     { 0x0a, "IDRP" },
    213     { 0x0b, "Connected" },
    214     { 0, NULL}
    215 };
    216 
    217 void
    218 eigrp_print(netdissect_options *ndo, const u_char *pptr, u_int len)
    219 {
    220     const struct eigrp_common_header *eigrp_com_header;
    221     const struct eigrp_tlv_header *eigrp_tlv_header;
    222     const u_char *tptr,*tlv_tptr;
    223     u_int tlen,eigrp_tlv_len,eigrp_tlv_type,tlv_tlen, byte_length, bit_length;
    224     uint8_t prefix[4];
    225 
    226     union {
    227         const struct eigrp_tlv_general_parm_t *eigrp_tlv_general_parm;
    228         const struct eigrp_tlv_sw_version_t *eigrp_tlv_sw_version;
    229         const struct eigrp_tlv_ip_int_t *eigrp_tlv_ip_int;
    230         const struct eigrp_tlv_ip_ext_t *eigrp_tlv_ip_ext;
    231         const struct eigrp_tlv_at_cable_setup_t *eigrp_tlv_at_cable_setup;
    232         const struct eigrp_tlv_at_int_t *eigrp_tlv_at_int;
    233         const struct eigrp_tlv_at_ext_t *eigrp_tlv_at_ext;
    234     } tlv_ptr;
    235 
    236     ndo->ndo_protocol = "eigrp";
    237     tptr=pptr;
    238     eigrp_com_header = (const struct eigrp_common_header *)pptr;
    239     ND_TCHECK_SIZE(eigrp_com_header);
    240 
    241     /*
    242      * Sanity checking of the header.
    243      */
    244     if (GET_U_1(eigrp_com_header->version) != EIGRP_VERSION) {
    245         ND_PRINT("EIGRP version %u packet not supported",
    246                  GET_U_1(eigrp_com_header->version));
    247         return;
    248     }
    249 
    250     /* in non-verbose mode just lets print the basic Message Type*/
    251     if (ndo->ndo_vflag < 1) {
    252         ND_PRINT("EIGRP %s, length: %u",
    253                tok2str(eigrp_opcode_values, "unknown (%u)",GET_U_1(eigrp_com_header->opcode)),
    254                len);
    255         return;
    256     }
    257 
    258     /* ok they seem to want to know everything - lets fully decode it */
    259 
    260     if (len < sizeof(struct eigrp_common_header)) {
    261         ND_PRINT("EIGRP %s, length: %u (too short, < %zu)",
    262                tok2str(eigrp_opcode_values, "unknown (%u)",GET_U_1(eigrp_com_header->opcode)),
    263                len, sizeof(struct eigrp_common_header));
    264         return;
    265     }
    266     tlen=len-sizeof(struct eigrp_common_header);
    267 
    268     ND_PRINT("\n\tEIGRP v%u, opcode: %s (%u), chksum: 0x%04x, Flags: [%s]"
    269              "\n\tseq: 0x%08x, ack: 0x%08x, VRID: %u, AS: %u, length: %u",
    270            GET_U_1(eigrp_com_header->version),
    271            tok2str(eigrp_opcode_values, "unknown, type: %u",GET_U_1(eigrp_com_header->opcode)),
    272            GET_U_1(eigrp_com_header->opcode),
    273            GET_BE_U_2(eigrp_com_header->checksum),
    274            bittok2str(eigrp_common_header_flag_values,
    275                    "none",
    276                    GET_BE_U_4(eigrp_com_header->flags)),
    277            GET_BE_U_4(eigrp_com_header->seq),
    278            GET_BE_U_4(eigrp_com_header->ack),
    279            GET_BE_U_2(eigrp_com_header->vrid),
    280            GET_BE_U_2(eigrp_com_header->asn),
    281            tlen);
    282 
    283     tptr+=sizeof(struct eigrp_common_header);
    284 
    285     while(tlen>0) {
    286         /* did we capture enough for fully decoding the object header ? */
    287         ND_TCHECK_LEN(tptr, sizeof(struct eigrp_tlv_header));
    288 
    289         eigrp_tlv_header = (const struct eigrp_tlv_header *)tptr;
    290         eigrp_tlv_len=GET_BE_U_2(eigrp_tlv_header->length);
    291         eigrp_tlv_type=GET_BE_U_2(eigrp_tlv_header->type);
    292 
    293 
    294         if (eigrp_tlv_len < sizeof(struct eigrp_tlv_header) ||
    295             eigrp_tlv_len > tlen) {
    296             print_unknown_data(ndo,tptr+sizeof(struct eigrp_tlv_header),"\n\t    ",tlen);
    297             return;
    298         }
    299 
    300         ND_PRINT("\n\t  %s TLV (0x%04x), length: %u",
    301                tok2str(eigrp_tlv_values,
    302                        "Unknown",
    303                        eigrp_tlv_type),
    304                eigrp_tlv_type,
    305                eigrp_tlv_len);
    306 
    307         if (eigrp_tlv_len < sizeof(struct eigrp_tlv_header)) {
    308                 ND_PRINT(" (too short, < %zu)",
    309                          sizeof(struct eigrp_tlv_header));
    310                 break;
    311         }
    312         tlv_tptr=tptr+sizeof(struct eigrp_tlv_header);
    313         tlv_tlen=eigrp_tlv_len-sizeof(struct eigrp_tlv_header);
    314 
    315         /* did we capture enough for fully decoding the object ? */
    316         ND_TCHECK_LEN(tptr, eigrp_tlv_len);
    317 
    318         switch(eigrp_tlv_type) {
    319 
    320         case EIGRP_TLV_GENERAL_PARM:
    321             tlv_ptr.eigrp_tlv_general_parm = (const struct eigrp_tlv_general_parm_t *)tlv_tptr;
    322             if (tlv_tlen < sizeof(*tlv_ptr.eigrp_tlv_general_parm)) {
    323                 ND_PRINT(" (too short, < %zu)",
    324 			 sizeof(struct eigrp_tlv_header) + sizeof(*tlv_ptr.eigrp_tlv_general_parm));
    325                 break;
    326             }
    327 
    328             ND_PRINT("\n\t    holdtime: %us, k1 %u, k2 %u, k3 %u, k4 %u, k5 %u",
    329                    GET_BE_U_2(tlv_ptr.eigrp_tlv_general_parm->holdtime),
    330                    GET_U_1(tlv_ptr.eigrp_tlv_general_parm->k1),
    331                    GET_U_1(tlv_ptr.eigrp_tlv_general_parm->k2),
    332                    GET_U_1(tlv_ptr.eigrp_tlv_general_parm->k3),
    333                    GET_U_1(tlv_ptr.eigrp_tlv_general_parm->k4),
    334                    GET_U_1(tlv_ptr.eigrp_tlv_general_parm->k5));
    335             break;
    336 
    337         case EIGRP_TLV_SW_VERSION:
    338             tlv_ptr.eigrp_tlv_sw_version = (const struct eigrp_tlv_sw_version_t *)tlv_tptr;
    339             if (tlv_tlen < sizeof(*tlv_ptr.eigrp_tlv_sw_version)) {
    340                 ND_PRINT(" (too short, < %zu)",
    341                          sizeof(struct eigrp_tlv_header) + sizeof(*tlv_ptr.eigrp_tlv_sw_version));
    342                 break;
    343             }
    344 
    345             ND_PRINT("\n\t    IOS version: %u.%u, EIGRP version %u.%u",
    346                    GET_U_1(tlv_ptr.eigrp_tlv_sw_version->ios_major),
    347                    GET_U_1(tlv_ptr.eigrp_tlv_sw_version->ios_minor),
    348                    GET_U_1(tlv_ptr.eigrp_tlv_sw_version->eigrp_major),
    349                    GET_U_1(tlv_ptr.eigrp_tlv_sw_version->eigrp_minor));
    350             break;
    351 
    352         case EIGRP_TLV_IP_INT:
    353             tlv_ptr.eigrp_tlv_ip_int = (const struct eigrp_tlv_ip_int_t *)tlv_tptr;
    354             if (tlv_tlen < sizeof(*tlv_ptr.eigrp_tlv_ip_int)) {
    355                 ND_PRINT(" (too short, < %zu)",
    356                          sizeof(struct eigrp_tlv_header) + sizeof(*tlv_ptr.eigrp_tlv_ip_int));
    357                 break;
    358             }
    359 
    360             bit_length = GET_U_1(tlv_ptr.eigrp_tlv_ip_int->plen);
    361             if (bit_length > 32) {
    362                 ND_PRINT("\n\t    illegal prefix length %u",bit_length);
    363                 break;
    364             }
    365             byte_length = (bit_length + 7) / 8; /* variable length encoding */
    366             memset(prefix, 0, 4);
    367             GET_CPY_BYTES(prefix, tlv_ptr.eigrp_tlv_ip_int->destination, byte_length);
    368 
    369             ND_PRINT("\n\t    IPv4 prefix: %15s/%u, nexthop: ",
    370                    ipaddr_string(ndo, prefix),	/* local buffer, not packet data; don't use GET_IPADDR_STRING() */
    371                    bit_length);
    372             if (GET_BE_U_4(tlv_ptr.eigrp_tlv_ip_int->nexthop) == 0)
    373                 ND_PRINT("self");
    374             else
    375                 ND_PRINT("%s",
    376                          GET_IPADDR_STRING(tlv_ptr.eigrp_tlv_ip_int->nexthop));
    377 
    378             ND_PRINT("\n\t      delay %u ms, bandwidth %u Kbps, mtu %u, hop %u, reliability %u, load %u",
    379                    (GET_BE_U_4(tlv_ptr.eigrp_tlv_ip_int->delay)/100),
    380                    GET_BE_U_4(tlv_ptr.eigrp_tlv_ip_int->bandwidth),
    381                    GET_BE_U_3(tlv_ptr.eigrp_tlv_ip_int->mtu),
    382                    GET_U_1(tlv_ptr.eigrp_tlv_ip_int->hopcount),
    383                    GET_U_1(tlv_ptr.eigrp_tlv_ip_int->reliability),
    384                    GET_U_1(tlv_ptr.eigrp_tlv_ip_int->load));
    385             break;
    386 
    387         case EIGRP_TLV_IP_EXT:
    388             tlv_ptr.eigrp_tlv_ip_ext = (const struct eigrp_tlv_ip_ext_t *)tlv_tptr;
    389             if (tlv_tlen < sizeof(*tlv_ptr.eigrp_tlv_ip_ext)) {
    390                 ND_PRINT(" (too short, < %zu)",
    391                          sizeof(struct eigrp_tlv_header) + sizeof(*tlv_ptr.eigrp_tlv_ip_ext));
    392                 break;
    393             }
    394 
    395             bit_length = GET_U_1(tlv_ptr.eigrp_tlv_ip_ext->plen);
    396             if (bit_length > 32) {
    397                 ND_PRINT("\n\t    illegal prefix length %u",bit_length);
    398                 break;
    399             }
    400             byte_length = (bit_length + 7) / 8; /* variable length encoding */
    401             memset(prefix, 0, 4);
    402             GET_CPY_BYTES(prefix, tlv_ptr.eigrp_tlv_ip_ext->destination, byte_length);
    403 
    404             ND_PRINT("\n\t    IPv4 prefix: %15s/%u, nexthop: ",
    405                    ipaddr_string(ndo, prefix),	/* local buffer, not packet data; don't use GET_IPADDR_STRING() */
    406                    bit_length);
    407             if (GET_BE_U_4(tlv_ptr.eigrp_tlv_ip_ext->nexthop) == 0)
    408                 ND_PRINT("self");
    409             else
    410                 ND_PRINT("%s",
    411                          GET_IPADDR_STRING(tlv_ptr.eigrp_tlv_ip_ext->nexthop));
    412 
    413             ND_PRINT("\n\t      origin-router %s, origin-as %u, origin-proto %s, flags [0x%02x], tag 0x%08x, metric %u",
    414                    GET_IPADDR_STRING(tlv_ptr.eigrp_tlv_ip_ext->origin_router),
    415                    GET_BE_U_4(tlv_ptr.eigrp_tlv_ip_ext->origin_as),
    416                    tok2str(eigrp_ext_proto_id_values,"unknown",GET_U_1(tlv_ptr.eigrp_tlv_ip_ext->proto_id)),
    417                    GET_U_1(tlv_ptr.eigrp_tlv_ip_ext->flags),
    418                    GET_BE_U_4(tlv_ptr.eigrp_tlv_ip_ext->tag),
    419                    GET_BE_U_4(tlv_ptr.eigrp_tlv_ip_ext->metric));
    420 
    421             ND_PRINT("\n\t      delay %u ms, bandwidth %u Kbps, mtu %u, hop %u, reliability %u, load %u",
    422                    (GET_BE_U_4(tlv_ptr.eigrp_tlv_ip_ext->delay)/100),
    423                    GET_BE_U_4(tlv_ptr.eigrp_tlv_ip_ext->bandwidth),
    424                    GET_BE_U_3(tlv_ptr.eigrp_tlv_ip_ext->mtu),
    425                    GET_U_1(tlv_ptr.eigrp_tlv_ip_ext->hopcount),
    426                    GET_U_1(tlv_ptr.eigrp_tlv_ip_ext->reliability),
    427                    GET_U_1(tlv_ptr.eigrp_tlv_ip_ext->load));
    428             break;
    429 
    430         case EIGRP_TLV_AT_CABLE_SETUP:
    431             tlv_ptr.eigrp_tlv_at_cable_setup = (const struct eigrp_tlv_at_cable_setup_t *)tlv_tptr;
    432             if (tlv_tlen < sizeof(*tlv_ptr.eigrp_tlv_at_cable_setup)) {
    433                 ND_PRINT(" (too short, < %zu)",
    434                          sizeof(struct eigrp_tlv_header) + sizeof(*tlv_ptr.eigrp_tlv_at_cable_setup));
    435                 break;
    436             }
    437 
    438             ND_PRINT("\n\t    Cable-range: %u-%u, Router-ID %u",
    439                    GET_BE_U_2(tlv_ptr.eigrp_tlv_at_cable_setup->cable_start),
    440                    GET_BE_U_2(tlv_ptr.eigrp_tlv_at_cable_setup->cable_end),
    441                    GET_BE_U_4(tlv_ptr.eigrp_tlv_at_cable_setup->router_id));
    442             break;
    443 
    444         case EIGRP_TLV_AT_INT:
    445             tlv_ptr.eigrp_tlv_at_int = (const struct eigrp_tlv_at_int_t *)tlv_tptr;
    446             if (tlv_tlen < sizeof(*tlv_ptr.eigrp_tlv_at_int)) {
    447                 ND_PRINT(" (too short, < %zu)",
    448                          sizeof(struct eigrp_tlv_header) + sizeof(*tlv_ptr.eigrp_tlv_at_int));
    449                 break;
    450             }
    451 
    452             ND_PRINT("\n\t     Cable-Range: %u-%u, nexthop: ",
    453                    GET_BE_U_2(tlv_ptr.eigrp_tlv_at_int->cable_start),
    454                    GET_BE_U_2(tlv_ptr.eigrp_tlv_at_int->cable_end));
    455 
    456             if (GET_BE_U_4(tlv_ptr.eigrp_tlv_at_int->nexthop) == 0)
    457                 ND_PRINT("self");
    458             else
    459                 ND_PRINT("%u.%u",
    460                        GET_BE_U_2(&tlv_ptr.eigrp_tlv_at_int->nexthop[0]),
    461                        GET_BE_U_2(&tlv_ptr.eigrp_tlv_at_int->nexthop[2]));
    462 
    463             ND_PRINT("\n\t      delay %u ms, bandwidth %u Kbps, mtu %u, hop %u, reliability %u, load %u",
    464                    (GET_BE_U_4(tlv_ptr.eigrp_tlv_at_int->delay)/100),
    465                    GET_BE_U_4(tlv_ptr.eigrp_tlv_at_int->bandwidth),
    466                    GET_BE_U_3(tlv_ptr.eigrp_tlv_at_int->mtu),
    467                    GET_U_1(tlv_ptr.eigrp_tlv_at_int->hopcount),
    468                    GET_U_1(tlv_ptr.eigrp_tlv_at_int->reliability),
    469                    GET_U_1(tlv_ptr.eigrp_tlv_at_int->load));
    470             break;
    471 
    472         case EIGRP_TLV_AT_EXT:
    473             tlv_ptr.eigrp_tlv_at_ext = (const struct eigrp_tlv_at_ext_t *)tlv_tptr;
    474             if (tlv_tlen < sizeof(*tlv_ptr.eigrp_tlv_at_ext)) {
    475                 ND_PRINT(" (too short, < %zu)",
    476                          sizeof(struct eigrp_tlv_header) + sizeof(*tlv_ptr.eigrp_tlv_at_ext));
    477                 break;
    478             }
    479 
    480             ND_PRINT("\n\t     Cable-Range: %u-%u, nexthop: ",
    481                    GET_BE_U_2(tlv_ptr.eigrp_tlv_at_ext->cable_start),
    482                    GET_BE_U_2(tlv_ptr.eigrp_tlv_at_ext->cable_end));
    483 
    484             if (GET_BE_U_4(tlv_ptr.eigrp_tlv_at_ext->nexthop) == 0)
    485                 ND_PRINT("self");
    486             else
    487                 ND_PRINT("%u.%u",
    488                        GET_BE_U_2(&tlv_ptr.eigrp_tlv_at_ext->nexthop[0]),
    489                        GET_BE_U_2(&tlv_ptr.eigrp_tlv_at_ext->nexthop[2]));
    490 
    491             ND_PRINT("\n\t      origin-router %u, origin-as %u, origin-proto %s, flags [0x%02x], tag 0x%08x, metric %u",
    492                    GET_BE_U_4(tlv_ptr.eigrp_tlv_at_ext->origin_router),
    493                    GET_BE_U_4(tlv_ptr.eigrp_tlv_at_ext->origin_as),
    494                    tok2str(eigrp_ext_proto_id_values,"unknown",GET_U_1(tlv_ptr.eigrp_tlv_at_ext->proto_id)),
    495                    GET_U_1(tlv_ptr.eigrp_tlv_at_ext->flags),
    496                    GET_BE_U_4(tlv_ptr.eigrp_tlv_at_ext->tag),
    497                    GET_BE_U_2(tlv_ptr.eigrp_tlv_at_ext->metric));
    498 
    499             ND_PRINT("\n\t      delay %u ms, bandwidth %u Kbps, mtu %u, hop %u, reliability %u, load %u",
    500                    (GET_BE_U_4(tlv_ptr.eigrp_tlv_at_ext->delay)/100),
    501                    GET_BE_U_4(tlv_ptr.eigrp_tlv_at_ext->bandwidth),
    502                    GET_BE_U_3(tlv_ptr.eigrp_tlv_at_ext->mtu),
    503                    GET_U_1(tlv_ptr.eigrp_tlv_at_ext->hopcount),
    504                    GET_U_1(tlv_ptr.eigrp_tlv_at_ext->reliability),
    505                    GET_U_1(tlv_ptr.eigrp_tlv_at_ext->load));
    506             break;
    507 
    508             /*
    509              * FIXME those are the defined TLVs that lack a decoder
    510              * you are welcome to contribute code ;-)
    511              */
    512 
    513         case EIGRP_TLV_AUTH:
    514         case EIGRP_TLV_SEQ:
    515         case EIGRP_TLV_MCAST_SEQ:
    516         case EIGRP_TLV_IPX_INT:
    517         case EIGRP_TLV_IPX_EXT:
    518 
    519         default:
    520             if (ndo->ndo_vflag <= 1)
    521                 print_unknown_data(ndo,tlv_tptr,"\n\t    ",tlv_tlen);
    522             break;
    523         }
    524         /* do we want to see an additionally hexdump ? */
    525         if (ndo->ndo_vflag > 1)
    526             print_unknown_data(ndo,tptr+sizeof(struct eigrp_tlv_header),"\n\t    ",
    527                                eigrp_tlv_len-sizeof(struct eigrp_tlv_header));
    528 
    529         tptr+=eigrp_tlv_len;
    530         tlen-=eigrp_tlv_len;
    531     }
    532     return;
    533 trunc:
    534     nd_print_trunc(ndo);
    535 }
    536