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