/src/wireshark/epan/dissectors/packet-brdwlk.c
Line | Count | Source |
1 | | /* packet-brdwlk.c |
2 | | * Routines for decoding MDS Port Analyzer Adapter (FC in Eth) Header |
3 | | * Copyright 2001, Dinesh G Dutt <ddutt@andiamo.com> |
4 | | * |
5 | | * Wireshark - Network traffic analyzer |
6 | | * By Gerald Combs <gerald@wireshark.org> |
7 | | * Copyright 1998 Gerald Combs |
8 | | * |
9 | | * SPDX-License-Identifier: GPL-2.0-or-later |
10 | | */ |
11 | | |
12 | | /* |
13 | | * https://www.cisco.com/en/US/docs/storage/san_switches/mds9000/hw/paa/installation/note/FPAA2.pdf |
14 | | * https://www.cisco.com/en/US/docs/storage/san_switches/mds9000/hw/paa/installation/note/FPAA2.html |
15 | | */ |
16 | | |
17 | | #include "config.h" |
18 | | |
19 | | #include <epan/packet.h> |
20 | | #include <epan/proto_data.h> |
21 | | #include <epan/tfs.h> |
22 | | #include "packet-fc.h" |
23 | | |
24 | 0 | #define BRDWLK_MAX_PACKET_CNT 0xFFFF |
25 | 224 | #define BRDWLK_TRUNCATED_BIT 0x8 |
26 | 1.18k | #define BRDWLK_HAS_PLEN 0x1 |
27 | | |
28 | | #define FCM_DELIM_SOFC1 0x01 |
29 | 622 | #define FCM_DELIM_SOFI1 0x02 |
30 | 643 | #define FCM_DELIM_SOFI2 0x04 |
31 | 1.19k | #define FCM_DELIM_SOFI3 0x06 |
32 | | #define FCM_DELIM_SOFN1 0x03 |
33 | | #define FCM_DELIM_SOFN2 0x05 |
34 | | #define FCM_DELIM_SOFN3 0x07 |
35 | 514 | #define FCM_DELIM_SOFF 0x08 |
36 | | #define FCM_DELIM_SOFC4 0x09 |
37 | 591 | #define FCM_DELIM_SOFI4 0x0A |
38 | | #define FCM_DELIM_SOFN4 0x0B |
39 | | |
40 | 13 | #define FCM_DELIM_EOFT 0x01 |
41 | | #define FCM_DELIM_EOFDT 0x02 |
42 | 1.18k | #define FCM_DELIM_EOFN 0x03 |
43 | | #define FCM_DELIM_EOFA 0x04 |
44 | | #define FCM_DELIM_EOFNI 0x07 |
45 | | #define FCM_DELIM_EOFDTI 0x06 |
46 | | #define FCM_DELIM_EOFRT 0x0A |
47 | | #define FCM_DELIM_EOFRTI 0x0E |
48 | | #define FCM_DELIM_NOEOF 0xF0 |
49 | | #define FCM_DELIM_EOFJUMBO 0xF1 |
50 | | |
51 | | void proto_register_brdwlk(void); |
52 | | void proto_reg_handoff_brdwlk(void); |
53 | | |
54 | | static const value_string brdwlk_sof_vals[] = { |
55 | | {FCM_DELIM_SOFI1, "SOFi1"}, |
56 | | {FCM_DELIM_SOFI2, "SOFi2"}, |
57 | | {FCM_DELIM_SOFI3, "SOFi3"}, |
58 | | {FCM_DELIM_SOFN1, "SOFn1"}, |
59 | | {FCM_DELIM_SOFN2, "SOFn2"}, |
60 | | {FCM_DELIM_SOFN3, "SOFn3"}, |
61 | | {FCM_DELIM_SOFF, "SOFf"}, |
62 | | {0, NULL}, |
63 | | }; |
64 | | |
65 | | static const value_string brdwlk_eof_vals[] = { |
66 | | {FCM_DELIM_EOFDT, "EOFdt"}, |
67 | | {FCM_DELIM_EOFA, "EOFa"}, |
68 | | {FCM_DELIM_EOFN, "EOFn"}, |
69 | | {FCM_DELIM_EOFT, "EOFt"}, |
70 | | {0, NULL}, |
71 | | }; |
72 | | |
73 | | static int hf_brdwlk_sof; |
74 | | static int hf_brdwlk_eof; |
75 | | static int hf_brdwlk_error; |
76 | | static int hf_brdwlk_vsan; |
77 | | static int hf_brdwlk_pktcnt; |
78 | | static int hf_brdwlk_drop; |
79 | | static int hf_brdwlk_plen; |
80 | | static int hf_brdwlk_error_plp; |
81 | | static int hf_brdwlk_error_ef; |
82 | | static int hf_brdwlk_error_nd; |
83 | | static int hf_brdwlk_error_tr; |
84 | | static int hf_brdwlk_error_badcrc; |
85 | | static int hf_brdwlk_error_ff; |
86 | | static int hf_brdwlk_error_jumbo; |
87 | | static int hf_brdwlk_error_ctrl; |
88 | | |
89 | | /* Initialize the subtree pointers */ |
90 | | static int ett_brdwlk; |
91 | | static int ett_brdwlk_error; |
92 | | |
93 | | static int proto_brdwlk; |
94 | | |
95 | | static uint16_t packet_count; |
96 | | static bool first_pkt = true; /* start of capture */ |
97 | | |
98 | | static dissector_handle_t fc_dissector_handle; |
99 | | static dissector_handle_t brdwlk_handle; |
100 | | |
101 | | |
102 | | static const true_false_string tfs_error_plp = { |
103 | | "Packet Length is PRESENT", |
104 | | "Packet length is NOT present" |
105 | | }; |
106 | | static const true_false_string tfs_error_ef = { |
107 | | "This is an Empty Frame", |
108 | | "Frame is NOT empty" |
109 | | }; |
110 | | static const true_false_string tfs_error_nd = { |
111 | | "This Frame has NO Data", |
112 | | "This frame carries data" |
113 | | }; |
114 | | static const true_false_string tfs_error_tr = { |
115 | | "This frame is TRUNCATED", |
116 | | "This frame is NOT truncated" |
117 | | }; |
118 | | static const true_false_string tfs_error_crc = { |
119 | | "This Frame has a BAD FC CRC", |
120 | | "This frame has a valid crc" |
121 | | }; |
122 | | static const true_false_string tfs_error_ff = { |
123 | | "Fifo is Full", |
124 | | "Fifo is NOT full" |
125 | | }; |
126 | | static const true_false_string tfs_error_jumbo = { |
127 | | "This is a JUMBO FC Frame", |
128 | | "This is a NORMAL FC Frame" |
129 | | }; |
130 | | static const true_false_string tfs_error_ctrl = { |
131 | | "Ctrl Characters inside the frame", |
132 | | "No ctrl chars inside the frame" |
133 | | }; |
134 | | |
135 | | static void |
136 | | dissect_brdwlk_err(proto_tree *parent_tree, tvbuff_t *tvb, int offset) |
137 | 1.18k | { |
138 | 1.18k | static int * const flags[] = { |
139 | 1.18k | &hf_brdwlk_error_plp, |
140 | 1.18k | &hf_brdwlk_error_ef, |
141 | 1.18k | &hf_brdwlk_error_nd, |
142 | 1.18k | &hf_brdwlk_error_tr, |
143 | 1.18k | &hf_brdwlk_error_badcrc, |
144 | 1.18k | &hf_brdwlk_error_ff, |
145 | 1.18k | &hf_brdwlk_error_jumbo, |
146 | 1.18k | &hf_brdwlk_error_ctrl, |
147 | 1.18k | NULL |
148 | 1.18k | }; |
149 | | |
150 | 1.18k | proto_tree_add_bitmask_with_flags(parent_tree, tvb, offset, hf_brdwlk_error, ett_brdwlk_error, flags, ENC_NA, BMT_NO_FALSE|BMT_NO_TFS); |
151 | 1.18k | } |
152 | | |
153 | | /* Code to actually dissect the packets */ |
154 | | static int |
155 | | dissect_brdwlk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
156 | 1.19k | { |
157 | | |
158 | | /* Set up structures needed to add the protocol subtree and manage it */ |
159 | 1.19k | proto_item *ti, *hidden_item; |
160 | 1.19k | proto_tree *brdwlk_tree; |
161 | 1.19k | tvbuff_t *next_tvb; |
162 | 1.19k | uint8_t error, eof, sof; |
163 | 1.19k | int hdrlen = 2, |
164 | 1.19k | offset = 0; |
165 | 1.19k | int len, reported_len, plen; |
166 | 1.19k | uint16_t pkt_cnt; |
167 | 1.19k | bool dropped_packets; |
168 | 1.19k | fc_data_t fc_data; |
169 | | |
170 | | /* Make entries in Protocol column and Info column on summary display */ |
171 | 1.19k | col_set_str(pinfo->cinfo, COL_PROTOCOL, "Boardwalk"); |
172 | | |
173 | 1.19k | col_clear(pinfo->cinfo, COL_INFO); |
174 | | |
175 | 1.19k | sof = (tvb_get_uint8(tvb, offset) & 0xF0) >> 4; |
176 | | |
177 | 1.19k | fc_data.sof_eof = 0; |
178 | 1.19k | if ((sof == FCM_DELIM_SOFI3) || (sof == FCM_DELIM_SOFI2) || (sof == FCM_DELIM_SOFI1) |
179 | 678 | || (sof == FCM_DELIM_SOFI4)) { |
180 | 678 | fc_data.sof_eof = FC_DATA_SOF_FIRST_FRAME; |
181 | 678 | } |
182 | 514 | else if (sof == FCM_DELIM_SOFF) { |
183 | 16 | fc_data.sof_eof = FC_DATA_SOF_SOFF; |
184 | 16 | } |
185 | | |
186 | 1.19k | ti = proto_tree_add_protocol_format(tree, proto_brdwlk, tvb, 0, |
187 | 1.19k | hdrlen, "Boardwalk"); |
188 | | |
189 | 1.19k | brdwlk_tree = proto_item_add_subtree(ti, ett_brdwlk); |
190 | | |
191 | 1.19k | proto_tree_add_item(brdwlk_tree, hf_brdwlk_sof, tvb, offset, 1, ENC_BIG_ENDIAN); |
192 | 1.19k | proto_tree_add_item(brdwlk_tree, hf_brdwlk_vsan, tvb, offset, 2, ENC_BIG_ENDIAN); |
193 | | |
194 | | /* Locate EOF which is the last 4 bytes of the frame */ |
195 | 1.19k | len = tvb_captured_length_remaining(tvb, hdrlen); |
196 | 1.19k | reported_len = tvb_reported_length_remaining(tvb, hdrlen); |
197 | 1.19k | if (reported_len < 4) { |
198 | | /* |
199 | | * This packet is claimed not to even have enough data for |
200 | | * a 4-byte EOF. |
201 | | * Don't try to process the EOF. |
202 | | */ |
203 | 12 | ; |
204 | 12 | } |
205 | 1.18k | else if (len < reported_len) { |
206 | | /* |
207 | | * This packet is claimed to have enough data for a 4-byte EOF, |
208 | | * but we didn't capture all of the packet. |
209 | | * Slice off the 4-byte EOF from the reported length, and trim |
210 | | * the captured length so it's no more than the reported length; |
211 | | * that will slice off what of the EOF, if any, is in the |
212 | | * captured length. |
213 | | */ |
214 | 0 | reported_len -= 4; |
215 | 0 | if (len > reported_len) |
216 | 0 | len = reported_len; |
217 | 0 | } |
218 | 1.18k | else { |
219 | | /* |
220 | | * We have the entire packet, and it includes a 4-byte EOF. |
221 | | * Slice it off, and put it into the tree if we're building |
222 | | * a tree. |
223 | | */ |
224 | 1.18k | len -= 4; |
225 | 1.18k | reported_len -= 4; |
226 | 1.18k | offset = tvb_reported_length(tvb) - 4; |
227 | 1.18k | pkt_cnt = tvb_get_ntohs(tvb, offset); |
228 | 1.18k | if (tree) { |
229 | 1.18k | proto_tree_add_uint(brdwlk_tree, hf_brdwlk_pktcnt, tvb, offset, |
230 | 1.18k | 2, pkt_cnt); |
231 | 1.18k | } |
232 | 1.18k | dropped_packets = false; |
233 | 1.18k | if (pinfo->fd->visited) { |
234 | | /* |
235 | | * This isn't the first pass, so we can't use the global |
236 | | * "packet_count" variable to determine whether there were |
237 | | * any dropped frames or not. |
238 | | * We therefore attach a non-null pointer as frame data to |
239 | | * any frame preceded by dropped packets. |
240 | | */ |
241 | 0 | if (p_get_proto_data(wmem_file_scope(), pinfo, proto_brdwlk, 0) != NULL) |
242 | 0 | dropped_packets = true; |
243 | 1.18k | } else { |
244 | | /* |
245 | | * This is the first pass, so we have to use the global |
246 | | * "packet_count" variable to determine whether there were |
247 | | * any dropped frames or not. |
248 | | * |
249 | | * XXX - can there be more than one stream of packets, so that |
250 | | * we can't just use a global variable? |
251 | | */ |
252 | 1.18k | if (pkt_cnt != packet_count + 1) { |
253 | 1.17k | if (!first_pkt && |
254 | 0 | (pkt_cnt != 0 || (packet_count != BRDWLK_MAX_PACKET_CNT))) { |
255 | 0 | dropped_packets = true; |
256 | | |
257 | | /* |
258 | | * Mark this frame as having been preceded by dropped |
259 | | * packets. (The data we use as the frame data doesn't |
260 | | * matter - it just matters that it's non-null.) |
261 | | */ |
262 | 0 | p_add_proto_data(wmem_file_scope(), pinfo, proto_brdwlk, 0, &packet_count); |
263 | 0 | } |
264 | 1.17k | } |
265 | 1.18k | } |
266 | | |
267 | 1.18k | hidden_item = proto_tree_add_boolean(brdwlk_tree, hf_brdwlk_drop, |
268 | 1.18k | tvb, offset, 0, dropped_packets); |
269 | 1.18k | proto_item_set_hidden(hidden_item); |
270 | | |
271 | 1.18k | packet_count = pkt_cnt; |
272 | | |
273 | 1.18k | error=tvb_get_uint8(tvb, offset+2); |
274 | 1.18k | dissect_brdwlk_err(brdwlk_tree, tvb, offset+2); |
275 | | |
276 | 1.18k | eof = tvb_get_uint8(tvb, offset+3); |
277 | 1.18k | if (eof != FCM_DELIM_EOFN) { |
278 | 1.16k | fc_data.sof_eof |= FC_DATA_EOF_LAST_FRAME; |
279 | 1.16k | } |
280 | 13 | else if (eof != FCM_DELIM_EOFT) { |
281 | 13 | fc_data.sof_eof |= FC_DATA_EOF_INVALID; |
282 | 13 | } |
283 | | |
284 | 1.18k | proto_tree_add_item(brdwlk_tree, hf_brdwlk_eof, tvb, offset+3, |
285 | 1.18k | 1, ENC_BIG_ENDIAN); |
286 | | |
287 | 1.18k | if ((error & BRDWLK_HAS_PLEN) && tree) { |
288 | | /* In newer Boardwalks, if this bit is set, the actual frame length |
289 | | * is also provided. This length is the size between SOF & EOF |
290 | | * including FC CRC, measured in words. |
291 | | * |
292 | | * XXX - It should be between 12 (36 bytes) and 528 (2112 bytes). |
293 | | */ |
294 | 224 | plen = tvb_get_ntohs(tvb, offset-4); |
295 | 224 | plen *= 4; |
296 | 224 | proto_tree_add_uint(brdwlk_tree, hf_brdwlk_plen, tvb, offset-4, |
297 | 224 | 2, plen); |
298 | | |
299 | 224 | if (error & BRDWLK_TRUNCATED_BIT) { |
300 | | #if 0 |
301 | | /* XXX - this would throw an exception if it would increase |
302 | | * the reported length. If it would decrease the reported |
303 | | * length, tvb_set_reported_length is used to help the Ethernet |
304 | | * dissector find a trailer - except that wouldn't work because |
305 | | * the EOF is located from the end of the frame, i.e. trailer |
306 | | * heuristics never work with this dissector. |
307 | | */ |
308 | | tvb_set_reported_length(tvb, plen); |
309 | | #endif |
310 | | /* Set the reported length for the FC subset tvb. */ |
311 | 83 | reported_len = plen; |
312 | 83 | } |
313 | 224 | } |
314 | 1.18k | } |
315 | | |
316 | 1.19k | fc_data.ethertype = ETHERTYPE_BRDWALK; |
317 | 1.19k | next_tvb = tvb_new_subset_length_caplen(tvb, 2, len, reported_len); |
318 | 1.19k | call_dissector_with_data(fc_dissector_handle, next_tvb, pinfo, tree, &fc_data); |
319 | 1.19k | return tvb_captured_length(tvb); |
320 | 1.19k | } |
321 | | |
322 | | static void |
323 | | brdwlk_init(void) |
324 | 14 | { |
325 | 14 | packet_count = 0; |
326 | 14 | first_pkt = true; |
327 | 14 | } |
328 | | |
329 | | /* Register the protocol with Wireshark */ |
330 | | |
331 | | /* this format is require because a script is used to build the C function |
332 | | that calls all the protocol registration. |
333 | | */ |
334 | | |
335 | | void |
336 | | proto_register_brdwlk(void) |
337 | 14 | { |
338 | | |
339 | | /* Setup list of header fields See Section 1.6.1 for details*/ |
340 | 14 | static hf_register_info hf[] = { |
341 | 14 | { &hf_brdwlk_sof, |
342 | 14 | {"SOF", "brdwlk.sof", FT_UINT8, BASE_HEX, VALS(brdwlk_sof_vals), |
343 | 14 | 0xF0, NULL, HFILL}}, |
344 | 14 | { &hf_brdwlk_eof, |
345 | 14 | {"EOF", "brdwlk.eof", FT_UINT8, BASE_HEX, VALS(brdwlk_eof_vals), |
346 | 14 | 0x0F, NULL, HFILL}}, |
347 | 14 | { &hf_brdwlk_error, |
348 | 14 | {"Error", "brdwlk.error", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, |
349 | 14 | HFILL}}, |
350 | 14 | { &hf_brdwlk_pktcnt, |
351 | 14 | {"Packet Count", "brdwlk.pktcnt", FT_UINT16, BASE_DEC, NULL, 0x0, |
352 | 14 | NULL, HFILL}}, |
353 | 14 | { &hf_brdwlk_drop, |
354 | 14 | {"Packet Dropped", "brdwlk.drop", FT_BOOLEAN, BASE_NONE, NULL, 0x0, |
355 | 14 | NULL, HFILL}}, |
356 | 14 | { &hf_brdwlk_vsan, |
357 | 14 | {"VSAN", "brdwlk.vsan", FT_UINT16, BASE_DEC, NULL, 0x0FFF, NULL, |
358 | 14 | HFILL}}, |
359 | 14 | { &hf_brdwlk_plen, |
360 | 14 | {"Original Packet Length", "brdwlk.plen", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, |
361 | 14 | HFILL}}, |
362 | 14 | { &hf_brdwlk_error_plp, |
363 | 14 | {"Packet Length Present", "brdwlk.error.plp", FT_BOOLEAN, 8, TFS(&tfs_error_plp), 0x01, NULL, |
364 | 14 | HFILL}}, |
365 | 14 | { &hf_brdwlk_error_ef, |
366 | 14 | {"Empty Frame", "brdwlk.error.ef", FT_BOOLEAN, 8, TFS(&tfs_error_ef), 0x02, NULL, |
367 | 14 | HFILL}}, |
368 | 14 | { &hf_brdwlk_error_nd, |
369 | 14 | {"No Data", "brdwlk.error.nd", FT_BOOLEAN, 8, TFS(&tfs_error_nd), 0x04, NULL, |
370 | 14 | HFILL}}, |
371 | 14 | { &hf_brdwlk_error_tr, |
372 | 14 | {"Truncated", "brdwlk.error.tr", FT_BOOLEAN, 8, TFS(&tfs_error_tr), 0x08, NULL, |
373 | 14 | HFILL}}, |
374 | 14 | { &hf_brdwlk_error_badcrc, |
375 | 14 | {"CRC", "brdwlk.error.crc", FT_BOOLEAN, 8, TFS(&tfs_error_crc), 0x10, NULL, |
376 | 14 | HFILL}}, |
377 | 14 | { &hf_brdwlk_error_ff, |
378 | 14 | {"Fifo Full", "brdwlk.error.ff", FT_BOOLEAN, 8, TFS(&tfs_error_ff), 0x20, NULL, |
379 | 14 | HFILL}}, |
380 | 14 | { &hf_brdwlk_error_jumbo, |
381 | 14 | {"Jumbo FC Frame", "brdwlk.error.jumbo", FT_BOOLEAN, 8, TFS(&tfs_error_jumbo), 0x40, NULL, |
382 | 14 | HFILL}}, |
383 | 14 | { &hf_brdwlk_error_ctrl, |
384 | 14 | {"Ctrl Char Inside Frame", "brdwlk.error.ctrl", FT_BOOLEAN, 8, TFS(&tfs_error_ctrl), 0x80, NULL, |
385 | 14 | HFILL}}, |
386 | 14 | }; |
387 | | |
388 | | /* Setup protocol subtree array */ |
389 | 14 | static int *ett[] = { |
390 | 14 | &ett_brdwlk, |
391 | 14 | &ett_brdwlk_error, |
392 | 14 | }; |
393 | | |
394 | | /* Register the protocol name and description */ |
395 | 14 | proto_brdwlk = proto_register_protocol("Boardwalk", "Boardwalk", "brdwlk"); |
396 | | |
397 | | /* Required function calls to register the header fields and subtrees used */ |
398 | 14 | proto_register_field_array(proto_brdwlk, hf, array_length(hf)); |
399 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
400 | | |
401 | 14 | register_init_routine(&brdwlk_init); |
402 | | |
403 | | /* Register the dissector */ |
404 | 14 | brdwlk_handle = register_dissector("brdwlk", dissect_brdwlk, proto_brdwlk); |
405 | 14 | } |
406 | | |
407 | | |
408 | | void |
409 | | proto_reg_handoff_brdwlk(void) |
410 | 14 | { |
411 | 14 | dissector_add_uint("ethertype", ETHERTYPE_BRDWALK, brdwlk_handle); |
412 | 14 | dissector_add_uint("ethertype", 0xABCD, brdwlk_handle); |
413 | 14 | fc_dissector_handle = find_dissector_add_dependency("fc", proto_brdwlk); |
414 | 14 | } |
415 | | |
416 | | /* |
417 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
418 | | * |
419 | | * Local variables: |
420 | | * c-basic-offset: 4 |
421 | | * tab-width: 8 |
422 | | * indent-tabs-mode: nil |
423 | | * End: |
424 | | * |
425 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
426 | | * :indentSize=4:tabSize=8:noTabs=true: |
427 | | */ |