xref: /freebsd/contrib/tcpdump/print-eigrp.c (revision 8bcb0991864975618c09697b1aca10683346d9f0)
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             ND_TCHECK2(tlv_ptr.eigrp_tlv_ip_int->destination, byte_length);
357             memcpy(prefix,&tlv_ptr.eigrp_tlv_ip_int->destination,byte_length);
358 
359             ND_PRINT((ndo, "\n\t    IPv4 prefix: %15s/%u, nexthop: ",
360                    ipaddr_string(ndo, prefix),
361                    bit_length));
362             if (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_ip_int->nexthop) == 0)
363                 ND_PRINT((ndo, "self"));
364             else
365                 ND_PRINT((ndo, "%s",ipaddr_string(ndo, &tlv_ptr.eigrp_tlv_ip_int->nexthop)));
366 
367             ND_PRINT((ndo, "\n\t      delay %u ms, bandwidth %u Kbps, mtu %u, hop %u, reliability %u, load %u",
368                    (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_ip_int->delay)/100),
369                    EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_ip_int->bandwidth),
370                    EXTRACT_24BITS(&tlv_ptr.eigrp_tlv_ip_int->mtu),
371                    tlv_ptr.eigrp_tlv_ip_int->hopcount,
372                    tlv_ptr.eigrp_tlv_ip_int->reliability,
373                    tlv_ptr.eigrp_tlv_ip_int->load));
374             break;
375 
376         case EIGRP_TLV_IP_EXT:
377             tlv_ptr.eigrp_tlv_ip_ext = (const struct eigrp_tlv_ip_ext_t *)tlv_tptr;
378             if (tlv_tlen < sizeof(*tlv_ptr.eigrp_tlv_ip_ext)) {
379                 ND_PRINT((ndo, " (too short, < %u)",
380                     (u_int) (sizeof(struct eigrp_tlv_header) + sizeof(*tlv_ptr.eigrp_tlv_ip_ext))));
381                 break;
382             }
383 
384             bit_length = tlv_ptr.eigrp_tlv_ip_ext->plen;
385             if (bit_length > 32) {
386                 ND_PRINT((ndo, "\n\t    illegal prefix length %u",bit_length));
387                 break;
388             }
389             byte_length = (bit_length + 7) / 8; /* variable length encoding */
390             memset(prefix, 0, 4);
391             ND_TCHECK2(tlv_ptr.eigrp_tlv_ip_ext->destination, byte_length);
392             memcpy(prefix,&tlv_ptr.eigrp_tlv_ip_ext->destination,byte_length);
393 
394             ND_PRINT((ndo, "\n\t    IPv4 prefix: %15s/%u, nexthop: ",
395                    ipaddr_string(ndo, prefix),
396                    bit_length));
397             if (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_ip_ext->nexthop) == 0)
398                 ND_PRINT((ndo, "self"));
399             else
400                 ND_PRINT((ndo, "%s",ipaddr_string(ndo, &tlv_ptr.eigrp_tlv_ip_ext->nexthop)));
401 
402             ND_PRINT((ndo, "\n\t      origin-router %s, origin-as %u, origin-proto %s, flags [0x%02x], tag 0x%08x, metric %u",
403                    ipaddr_string(ndo, tlv_ptr.eigrp_tlv_ip_ext->origin_router),
404                    EXTRACT_32BITS(tlv_ptr.eigrp_tlv_ip_ext->origin_as),
405                    tok2str(eigrp_ext_proto_id_values,"unknown",tlv_ptr.eigrp_tlv_ip_ext->proto_id),
406                    tlv_ptr.eigrp_tlv_ip_ext->flags,
407                    EXTRACT_32BITS(tlv_ptr.eigrp_tlv_ip_ext->tag),
408                    EXTRACT_32BITS(tlv_ptr.eigrp_tlv_ip_ext->metric)));
409 
410             ND_PRINT((ndo, "\n\t      delay %u ms, bandwidth %u Kbps, mtu %u, hop %u, reliability %u, load %u",
411                    (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_ip_ext->delay)/100),
412                    EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_ip_ext->bandwidth),
413                    EXTRACT_24BITS(&tlv_ptr.eigrp_tlv_ip_ext->mtu),
414                    tlv_ptr.eigrp_tlv_ip_ext->hopcount,
415                    tlv_ptr.eigrp_tlv_ip_ext->reliability,
416                    tlv_ptr.eigrp_tlv_ip_ext->load));
417             break;
418 
419         case EIGRP_TLV_AT_CABLE_SETUP:
420             tlv_ptr.eigrp_tlv_at_cable_setup = (const struct eigrp_tlv_at_cable_setup_t *)tlv_tptr;
421             if (tlv_tlen < sizeof(*tlv_ptr.eigrp_tlv_at_cable_setup)) {
422                 ND_PRINT((ndo, " (too short, < %u)",
423                     (u_int) (sizeof(struct eigrp_tlv_header) + sizeof(*tlv_ptr.eigrp_tlv_at_cable_setup))));
424                 break;
425             }
426 
427             ND_PRINT((ndo, "\n\t    Cable-range: %u-%u, Router-ID %u",
428                    EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_cable_setup->cable_start),
429                    EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_cable_setup->cable_end),
430                    EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_cable_setup->router_id)));
431             break;
432 
433         case EIGRP_TLV_AT_INT:
434             tlv_ptr.eigrp_tlv_at_int = (const struct eigrp_tlv_at_int_t *)tlv_tptr;
435             if (tlv_tlen < sizeof(*tlv_ptr.eigrp_tlv_at_int)) {
436                 ND_PRINT((ndo, " (too short, < %u)",
437                     (u_int) (sizeof(struct eigrp_tlv_header) + sizeof(*tlv_ptr.eigrp_tlv_at_int))));
438                 break;
439             }
440 
441             ND_PRINT((ndo, "\n\t     Cable-Range: %u-%u, nexthop: ",
442                    EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_int->cable_start),
443                    EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_int->cable_end)));
444 
445             if (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_int->nexthop) == 0)
446                 ND_PRINT((ndo, "self"));
447             else
448                 ND_PRINT((ndo, "%u.%u",
449                        EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_int->nexthop),
450                        EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_int->nexthop[2])));
451 
452             ND_PRINT((ndo, "\n\t      delay %u ms, bandwidth %u Kbps, mtu %u, hop %u, reliability %u, load %u",
453                    (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_int->delay)/100),
454                    EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_int->bandwidth),
455                    EXTRACT_24BITS(&tlv_ptr.eigrp_tlv_at_int->mtu),
456                    tlv_ptr.eigrp_tlv_at_int->hopcount,
457                    tlv_ptr.eigrp_tlv_at_int->reliability,
458                    tlv_ptr.eigrp_tlv_at_int->load));
459             break;
460 
461         case EIGRP_TLV_AT_EXT:
462             tlv_ptr.eigrp_tlv_at_ext = (const struct eigrp_tlv_at_ext_t *)tlv_tptr;
463             if (tlv_tlen < sizeof(*tlv_ptr.eigrp_tlv_at_ext)) {
464                 ND_PRINT((ndo, " (too short, < %u)",
465                     (u_int) (sizeof(struct eigrp_tlv_header) + sizeof(*tlv_ptr.eigrp_tlv_at_ext))));
466                 break;
467             }
468 
469             ND_PRINT((ndo, "\n\t     Cable-Range: %u-%u, nexthop: ",
470                    EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_ext->cable_start),
471                    EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_ext->cable_end)));
472 
473             if (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_ext->nexthop) == 0)
474                 ND_PRINT((ndo, "self"));
475             else
476                 ND_PRINT((ndo, "%u.%u",
477                        EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_ext->nexthop),
478                        EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_ext->nexthop[2])));
479 
480             ND_PRINT((ndo, "\n\t      origin-router %u, origin-as %u, origin-proto %s, flags [0x%02x], tag 0x%08x, metric %u",
481                    EXTRACT_32BITS(tlv_ptr.eigrp_tlv_at_ext->origin_router),
482                    EXTRACT_32BITS(tlv_ptr.eigrp_tlv_at_ext->origin_as),
483                    tok2str(eigrp_ext_proto_id_values,"unknown",tlv_ptr.eigrp_tlv_at_ext->proto_id),
484                    tlv_ptr.eigrp_tlv_at_ext->flags,
485                    EXTRACT_32BITS(tlv_ptr.eigrp_tlv_at_ext->tag),
486                    EXTRACT_16BITS(tlv_ptr.eigrp_tlv_at_ext->metric)));
487 
488             ND_PRINT((ndo, "\n\t      delay %u ms, bandwidth %u Kbps, mtu %u, hop %u, reliability %u, load %u",
489                    (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_ext->delay)/100),
490                    EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_ext->bandwidth),
491                    EXTRACT_24BITS(&tlv_ptr.eigrp_tlv_at_ext->mtu),
492                    tlv_ptr.eigrp_tlv_at_ext->hopcount,
493                    tlv_ptr.eigrp_tlv_at_ext->reliability,
494                    tlv_ptr.eigrp_tlv_at_ext->load));
495             break;
496 
497             /*
498              * FIXME those are the defined TLVs that lack a decoder
499              * you are welcome to contribute code ;-)
500              */
501 
502         case EIGRP_TLV_AUTH:
503         case EIGRP_TLV_SEQ:
504         case EIGRP_TLV_MCAST_SEQ:
505         case EIGRP_TLV_IPX_INT:
506         case EIGRP_TLV_IPX_EXT:
507 
508         default:
509             if (ndo->ndo_vflag <= 1)
510                 print_unknown_data(ndo,tlv_tptr,"\n\t    ",tlv_tlen);
511             break;
512         }
513         /* do we want to see an additionally hexdump ? */
514         if (ndo->ndo_vflag > 1)
515             print_unknown_data(ndo,tptr+sizeof(struct eigrp_tlv_header),"\n\t    ",
516                                eigrp_tlv_len-sizeof(struct eigrp_tlv_header));
517 
518         tptr+=eigrp_tlv_len;
519         tlen-=eigrp_tlv_len;
520     }
521     return;
522 trunc:
523     ND_PRINT((ndo, "\n\t\t packet exceeded snapshot"));
524 }
525