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