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