Home | History | Annotate | Line # | Download | only in dist
print-slow.c revision 1.1.1.9
      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 (at) 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