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