]> The Tcpdump Group git mirrors - tcpdump/blob - print-slow.c
CARP: NDOize
[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 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <tcpdump-stdinc.h>
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "interface.h"
32 #include "extract.h"
33 #include "addrtoname.h"
34 #include "ether.h"
35 #include "oui.h"
36
37 struct slow_common_header_t {
38 u_int8_t proto_subtype;
39 u_int8_t version;
40 };
41
42 #define SLOW_PROTO_LACP 1
43 #define SLOW_PROTO_MARKER 2
44 #define SLOW_PROTO_OAM 3
45
46 #define LACP_VERSION 1
47 #define MARKER_VERSION 1
48
49 static const struct tok slow_proto_values[] = {
50 { SLOW_PROTO_LACP, "LACP" },
51 { SLOW_PROTO_MARKER, "MARKER" },
52 { SLOW_PROTO_OAM, "OAM" },
53 { 0, NULL}
54 };
55
56 static const struct tok slow_oam_flag_values[] = {
57 { 0x0001, "Link Fault" },
58 { 0x0002, "Dying Gasp" },
59 { 0x0004, "Critical Event" },
60 { 0x0008, "Local Evaluating" },
61 { 0x0010, "Local Stable" },
62 { 0x0020, "Remote Evaluating" },
63 { 0x0040, "Remote Stable" },
64 { 0, NULL}
65 };
66
67 #define SLOW_OAM_CODE_INFO 0x00
68 #define SLOW_OAM_CODE_EVENT_NOTIF 0x01
69 #define SLOW_OAM_CODE_VAR_REQUEST 0x02
70 #define SLOW_OAM_CODE_VAR_RESPONSE 0x03
71 #define SLOW_OAM_CODE_LOOPBACK_CTRL 0x04
72 #define SLOW_OAM_CODE_PRIVATE 0xfe
73
74 static const struct tok slow_oam_code_values[] = {
75 { SLOW_OAM_CODE_INFO, "Information" },
76 { SLOW_OAM_CODE_EVENT_NOTIF, "Event Notification" },
77 { SLOW_OAM_CODE_VAR_REQUEST, "Variable Request" },
78 { SLOW_OAM_CODE_VAR_RESPONSE, "Variable Response" },
79 { SLOW_OAM_CODE_LOOPBACK_CTRL, "Loopback Control" },
80 { SLOW_OAM_CODE_PRIVATE, "Vendor Private" },
81 { 0, NULL}
82 };
83
84 struct slow_oam_info_t {
85 u_int8_t info_type;
86 u_int8_t info_length;
87 u_int8_t oam_version;
88 u_int8_t revision[2];
89 u_int8_t state;
90 u_int8_t oam_config;
91 u_int8_t oam_pdu_config[2];
92 u_int8_t oui[3];
93 u_int8_t vendor_private[4];
94 };
95
96 #define SLOW_OAM_INFO_TYPE_END_OF_TLV 0x00
97 #define SLOW_OAM_INFO_TYPE_LOCAL 0x01
98 #define SLOW_OAM_INFO_TYPE_REMOTE 0x02
99 #define SLOW_OAM_INFO_TYPE_ORG_SPECIFIC 0xfe
100
101 static const struct tok slow_oam_info_type_values[] = {
102 { SLOW_OAM_INFO_TYPE_END_OF_TLV, "End of TLV marker" },
103 { SLOW_OAM_INFO_TYPE_LOCAL, "Local" },
104 { SLOW_OAM_INFO_TYPE_REMOTE, "Remote" },
105 { SLOW_OAM_INFO_TYPE_ORG_SPECIFIC, "Organization specific" },
106 { 0, NULL}
107 };
108
109 #define OAM_INFO_TYPE_PARSER_MASK 0x3
110 static const struct tok slow_oam_info_type_state_parser_values[] = {
111 { 0x00, "forwarding" },
112 { 0x01, "looping back" },
113 { 0x02, "discarding" },
114 { 0x03, "reserved" },
115 { 0, NULL}
116 };
117
118 #define OAM_INFO_TYPE_MUX_MASK 0x4
119 static const struct tok slow_oam_info_type_state_mux_values[] = {
120 { 0x00, "forwarding" },
121 { 0x04, "discarding" },
122 { 0, NULL}
123 };
124
125 static const struct tok slow_oam_info_type_oam_config_values[] = {
126 { 0x01, "Active" },
127 { 0x02, "Unidirectional" },
128 { 0x04, "Remote-Loopback" },
129 { 0x08, "Link-Events" },
130 { 0x10, "Variable-Retrieval" },
131 { 0, NULL}
132 };
133
134 /* 11 Bits */
135 #define OAM_INFO_TYPE_PDU_SIZE_MASK 0x7ff
136
137 #define SLOW_OAM_LINK_EVENT_END_OF_TLV 0x00
138 #define SLOW_OAM_LINK_EVENT_ERR_SYM_PER 0x01
139 #define SLOW_OAM_LINK_EVENT_ERR_FRM 0x02
140 #define SLOW_OAM_LINK_EVENT_ERR_FRM_PER 0x03
141 #define SLOW_OAM_LINK_EVENT_ERR_FRM_SUMM 0x04
142 #define SLOW_OAM_LINK_EVENT_ORG_SPECIFIC 0xfe
143
144 static const struct tok slow_oam_link_event_values[] = {
145 { SLOW_OAM_LINK_EVENT_END_OF_TLV, "End of TLV marker" },
146 { SLOW_OAM_LINK_EVENT_ERR_SYM_PER, "Errored Symbol Period Event" },
147 { SLOW_OAM_LINK_EVENT_ERR_FRM, "Errored Frame Event" },
148 { SLOW_OAM_LINK_EVENT_ERR_FRM_PER, "Errored Frame Period Event" },
149 { SLOW_OAM_LINK_EVENT_ERR_FRM_SUMM, "Errored Frame Seconds Summary Event" },
150 { SLOW_OAM_LINK_EVENT_ORG_SPECIFIC, "Organization specific" },
151 { 0, NULL}
152 };
153
154 struct slow_oam_link_event_t {
155 u_int8_t event_type;
156 u_int8_t event_length;
157 u_int8_t time_stamp[2];
158 u_int8_t window[8];
159 u_int8_t threshold[8];
160 u_int8_t errors[8];
161 u_int8_t errors_running_total[8];
162 u_int8_t event_running_total[4];
163 };
164
165 struct slow_oam_variablerequest_t {
166 u_int8_t branch;
167 u_int8_t leaf[2];
168 };
169
170 struct slow_oam_variableresponse_t {
171 u_int8_t branch;
172 u_int8_t leaf[2];
173 u_int8_t length;
174 };
175
176 struct slow_oam_loopbackctrl_t {
177 u_int8_t command;
178 };
179
180 static const struct tok slow_oam_loopbackctrl_cmd_values[] = {
181 { 0x01, "Enable OAM Remote Loopback" },
182 { 0x02, "Disable OAM Remote Loopback" },
183 { 0, NULL}
184 };
185
186 struct tlv_header_t {
187 u_int8_t type;
188 u_int8_t length;
189 };
190
191 #define LACP_TLV_TERMINATOR 0x00
192 #define LACP_TLV_ACTOR_INFO 0x01
193 #define LACP_TLV_PARTNER_INFO 0x02
194 #define LACP_TLV_COLLECTOR_INFO 0x03
195
196 #define MARKER_TLV_TERMINATOR 0x00
197 #define MARKER_TLV_MARKER_INFO 0x01
198
199 static const struct tok slow_tlv_values[] = {
200 { (SLOW_PROTO_LACP << 8) + LACP_TLV_TERMINATOR, "Terminator"},
201 { (SLOW_PROTO_LACP << 8) + LACP_TLV_ACTOR_INFO, "Actor Information"},
202 { (SLOW_PROTO_LACP << 8) + LACP_TLV_PARTNER_INFO, "Partner Information"},
203 { (SLOW_PROTO_LACP << 8) + LACP_TLV_COLLECTOR_INFO, "Collector Information"},
204
205 { (SLOW_PROTO_MARKER << 8) + MARKER_TLV_TERMINATOR, "Terminator"},
206 { (SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_INFO, "Marker Information"},
207 { 0, NULL}
208 };
209
210 struct lacp_tlv_actor_partner_info_t {
211 u_int8_t sys_pri[2];
212 u_int8_t sys[ETHER_ADDR_LEN];
213 u_int8_t key[2];
214 u_int8_t port_pri[2];
215 u_int8_t port[2];
216 u_int8_t state;
217 u_int8_t pad[3];
218 };
219
220 static const struct tok lacp_tlv_actor_partner_info_state_values[] = {
221 { 0x01, "Activity"},
222 { 0x02, "Timeout"},
223 { 0x04, "Aggregation"},
224 { 0x08, "Synchronization"},
225 { 0x10, "Collecting"},
226 { 0x20, "Distributing"},
227 { 0x40, "Default"},
228 { 0x80, "Expired"},
229 { 0, NULL}
230 };
231
232 struct lacp_tlv_collector_info_t {
233 u_int8_t max_delay[2];
234 u_int8_t pad[12];
235 };
236
237 struct marker_tlv_marker_info_t {
238 u_int8_t req_port[2];
239 u_int8_t req_sys[ETHER_ADDR_LEN];
240 u_int8_t req_trans_id[4];
241 u_int8_t pad[2];
242 };
243
244 struct lacp_marker_tlv_terminator_t {
245 u_int8_t pad[50];
246 };
247
248 void slow_marker_lacp_print(register const u_char *, register u_int);
249 void slow_oam_print(register const u_char *, register u_int);
250
251 const struct slow_common_header_t *slow_com_header;
252
253 void
254 slow_print(register const u_char *pptr, register u_int len) {
255
256 int print_version;
257
258 slow_com_header = (const struct slow_common_header_t *)pptr;
259 TCHECK(*slow_com_header);
260
261 /*
262 * Sanity checking of the header.
263 */
264 switch (slow_com_header->proto_subtype) {
265 case SLOW_PROTO_LACP:
266 if (slow_com_header->version != LACP_VERSION) {
267 printf("LACP version %u packet not supported",slow_com_header->version);
268 return;
269 }
270 print_version = 1;
271 break;
272
273 case SLOW_PROTO_MARKER:
274 if (slow_com_header->version != MARKER_VERSION) {
275 printf("MARKER version %u packet not supported",slow_com_header->version);
276 return;
277 }
278 print_version = 1;
279 break;
280
281 case SLOW_PROTO_OAM: /* fall through */
282 print_version = 0;
283 break;
284
285 default:
286 /* print basic information and exit */
287 print_version = -1;
288 break;
289 }
290
291 if (print_version) {
292 printf("%sv%u, length %u",
293 tok2str(slow_proto_values, "unknown (%u)",slow_com_header->proto_subtype),
294 slow_com_header->version,
295 len);
296 } else {
297 /* some slow protos don't have a version number in the header */
298 printf("%s, length %u",
299 tok2str(slow_proto_values, "unknown (%u)",slow_com_header->proto_subtype),
300 len);
301 }
302
303 /* unrecognized subtype */
304 if (print_version == -1) {
305 print_unknown_data(gndo,pptr, "\n\t", len);
306 return;
307 }
308
309 if (!vflag)
310 return;
311
312 switch (slow_com_header->proto_subtype) {
313 default: /* should not happen */
314 break;
315
316 case SLOW_PROTO_OAM:
317 /* skip proto_subtype */
318 slow_oam_print(pptr+1, len-1);
319 break;
320
321 case SLOW_PROTO_LACP: /* LACP and MARKER share the same semantics */
322 case SLOW_PROTO_MARKER:
323 /* skip slow_common_header */
324 len -= sizeof(const struct slow_common_header_t);
325 pptr += sizeof(const struct slow_common_header_t);
326 slow_marker_lacp_print(pptr, len);
327 break;
328 }
329 return;
330
331 trunc:
332 printf("\n\t\t packet exceeded snapshot");
333 }
334
335 void slow_marker_lacp_print(register const u_char *tptr, register u_int tlen) {
336
337 const struct tlv_header_t *tlv_header;
338 const u_char *tlv_tptr;
339 u_int tlv_len, tlv_tlen;
340
341 union {
342 const struct lacp_marker_tlv_terminator_t *lacp_marker_tlv_terminator;
343 const struct lacp_tlv_actor_partner_info_t *lacp_tlv_actor_partner_info;
344 const struct lacp_tlv_collector_info_t *lacp_tlv_collector_info;
345 const struct marker_tlv_marker_info_t *marker_tlv_marker_info;
346 } tlv_ptr;
347
348 while(tlen>0) {
349 /* did we capture enough for fully decoding the tlv header ? */
350 TCHECK2(*tptr, sizeof(struct tlv_header_t));
351 tlv_header = (const struct tlv_header_t *)tptr;
352 tlv_len = tlv_header->length;
353
354 printf("\n\t%s TLV (0x%02x), length %u",
355 tok2str(slow_tlv_values,
356 "Unknown",
357 (slow_com_header->proto_subtype << 8) + tlv_header->type),
358 tlv_header->type,
359 tlv_len);
360
361 if ((tlv_len < sizeof(struct tlv_header_t) ||
362 tlv_len > tlen) &&
363 tlv_header->type != LACP_TLV_TERMINATOR &&
364 tlv_header->type != MARKER_TLV_TERMINATOR) {
365 printf("\n\t-----trailing data-----");
366 print_unknown_data(gndo,tptr+sizeof(struct tlv_header_t),"\n\t ",tlen);
367 return;
368 }
369
370 tlv_tptr=tptr+sizeof(struct tlv_header_t);
371 tlv_tlen=tlv_len-sizeof(struct tlv_header_t);
372
373 /* did we capture enough for fully decoding the tlv ? */
374 TCHECK2(*tptr, tlv_len);
375
376 switch((slow_com_header->proto_subtype << 8) + tlv_header->type) {
377
378 /* those two TLVs have the same structure -> fall through */
379 case ((SLOW_PROTO_LACP << 8) + LACP_TLV_ACTOR_INFO):
380 case ((SLOW_PROTO_LACP << 8) + LACP_TLV_PARTNER_INFO):
381 tlv_ptr.lacp_tlv_actor_partner_info = (const struct lacp_tlv_actor_partner_info_t *)tlv_tptr;
382
383 printf("\n\t System %s, System Priority %u, Key %u" \
384 ", Port %u, Port Priority %u\n\t State Flags [%s]",
385 etheraddr_string(tlv_ptr.lacp_tlv_actor_partner_info->sys),
386 EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->sys_pri),
387 EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->key),
388 EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->port),
389 EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->port_pri),
390 bittok2str(lacp_tlv_actor_partner_info_state_values,
391 "none",
392 tlv_ptr.lacp_tlv_actor_partner_info->state));
393
394 break;
395
396 case ((SLOW_PROTO_LACP << 8) + LACP_TLV_COLLECTOR_INFO):
397 tlv_ptr.lacp_tlv_collector_info = (const struct lacp_tlv_collector_info_t *)tlv_tptr;
398
399 printf("\n\t Max Delay %u",
400 EXTRACT_16BITS(tlv_ptr.lacp_tlv_collector_info->max_delay));
401
402 break;
403
404 case ((SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_INFO):
405 tlv_ptr.marker_tlv_marker_info = (const struct marker_tlv_marker_info_t *)tlv_tptr;
406
407 printf("\n\t Request System %s, Request Port %u, Request Transaction ID 0x%08x",
408 etheraddr_string(tlv_ptr.marker_tlv_marker_info->req_sys),
409 EXTRACT_16BITS(tlv_ptr.marker_tlv_marker_info->req_port),
410 EXTRACT_32BITS(tlv_ptr.marker_tlv_marker_info->req_trans_id));
411
412 break;
413
414 /* those two TLVs have the same structure -> fall through */
415 case ((SLOW_PROTO_LACP << 8) + LACP_TLV_TERMINATOR):
416 case ((SLOW_PROTO_MARKER << 8) + LACP_TLV_TERMINATOR):
417 tlv_ptr.lacp_marker_tlv_terminator = (const struct lacp_marker_tlv_terminator_t *)tlv_tptr;
418 if (tlv_len == 0) {
419 tlv_len = sizeof(tlv_ptr.lacp_marker_tlv_terminator->pad) +
420 sizeof(struct tlv_header_t);
421 /* tell the user that we modified the length field */
422 if (vflag>1)
423 printf(" (=%u)",tlv_len);
424 /* we have messed around with the length field - now we need to check
425 * again if there are enough bytes on the wire for the hexdump */
426 TCHECK2(tlv_ptr.lacp_marker_tlv_terminator->pad[0],
427 sizeof(tlv_ptr.lacp_marker_tlv_terminator->pad));
428 }
429
430 break;
431
432 default:
433 if (vflag <= 1)
434 print_unknown_data(gndo,tlv_tptr,"\n\t ",tlv_tlen);
435 break;
436 }
437 /* do we want to see an additional hexdump ? */
438 if (vflag > 1) {
439 print_unknown_data(gndo,tptr+sizeof(struct tlv_header_t),"\n\t ",
440 tlv_len-sizeof(struct tlv_header_t));
441 }
442
443 tptr+=tlv_len;
444 tlen-=tlv_len;
445 }
446 return;
447 trunc:
448 printf("\n\t\t packet exceeded snapshot");
449 }
450
451 void slow_oam_print(register const u_char *tptr, register u_int tlen) {
452
453 u_int hexdump;
454
455 struct slow_oam_common_header_t {
456 u_int8_t flags[2];
457 u_int8_t code;
458 };
459
460 struct slow_oam_tlv_header_t {
461 u_int8_t type;
462 u_int8_t length;
463 };
464
465 union {
466 const struct slow_oam_common_header_t *slow_oam_common_header;
467 const struct slow_oam_tlv_header_t *slow_oam_tlv_header;
468 } ptr;
469
470 union {
471 const struct slow_oam_info_t *slow_oam_info;
472 const struct slow_oam_link_event_t *slow_oam_link_event;
473 const struct slow_oam_variablerequest_t *slow_oam_variablerequest;
474 const struct slow_oam_variableresponse_t *slow_oam_variableresponse;
475 const struct slow_oam_loopbackctrl_t *slow_oam_loopbackctrl;
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 %lu",
513 (unsigned long) 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-Parser-Action %s, State-MUX-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(gndo,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 %lu",
589 (unsigned long) 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(gndo,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 case SLOW_OAM_CODE_LOOPBACK_CTRL:
632 tlv.slow_oam_loopbackctrl = (const struct slow_oam_loopbackctrl_t *)tptr;
633 printf("\n\t Command %s (%u)",
634 tok2str(slow_oam_loopbackctrl_cmd_values,
635 "Unknown",
636 tlv.slow_oam_loopbackctrl->command),
637 tlv.slow_oam_loopbackctrl->command);
638 tptr ++;
639 tlen --;
640 break;
641
642 /*
643 * FIXME those are the defined codes that lack a decoder
644 * you are welcome to contribute code ;-)
645 */
646 case SLOW_OAM_CODE_VAR_REQUEST:
647 case SLOW_OAM_CODE_VAR_RESPONSE:
648 case SLOW_OAM_CODE_PRIVATE:
649 default:
650 if (vflag <= 1) {
651 print_unknown_data(gndo,tptr,"\n\t ", tlen);
652 }
653 break;
654 }
655 return;
656 }