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