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