1/* 2 * Copyright (c) 1998-2006 The TCPDUMP project 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that: (1) source code 6 * distributions retain the above copyright notice and this paragraph 7 * in its entirety, and (2) distributions including binary code include 8 * the above copyright notice and this paragraph in its entirety in 9 * the documentation or other materials provided with the distribution. 10 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 11 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT 12 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 13 * FOR A PARTICULAR PURPOSE. 14 * 15 * support for the IEEE "slow protocols" LACP, MARKER as per 802.3ad 16 * OAM as per 802.3ah 17 * 18 * Original code by Hannes Gredler (hannes@juniper.net) 19 */ 20 21#define NETDISSECT_REWORKED 22#ifdef HAVE_CONFIG_H 23#include "config.h" 24#endif 25 26#include <tcpdump-stdinc.h> 27 28#include "interface.h" 29#include "extract.h" 30#include "addrtoname.h" 31#include "ether.h" 32#include "oui.h" 33 34struct slow_common_header_t { 35 uint8_t proto_subtype; 36 uint8_t version; 37}; 38 39#define SLOW_PROTO_LACP 1 40#define SLOW_PROTO_MARKER 2 41#define SLOW_PROTO_OAM 3 42 43#define LACP_VERSION 1 44#define MARKER_VERSION 1 45 46static const struct tok slow_proto_values[] = { 47 { SLOW_PROTO_LACP, "LACP" }, 48 { SLOW_PROTO_MARKER, "MARKER" }, 49 { SLOW_PROTO_OAM, "OAM" }, 50 { 0, NULL} 51}; 52 53static const struct tok slow_oam_flag_values[] = { 54 { 0x0001, "Link Fault" }, 55 { 0x0002, "Dying Gasp" }, 56 { 0x0004, "Critical Event" }, 57 { 0x0008, "Local Evaluating" }, 58 { 0x0010, "Local Stable" }, 59 { 0x0020, "Remote Evaluating" }, 60 { 0x0040, "Remote Stable" }, 61 { 0, NULL} 62}; 63 64#define SLOW_OAM_CODE_INFO 0x00 65#define SLOW_OAM_CODE_EVENT_NOTIF 0x01 66#define SLOW_OAM_CODE_VAR_REQUEST 0x02 67#define SLOW_OAM_CODE_VAR_RESPONSE 0x03 68#define SLOW_OAM_CODE_LOOPBACK_CTRL 0x04 69#define SLOW_OAM_CODE_PRIVATE 0xfe 70 71static const struct tok slow_oam_code_values[] = { 72 { SLOW_OAM_CODE_INFO, "Information" }, 73 { SLOW_OAM_CODE_EVENT_NOTIF, "Event Notification" }, 74 { SLOW_OAM_CODE_VAR_REQUEST, "Variable Request" }, 75 { SLOW_OAM_CODE_VAR_RESPONSE, "Variable Response" }, 76 { SLOW_OAM_CODE_LOOPBACK_CTRL, "Loopback Control" }, 77 { SLOW_OAM_CODE_PRIVATE, "Vendor Private" }, 78 { 0, NULL} 79}; 80 81struct slow_oam_info_t { 82 uint8_t info_type; 83 uint8_t info_length; 84 uint8_t oam_version; 85 uint8_t revision[2]; 86 uint8_t state; 87 uint8_t oam_config; 88 uint8_t oam_pdu_config[2]; 89 uint8_t oui[3]; 90 uint8_t vendor_private[4]; 91}; 92 93#define SLOW_OAM_INFO_TYPE_END_OF_TLV 0x00 94#define SLOW_OAM_INFO_TYPE_LOCAL 0x01 95#define SLOW_OAM_INFO_TYPE_REMOTE 0x02 96#define SLOW_OAM_INFO_TYPE_ORG_SPECIFIC 0xfe 97 98static const struct tok slow_oam_info_type_values[] = { 99 { SLOW_OAM_INFO_TYPE_END_OF_TLV, "End of TLV marker" }, 100 { SLOW_OAM_INFO_TYPE_LOCAL, "Local" }, 101 { SLOW_OAM_INFO_TYPE_REMOTE, "Remote" }, 102 { SLOW_OAM_INFO_TYPE_ORG_SPECIFIC, "Organization specific" }, 103 { 0, NULL} 104}; 105 106#define OAM_INFO_TYPE_PARSER_MASK 0x3 107static const struct tok slow_oam_info_type_state_parser_values[] = { 108 { 0x00, "forwarding" }, 109 { 0x01, "looping back" }, 110 { 0x02, "discarding" }, 111 { 0x03, "reserved" }, 112 { 0, NULL} 113}; 114 115#define OAM_INFO_TYPE_MUX_MASK 0x4 116static const struct tok slow_oam_info_type_state_mux_values[] = { 117 { 0x00, "forwarding" }, 118 { 0x04, "discarding" }, 119 { 0, NULL} 120}; 121 122static const struct tok slow_oam_info_type_oam_config_values[] = { 123 { 0x01, "Active" }, 124 { 0x02, "Unidirectional" }, 125 { 0x04, "Remote-Loopback" }, 126 { 0x08, "Link-Events" }, 127 { 0x10, "Variable-Retrieval" }, 128 { 0, NULL} 129}; 130 131/* 11 Bits */ 132#define OAM_INFO_TYPE_PDU_SIZE_MASK 0x7ff 133 134#define SLOW_OAM_LINK_EVENT_END_OF_TLV 0x00 135#define SLOW_OAM_LINK_EVENT_ERR_SYM_PER 0x01 136#define SLOW_OAM_LINK_EVENT_ERR_FRM 0x02 137#define SLOW_OAM_LINK_EVENT_ERR_FRM_PER 0x03 138#define SLOW_OAM_LINK_EVENT_ERR_FRM_SUMM 0x04 139#define SLOW_OAM_LINK_EVENT_ORG_SPECIFIC 0xfe 140 141static const struct tok slow_oam_link_event_values[] = { 142 { SLOW_OAM_LINK_EVENT_END_OF_TLV, "End of TLV marker" }, 143 { SLOW_OAM_LINK_EVENT_ERR_SYM_PER, "Errored Symbol Period Event" }, 144 { SLOW_OAM_LINK_EVENT_ERR_FRM, "Errored Frame Event" }, 145 { SLOW_OAM_LINK_EVENT_ERR_FRM_PER, "Errored Frame Period Event" }, 146 { SLOW_OAM_LINK_EVENT_ERR_FRM_SUMM, "Errored Frame Seconds Summary Event" }, 147 { SLOW_OAM_LINK_EVENT_ORG_SPECIFIC, "Organization specific" }, 148 { 0, NULL} 149}; 150 151struct slow_oam_link_event_t { 152 uint8_t event_type; 153 uint8_t event_length; 154 uint8_t time_stamp[2]; 155 uint8_t window[8]; 156 uint8_t threshold[8]; 157 uint8_t errors[8]; 158 uint8_t errors_running_total[8]; 159 uint8_t event_running_total[4]; 160}; 161 162struct slow_oam_variablerequest_t { 163 uint8_t branch; 164 uint8_t leaf[2]; 165}; 166 167struct slow_oam_variableresponse_t { 168 uint8_t branch; 169 uint8_t leaf[2]; 170 uint8_t length; 171}; 172 173struct slow_oam_loopbackctrl_t { 174 uint8_t command; 175}; 176 177static const struct tok slow_oam_loopbackctrl_cmd_values[] = { 178 { 0x01, "Enable OAM Remote Loopback" }, 179 { 0x02, "Disable OAM Remote Loopback" }, 180 { 0, NULL} 181}; 182 183struct tlv_header_t { 184 uint8_t type; 185 uint8_t length; 186}; 187 188#define LACP_TLV_TERMINATOR 0x00 189#define LACP_TLV_ACTOR_INFO 0x01 190#define LACP_TLV_PARTNER_INFO 0x02 191#define LACP_TLV_COLLECTOR_INFO 0x03 192 193#define MARKER_TLV_TERMINATOR 0x00 194#define MARKER_TLV_MARKER_INFO 0x01 195 196static const struct tok slow_tlv_values[] = { 197 { (SLOW_PROTO_LACP << 8) + LACP_TLV_TERMINATOR, "Terminator"}, 198 { (SLOW_PROTO_LACP << 8) + LACP_TLV_ACTOR_INFO, "Actor Information"}, 199 { (SLOW_PROTO_LACP << 8) + LACP_TLV_PARTNER_INFO, "Partner Information"}, 200 { (SLOW_PROTO_LACP << 8) + LACP_TLV_COLLECTOR_INFO, "Collector Information"}, 201 202 { (SLOW_PROTO_MARKER << 8) + MARKER_TLV_TERMINATOR, "Terminator"}, 203 { (SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_INFO, "Marker Information"}, 204 { 0, NULL} 205}; 206 207struct lacp_tlv_actor_partner_info_t { 208 uint8_t sys_pri[2]; 209 uint8_t sys[ETHER_ADDR_LEN]; 210 uint8_t key[2]; 211 uint8_t port_pri[2]; 212 uint8_t port[2]; 213 uint8_t state; 214 uint8_t pad[3]; 215}; 216 217static const struct tok lacp_tlv_actor_partner_info_state_values[] = { 218 { 0x01, "Activity"}, 219 { 0x02, "Timeout"}, 220 { 0x04, "Aggregation"}, 221 { 0x08, "Synchronization"}, 222 { 0x10, "Collecting"}, 223 { 0x20, "Distributing"}, 224 { 0x40, "Default"}, 225 { 0x80, "Expired"}, 226 { 0, NULL} 227}; 228 229struct lacp_tlv_collector_info_t { 230 uint8_t max_delay[2]; 231 uint8_t pad[12]; 232}; 233 234struct marker_tlv_marker_info_t { 235 uint8_t req_port[2]; 236 uint8_t req_sys[ETHER_ADDR_LEN]; 237 uint8_t req_trans_id[4]; 238 uint8_t pad[2]; 239}; 240 241struct lacp_marker_tlv_terminator_t { 242 uint8_t pad[50]; 243}; 244 245static void slow_marker_lacp_print(netdissect_options *, register const u_char *, register u_int); 246static void slow_oam_print(netdissect_options *, register const u_char *, register u_int); 247 248const struct slow_common_header_t *slow_com_header; 249 250void 251slow_print(netdissect_options *ndo, 252 register const u_char *pptr, register u_int len) 253{ 254 int print_version; 255 256 slow_com_header = (const struct slow_common_header_t *)pptr; 257 ND_TCHECK(*slow_com_header); 258 259 /* 260 * Sanity checking of the header. 261 */ 262 switch (slow_com_header->proto_subtype) { 263 case SLOW_PROTO_LACP: 264 if (slow_com_header->version != LACP_VERSION) { 265 ND_PRINT((ndo, "LACP version %u packet not supported",slow_com_header->version)); 266 return; 267 } 268 print_version = 1; 269 break; 270 271 case SLOW_PROTO_MARKER: 272 if (slow_com_header->version != MARKER_VERSION) { 273 ND_PRINT((ndo, "MARKER version %u packet not supported",slow_com_header->version)); 274 return; 275 } 276 print_version = 1; 277 break; 278 279 case SLOW_PROTO_OAM: /* fall through */ 280 print_version = 0; 281 break; 282 283 default: 284 /* print basic information and exit */ 285 print_version = -1; 286 break; 287 } 288 289 if (print_version) { 290 ND_PRINT((ndo, "%sv%u, length %u", 291 tok2str(slow_proto_values, "unknown (%u)",slow_com_header->proto_subtype), 292 slow_com_header->version, 293 len)); 294 } else { 295 /* some slow protos don't have a version number in the header */ 296 ND_PRINT((ndo, "%s, length %u", 297 tok2str(slow_proto_values, "unknown (%u)",slow_com_header->proto_subtype), 298 len)); 299 } 300 301 /* unrecognized subtype */ 302 if (print_version == -1) { 303 print_unknown_data(ndo, pptr, "\n\t", len); 304 return; 305 } 306 307 if (!ndo->ndo_vflag) 308 return; 309 310 switch (slow_com_header->proto_subtype) { 311 default: /* should not happen */ 312 break; 313 314 case SLOW_PROTO_OAM: 315 /* skip proto_subtype */ 316 slow_oam_print(ndo, pptr+1, len-1); 317 break; 318 319 case SLOW_PROTO_LACP: /* LACP and MARKER share the same semantics */ 320 case SLOW_PROTO_MARKER: 321 /* skip slow_common_header */ 322 len -= sizeof(const struct slow_common_header_t); 323 pptr += sizeof(const struct slow_common_header_t); 324 slow_marker_lacp_print(ndo, pptr, len); 325 break; 326 } 327 return; 328 329trunc: 330 ND_PRINT((ndo, "\n\t\t packet exceeded snapshot")); 331} 332 333static void 334slow_marker_lacp_print(netdissect_options *ndo, 335 register const u_char *tptr, register u_int tlen) 336{ 337 const struct tlv_header_t *tlv_header; 338 const u_char *tlv_tptr; 339 u_int tlv_len, tlv_tlen; 340 341 union { 342 const struct lacp_marker_tlv_terminator_t *lacp_marker_tlv_terminator; 343 const struct lacp_tlv_actor_partner_info_t *lacp_tlv_actor_partner_info; 344 const struct lacp_tlv_collector_info_t *lacp_tlv_collector_info; 345 const struct marker_tlv_marker_info_t *marker_tlv_marker_info; 346 } tlv_ptr; 347 348 while(tlen>0) { 349 /* did we capture enough for fully decoding the tlv header ? */ 350 ND_TCHECK2(*tptr, sizeof(struct tlv_header_t)); 351 tlv_header = (const struct tlv_header_t *)tptr; 352 tlv_len = tlv_header->length; 353 354 ND_PRINT((ndo, "\n\t%s TLV (0x%02x), length %u", 355 tok2str(slow_tlv_values, 356 "Unknown", 357 (slow_com_header->proto_subtype << 8) + tlv_header->type), 358 tlv_header->type, 359 tlv_len)); 360 361 if ((tlv_len < sizeof(struct tlv_header_t) || 362 tlv_len > tlen) && 363 tlv_header->type != LACP_TLV_TERMINATOR && 364 tlv_header->type != MARKER_TLV_TERMINATOR) { 365 ND_PRINT((ndo, "\n\t-----trailing data-----")); 366 print_unknown_data(ndo, tptr+sizeof(struct tlv_header_t), "\n\t ", tlen); 367 return; 368 } 369 370 tlv_tptr=tptr+sizeof(struct tlv_header_t); 371 tlv_tlen=tlv_len-sizeof(struct tlv_header_t); 372 373 /* did we capture enough for fully decoding the tlv ? */ 374 ND_TCHECK2(*tptr, tlv_len); 375 376 switch((slow_com_header->proto_subtype << 8) + tlv_header->type) { 377 378 /* those two TLVs have the same structure -> fall through */ 379 case ((SLOW_PROTO_LACP << 8) + LACP_TLV_ACTOR_INFO): 380 case ((SLOW_PROTO_LACP << 8) + LACP_TLV_PARTNER_INFO): 381 tlv_ptr.lacp_tlv_actor_partner_info = (const struct lacp_tlv_actor_partner_info_t *)tlv_tptr; 382 383 ND_PRINT((ndo, "\n\t System %s, System Priority %u, Key %u" \ 384 ", Port %u, Port Priority %u\n\t State Flags [%s]", 385 etheraddr_string(ndo, tlv_ptr.lacp_tlv_actor_partner_info->sys), 386 EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->sys_pri), 387 EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->key), 388 EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->port), 389 EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->port_pri), 390 bittok2str(lacp_tlv_actor_partner_info_state_values, 391 "none", 392 tlv_ptr.lacp_tlv_actor_partner_info->state))); 393 394 break; 395 396 case ((SLOW_PROTO_LACP << 8) + LACP_TLV_COLLECTOR_INFO): 397 tlv_ptr.lacp_tlv_collector_info = (const struct lacp_tlv_collector_info_t *)tlv_tptr; 398 399 ND_PRINT((ndo, "\n\t Max Delay %u", 400 EXTRACT_16BITS(tlv_ptr.lacp_tlv_collector_info->max_delay))); 401 402 break; 403 404 case ((SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_INFO): 405 tlv_ptr.marker_tlv_marker_info = (const struct marker_tlv_marker_info_t *)tlv_tptr; 406 407 ND_PRINT((ndo, "\n\t Request System %s, Request Port %u, Request Transaction ID 0x%08x", 408 etheraddr_string(ndo, tlv_ptr.marker_tlv_marker_info->req_sys), 409 EXTRACT_16BITS(tlv_ptr.marker_tlv_marker_info->req_port), 410 EXTRACT_32BITS(tlv_ptr.marker_tlv_marker_info->req_trans_id))); 411 412 break; 413 414 /* those two TLVs have the same structure -> fall through */ 415 case ((SLOW_PROTO_LACP << 8) + LACP_TLV_TERMINATOR): 416 case ((SLOW_PROTO_MARKER << 8) + LACP_TLV_TERMINATOR): 417 tlv_ptr.lacp_marker_tlv_terminator = (const struct lacp_marker_tlv_terminator_t *)tlv_tptr; 418 if (tlv_len == 0) { 419 tlv_len = sizeof(tlv_ptr.lacp_marker_tlv_terminator->pad) + 420 sizeof(struct tlv_header_t); 421 /* tell the user that we modified the length field */ 422 if (ndo->ndo_vflag>1) 423 ND_PRINT((ndo, " (=%u)", tlv_len)); 424 /* we have messed around with the length field - now we need to check 425 * again if there are enough bytes on the wire for the hexdump */ 426 ND_TCHECK2(tlv_ptr.lacp_marker_tlv_terminator->pad[0], 427 sizeof(tlv_ptr.lacp_marker_tlv_terminator->pad)); 428 } 429 430 break; 431 432 default: 433 if (ndo->ndo_vflag <= 1) 434 print_unknown_data(ndo, tlv_tptr, "\n\t ", tlv_tlen); 435 break; 436 } 437 /* do we want to see an additional hexdump ? */ 438 if (ndo->ndo_vflag > 1) { 439 print_unknown_data(ndo, tptr+sizeof(struct tlv_header_t), "\n\t ", 440 tlv_len-sizeof(struct tlv_header_t)); 441 } 442 443 tptr+=tlv_len; 444 tlen-=tlv_len; 445 } 446 return; 447trunc: 448 ND_PRINT((ndo, "\n\t\t packet exceeded snapshot")); 449} 450 451static void 452slow_oam_print(netdissect_options *ndo, 453 register const u_char *tptr, register u_int tlen) 454{ 455 u_int hexdump; 456 457 struct slow_oam_common_header_t { 458 uint8_t flags[2]; 459 uint8_t code; 460 }; 461 462 struct slow_oam_tlv_header_t { 463 uint8_t type; 464 uint8_t length; 465 }; 466 467 union { 468 const struct slow_oam_common_header_t *slow_oam_common_header; 469 const struct slow_oam_tlv_header_t *slow_oam_tlv_header; 470 } ptr; 471 472 union { 473 const struct slow_oam_info_t *slow_oam_info; 474 const struct slow_oam_link_event_t *slow_oam_link_event; 475 const struct slow_oam_variablerequest_t *slow_oam_variablerequest; 476 const struct slow_oam_variableresponse_t *slow_oam_variableresponse; 477 const struct slow_oam_loopbackctrl_t *slow_oam_loopbackctrl; 478 } tlv; 479 480 ptr.slow_oam_common_header = (struct slow_oam_common_header_t *)tptr; 481 tptr += sizeof(struct slow_oam_common_header_t); 482 tlen -= sizeof(struct slow_oam_common_header_t); 483 484 ND_PRINT((ndo, "\n\tCode %s OAM PDU, Flags [%s]", 485 tok2str(slow_oam_code_values, "Unknown (%u)", ptr.slow_oam_common_header->code), 486 bittok2str(slow_oam_flag_values, 487 "none", 488 EXTRACT_16BITS(&ptr.slow_oam_common_header->flags)))); 489 490 switch (ptr.slow_oam_common_header->code) { 491 case SLOW_OAM_CODE_INFO: 492 while (tlen > 0) { 493 ptr.slow_oam_tlv_header = (const struct slow_oam_tlv_header_t *)tptr; 494 ND_PRINT((ndo, "\n\t %s Information Type (%u), length %u", 495 tok2str(slow_oam_info_type_values, "Reserved", 496 ptr.slow_oam_tlv_header->type), 497 ptr.slow_oam_tlv_header->type, 498 ptr.slow_oam_tlv_header->length)); 499 500 hexdump = FALSE; 501 switch (ptr.slow_oam_tlv_header->type) { 502 case SLOW_OAM_INFO_TYPE_END_OF_TLV: 503 if (ptr.slow_oam_tlv_header->length != 0) { 504 ND_PRINT((ndo, "\n\t ERROR: illegal length - should be 0")); 505 } 506 return; 507 508 case SLOW_OAM_INFO_TYPE_LOCAL: /* identical format - fall through */ 509 case SLOW_OAM_INFO_TYPE_REMOTE: 510 tlv.slow_oam_info = (const struct slow_oam_info_t *)tptr; 511 512 if (tlv.slow_oam_info->info_length != 513 sizeof(struct slow_oam_info_t)) { 514 ND_PRINT((ndo, "\n\t ERROR: illegal length - should be %lu", 515 (unsigned long) sizeof(struct slow_oam_info_t))); 516 return; 517 } 518 519 ND_PRINT((ndo, "\n\t OAM-Version %u, Revision %u", 520 tlv.slow_oam_info->oam_version, 521 EXTRACT_16BITS(&tlv.slow_oam_info->revision))); 522 523 ND_PRINT((ndo, "\n\t State-Parser-Action %s, State-MUX-Action %s", 524 tok2str(slow_oam_info_type_state_parser_values, "Reserved", 525 tlv.slow_oam_info->state & OAM_INFO_TYPE_PARSER_MASK), 526 tok2str(slow_oam_info_type_state_mux_values, "Reserved", 527 tlv.slow_oam_info->state & OAM_INFO_TYPE_MUX_MASK))); 528 ND_PRINT((ndo, "\n\t OAM-Config Flags [%s], OAM-PDU-Config max-PDU size %u", 529 bittok2str(slow_oam_info_type_oam_config_values, "none", 530 tlv.slow_oam_info->oam_config), 531 EXTRACT_16BITS(&tlv.slow_oam_info->oam_pdu_config) & 532 OAM_INFO_TYPE_PDU_SIZE_MASK)); 533 ND_PRINT((ndo, "\n\t OUI %s (0x%06x), Vendor-Private 0x%08x", 534 tok2str(oui_values, "Unknown", 535 EXTRACT_24BITS(&tlv.slow_oam_info->oui)), 536 EXTRACT_24BITS(&tlv.slow_oam_info->oui), 537 EXTRACT_32BITS(&tlv.slow_oam_info->vendor_private))); 538 break; 539 540 case SLOW_OAM_INFO_TYPE_ORG_SPECIFIC: 541 hexdump = TRUE; 542 break; 543 544 default: 545 hexdump = TRUE; 546 break; 547 } 548 549 /* infinite loop check */ 550 if (!ptr.slow_oam_tlv_header->length) { 551 return; 552 } 553 554 /* do we also want to see a hex dump ? */ 555 if (ndo->ndo_vflag > 1 || hexdump==TRUE) { 556 print_unknown_data(ndo, tptr, "\n\t ", 557 ptr.slow_oam_tlv_header->length); 558 } 559 560 tlen -= ptr.slow_oam_tlv_header->length; 561 tptr += ptr.slow_oam_tlv_header->length; 562 } 563 break; 564 565 case SLOW_OAM_CODE_EVENT_NOTIF: 566 while (tlen > 0) { 567 ptr.slow_oam_tlv_header = (const struct slow_oam_tlv_header_t *)tptr; 568 ND_PRINT((ndo, "\n\t %s Link Event Type (%u), length %u", 569 tok2str(slow_oam_link_event_values, "Reserved", 570 ptr.slow_oam_tlv_header->type), 571 ptr.slow_oam_tlv_header->type, 572 ptr.slow_oam_tlv_header->length)); 573 574 hexdump = FALSE; 575 switch (ptr.slow_oam_tlv_header->type) { 576 case SLOW_OAM_LINK_EVENT_END_OF_TLV: 577 if (ptr.slow_oam_tlv_header->length != 0) { 578 ND_PRINT((ndo, "\n\t ERROR: illegal length - should be 0")); 579 } 580 return; 581 582 case SLOW_OAM_LINK_EVENT_ERR_SYM_PER: /* identical format - fall through */ 583 case SLOW_OAM_LINK_EVENT_ERR_FRM: 584 case SLOW_OAM_LINK_EVENT_ERR_FRM_PER: 585 case SLOW_OAM_LINK_EVENT_ERR_FRM_SUMM: 586 tlv.slow_oam_link_event = (const struct slow_oam_link_event_t *)tptr; 587 588 if (tlv.slow_oam_link_event->event_length != 589 sizeof(struct slow_oam_link_event_t)) { 590 ND_PRINT((ndo, "\n\t ERROR: illegal length - should be %lu", 591 (unsigned long) sizeof(struct slow_oam_link_event_t))); 592 return; 593 } 594 595 ND_PRINT((ndo, "\n\t Timestamp %u ms, Errored Window %" PRIu64 596 "\n\t Errored Threshold %" PRIu64 597 "\n\t Errors %" PRIu64 598 "\n\t Error Running Total %" PRIu64 599 "\n\t Event Running Total %u", 600 EXTRACT_16BITS(&tlv.slow_oam_link_event->time_stamp)*100, 601 EXTRACT_64BITS(&tlv.slow_oam_link_event->window), 602 EXTRACT_64BITS(&tlv.slow_oam_link_event->threshold), 603 EXTRACT_64BITS(&tlv.slow_oam_link_event->errors), 604 EXTRACT_64BITS(&tlv.slow_oam_link_event->errors_running_total), 605 EXTRACT_32BITS(&tlv.slow_oam_link_event->event_running_total))); 606 break; 607 608 case SLOW_OAM_LINK_EVENT_ORG_SPECIFIC: 609 hexdump = TRUE; 610 break; 611 612 default: 613 hexdump = TRUE; 614 break; 615 } 616 617 /* infinite loop check */ 618 if (!ptr.slow_oam_tlv_header->length) { 619 return; 620 } 621 622 /* do we also want to see a hex dump ? */ 623 if (ndo->ndo_vflag > 1 || hexdump==TRUE) { 624 print_unknown_data(ndo, tptr, "\n\t ", 625 ptr.slow_oam_tlv_header->length); 626 } 627 628 tlen -= ptr.slow_oam_tlv_header->length; 629 tptr += ptr.slow_oam_tlv_header->length; 630 } 631 break; 632 633 case SLOW_OAM_CODE_LOOPBACK_CTRL: 634 tlv.slow_oam_loopbackctrl = (const struct slow_oam_loopbackctrl_t *)tptr; 635 ND_PRINT((ndo, "\n\t Command %s (%u)", 636 tok2str(slow_oam_loopbackctrl_cmd_values, 637 "Unknown", 638 tlv.slow_oam_loopbackctrl->command), 639 tlv.slow_oam_loopbackctrl->command)); 640 tptr ++; 641 tlen --; 642 break; 643 644 /* 645 * FIXME those are the defined codes that lack a decoder 646 * you are welcome to contribute code ;-) 647 */ 648 case SLOW_OAM_CODE_VAR_REQUEST: 649 case SLOW_OAM_CODE_VAR_RESPONSE: 650 case SLOW_OAM_CODE_PRIVATE: 651 default: 652 if (ndo->ndo_vflag <= 1) { 653 print_unknown_data(ndo, tptr, "\n\t ", tlen); 654 } 655 break; 656 } 657 return; 658} 659