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