Commit | Line | Data |
---|---|---|
c8cf0f94 PA |
1 | /* |
2 | * Copyright (c) 1998-2005 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 | * | |
17 | * Original code by Hannes Gredler (hannes@juniper.net) | |
18 | */ | |
19 | ||
20 | #ifndef lint | |
21 | static const char rcsid[] _U_ = | |
22 | "@(#) $Header: /tcpdump/master/tcpdump/print-slow.c,v 1.1.2.1 2005/07/10 14:47:56 hannes Exp $"; | |
23 | #endif | |
24 | ||
25 | #ifdef HAVE_CONFIG_H | |
26 | #include "config.h" | |
27 | #endif | |
28 | ||
29 | #include <tcpdump-stdinc.h> | |
30 | ||
31 | #include <stdio.h> | |
32 | #include <stdlib.h> | |
33 | #include <string.h> | |
34 | ||
35 | #include "interface.h" | |
36 | #include "extract.h" | |
37 | #include "addrtoname.h" | |
38 | #include "ether.h" | |
39 | ||
40 | struct slow_common_header { | |
41 | u_int8_t proto_subtype; | |
42 | u_int8_t version; | |
43 | }; | |
44 | ||
45 | #define SLOW_PROTO_LACP 1 | |
46 | #define SLOW_PROTO_MARKER 2 | |
47 | ||
48 | #define LACP_VERSION 1 | |
49 | #define MARKER_VERSION 1 | |
50 | ||
51 | static const struct tok slow_proto_values[] = { | |
52 | { SLOW_PROTO_LACP, "LACP" }, | |
53 | { SLOW_PROTO_MARKER, "MARKER" }, | |
54 | { 0, NULL} | |
55 | }; | |
56 | ||
57 | struct tlv_header_t { | |
58 | u_int8_t type; | |
59 | u_int8_t length; | |
60 | }; | |
61 | ||
62 | #define LACP_TLV_TERMINATOR 0x00 | |
63 | #define LACP_TLV_ACTOR_INFO 0x01 | |
64 | #define LACP_TLV_PARTNER_INFO 0x02 | |
65 | #define LACP_TLV_COLLECTOR_INFO 0x03 | |
66 | ||
67 | #define MARKER_TLV_TERMINATOR 0x00 | |
68 | #define MARKER_TLV_MARKER_INFO 0x01 | |
69 | ||
70 | static const struct tok slow_tlv_values[] = { | |
71 | { (SLOW_PROTO_LACP << 8) + LACP_TLV_TERMINATOR, "Terminator"}, | |
72 | { (SLOW_PROTO_LACP << 8) + LACP_TLV_ACTOR_INFO, "Actor Information"}, | |
73 | { (SLOW_PROTO_LACP << 8) + LACP_TLV_PARTNER_INFO, "Partner Information"}, | |
74 | { (SLOW_PROTO_LACP << 8) + LACP_TLV_COLLECTOR_INFO, "Collector Information"}, | |
75 | ||
76 | { (SLOW_PROTO_MARKER << 8) + MARKER_TLV_TERMINATOR, "Terminator"}, | |
77 | { (SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_INFO, "Marker Information"}, | |
78 | { 0, NULL} | |
79 | }; | |
80 | ||
81 | struct lacp_tlv_actor_partner_info_t { | |
82 | u_int8_t sys_pri[2]; | |
83 | u_int8_t sys[ETHER_ADDR_LEN]; | |
84 | u_int8_t key[2]; | |
85 | u_int8_t port_pri[2]; | |
86 | u_int8_t port[2]; | |
87 | u_int8_t state; | |
88 | u_int8_t pad[3]; | |
89 | }; | |
90 | ||
91 | static const struct tok lacp_tlv_actor_partner_info_state_values[] = { | |
92 | { 0x01, "Activity"}, | |
93 | { 0x02, "Timeout"}, | |
94 | { 0x04, "Aggregation"}, | |
95 | { 0x08, "Synchronization"}, | |
96 | { 0x10, "Collecting"}, | |
97 | { 0x20, "Distributing"}, | |
98 | { 0x40, "Default"}, | |
99 | { 0x80, "Expired"}, | |
100 | { 0, NULL} | |
101 | }; | |
102 | ||
103 | struct lacp_tlv_collector_info_t { | |
104 | u_int8_t max_delay[2]; | |
105 | u_int8_t pad[12]; | |
106 | }; | |
107 | ||
108 | struct marker_tlv_marker_info_t { | |
109 | u_int8_t req_port[2]; | |
110 | u_int8_t req_sys[ETHER_ADDR_LEN]; | |
111 | u_int8_t req_trans_id[4]; | |
112 | u_int8_t pad[2]; | |
113 | }; | |
114 | ||
115 | struct lacp_marker_tlv_terminator_t { | |
116 | u_int8_t pad[50]; | |
117 | }; | |
118 | ||
119 | void | |
120 | slow_print(register const u_char *pptr, register u_int len) { | |
121 | ||
122 | const struct slow_common_header *slow_com_header; | |
123 | const struct tlv_header_t *tlv_header; | |
124 | const u_char *tptr,*tlv_tptr; | |
125 | u_int tlv_len,tlen,tlv_tlen; | |
126 | ||
127 | union { | |
128 | const struct lacp_marker_tlv_terminator_t *lacp_marker_tlv_terminator; | |
129 | const struct lacp_tlv_actor_partner_info_t *lacp_tlv_actor_partner_info; | |
130 | const struct lacp_tlv_collector_info_t *lacp_tlv_collector_info; | |
131 | const struct marker_tlv_marker_info_t *marker_tlv_marker_info; | |
132 | } tlv_ptr; | |
133 | ||
134 | tptr=pptr; | |
135 | slow_com_header = (const struct slow_common_header *)pptr; | |
136 | TCHECK(*slow_com_header); | |
137 | ||
138 | /* | |
139 | * Sanity checking of the header. | |
140 | */ | |
141 | if (slow_com_header->proto_subtype == SLOW_PROTO_LACP && | |
142 | slow_com_header->version != LACP_VERSION) { | |
143 | printf("LACP version %u packet not supported",slow_com_header->version); | |
144 | return; | |
145 | } | |
146 | if (slow_com_header->proto_subtype == SLOW_PROTO_MARKER && | |
147 | slow_com_header->version != MARKER_VERSION) { | |
148 | printf("MARKER version %u packet not supported",slow_com_header->version); | |
149 | return; | |
150 | } | |
151 | ||
152 | printf("%sv%u, length: %u", | |
153 | tok2str(slow_proto_values, "unknown (%u)",slow_com_header->proto_subtype), | |
154 | slow_com_header->version, | |
155 | len); | |
156 | ||
157 | if (!vflag) | |
158 | return; | |
159 | ||
160 | /* ok they seem to want to know everything - lets fully decode it */ | |
161 | tlen=len-sizeof(struct slow_common_header); | |
162 | tptr+=sizeof(const struct slow_common_header); | |
163 | ||
164 | while(tlen>0) { | |
165 | /* did we capture enough for fully decoding the tlv header ? */ | |
166 | TCHECK2(*tptr, sizeof(struct tlv_header_t)); | |
167 | tlv_header = (const struct tlv_header_t *)tptr; | |
168 | tlv_len = tlv_header->length; | |
169 | ||
170 | printf("\n\t%s TLV (0x%02x), length: %u", | |
171 | tok2str(slow_tlv_values, | |
172 | "Unknown", | |
173 | (slow_com_header->proto_subtype << 8) + tlv_header->type), | |
174 | tlv_header->type, | |
175 | tlv_len); | |
176 | ||
177 | if ((tlv_len < sizeof(struct tlv_header_t) || | |
178 | tlv_len > tlen) && | |
179 | tlv_header->type != LACP_TLV_TERMINATOR && | |
180 | tlv_header->type != MARKER_TLV_TERMINATOR) { | |
181 | printf("\n\t-----trailing data-----"); | |
182 | print_unknown_data(tptr+sizeof(sizeof(struct tlv_header_t)),"\n\t ",tlen); | |
183 | return; | |
184 | } | |
185 | ||
186 | tlv_tptr=tptr+sizeof(struct tlv_header_t); | |
187 | tlv_tlen=tlv_len-sizeof(struct tlv_header_t); | |
188 | ||
189 | /* did we capture enough for fully decoding the tlv ? */ | |
190 | TCHECK2(*tptr, tlv_len); | |
191 | ||
192 | switch((slow_com_header->proto_subtype << 8) + tlv_header->type) { | |
193 | ||
194 | /* those two TLVs have the same structure -> fall through */ | |
195 | case ((SLOW_PROTO_LACP << 8) + LACP_TLV_ACTOR_INFO): | |
196 | case ((SLOW_PROTO_LACP << 8) + LACP_TLV_PARTNER_INFO): | |
197 | tlv_ptr.lacp_tlv_actor_partner_info = (const struct lacp_tlv_actor_partner_info_t *)tlv_tptr; | |
198 | ||
199 | printf("\n\t System %s, System Priority %u, Key %u" \ | |
200 | ", Port %u, Port Priority %u\n\t State Flags [%s]", | |
201 | etheraddr_string(tlv_ptr.lacp_tlv_actor_partner_info->sys), | |
202 | EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->sys_pri), | |
203 | EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->key), | |
204 | EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->port), | |
205 | EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->port_pri), | |
206 | bittok2str(lacp_tlv_actor_partner_info_state_values, | |
207 | "none", | |
208 | tlv_ptr.lacp_tlv_actor_partner_info->state)); | |
209 | ||
210 | break; | |
211 | ||
212 | case ((SLOW_PROTO_LACP << 8) + LACP_TLV_COLLECTOR_INFO): | |
213 | tlv_ptr.lacp_tlv_collector_info = (const struct lacp_tlv_collector_info_t *)tlv_tptr; | |
214 | ||
215 | printf("\n\t Max Delay %u", | |
216 | EXTRACT_16BITS(tlv_ptr.lacp_tlv_collector_info->max_delay)); | |
217 | ||
218 | break; | |
219 | ||
220 | case ((SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_INFO): | |
221 | tlv_ptr.marker_tlv_marker_info = (const struct marker_tlv_marker_info_t *)tlv_tptr; | |
222 | ||
223 | printf("\n\t Request System %s, Request Port %u, Request Transaction ID 0x%08x", | |
224 | etheraddr_string(tlv_ptr.marker_tlv_marker_info->req_sys), | |
225 | EXTRACT_16BITS(tlv_ptr.marker_tlv_marker_info->req_port), | |
226 | EXTRACT_32BITS(tlv_ptr.marker_tlv_marker_info->req_trans_id)); | |
227 | ||
228 | break; | |
229 | ||
230 | /* those two TLVs have the same structure -> fall through */ | |
231 | case ((SLOW_PROTO_LACP << 8) + LACP_TLV_TERMINATOR): | |
232 | case ((SLOW_PROTO_MARKER << 8) + LACP_TLV_TERMINATOR): | |
233 | tlv_ptr.lacp_marker_tlv_terminator = (const struct lacp_marker_tlv_terminator_t *)tlv_tptr; | |
234 | if (tlv_len == 0) { | |
235 | tlv_len = sizeof(tlv_ptr.lacp_marker_tlv_terminator->pad) + | |
236 | sizeof(struct tlv_header_t); | |
237 | /* tell the user that we modified the length field */ | |
238 | if (vflag>1) | |
239 | printf(" (=%u)",tlv_len); | |
240 | /* we have messed around with the length field - now we need to check | |
241 | * again if there are enough bytes on the wire for the hexdump */ | |
242 | TCHECK2(tlv_ptr.lacp_marker_tlv_terminator->pad[0], | |
243 | sizeof(tlv_ptr.lacp_marker_tlv_terminator->pad)); | |
244 | } | |
245 | ||
246 | break; | |
247 | ||
248 | default: | |
249 | if (vflag <= 1) | |
250 | print_unknown_data(tlv_tptr,"\n\t ",tlv_tlen); | |
251 | break; | |
252 | } | |
253 | /* do we want to see an additionally hexdump ? */ | |
254 | if (vflag > 1) | |
255 | print_unknown_data(tptr+sizeof(sizeof(struct tlv_header_t)),"\n\t ", | |
256 | tlv_len-sizeof(struct tlv_header_t)); | |
257 | ||
258 | tptr+=tlv_len; | |
259 | tlen-=tlv_len; | |
260 | } | |
261 | return; | |
262 | trunc: | |
263 | printf("\n\t\t packet exceeded snapshot"); | |
264 | } |