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