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