]> The Tcpdump Group git mirrors - tcpdump/blob - print-slow.c
add basic support for Ethernet OAM Frames as per 802.3ah
[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.2 2006-02-16 16:42:44 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
41 struct slow_common_header_t {
42 u_int8_t proto_subtype;
43 u_int8_t version;
44 };
45
46 #define SLOW_PROTO_LACP 1
47 #define SLOW_PROTO_MARKER 2
48 #define SLOW_PROTO_OAM 3
49
50 #define LACP_VERSION 1
51 #define MARKER_VERSION 1
52
53 static const struct tok slow_proto_values[] = {
54 { SLOW_PROTO_LACP, "LACP" },
55 { SLOW_PROTO_MARKER, "MARKER" },
56 { SLOW_PROTO_OAM, "OAM" },
57 { 0, NULL}
58 };
59
60 static const struct tok slow_oam_flag_values[] = {
61 { 0x0001, "Link Fault" },
62 { 0x0002, "Dying Gasp" },
63 { 0x0004, "Critical Event" },
64 { 0x0008, "Local Evaluating" },
65 { 0x0010, "Local Stable" },
66 { 0x0020, "Remote Evaluating" },
67 { 0x0040, "Remote Stable" },
68 { 0, NULL}
69 };
70
71 #define SLOW_OAM_CODE_INFO 0x00
72 #define SLOW_OAM_CODE_EVENT_NOTIF 0x01
73 #define SLOW_OAM_CODE_VAR_REQUEST 0x02
74 #define SLOW_OAM_CODE_VAR_RESPONSE 0x03
75 #define SLOW_OAM_CODE_LOOPBACK_CTRL 0x04
76 #define SLOW_OAM_CODE_PRIVATE 0xfe
77
78 static const struct tok slow_oam_code_values[] = {
79 { SLOW_OAM_CODE_INFO, "Information" },
80 { SLOW_OAM_CODE_EVENT_NOTIF, "Event Notification" },
81 { SLOW_OAM_CODE_VAR_REQUEST, "Variable Request" },
82 { SLOW_OAM_CODE_VAR_RESPONSE, "Variable Response" },
83 { SLOW_OAM_CODE_LOOPBACK_CTRL, "Loopback Control" },
84 { SLOW_OAM_CODE_PRIVATE, "Vendor Private" },
85 { 0, NULL}
86 };
87
88 struct tlv_header_t {
89 u_int8_t type;
90 u_int8_t length;
91 };
92
93 #define LACP_TLV_TERMINATOR 0x00
94 #define LACP_TLV_ACTOR_INFO 0x01
95 #define LACP_TLV_PARTNER_INFO 0x02
96 #define LACP_TLV_COLLECTOR_INFO 0x03
97
98 #define MARKER_TLV_TERMINATOR 0x00
99 #define MARKER_TLV_MARKER_INFO 0x01
100
101 static const struct tok slow_tlv_values[] = {
102 { (SLOW_PROTO_LACP << 8) + LACP_TLV_TERMINATOR, "Terminator"},
103 { (SLOW_PROTO_LACP << 8) + LACP_TLV_ACTOR_INFO, "Actor Information"},
104 { (SLOW_PROTO_LACP << 8) + LACP_TLV_PARTNER_INFO, "Partner Information"},
105 { (SLOW_PROTO_LACP << 8) + LACP_TLV_COLLECTOR_INFO, "Collector Information"},
106
107 { (SLOW_PROTO_MARKER << 8) + MARKER_TLV_TERMINATOR, "Terminator"},
108 { (SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_INFO, "Marker Information"},
109 { 0, NULL}
110 };
111
112 struct lacp_tlv_actor_partner_info_t {
113 u_int8_t sys_pri[2];
114 u_int8_t sys[ETHER_ADDR_LEN];
115 u_int8_t key[2];
116 u_int8_t port_pri[2];
117 u_int8_t port[2];
118 u_int8_t state;
119 u_int8_t pad[3];
120 };
121
122 static const struct tok lacp_tlv_actor_partner_info_state_values[] = {
123 { 0x01, "Activity"},
124 { 0x02, "Timeout"},
125 { 0x04, "Aggregation"},
126 { 0x08, "Synchronization"},
127 { 0x10, "Collecting"},
128 { 0x20, "Distributing"},
129 { 0x40, "Default"},
130 { 0x80, "Expired"},
131 { 0, NULL}
132 };
133
134 struct lacp_tlv_collector_info_t {
135 u_int8_t max_delay[2];
136 u_int8_t pad[12];
137 };
138
139 struct marker_tlv_marker_info_t {
140 u_int8_t req_port[2];
141 u_int8_t req_sys[ETHER_ADDR_LEN];
142 u_int8_t req_trans_id[4];
143 u_int8_t pad[2];
144 };
145
146 struct lacp_marker_tlv_terminator_t {
147 u_int8_t pad[50];
148 };
149
150 void slow_marker_lacp_print(register const u_char *, register u_int);
151 void slow_oam_print(register const u_char *, register u_int);
152
153 const struct slow_common_header_t *slow_com_header;
154
155 void
156 slow_print(register const u_char *pptr, register u_int len) {
157
158 int print_version;
159
160 slow_com_header = (const struct slow_common_header_t *)pptr;
161 TCHECK(*slow_com_header);
162
163 /*
164 * Sanity checking of the header.
165 */
166 switch (slow_com_header->proto_subtype) {
167 case SLOW_PROTO_LACP:
168 if (slow_com_header->version != LACP_VERSION) {
169 printf("LACP version %u packet not supported",slow_com_header->version);
170 return;
171 }
172 print_version = 1;
173 break;
174
175 case SLOW_PROTO_MARKER:
176 if (slow_com_header->version != MARKER_VERSION) {
177 printf("MARKER version %u packet not supported",slow_com_header->version);
178 return;
179 }
180 print_version = 1;
181 break;
182
183 case SLOW_PROTO_OAM: /* fall through */
184 print_version = 0;
185 break;
186
187 default:
188 /* print basic information and exit */
189 print_version = -1;
190 break;
191 }
192
193 if (print_version) {
194 printf("%sv%u, length %u",
195 tok2str(slow_proto_values, "unknown (%u)",slow_com_header->proto_subtype),
196 slow_com_header->version,
197 len);
198 } else {
199 /* some slow protos don't have a version number in the header */
200 printf("%s, length %u",
201 tok2str(slow_proto_values, "unknown (%u)",slow_com_header->proto_subtype),
202 len);
203 }
204
205 /* unrecognized subtype */
206 if (print_version == -1) {
207 print_unknown_data(pptr, "\n\t", len);
208 return;
209 }
210
211 if (!vflag)
212 return;
213
214 switch (slow_com_header->proto_subtype) {
215 default: /* should not happen */
216 break;
217
218 case SLOW_PROTO_OAM:
219 /* skip proto_subtype */
220 slow_oam_print(pptr+1, len-1);
221 break;
222
223 case SLOW_PROTO_LACP: /* LACP and MARKER share the same semantics */
224 case SLOW_PROTO_MARKER:
225 /* skip slow_common_header */
226 len -= sizeof(const struct slow_common_header_t);
227 pptr += sizeof(const struct slow_common_header_t);
228 slow_marker_lacp_print(pptr, len);
229 break;
230 }
231 return;
232
233 trunc:
234 printf("\n\t\t packet exceeded snapshot");
235 }
236
237 void slow_marker_lacp_print(register const u_char *tptr, register u_int tlen) {
238
239 const struct tlv_header_t *tlv_header;
240 const u_char *tlv_tptr;
241 u_int tlv_len, tlv_tlen;
242
243 union {
244 const struct lacp_marker_tlv_terminator_t *lacp_marker_tlv_terminator;
245 const struct lacp_tlv_actor_partner_info_t *lacp_tlv_actor_partner_info;
246 const struct lacp_tlv_collector_info_t *lacp_tlv_collector_info;
247 const struct marker_tlv_marker_info_t *marker_tlv_marker_info;
248 } tlv_ptr;
249
250 while(tlen>0) {
251 /* did we capture enough for fully decoding the tlv header ? */
252 TCHECK2(*tptr, sizeof(struct tlv_header_t));
253 tlv_header = (const struct tlv_header_t *)tptr;
254 tlv_len = tlv_header->length;
255
256 printf("\n\t%s TLV (0x%02x), length %u",
257 tok2str(slow_tlv_values,
258 "Unknown",
259 (slow_com_header->proto_subtype << 8) + tlv_header->type),
260 tlv_header->type,
261 tlv_len);
262
263 if ((tlv_len < sizeof(struct tlv_header_t) ||
264 tlv_len > tlen) &&
265 tlv_header->type != LACP_TLV_TERMINATOR &&
266 tlv_header->type != MARKER_TLV_TERMINATOR) {
267 printf("\n\t-----trailing data-----");
268 print_unknown_data(tptr+sizeof(sizeof(struct tlv_header_t)),"\n\t ",tlen);
269 return;
270 }
271
272 tlv_tptr=tptr+sizeof(struct tlv_header_t);
273 tlv_tlen=tlv_len-sizeof(struct tlv_header_t);
274
275 /* did we capture enough for fully decoding the tlv ? */
276 TCHECK2(*tptr, tlv_len);
277
278 switch((slow_com_header->proto_subtype << 8) + tlv_header->type) {
279
280 /* those two TLVs have the same structure -> fall through */
281 case ((SLOW_PROTO_LACP << 8) + LACP_TLV_ACTOR_INFO):
282 case ((SLOW_PROTO_LACP << 8) + LACP_TLV_PARTNER_INFO):
283 tlv_ptr.lacp_tlv_actor_partner_info = (const struct lacp_tlv_actor_partner_info_t *)tlv_tptr;
284
285 printf("\n\t System %s, System Priority %u, Key %u" \
286 ", Port %u, Port Priority %u\n\t State Flags [%s]",
287 etheraddr_string(tlv_ptr.lacp_tlv_actor_partner_info->sys),
288 EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->sys_pri),
289 EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->key),
290 EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->port),
291 EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->port_pri),
292 bittok2str(lacp_tlv_actor_partner_info_state_values,
293 "none",
294 tlv_ptr.lacp_tlv_actor_partner_info->state));
295
296 break;
297
298 case ((SLOW_PROTO_LACP << 8) + LACP_TLV_COLLECTOR_INFO):
299 tlv_ptr.lacp_tlv_collector_info = (const struct lacp_tlv_collector_info_t *)tlv_tptr;
300
301 printf("\n\t Max Delay %u",
302 EXTRACT_16BITS(tlv_ptr.lacp_tlv_collector_info->max_delay));
303
304 break;
305
306 case ((SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_INFO):
307 tlv_ptr.marker_tlv_marker_info = (const struct marker_tlv_marker_info_t *)tlv_tptr;
308
309 printf("\n\t Request System %s, Request Port %u, Request Transaction ID 0x%08x",
310 etheraddr_string(tlv_ptr.marker_tlv_marker_info->req_sys),
311 EXTRACT_16BITS(tlv_ptr.marker_tlv_marker_info->req_port),
312 EXTRACT_32BITS(tlv_ptr.marker_tlv_marker_info->req_trans_id));
313
314 break;
315
316 /* those two TLVs have the same structure -> fall through */
317 case ((SLOW_PROTO_LACP << 8) + LACP_TLV_TERMINATOR):
318 case ((SLOW_PROTO_MARKER << 8) + LACP_TLV_TERMINATOR):
319 tlv_ptr.lacp_marker_tlv_terminator = (const struct lacp_marker_tlv_terminator_t *)tlv_tptr;
320 if (tlv_len == 0) {
321 tlv_len = sizeof(tlv_ptr.lacp_marker_tlv_terminator->pad) +
322 sizeof(struct tlv_header_t);
323 /* tell the user that we modified the length field */
324 if (vflag>1)
325 printf(" (=%u)",tlv_len);
326 /* we have messed around with the length field - now we need to check
327 * again if there are enough bytes on the wire for the hexdump */
328 TCHECK2(tlv_ptr.lacp_marker_tlv_terminator->pad[0],
329 sizeof(tlv_ptr.lacp_marker_tlv_terminator->pad));
330 }
331
332 break;
333
334 default:
335 if (vflag <= 1)
336 print_unknown_data(tlv_tptr,"\n\t ",tlv_tlen);
337 break;
338 }
339 /* do we want to see an additional hexdump ? */
340 if (vflag > 1) {
341 print_unknown_data(tptr+sizeof(sizeof(struct tlv_header_t)),"\n\t ",
342 tlv_len-sizeof(struct tlv_header_t));
343 }
344
345 tptr+=tlv_len;
346 tlen-=tlv_len;
347 }
348 return;
349 trunc:
350 printf("\n\t\t packet exceeded snapshot");
351 }
352
353 void slow_oam_print(register const u_char *tptr, register u_int tlen) {
354
355 struct slow_oam_common_header_t {
356 u_int8_t flags[2];
357 u_int8_t code;
358 };
359 const struct slow_oam_common_header_t *slow_oam_common_header;
360
361 slow_oam_common_header = (struct slow_oam_common_header_t *)tptr;
362
363 printf("Flags [ %s ], Code %s",
364 bittok2str(slow_oam_flag_values,
365 "none",
366 EXTRACT_16BITS(&slow_oam_common_header->flags)),
367 tok2str(slow_oam_code_values, "Unknown (%u)", slow_oam_common_header->code));
368
369 switch (slow_oam_common_header->code) {
370 /* FIXME no codes yet known - just hexdump for now */
371 case SLOW_OAM_CODE_INFO:
372 case SLOW_OAM_CODE_EVENT_NOTIF:
373 case SLOW_OAM_CODE_VAR_REQUEST:
374 case SLOW_OAM_CODE_VAR_RESPONSE:
375 case SLOW_OAM_CODE_LOOPBACK_CTRL:
376 case SLOW_OAM_CODE_PRIVATE:
377 default:
378 if (vflag <= 1) {
379 print_unknown_data(tptr,"\n\t ", tlen);
380 }
381 break;
382 }
383 /* do we want to see an additional hexdump ? */
384 if (vflag > 1) {
385 print_unknown_data(tptr,"\n\t ", tlen);
386 }
387
388 return;
389 }