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