1162017Ssam/* 2190207Srpaulo * Copyright (c) 1998-2006 The TCPDUMP project 3162017Ssam * 4162017Ssam * Redistribution and use in source and binary forms, with or without 5162017Ssam * modification, are permitted provided that: (1) source code 6162017Ssam * distributions retain the above copyright notice and this paragraph 7162017Ssam * in its entirety, and (2) distributions including binary code include 8162017Ssam * the above copyright notice and this paragraph in its entirety in 9162017Ssam * the documentation or other materials provided with the distribution. 10162017Ssam * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 11162017Ssam * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT 12162017Ssam * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 13162017Ssam * FOR A PARTICULAR PURPOSE. 14162017Ssam * 15162017Ssam * support for the IEEE "slow protocols" LACP, MARKER as per 802.3ad 16190207Srpaulo * OAM as per 802.3ah 17162017Ssam * 18162017Ssam * Original code by Hannes Gredler (hannes@juniper.net) 19162017Ssam */ 20162017Ssam 21162017Ssam#ifndef lint 22162017Ssamstatic const char rcsid[] _U_ = 23190207Srpaulo "@(#) $Header: /tcpdump/master/tcpdump/print-slow.c,v 1.8 2006-10-12 05:44:33 hannes Exp $"; 24162017Ssam#endif 25162017Ssam 26162017Ssam#ifdef HAVE_CONFIG_H 27162017Ssam#include "config.h" 28162017Ssam#endif 29162017Ssam 30162017Ssam#include <tcpdump-stdinc.h> 31162017Ssam 32162017Ssam#include <stdio.h> 33162017Ssam#include <stdlib.h> 34162017Ssam#include <string.h> 35162017Ssam 36162017Ssam#include "interface.h" 37162017Ssam#include "extract.h" 38162017Ssam#include "addrtoname.h" 39162017Ssam#include "ether.h" 40190207Srpaulo#include "oui.h" 41162017Ssam 42190207Srpaulostruct slow_common_header_t { 43162017Ssam u_int8_t proto_subtype; 44162017Ssam u_int8_t version; 45162017Ssam}; 46162017Ssam 47162017Ssam#define SLOW_PROTO_LACP 1 48162017Ssam#define SLOW_PROTO_MARKER 2 49190207Srpaulo#define SLOW_PROTO_OAM 3 50162017Ssam 51162017Ssam#define LACP_VERSION 1 52162017Ssam#define MARKER_VERSION 1 53162017Ssam 54162017Ssamstatic const struct tok slow_proto_values[] = { 55162017Ssam { SLOW_PROTO_LACP, "LACP" }, 56162017Ssam { SLOW_PROTO_MARKER, "MARKER" }, 57190207Srpaulo { SLOW_PROTO_OAM, "OAM" }, 58162017Ssam { 0, NULL} 59162017Ssam}; 60162017Ssam 61190207Srpaulostatic const struct tok slow_oam_flag_values[] = { 62190207Srpaulo { 0x0001, "Link Fault" }, 63190207Srpaulo { 0x0002, "Dying Gasp" }, 64190207Srpaulo { 0x0004, "Critical Event" }, 65190207Srpaulo { 0x0008, "Local Evaluating" }, 66190207Srpaulo { 0x0010, "Local Stable" }, 67190207Srpaulo { 0x0020, "Remote Evaluating" }, 68190207Srpaulo { 0x0040, "Remote Stable" }, 69190207Srpaulo { 0, NULL} 70190207Srpaulo}; 71190207Srpaulo 72190207Srpaulo#define SLOW_OAM_CODE_INFO 0x00 73190207Srpaulo#define SLOW_OAM_CODE_EVENT_NOTIF 0x01 74190207Srpaulo#define SLOW_OAM_CODE_VAR_REQUEST 0x02 75190207Srpaulo#define SLOW_OAM_CODE_VAR_RESPONSE 0x03 76190207Srpaulo#define SLOW_OAM_CODE_LOOPBACK_CTRL 0x04 77190207Srpaulo#define SLOW_OAM_CODE_PRIVATE 0xfe 78190207Srpaulo 79190207Srpaulostatic const struct tok slow_oam_code_values[] = { 80190207Srpaulo { SLOW_OAM_CODE_INFO, "Information" }, 81190207Srpaulo { SLOW_OAM_CODE_EVENT_NOTIF, "Event Notification" }, 82190207Srpaulo { SLOW_OAM_CODE_VAR_REQUEST, "Variable Request" }, 83190207Srpaulo { SLOW_OAM_CODE_VAR_RESPONSE, "Variable Response" }, 84190207Srpaulo { SLOW_OAM_CODE_LOOPBACK_CTRL, "Loopback Control" }, 85190207Srpaulo { SLOW_OAM_CODE_PRIVATE, "Vendor Private" }, 86190207Srpaulo { 0, NULL} 87190207Srpaulo}; 88190207Srpaulo 89190207Srpaulostruct slow_oam_info_t { 90190207Srpaulo u_int8_t info_type; 91190207Srpaulo u_int8_t info_length; 92190207Srpaulo u_int8_t oam_version; 93190207Srpaulo u_int8_t revision[2]; 94190207Srpaulo u_int8_t state; 95190207Srpaulo u_int8_t oam_config; 96190207Srpaulo u_int8_t oam_pdu_config[2]; 97190207Srpaulo u_int8_t oui[3]; 98190207Srpaulo u_int8_t vendor_private[4]; 99190207Srpaulo}; 100190207Srpaulo 101190207Srpaulo#define SLOW_OAM_INFO_TYPE_END_OF_TLV 0x00 102190207Srpaulo#define SLOW_OAM_INFO_TYPE_LOCAL 0x01 103190207Srpaulo#define SLOW_OAM_INFO_TYPE_REMOTE 0x02 104190207Srpaulo#define SLOW_OAM_INFO_TYPE_ORG_SPECIFIC 0xfe 105190207Srpaulo 106190207Srpaulostatic const struct tok slow_oam_info_type_values[] = { 107190207Srpaulo { SLOW_OAM_INFO_TYPE_END_OF_TLV, "End of TLV marker" }, 108190207Srpaulo { SLOW_OAM_INFO_TYPE_LOCAL, "Local" }, 109190207Srpaulo { SLOW_OAM_INFO_TYPE_REMOTE, "Remote" }, 110190207Srpaulo { SLOW_OAM_INFO_TYPE_ORG_SPECIFIC, "Organization specific" }, 111190207Srpaulo { 0, NULL} 112190207Srpaulo}; 113190207Srpaulo 114190207Srpaulo#define OAM_INFO_TYPE_PARSER_MASK 0x3 115190207Srpaulostatic const struct tok slow_oam_info_type_state_parser_values[] = { 116190207Srpaulo { 0x00, "forwarding" }, 117190207Srpaulo { 0x01, "looping back" }, 118190207Srpaulo { 0x02, "discarding" }, 119190207Srpaulo { 0x03, "reserved" }, 120190207Srpaulo { 0, NULL} 121190207Srpaulo}; 122190207Srpaulo 123190207Srpaulo#define OAM_INFO_TYPE_MUX_MASK 0x4 124190207Srpaulostatic const struct tok slow_oam_info_type_state_mux_values[] = { 125190207Srpaulo { 0x00, "forwarding" }, 126190207Srpaulo { 0x04, "discarding" }, 127190207Srpaulo { 0, NULL} 128190207Srpaulo}; 129190207Srpaulo 130190207Srpaulostatic const struct tok slow_oam_info_type_oam_config_values[] = { 131190207Srpaulo { 0x01, "Active" }, 132190207Srpaulo { 0x02, "Unidirectional" }, 133190207Srpaulo { 0x04, "Remote-Loopback" }, 134190207Srpaulo { 0x08, "Link-Events" }, 135190207Srpaulo { 0x10, "Variable-Retrieval" }, 136190207Srpaulo { 0, NULL} 137190207Srpaulo}; 138190207Srpaulo 139190207Srpaulo/* 11 Bits */ 140190207Srpaulo#define OAM_INFO_TYPE_PDU_SIZE_MASK 0x7ff 141190207Srpaulo 142190207Srpaulo#define SLOW_OAM_LINK_EVENT_END_OF_TLV 0x00 143190207Srpaulo#define SLOW_OAM_LINK_EVENT_ERR_SYM_PER 0x01 144190207Srpaulo#define SLOW_OAM_LINK_EVENT_ERR_FRM 0x02 145190207Srpaulo#define SLOW_OAM_LINK_EVENT_ERR_FRM_PER 0x03 146190207Srpaulo#define SLOW_OAM_LINK_EVENT_ERR_FRM_SUMM 0x04 147190207Srpaulo#define SLOW_OAM_LINK_EVENT_ORG_SPECIFIC 0xfe 148190207Srpaulo 149190207Srpaulostatic const struct tok slow_oam_link_event_values[] = { 150190207Srpaulo { SLOW_OAM_LINK_EVENT_END_OF_TLV, "End of TLV marker" }, 151190207Srpaulo { SLOW_OAM_LINK_EVENT_ERR_SYM_PER, "Errored Symbol Period Event" }, 152190207Srpaulo { SLOW_OAM_LINK_EVENT_ERR_FRM, "Errored Frame Event" }, 153190207Srpaulo { SLOW_OAM_LINK_EVENT_ERR_FRM_PER, "Errored Frame Period Event" }, 154190207Srpaulo { SLOW_OAM_LINK_EVENT_ERR_FRM_SUMM, "Errored Frame Seconds Summary Event" }, 155190207Srpaulo { SLOW_OAM_LINK_EVENT_ORG_SPECIFIC, "Organization specific" }, 156190207Srpaulo { 0, NULL} 157190207Srpaulo}; 158190207Srpaulo 159190207Srpaulostruct slow_oam_link_event_t { 160190207Srpaulo u_int8_t event_type; 161190207Srpaulo u_int8_t event_length; 162190207Srpaulo u_int8_t time_stamp[2]; 163190207Srpaulo u_int8_t window[8]; 164190207Srpaulo u_int8_t threshold[8]; 165190207Srpaulo u_int8_t errors[8]; 166190207Srpaulo u_int8_t errors_running_total[8]; 167190207Srpaulo u_int8_t event_running_total[4]; 168190207Srpaulo}; 169190207Srpaulo 170190207Srpaulostruct slow_oam_variablerequest_t { 171190207Srpaulo u_int8_t branch; 172190207Srpaulo u_int8_t leaf[2]; 173190207Srpaulo}; 174190207Srpaulo 175190207Srpaulostruct slow_oam_variableresponse_t { 176190207Srpaulo u_int8_t branch; 177190207Srpaulo u_int8_t leaf[2]; 178190207Srpaulo u_int8_t length; 179190207Srpaulo}; 180190207Srpaulo 181190207Srpaulostruct slow_oam_loopbackctrl_t { 182190207Srpaulo u_int8_t command; 183190207Srpaulo}; 184190207Srpaulo 185190207Srpaulostatic const struct tok slow_oam_loopbackctrl_cmd_values[] = { 186190207Srpaulo { 0x01, "Enable OAM Remote Loopback" }, 187190207Srpaulo { 0x02, "Disable OAM Remote Loopback" }, 188190207Srpaulo { 0, NULL} 189190207Srpaulo}; 190190207Srpaulo 191162017Ssamstruct tlv_header_t { 192162017Ssam u_int8_t type; 193162017Ssam u_int8_t length; 194162017Ssam}; 195162017Ssam 196162017Ssam#define LACP_TLV_TERMINATOR 0x00 197162017Ssam#define LACP_TLV_ACTOR_INFO 0x01 198162017Ssam#define LACP_TLV_PARTNER_INFO 0x02 199162017Ssam#define LACP_TLV_COLLECTOR_INFO 0x03 200162017Ssam 201162017Ssam#define MARKER_TLV_TERMINATOR 0x00 202162017Ssam#define MARKER_TLV_MARKER_INFO 0x01 203162017Ssam 204162017Ssamstatic const struct tok slow_tlv_values[] = { 205162017Ssam { (SLOW_PROTO_LACP << 8) + LACP_TLV_TERMINATOR, "Terminator"}, 206162017Ssam { (SLOW_PROTO_LACP << 8) + LACP_TLV_ACTOR_INFO, "Actor Information"}, 207162017Ssam { (SLOW_PROTO_LACP << 8) + LACP_TLV_PARTNER_INFO, "Partner Information"}, 208162017Ssam { (SLOW_PROTO_LACP << 8) + LACP_TLV_COLLECTOR_INFO, "Collector Information"}, 209162017Ssam 210162017Ssam { (SLOW_PROTO_MARKER << 8) + MARKER_TLV_TERMINATOR, "Terminator"}, 211162017Ssam { (SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_INFO, "Marker Information"}, 212162017Ssam { 0, NULL} 213162017Ssam}; 214162017Ssam 215162017Ssamstruct lacp_tlv_actor_partner_info_t { 216162017Ssam u_int8_t sys_pri[2]; 217162017Ssam u_int8_t sys[ETHER_ADDR_LEN]; 218162017Ssam u_int8_t key[2]; 219162017Ssam u_int8_t port_pri[2]; 220162017Ssam u_int8_t port[2]; 221162017Ssam u_int8_t state; 222162017Ssam u_int8_t pad[3]; 223162017Ssam}; 224162017Ssam 225162017Ssamstatic const struct tok lacp_tlv_actor_partner_info_state_values[] = { 226162017Ssam { 0x01, "Activity"}, 227162017Ssam { 0x02, "Timeout"}, 228162017Ssam { 0x04, "Aggregation"}, 229162017Ssam { 0x08, "Synchronization"}, 230162017Ssam { 0x10, "Collecting"}, 231162017Ssam { 0x20, "Distributing"}, 232162017Ssam { 0x40, "Default"}, 233162017Ssam { 0x80, "Expired"}, 234162017Ssam { 0, NULL} 235162017Ssam}; 236162017Ssam 237162017Ssamstruct lacp_tlv_collector_info_t { 238162017Ssam u_int8_t max_delay[2]; 239162017Ssam u_int8_t pad[12]; 240162017Ssam}; 241162017Ssam 242162017Ssamstruct marker_tlv_marker_info_t { 243162017Ssam u_int8_t req_port[2]; 244162017Ssam u_int8_t req_sys[ETHER_ADDR_LEN]; 245162017Ssam u_int8_t req_trans_id[4]; 246162017Ssam u_int8_t pad[2]; 247162017Ssam}; 248162017Ssam 249162017Ssamstruct lacp_marker_tlv_terminator_t { 250162017Ssam u_int8_t pad[50]; 251162017Ssam}; 252162017Ssam 253190207Srpaulovoid slow_marker_lacp_print(register const u_char *, register u_int); 254190207Srpaulovoid slow_oam_print(register const u_char *, register u_int); 255190207Srpaulo 256190207Srpauloconst struct slow_common_header_t *slow_com_header; 257190207Srpaulo 258162017Ssamvoid 259162017Ssamslow_print(register const u_char *pptr, register u_int len) { 260162017Ssam 261190207Srpaulo int print_version; 262162017Ssam 263190207Srpaulo slow_com_header = (const struct slow_common_header_t *)pptr; 264162017Ssam TCHECK(*slow_com_header); 265162017Ssam 266162017Ssam /* 267162017Ssam * Sanity checking of the header. 268162017Ssam */ 269190207Srpaulo switch (slow_com_header->proto_subtype) { 270190207Srpaulo case SLOW_PROTO_LACP: 271190207Srpaulo if (slow_com_header->version != LACP_VERSION) { 272190207Srpaulo printf("LACP version %u packet not supported",slow_com_header->version); 273190207Srpaulo return; 274190207Srpaulo } 275190207Srpaulo print_version = 1; 276190207Srpaulo break; 277190207Srpaulo 278190207Srpaulo case SLOW_PROTO_MARKER: 279190207Srpaulo if (slow_com_header->version != MARKER_VERSION) { 280190207Srpaulo printf("MARKER version %u packet not supported",slow_com_header->version); 281190207Srpaulo return; 282190207Srpaulo } 283190207Srpaulo print_version = 1; 284190207Srpaulo break; 285190207Srpaulo 286190207Srpaulo case SLOW_PROTO_OAM: /* fall through */ 287190207Srpaulo print_version = 0; 288190207Srpaulo break; 289190207Srpaulo 290190207Srpaulo default: 291190207Srpaulo /* print basic information and exit */ 292190207Srpaulo print_version = -1; 293190207Srpaulo break; 294162017Ssam } 295190207Srpaulo 296190207Srpaulo if (print_version) { 297190207Srpaulo printf("%sv%u, length %u", 298190207Srpaulo tok2str(slow_proto_values, "unknown (%u)",slow_com_header->proto_subtype), 299190207Srpaulo slow_com_header->version, 300190207Srpaulo len); 301190207Srpaulo } else { 302190207Srpaulo /* some slow protos don't have a version number in the header */ 303190207Srpaulo printf("%s, length %u", 304190207Srpaulo tok2str(slow_proto_values, "unknown (%u)",slow_com_header->proto_subtype), 305190207Srpaulo len); 306162017Ssam } 307162017Ssam 308190207Srpaulo /* unrecognized subtype */ 309190207Srpaulo if (print_version == -1) { 310190207Srpaulo print_unknown_data(pptr, "\n\t", len); 311190207Srpaulo return; 312190207Srpaulo } 313162017Ssam 314162017Ssam if (!vflag) 315162017Ssam return; 316162017Ssam 317190207Srpaulo switch (slow_com_header->proto_subtype) { 318190207Srpaulo default: /* should not happen */ 319190207Srpaulo break; 320162017Ssam 321190207Srpaulo case SLOW_PROTO_OAM: 322190207Srpaulo /* skip proto_subtype */ 323190207Srpaulo slow_oam_print(pptr+1, len-1); 324190207Srpaulo break; 325190207Srpaulo 326190207Srpaulo case SLOW_PROTO_LACP: /* LACP and MARKER share the same semantics */ 327190207Srpaulo case SLOW_PROTO_MARKER: 328190207Srpaulo /* skip slow_common_header */ 329190207Srpaulo len -= sizeof(const struct slow_common_header_t); 330190207Srpaulo pptr += sizeof(const struct slow_common_header_t); 331190207Srpaulo slow_marker_lacp_print(pptr, len); 332190207Srpaulo break; 333190207Srpaulo } 334190207Srpaulo return; 335190207Srpaulo 336190207Srpaulotrunc: 337190207Srpaulo printf("\n\t\t packet exceeded snapshot"); 338190207Srpaulo} 339190207Srpaulo 340190207Srpaulovoid slow_marker_lacp_print(register const u_char *tptr, register u_int tlen) { 341190207Srpaulo 342190207Srpaulo const struct tlv_header_t *tlv_header; 343190207Srpaulo const u_char *tlv_tptr; 344190207Srpaulo u_int tlv_len, tlv_tlen; 345190207Srpaulo 346190207Srpaulo union { 347190207Srpaulo const struct lacp_marker_tlv_terminator_t *lacp_marker_tlv_terminator; 348190207Srpaulo const struct lacp_tlv_actor_partner_info_t *lacp_tlv_actor_partner_info; 349190207Srpaulo const struct lacp_tlv_collector_info_t *lacp_tlv_collector_info; 350190207Srpaulo const struct marker_tlv_marker_info_t *marker_tlv_marker_info; 351190207Srpaulo } tlv_ptr; 352190207Srpaulo 353162017Ssam while(tlen>0) { 354162017Ssam /* did we capture enough for fully decoding the tlv header ? */ 355162017Ssam TCHECK2(*tptr, sizeof(struct tlv_header_t)); 356162017Ssam tlv_header = (const struct tlv_header_t *)tptr; 357162017Ssam tlv_len = tlv_header->length; 358162017Ssam 359190207Srpaulo printf("\n\t%s TLV (0x%02x), length %u", 360162017Ssam tok2str(slow_tlv_values, 361162017Ssam "Unknown", 362162017Ssam (slow_com_header->proto_subtype << 8) + tlv_header->type), 363162017Ssam tlv_header->type, 364162017Ssam tlv_len); 365162017Ssam 366162017Ssam if ((tlv_len < sizeof(struct tlv_header_t) || 367162017Ssam tlv_len > tlen) && 368162017Ssam tlv_header->type != LACP_TLV_TERMINATOR && 369162017Ssam tlv_header->type != MARKER_TLV_TERMINATOR) { 370162017Ssam printf("\n\t-----trailing data-----"); 371228926Skevlo print_unknown_data(tptr+sizeof(struct tlv_header_t),"\n\t ",tlen); 372162017Ssam return; 373162017Ssam } 374162017Ssam 375162017Ssam tlv_tptr=tptr+sizeof(struct tlv_header_t); 376162017Ssam tlv_tlen=tlv_len-sizeof(struct tlv_header_t); 377162017Ssam 378162017Ssam /* did we capture enough for fully decoding the tlv ? */ 379162017Ssam TCHECK2(*tptr, tlv_len); 380162017Ssam 381162017Ssam switch((slow_com_header->proto_subtype << 8) + tlv_header->type) { 382162017Ssam 383162017Ssam /* those two TLVs have the same structure -> fall through */ 384162017Ssam case ((SLOW_PROTO_LACP << 8) + LACP_TLV_ACTOR_INFO): 385162017Ssam case ((SLOW_PROTO_LACP << 8) + LACP_TLV_PARTNER_INFO): 386162017Ssam tlv_ptr.lacp_tlv_actor_partner_info = (const struct lacp_tlv_actor_partner_info_t *)tlv_tptr; 387162017Ssam 388162017Ssam printf("\n\t System %s, System Priority %u, Key %u" \ 389162017Ssam ", Port %u, Port Priority %u\n\t State Flags [%s]", 390162017Ssam etheraddr_string(tlv_ptr.lacp_tlv_actor_partner_info->sys), 391162017Ssam EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->sys_pri), 392162017Ssam EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->key), 393162017Ssam EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->port), 394162017Ssam EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->port_pri), 395162017Ssam bittok2str(lacp_tlv_actor_partner_info_state_values, 396162017Ssam "none", 397162017Ssam tlv_ptr.lacp_tlv_actor_partner_info->state)); 398162017Ssam 399162017Ssam break; 400162017Ssam 401162017Ssam case ((SLOW_PROTO_LACP << 8) + LACP_TLV_COLLECTOR_INFO): 402162017Ssam tlv_ptr.lacp_tlv_collector_info = (const struct lacp_tlv_collector_info_t *)tlv_tptr; 403162017Ssam 404162017Ssam printf("\n\t Max Delay %u", 405162017Ssam EXTRACT_16BITS(tlv_ptr.lacp_tlv_collector_info->max_delay)); 406162017Ssam 407162017Ssam break; 408162017Ssam 409162017Ssam case ((SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_INFO): 410162017Ssam tlv_ptr.marker_tlv_marker_info = (const struct marker_tlv_marker_info_t *)tlv_tptr; 411162017Ssam 412162017Ssam printf("\n\t Request System %s, Request Port %u, Request Transaction ID 0x%08x", 413162017Ssam etheraddr_string(tlv_ptr.marker_tlv_marker_info->req_sys), 414162017Ssam EXTRACT_16BITS(tlv_ptr.marker_tlv_marker_info->req_port), 415162017Ssam EXTRACT_32BITS(tlv_ptr.marker_tlv_marker_info->req_trans_id)); 416162017Ssam 417162017Ssam break; 418162017Ssam 419162017Ssam /* those two TLVs have the same structure -> fall through */ 420162017Ssam case ((SLOW_PROTO_LACP << 8) + LACP_TLV_TERMINATOR): 421162017Ssam case ((SLOW_PROTO_MARKER << 8) + LACP_TLV_TERMINATOR): 422162017Ssam tlv_ptr.lacp_marker_tlv_terminator = (const struct lacp_marker_tlv_terminator_t *)tlv_tptr; 423162017Ssam if (tlv_len == 0) { 424162017Ssam tlv_len = sizeof(tlv_ptr.lacp_marker_tlv_terminator->pad) + 425162017Ssam sizeof(struct tlv_header_t); 426162017Ssam /* tell the user that we modified the length field */ 427162017Ssam if (vflag>1) 428162017Ssam printf(" (=%u)",tlv_len); 429162017Ssam /* we have messed around with the length field - now we need to check 430162017Ssam * again if there are enough bytes on the wire for the hexdump */ 431162017Ssam TCHECK2(tlv_ptr.lacp_marker_tlv_terminator->pad[0], 432162017Ssam sizeof(tlv_ptr.lacp_marker_tlv_terminator->pad)); 433162017Ssam } 434162017Ssam 435162017Ssam break; 436162017Ssam 437162017Ssam default: 438162017Ssam if (vflag <= 1) 439162017Ssam print_unknown_data(tlv_tptr,"\n\t ",tlv_tlen); 440162017Ssam break; 441162017Ssam } 442190207Srpaulo /* do we want to see an additional hexdump ? */ 443190207Srpaulo if (vflag > 1) { 444228926Skevlo print_unknown_data(tptr+sizeof(struct tlv_header_t),"\n\t ", 445162017Ssam tlv_len-sizeof(struct tlv_header_t)); 446190207Srpaulo } 447162017Ssam 448162017Ssam tptr+=tlv_len; 449162017Ssam tlen-=tlv_len; 450162017Ssam } 451162017Ssam return; 452162017Ssamtrunc: 453162017Ssam printf("\n\t\t packet exceeded snapshot"); 454162017Ssam} 455190207Srpaulo 456190207Srpaulovoid slow_oam_print(register const u_char *tptr, register u_int tlen) { 457190207Srpaulo 458190207Srpaulo u_int hexdump; 459190207Srpaulo 460190207Srpaulo struct slow_oam_common_header_t { 461190207Srpaulo u_int8_t flags[2]; 462190207Srpaulo u_int8_t code; 463190207Srpaulo }; 464190207Srpaulo 465190207Srpaulo struct slow_oam_tlv_header_t { 466190207Srpaulo u_int8_t type; 467190207Srpaulo u_int8_t length; 468190207Srpaulo }; 469190207Srpaulo 470190207Srpaulo union { 471190207Srpaulo const struct slow_oam_common_header_t *slow_oam_common_header; 472190207Srpaulo const struct slow_oam_tlv_header_t *slow_oam_tlv_header; 473190207Srpaulo } ptr; 474190207Srpaulo 475190207Srpaulo union { 476190207Srpaulo const struct slow_oam_info_t *slow_oam_info; 477190207Srpaulo const struct slow_oam_link_event_t *slow_oam_link_event; 478190207Srpaulo const struct slow_oam_variablerequest_t *slow_oam_variablerequest; 479190207Srpaulo const struct slow_oam_variableresponse_t *slow_oam_variableresponse; 480190207Srpaulo const struct slow_oam_loopbackctrl_t *slow_oam_loopbackctrl; 481190207Srpaulo } tlv; 482190207Srpaulo 483190207Srpaulo ptr.slow_oam_common_header = (struct slow_oam_common_header_t *)tptr; 484190207Srpaulo tptr += sizeof(struct slow_oam_common_header_t); 485190207Srpaulo tlen -= sizeof(struct slow_oam_common_header_t); 486190207Srpaulo 487190207Srpaulo printf("\n\tCode %s OAM PDU, Flags [%s]", 488190207Srpaulo tok2str(slow_oam_code_values, "Unknown (%u)", ptr.slow_oam_common_header->code), 489190207Srpaulo bittok2str(slow_oam_flag_values, 490190207Srpaulo "none", 491190207Srpaulo EXTRACT_16BITS(&ptr.slow_oam_common_header->flags))); 492190207Srpaulo 493190207Srpaulo switch (ptr.slow_oam_common_header->code) { 494190207Srpaulo case SLOW_OAM_CODE_INFO: 495190207Srpaulo while (tlen > 0) { 496190207Srpaulo ptr.slow_oam_tlv_header = (const struct slow_oam_tlv_header_t *)tptr; 497190207Srpaulo printf("\n\t %s Information Type (%u), length %u", 498190207Srpaulo tok2str(slow_oam_info_type_values, "Reserved", 499190207Srpaulo ptr.slow_oam_tlv_header->type), 500190207Srpaulo ptr.slow_oam_tlv_header->type, 501190207Srpaulo ptr.slow_oam_tlv_header->length); 502190207Srpaulo 503190207Srpaulo hexdump = FALSE; 504190207Srpaulo switch (ptr.slow_oam_tlv_header->type) { 505190207Srpaulo case SLOW_OAM_INFO_TYPE_END_OF_TLV: 506190207Srpaulo if (ptr.slow_oam_tlv_header->length != 0) { 507190207Srpaulo printf("\n\t ERROR: illegal length - should be 0"); 508190207Srpaulo } 509190207Srpaulo return; 510190207Srpaulo 511190207Srpaulo case SLOW_OAM_INFO_TYPE_LOCAL: /* identical format - fall through */ 512190207Srpaulo case SLOW_OAM_INFO_TYPE_REMOTE: 513190207Srpaulo tlv.slow_oam_info = (const struct slow_oam_info_t *)tptr; 514190207Srpaulo 515190207Srpaulo if (tlv.slow_oam_info->info_length != 516190207Srpaulo sizeof(struct slow_oam_info_t)) { 517190207Srpaulo printf("\n\t ERROR: illegal length - should be %lu", 518190207Srpaulo (unsigned long) sizeof(struct slow_oam_info_t)); 519190207Srpaulo return; 520190207Srpaulo } 521190207Srpaulo 522190207Srpaulo printf("\n\t OAM-Version %u, Revision %u", 523190207Srpaulo tlv.slow_oam_info->oam_version, 524190207Srpaulo EXTRACT_16BITS(&tlv.slow_oam_info->revision)); 525190207Srpaulo 526190207Srpaulo printf("\n\t State-Parser-Action %s, State-MUX-Action %s", 527190207Srpaulo tok2str(slow_oam_info_type_state_parser_values, "Reserved", 528190207Srpaulo tlv.slow_oam_info->state & OAM_INFO_TYPE_PARSER_MASK), 529190207Srpaulo tok2str(slow_oam_info_type_state_mux_values, "Reserved", 530190207Srpaulo tlv.slow_oam_info->state & OAM_INFO_TYPE_MUX_MASK)); 531190207Srpaulo printf("\n\t OAM-Config Flags [%s], OAM-PDU-Config max-PDU size %u", 532190207Srpaulo bittok2str(slow_oam_info_type_oam_config_values, "none", 533190207Srpaulo tlv.slow_oam_info->oam_config), 534190207Srpaulo EXTRACT_16BITS(&tlv.slow_oam_info->oam_pdu_config) & 535190207Srpaulo OAM_INFO_TYPE_PDU_SIZE_MASK); 536190207Srpaulo printf("\n\t OUI %s (0x%06x), Vendor-Private 0x%08x", 537190207Srpaulo tok2str(oui_values, "Unknown", 538190207Srpaulo EXTRACT_24BITS(&tlv.slow_oam_info->oui)), 539190207Srpaulo EXTRACT_24BITS(&tlv.slow_oam_info->oui), 540190207Srpaulo EXTRACT_32BITS(&tlv.slow_oam_info->vendor_private)); 541190207Srpaulo break; 542190207Srpaulo 543190207Srpaulo case SLOW_OAM_INFO_TYPE_ORG_SPECIFIC: 544190207Srpaulo hexdump = TRUE; 545190207Srpaulo break; 546190207Srpaulo 547190207Srpaulo default: 548190207Srpaulo hexdump = TRUE; 549190207Srpaulo break; 550190207Srpaulo } 551190207Srpaulo 552190207Srpaulo /* infinite loop check */ 553190207Srpaulo if (!ptr.slow_oam_tlv_header->length) { 554190207Srpaulo return; 555190207Srpaulo } 556190207Srpaulo 557190207Srpaulo /* do we also want to see a hex dump ? */ 558190207Srpaulo if (vflag > 1 || hexdump==TRUE) { 559190207Srpaulo print_unknown_data(tptr,"\n\t ", 560190207Srpaulo ptr.slow_oam_tlv_header->length); 561190207Srpaulo } 562190207Srpaulo 563190207Srpaulo tlen -= ptr.slow_oam_tlv_header->length; 564190207Srpaulo tptr += ptr.slow_oam_tlv_header->length; 565190207Srpaulo } 566190207Srpaulo break; 567190207Srpaulo 568190207Srpaulo case SLOW_OAM_CODE_EVENT_NOTIF: 569190207Srpaulo while (tlen > 0) { 570190207Srpaulo ptr.slow_oam_tlv_header = (const struct slow_oam_tlv_header_t *)tptr; 571190207Srpaulo printf("\n\t %s Link Event Type (%u), length %u", 572190207Srpaulo tok2str(slow_oam_link_event_values, "Reserved", 573190207Srpaulo ptr.slow_oam_tlv_header->type), 574190207Srpaulo ptr.slow_oam_tlv_header->type, 575190207Srpaulo ptr.slow_oam_tlv_header->length); 576190207Srpaulo 577190207Srpaulo hexdump = FALSE; 578190207Srpaulo switch (ptr.slow_oam_tlv_header->type) { 579190207Srpaulo case SLOW_OAM_LINK_EVENT_END_OF_TLV: 580190207Srpaulo if (ptr.slow_oam_tlv_header->length != 0) { 581190207Srpaulo printf("\n\t ERROR: illegal length - should be 0"); 582190207Srpaulo } 583190207Srpaulo return; 584190207Srpaulo 585190207Srpaulo case SLOW_OAM_LINK_EVENT_ERR_SYM_PER: /* identical format - fall through */ 586190207Srpaulo case SLOW_OAM_LINK_EVENT_ERR_FRM: 587190207Srpaulo case SLOW_OAM_LINK_EVENT_ERR_FRM_PER: 588190207Srpaulo case SLOW_OAM_LINK_EVENT_ERR_FRM_SUMM: 589190207Srpaulo tlv.slow_oam_link_event = (const struct slow_oam_link_event_t *)tptr; 590190207Srpaulo 591190207Srpaulo if (tlv.slow_oam_link_event->event_length != 592190207Srpaulo sizeof(struct slow_oam_link_event_t)) { 593190207Srpaulo printf("\n\t ERROR: illegal length - should be %lu", 594190207Srpaulo (unsigned long) sizeof(struct slow_oam_link_event_t)); 595190207Srpaulo return; 596190207Srpaulo } 597190207Srpaulo 598190207Srpaulo printf("\n\t Timestamp %u ms, Errored Window %" PRIu64 599190207Srpaulo "\n\t Errored Threshold %" PRIu64 600190207Srpaulo "\n\t Errors %" PRIu64 601190207Srpaulo "\n\t Error Running Total %" PRIu64 602190207Srpaulo "\n\t Event Running Total %u", 603190207Srpaulo EXTRACT_16BITS(&tlv.slow_oam_link_event->time_stamp)*100, 604190207Srpaulo EXTRACT_64BITS(&tlv.slow_oam_link_event->window), 605190207Srpaulo EXTRACT_64BITS(&tlv.slow_oam_link_event->threshold), 606190207Srpaulo EXTRACT_64BITS(&tlv.slow_oam_link_event->errors), 607190207Srpaulo EXTRACT_64BITS(&tlv.slow_oam_link_event->errors_running_total), 608190207Srpaulo EXTRACT_32BITS(&tlv.slow_oam_link_event->event_running_total)); 609190207Srpaulo break; 610190207Srpaulo 611190207Srpaulo case SLOW_OAM_LINK_EVENT_ORG_SPECIFIC: 612190207Srpaulo hexdump = TRUE; 613190207Srpaulo break; 614190207Srpaulo 615190207Srpaulo default: 616190207Srpaulo hexdump = TRUE; 617190207Srpaulo break; 618190207Srpaulo } 619190207Srpaulo 620190207Srpaulo /* infinite loop check */ 621190207Srpaulo if (!ptr.slow_oam_tlv_header->length) { 622190207Srpaulo return; 623190207Srpaulo } 624190207Srpaulo 625190207Srpaulo /* do we also want to see a hex dump ? */ 626190207Srpaulo if (vflag > 1 || hexdump==TRUE) { 627190207Srpaulo print_unknown_data(tptr,"\n\t ", 628190207Srpaulo ptr.slow_oam_tlv_header->length); 629190207Srpaulo } 630190207Srpaulo 631190207Srpaulo tlen -= ptr.slow_oam_tlv_header->length; 632190207Srpaulo tptr += ptr.slow_oam_tlv_header->length; 633190207Srpaulo } 634190207Srpaulo break; 635190207Srpaulo 636190207Srpaulo case SLOW_OAM_CODE_LOOPBACK_CTRL: 637190207Srpaulo tlv.slow_oam_loopbackctrl = (const struct slow_oam_loopbackctrl_t *)tptr; 638190207Srpaulo printf("\n\t Command %s (%u)", 639190207Srpaulo tok2str(slow_oam_loopbackctrl_cmd_values, 640190207Srpaulo "Unknown", 641190207Srpaulo tlv.slow_oam_loopbackctrl->command), 642190207Srpaulo tlv.slow_oam_loopbackctrl->command); 643190207Srpaulo tptr ++; 644190207Srpaulo tlen --; 645190207Srpaulo break; 646190207Srpaulo 647190207Srpaulo /* 648190207Srpaulo * FIXME those are the defined codes that lack a decoder 649190207Srpaulo * you are welcome to contribute code ;-) 650190207Srpaulo */ 651190207Srpaulo case SLOW_OAM_CODE_VAR_REQUEST: 652190207Srpaulo case SLOW_OAM_CODE_VAR_RESPONSE: 653190207Srpaulo case SLOW_OAM_CODE_PRIVATE: 654190207Srpaulo default: 655190207Srpaulo if (vflag <= 1) { 656190207Srpaulo print_unknown_data(tptr,"\n\t ", tlen); 657190207Srpaulo } 658190207Srpaulo break; 659190207Srpaulo } 660190207Srpaulo return; 661190207Srpaulo} 662