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