]> The Tcpdump Group git mirrors - tcpdump/blob - print-slow.c
continue work on the 802.3AH printer:
[tcpdump] / print-slow.c
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@juniper.net)
19 */
20
21 #ifndef lint
22 static const char rcsid[] _U_ =
23 "@(#) $Header: /tcpdump/master/tcpdump/print-slow.c,v 1.5 2006-05-18 08:23:26 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;
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 static const struct tok slow_oam_loopbackctrl_cmd_values[] = {
182 { 0x01, "Enable OAM Remote Loopback" },
183 { 0x02, "Disable OAM Remote Loopback" },
184 { 0, NULL}
185 };
186
187 struct tlv_header_t {
188 u_int8_t type;
189 u_int8_t length;
190 };
191
192 #define LACP_TLV_TERMINATOR 0x00
193 #define LACP_TLV_ACTOR_INFO 0x01
194 #define LACP_TLV_PARTNER_INFO 0x02
195 #define LACP_TLV_COLLECTOR_INFO 0x03
196
197 #define MARKER_TLV_TERMINATOR 0x00
198 #define MARKER_TLV_MARKER_INFO 0x01
199
200 static const struct tok slow_tlv_values[] = {
201 { (SLOW_PROTO_LACP << 8) + LACP_TLV_TERMINATOR, "Terminator"},
202 { (SLOW_PROTO_LACP << 8) + LACP_TLV_ACTOR_INFO, "Actor Information"},
203 { (SLOW_PROTO_LACP << 8) + LACP_TLV_PARTNER_INFO, "Partner Information"},
204 { (SLOW_PROTO_LACP << 8) + LACP_TLV_COLLECTOR_INFO, "Collector Information"},
205
206 { (SLOW_PROTO_MARKER << 8) + MARKER_TLV_TERMINATOR, "Terminator"},
207 { (SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_INFO, "Marker Information"},
208 { 0, NULL}
209 };
210
211 struct lacp_tlv_actor_partner_info_t {
212 u_int8_t sys_pri[2];
213 u_int8_t sys[ETHER_ADDR_LEN];
214 u_int8_t key[2];
215 u_int8_t port_pri[2];
216 u_int8_t port[2];
217 u_int8_t state;
218 u_int8_t pad[3];
219 };
220
221 static const struct tok lacp_tlv_actor_partner_info_state_values[] = {
222 { 0x01, "Activity"},
223 { 0x02, "Timeout"},
224 { 0x04, "Aggregation"},
225 { 0x08, "Synchronization"},
226 { 0x10, "Collecting"},
227 { 0x20, "Distributing"},
228 { 0x40, "Default"},
229 { 0x80, "Expired"},
230 { 0, NULL}
231 };
232
233 struct lacp_tlv_collector_info_t {
234 u_int8_t max_delay[2];
235 u_int8_t pad[12];
236 };
237
238 struct marker_tlv_marker_info_t {
239 u_int8_t req_port[2];
240 u_int8_t req_sys[ETHER_ADDR_LEN];
241 u_int8_t req_trans_id[4];
242 u_int8_t pad[2];
243 };
244
245 struct lacp_marker_tlv_terminator_t {
246 u_int8_t pad[50];
247 };
248
249 void slow_marker_lacp_print(register const u_char *, register u_int);
250 void slow_oam_print(register const u_char *, register u_int);
251
252 const struct slow_common_header_t *slow_com_header;
253
254 void
255 slow_print(register const u_char *pptr, register u_int len) {
256
257 int print_version;
258
259 slow_com_header = (const struct slow_common_header_t *)pptr;
260 TCHECK(*slow_com_header);
261
262 /*
263 * Sanity checking of the header.
264 */
265 switch (slow_com_header->proto_subtype) {
266 case SLOW_PROTO_LACP:
267 if (slow_com_header->version != LACP_VERSION) {
268 printf("LACP version %u packet not supported",slow_com_header->version);
269 return;
270 }
271 print_version = 1;
272 break;
273
274 case SLOW_PROTO_MARKER:
275 if (slow_com_header->version != MARKER_VERSION) {
276 printf("MARKER version %u packet not supported",slow_com_header->version);
277 return;
278 }
279 print_version = 1;
280 break;
281
282 case SLOW_PROTO_OAM: /* fall through */
283 print_version = 0;
284 break;
285
286 default:
287 /* print basic information and exit */
288 print_version = -1;
289 break;
290 }
291
292 if (print_version) {
293 printf("%sv%u, length %u",
294 tok2str(slow_proto_values, "unknown (%u)",slow_com_header->proto_subtype),
295 slow_com_header->version,
296 len);
297 } else {
298 /* some slow protos don't have a version number in the header */
299 printf("%s, length %u",
300 tok2str(slow_proto_values, "unknown (%u)",slow_com_header->proto_subtype),
301 len);
302 }
303
304 /* unrecognized subtype */
305 if (print_version == -1) {
306 print_unknown_data(pptr, "\n\t", len);
307 return;
308 }
309
310 if (!vflag)
311 return;
312
313 switch (slow_com_header->proto_subtype) {
314 default: /* should not happen */
315 break;
316
317 case SLOW_PROTO_OAM:
318 /* skip proto_subtype */
319 slow_oam_print(pptr+1, len-1);
320 break;
321
322 case SLOW_PROTO_LACP: /* LACP and MARKER share the same semantics */
323 case SLOW_PROTO_MARKER:
324 /* skip slow_common_header */
325 len -= sizeof(const struct slow_common_header_t);
326 pptr += sizeof(const struct slow_common_header_t);
327 slow_marker_lacp_print(pptr, len);
328 break;
329 }
330 return;
331
332 trunc:
333 printf("\n\t\t packet exceeded snapshot");
334 }
335
336 void slow_marker_lacp_print(register const u_char *tptr, register u_int tlen) {
337
338 const struct tlv_header_t *tlv_header;
339 const u_char *tlv_tptr;
340 u_int tlv_len, tlv_tlen;
341
342 union {
343 const struct lacp_marker_tlv_terminator_t *lacp_marker_tlv_terminator;
344 const struct lacp_tlv_actor_partner_info_t *lacp_tlv_actor_partner_info;
345 const struct lacp_tlv_collector_info_t *lacp_tlv_collector_info;
346 const struct marker_tlv_marker_info_t *marker_tlv_marker_info;
347 } tlv_ptr;
348
349 while(tlen>0) {
350 /* did we capture enough for fully decoding the tlv header ? */
351 TCHECK2(*tptr, sizeof(struct tlv_header_t));
352 tlv_header = (const struct tlv_header_t *)tptr;
353 tlv_len = tlv_header->length;
354
355 printf("\n\t%s TLV (0x%02x), length %u",
356 tok2str(slow_tlv_values,
357 "Unknown",
358 (slow_com_header->proto_subtype << 8) + tlv_header->type),
359 tlv_header->type,
360 tlv_len);
361
362 if ((tlv_len < sizeof(struct tlv_header_t) ||
363 tlv_len > tlen) &&
364 tlv_header->type != LACP_TLV_TERMINATOR &&
365 tlv_header->type != MARKER_TLV_TERMINATOR) {
366 printf("\n\t-----trailing data-----");
367 print_unknown_data(tptr+sizeof(sizeof(struct tlv_header_t)),"\n\t ",tlen);
368 return;
369 }
370
371 tlv_tptr=tptr+sizeof(struct tlv_header_t);
372 tlv_tlen=tlv_len-sizeof(struct tlv_header_t);
373
374 /* did we capture enough for fully decoding the tlv ? */
375 TCHECK2(*tptr, tlv_len);
376
377 switch((slow_com_header->proto_subtype << 8) + tlv_header->type) {
378
379 /* those two TLVs have the same structure -> fall through */
380 case ((SLOW_PROTO_LACP << 8) + LACP_TLV_ACTOR_INFO):
381 case ((SLOW_PROTO_LACP << 8) + LACP_TLV_PARTNER_INFO):
382 tlv_ptr.lacp_tlv_actor_partner_info = (const struct lacp_tlv_actor_partner_info_t *)tlv_tptr;
383
384 printf("\n\t System %s, System Priority %u, Key %u" \
385 ", Port %u, Port Priority %u\n\t State Flags [%s]",
386 etheraddr_string(tlv_ptr.lacp_tlv_actor_partner_info->sys),
387 EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->sys_pri),
388 EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->key),
389 EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->port),
390 EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->port_pri),
391 bittok2str(lacp_tlv_actor_partner_info_state_values,
392 "none",
393 tlv_ptr.lacp_tlv_actor_partner_info->state));
394
395 break;
396
397 case ((SLOW_PROTO_LACP << 8) + LACP_TLV_COLLECTOR_INFO):
398 tlv_ptr.lacp_tlv_collector_info = (const struct lacp_tlv_collector_info_t *)tlv_tptr;
399
400 printf("\n\t Max Delay %u",
401 EXTRACT_16BITS(tlv_ptr.lacp_tlv_collector_info->max_delay));
402
403 break;
404
405 case ((SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_INFO):
406 tlv_ptr.marker_tlv_marker_info = (const struct marker_tlv_marker_info_t *)tlv_tptr;
407
408 printf("\n\t Request System %s, Request Port %u, Request Transaction ID 0x%08x",
409 etheraddr_string(tlv_ptr.marker_tlv_marker_info->req_sys),
410 EXTRACT_16BITS(tlv_ptr.marker_tlv_marker_info->req_port),
411 EXTRACT_32BITS(tlv_ptr.marker_tlv_marker_info->req_trans_id));
412
413 break;
414
415 /* those two TLVs have the same structure -> fall through */
416 case ((SLOW_PROTO_LACP << 8) + LACP_TLV_TERMINATOR):
417 case ((SLOW_PROTO_MARKER << 8) + LACP_TLV_TERMINATOR):
418 tlv_ptr.lacp_marker_tlv_terminator = (const struct lacp_marker_tlv_terminator_t *)tlv_tptr;
419 if (tlv_len == 0) {
420 tlv_len = sizeof(tlv_ptr.lacp_marker_tlv_terminator->pad) +
421 sizeof(struct tlv_header_t);
422 /* tell the user that we modified the length field */
423 if (vflag>1)
424 printf(" (=%u)",tlv_len);
425 /* we have messed around with the length field - now we need to check
426 * again if there are enough bytes on the wire for the hexdump */
427 TCHECK2(tlv_ptr.lacp_marker_tlv_terminator->pad[0],
428 sizeof(tlv_ptr.lacp_marker_tlv_terminator->pad));
429 }
430
431 break;
432
433 default:
434 if (vflag <= 1)
435 print_unknown_data(tlv_tptr,"\n\t ",tlv_tlen);
436 break;
437 }
438 /* do we want to see an additional hexdump ? */
439 if (vflag > 1) {
440 print_unknown_data(tptr+sizeof(sizeof(struct tlv_header_t)),"\n\t ",
441 tlv_len-sizeof(struct tlv_header_t));
442 }
443
444 tptr+=tlv_len;
445 tlen-=tlv_len;
446 }
447 return;
448 trunc:
449 printf("\n\t\t packet exceeded snapshot");
450 }
451
452 void slow_oam_print(register const u_char *tptr, register u_int tlen) {
453
454 u_int hexdump;
455
456 struct slow_oam_common_header_t {
457 u_int8_t flags[2];
458 u_int8_t code;
459 };
460
461 struct slow_oam_tlv_header_t {
462 u_int8_t type;
463 u_int8_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 } tlv;
477
478 ptr.slow_oam_common_header = (struct slow_oam_common_header_t *)tptr;
479 tptr += sizeof(struct slow_oam_common_header_t);
480 tlen -= sizeof(struct slow_oam_common_header_t);
481
482 printf("\n\tCode %s OAM PDU, Flags [%s]",
483 tok2str(slow_oam_code_values, "Unknown (%u)", ptr.slow_oam_common_header->code),
484 bittok2str(slow_oam_flag_values,
485 "none",
486 EXTRACT_16BITS(&ptr.slow_oam_common_header->flags)));
487
488 switch (ptr.slow_oam_common_header->code) {
489 case SLOW_OAM_CODE_INFO:
490 while (tlen > 0) {
491 ptr.slow_oam_tlv_header = (const struct slow_oam_tlv_header_t *)tptr;
492 printf("\n\t %s Information Type (%u), length %u",
493 tok2str(slow_oam_info_type_values, "Reserved",
494 ptr.slow_oam_tlv_header->type),
495 ptr.slow_oam_tlv_header->type,
496 ptr.slow_oam_tlv_header->length);
497
498 hexdump = FALSE;
499 switch (ptr.slow_oam_tlv_header->type) {
500 case SLOW_OAM_INFO_TYPE_END_OF_TLV:
501 if (ptr.slow_oam_tlv_header->length != 0) {
502 printf("\n\t ERROR: illegal length - should be 0");
503 }
504 return;
505
506 case SLOW_OAM_INFO_TYPE_LOCAL: /* identical format - fall through */
507 case SLOW_OAM_INFO_TYPE_REMOTE:
508 tlv.slow_oam_info = (const struct slow_oam_info_t *)tptr;
509
510 if (tlv.slow_oam_info->info_length !=
511 sizeof(struct slow_oam_info_t)) {
512 printf("\n\t ERROR: illegal length - should be %u",
513 sizeof(struct slow_oam_info_t));
514 return;
515 }
516
517 printf("\n\t OAM-Version %u, Revision %u",
518 tlv.slow_oam_info->oam_version,
519 EXTRACT_16BITS(&tlv.slow_oam_info->revision));
520
521 printf("\n\t State-MUX-Action %s, State-Parser-Action %s",
522 tok2str(slow_oam_info_type_state_parser_values, "Reserved",
523 tlv.slow_oam_info->state & OAM_INFO_TYPE_PARSER_MASK),
524 tok2str(slow_oam_info_type_state_mux_values, "Reserved",
525 tlv.slow_oam_info->state & OAM_INFO_TYPE_MUX_MASK));
526 printf("\n\t OAM-Config Flags [%s], OAM-PDU-Config max-PDU size %u",
527 bittok2str(slow_oam_info_type_oam_config_values, "none",
528 tlv.slow_oam_info->oam_config),
529 EXTRACT_16BITS(&tlv.slow_oam_info->oam_pdu_config) &
530 OAM_INFO_TYPE_PDU_SIZE_MASK);
531 printf("\n\t OUI %s (0x%06x), Vendor-Private 0x%08x",
532 tok2str(oui_values, "Unknown",
533 EXTRACT_24BITS(&tlv.slow_oam_info->oui)),
534 EXTRACT_24BITS(&tlv.slow_oam_info->oui),
535 EXTRACT_32BITS(&tlv.slow_oam_info->vendor_private));
536 break;
537
538 case SLOW_OAM_INFO_TYPE_ORG_SPECIFIC:
539 hexdump = TRUE;
540 break;
541
542 default:
543 hexdump = TRUE;
544 break;
545 }
546
547 /* infinite loop check */
548 if (!ptr.slow_oam_tlv_header->length) {
549 return;
550 }
551
552 /* do we also want to see a hex dump ? */
553 if (vflag > 1 || hexdump==TRUE) {
554 print_unknown_data(tptr,"\n\t ",
555 ptr.slow_oam_tlv_header->length);
556 }
557
558 tlen -= ptr.slow_oam_tlv_header->length;
559 tptr += ptr.slow_oam_tlv_header->length;
560 }
561 break;
562
563 case SLOW_OAM_CODE_EVENT_NOTIF:
564 while (tlen > 0) {
565 ptr.slow_oam_tlv_header = (const struct slow_oam_tlv_header_t *)tptr;
566 printf("\n\t %s Link Event Type (%u), length %u",
567 tok2str(slow_oam_link_event_values, "Reserved",
568 ptr.slow_oam_tlv_header->type),
569 ptr.slow_oam_tlv_header->type,
570 ptr.slow_oam_tlv_header->length);
571
572 hexdump = FALSE;
573 switch (ptr.slow_oam_tlv_header->type) {
574 case SLOW_OAM_LINK_EVENT_END_OF_TLV:
575 if (ptr.slow_oam_tlv_header->length != 0) {
576 printf("\n\t ERROR: illegal length - should be 0");
577 }
578 return;
579
580 case SLOW_OAM_LINK_EVENT_ERR_SYM_PER: /* identical format - fall through */
581 case SLOW_OAM_LINK_EVENT_ERR_FRM:
582 case SLOW_OAM_LINK_EVENT_ERR_FRM_PER:
583 case SLOW_OAM_LINK_EVENT_ERR_FRM_SUMM:
584 tlv.slow_oam_link_event = (const struct slow_oam_link_event_t *)tptr;
585
586 if (tlv.slow_oam_link_event->event_length !=
587 sizeof(struct slow_oam_link_event_t)) {
588 printf("\n\t ERROR: illegal length - should be %u",
589 sizeof(struct slow_oam_link_event_t));
590 return;
591 }
592
593 printf("\n\t Timestamp %u ms, Errored Window %" PRIu64
594 "\n\t Errored Threshold %" PRIu64
595 "\n\t Errors %" PRIu64
596 "\n\t Error Running Total %" PRIu64
597 "\n\t Event Running Total %u",
598 EXTRACT_16BITS(&tlv.slow_oam_link_event->time_stamp)*100,
599 EXTRACT_64BITS(&tlv.slow_oam_link_event->window),
600 EXTRACT_64BITS(&tlv.slow_oam_link_event->threshold),
601 EXTRACT_64BITS(&tlv.slow_oam_link_event->errors),
602 EXTRACT_64BITS(&tlv.slow_oam_link_event->errors_running_total),
603 EXTRACT_32BITS(&tlv.slow_oam_link_event->event_running_total));
604 break;
605
606 case SLOW_OAM_LINK_EVENT_ORG_SPECIFIC:
607 hexdump = TRUE;
608 break;
609
610 default:
611 hexdump = TRUE;
612 break;
613 }
614
615 /* infinite loop check */
616 if (!ptr.slow_oam_tlv_header->length) {
617 return;
618 }
619
620 /* do we also want to see a hex dump ? */
621 if (vflag > 1 || hexdump==TRUE) {
622 print_unknown_data(tptr,"\n\t ",
623 ptr.slow_oam_tlv_header->length);
624 }
625
626 tlen -= ptr.slow_oam_tlv_header->length;
627 tptr += ptr.slow_oam_tlv_header->length;
628 }
629 break;
630
631 /*
632 * FIXME those are the defined codes that lack a decoder
633 * you are welcome to contribute code ;-)
634 */
635 case SLOW_OAM_CODE_VAR_REQUEST:
636 case SLOW_OAM_CODE_VAR_RESPONSE:
637 case SLOW_OAM_CODE_LOOPBACK_CTRL:
638 case SLOW_OAM_CODE_PRIVATE:
639 default:
640 if (vflag <= 1) {
641 print_unknown_data(tptr,"\n\t ", tlen);
642 }
643 break;
644 }
645 return;
646 }