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