/src/wireshark/epan/dissectors/packet-fcip.c
Line | Count | Source |
1 | | /* packet-fcip.c |
2 | | * Routines for FCIP dissection |
3 | | * RFC 3821, RFC 3643 |
4 | | * Copyright 2001, Dinesh G Dutt (ddutt@cisco.com) |
5 | | * |
6 | | * Wireshark - Network traffic analyzer |
7 | | * By Gerald Combs <gerald@wireshark.org> |
8 | | * Copyright 1998 Gerald Combs |
9 | | * |
10 | | * SPDX-License-Identifier: GPL-2.0-or-later |
11 | | */ |
12 | | |
13 | | #include "config.h" |
14 | | |
15 | | #include <epan/packet.h> |
16 | | #include <epan/prefs.h> |
17 | | #include <epan/to_str.h> |
18 | | #include "packet-fc.h" |
19 | | |
20 | | void proto_register_fcip(void); |
21 | | void proto_reg_handoff_fcip(void); |
22 | | |
23 | 5.44k | #define FCIP_ENCAP_HEADER_LEN 28 |
24 | | #define FCIP_MIN_HEADER_LEN 16 /* up to frame len field */ |
25 | 1 | #define FCIP_IS_SF(pflags) ((pflags & 0x1) == 0x1) |
26 | 1 | #define FCIP_IS_CH(pflags) ((pflags & 0x80) == 0x80) |
27 | | |
28 | | typedef enum { |
29 | | FCIP_EOFn = 0x41, |
30 | | FCIP_EOFt = 0x42, |
31 | | FCIP_EOFrt = 0x44, |
32 | | FCIP_EOFdt = 0x46, |
33 | | FCIP_EOFni = 0x49, |
34 | | FCIP_EOFdti = 0x4E, |
35 | | FCIP_EOFrti = 0x4F, |
36 | | FCIP_EOFa = 0x50 |
37 | | } fcip_eof_t; |
38 | | |
39 | | typedef enum { |
40 | | FCIP_SOFf = 0x28, |
41 | | FCIP_SOFi4 = 0x29, |
42 | | FCIP_SOFi2 = 0x2D, |
43 | | FCIP_SOFi3 = 0x2E, |
44 | | FCIP_SOFn4 = 0x31, |
45 | | FCIP_SOFn2 = 0x35, |
46 | | FCIP_SOFn3 = 0x36, |
47 | | FCIP_SOFc4 = 0x39 |
48 | | } fcip_sof_t; |
49 | | |
50 | | typedef enum { |
51 | | FCENCAP_PROTO_FCIP = 1, |
52 | | FCENCAP_PROTO_iFCP = 2 |
53 | | } fcencap_proto_t; |
54 | | |
55 | | static const value_string fcip_eof_vals[] = { |
56 | | {FCIP_EOFn, "EOFn" }, |
57 | | {FCIP_EOFt, "EOFt" }, |
58 | | {FCIP_EOFrt, "EOFrt" }, |
59 | | {FCIP_EOFdt, "EOFdt" }, |
60 | | {FCIP_EOFni, "EOFni" }, |
61 | | {FCIP_EOFdti, "EOFdti" }, |
62 | | {FCIP_EOFrti, "EOFrti" }, |
63 | | {FCIP_EOFa, "EOFa" }, |
64 | | {0, NULL}, |
65 | | }; |
66 | | |
67 | | static const value_string fcip_sof_vals[] = { |
68 | | {FCIP_SOFf, "SOFf" }, |
69 | | {FCIP_SOFi4, "SOFi4" }, |
70 | | {FCIP_SOFi2, "SOFi2" }, |
71 | | {FCIP_SOFi3, "SOFi3" }, |
72 | | {FCIP_SOFn4, "SOFn4" }, |
73 | | {FCIP_SOFn2, "SOFn2" }, |
74 | | {FCIP_SOFn3, "SOFn3" }, |
75 | | {FCIP_SOFc4, "SOFc4" }, |
76 | | {0, NULL}, |
77 | | }; |
78 | | |
79 | | static const value_string fcencap_proto_vals[] = { |
80 | | {FCENCAP_PROTO_FCIP, "FCIP" }, |
81 | | {FCENCAP_PROTO_iFCP, "iFCP" }, |
82 | | {0, NULL}, |
83 | | }; |
84 | | |
85 | | static const uint8_t fcip_header_8_bytes[8] = { |
86 | | 0x01, 0x01, 0xFE, 0xFE, |
87 | | 0x01, 0x01, 0xFE, 0xFE |
88 | | }; |
89 | | |
90 | | static int proto_fcip; |
91 | | |
92 | | static int hf_fcip_protocol; |
93 | | static int hf_fcip_protocol_c; |
94 | | static int hf_fcip_version; |
95 | | static int hf_fcip_version_c; |
96 | | static int hf_fcip_encap_word1; |
97 | | static int hf_fcip_flags; |
98 | | static int hf_fcip_flags_c; |
99 | | static int hf_fcip_framelen; |
100 | | static int hf_fcip_framelen_c; |
101 | | static int hf_fcip_tsec; |
102 | | static int hf_fcip_tusec; |
103 | | static int hf_fcip_encap_crc; |
104 | | static int hf_fcip_sof; |
105 | | static int hf_fcip_sof_c; |
106 | | static int hf_fcip_eof; |
107 | | static int hf_fcip_eof_c; |
108 | | static int hf_fcip_pflags_changed; |
109 | | static int hf_fcip_pflags_special; |
110 | | static int hf_fcip_pflags_c; |
111 | | static int hf_fcip_src_wwn; |
112 | | static int hf_fcip_dst_wwn; |
113 | | static int hf_fcip_conn_code; |
114 | | static int hf_fcip_katov; |
115 | | static int hf_fcip_src_entity_id; |
116 | | static int hf_fcip_conn_nonce; |
117 | | static int hf_fcip_conn_flags; |
118 | | |
119 | | static int ett_fcip; |
120 | | |
121 | | static unsigned fcip_port = 3225; |
122 | | static bool fcip_desegment = true; |
123 | | |
124 | | static dissector_handle_t fc_handle; |
125 | | static dissector_handle_t fcip_handle; |
126 | | |
127 | | |
128 | | /* This routine attempts to locate the position of the next header in the |
129 | | * provided segment |
130 | | */ |
131 | | static unsigned |
132 | | get_next_fcip_header_offset (tvbuff_t *tvb, packet_info *pinfo, int offset) |
133 | 19 | { |
134 | 19 | int bytes_remaining = tvb_reported_length_remaining (tvb, offset); |
135 | 19 | int frame_len; |
136 | 19 | uint16_t flen, flen1; |
137 | 19 | fcip_eof_t eof, eofc; |
138 | | |
139 | | /* |
140 | | * As per the FCIP standard, the following tests must PASS: |
141 | | * 1) Frame Length field validation -- 15 < Frame Length < 545; |
142 | | * 2) Comparison of Frame Length field to its ones complement; and |
143 | | * 3) A valid EOF is found in the word preceding the start of the next |
144 | | * FCIP header as indicated by the Frame Length field, to be tested |
145 | | * as follows: |
146 | | * 1) Bits 24-31 and 16-23 contain identical legal EOF values (the |
147 | | * list of legal EOF values is in the FC Frame Encapsulation |
148 | | * [21]); and |
149 | | * 2) Bits 8-15 and 0-7 contain the ones complement of the EOF |
150 | | * value found in bits 24-31. |
151 | | * |
152 | | * As per the FCIP standard, in addition, at least 3 of the following set |
153 | | * of tests must be performed to identify that we've located the start of |
154 | | * an FCIP frame. |
155 | | * a) Protocol# ones complement field (1 test); |
156 | | * b) Version ones complement field (1 test); |
157 | | * c) Replication of encapsulation word 0 in word 1 (1 test); |
158 | | * d) Reserved field and its ones complement (2 tests); |
159 | | * e) Flags field and its ones complement (2 tests); |
160 | | * f) CRC field is equal to zero (1 test); (DON'T DO THIS TEST!) |
161 | | * g) SOF fields and ones complement fields (4 tests); |
162 | | * h) Format and values of FC header (1 test); |
163 | | * i) CRC of FC Frame (2 tests); |
164 | | * j) FC Frame Encapsulation header information in the next FCIP Frame |
165 | | * (1 test). |
166 | | * |
167 | | * At least 3 of the 16 tests listed above SHALL be performed. Failure |
168 | | * of any of the above tests actually performed SHALL indicate an |
169 | | * encapsulation error and the FC Frame SHALL NOT be forwarded on to |
170 | | * the FC Entity. |
171 | | */ |
172 | | |
173 | 3.17k | NXT_BYTE: while (bytes_remaining) { |
174 | 3.15k | if (bytes_remaining < FCIP_ENCAP_HEADER_LEN) { |
175 | 500 | if(fcip_desegment && pinfo->can_desegment) { |
176 | | /* |
177 | | * This frame doesn't have all of the data for |
178 | | * the message header, but we can do reassembly on it. |
179 | | * |
180 | | * Tell the TCP dissector where the data for this |
181 | | * message starts in the data it handed us, and that we need |
182 | | * "some more data." Don't tell it exactly how many bytes |
183 | | * we need because if/when we ask for even more (after the |
184 | | * header) that will break reassembly. |
185 | | */ |
186 | 0 | pinfo->desegment_offset = offset; |
187 | 0 | pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT; |
188 | 0 | return -2; |
189 | 0 | } |
190 | 500 | } |
191 | | |
192 | | /* I check that we have a valid header before checking for the frame |
193 | | * length and the other initial tests. |
194 | | */ |
195 | | |
196 | | /* |
197 | | * Tests a, b and c |
198 | | */ |
199 | 3.15k | if (tvb_memeql(tvb, offset, fcip_header_8_bytes, 8) != 0) { |
200 | 3.14k | offset++; |
201 | 3.14k | bytes_remaining--; |
202 | 3.14k | goto NXT_BYTE; |
203 | 3.14k | } |
204 | | |
205 | 6 | flen = (tvb_get_ntohs (tvb, offset+12)) & 0x03FF; |
206 | 6 | frame_len = (tvb_get_ntohs (tvb, offset+12) & 0x03FF)*4; |
207 | | |
208 | 6 | if ((flen < 15) || (flen > 545)) { |
209 | | /* Frame length check failed. Skip byte and try again */ |
210 | 4 | offset++; |
211 | 4 | bytes_remaining--; |
212 | 4 | goto NXT_BYTE; |
213 | 4 | } |
214 | | |
215 | 2 | flen1 = (tvb_get_ntohs (tvb, offset+14)) & 0x03FF; |
216 | | |
217 | 2 | if ((flen & 0x03FF) != ((~flen1)&0x03FF)) { |
218 | | /* frame_len and its one's complement are not the same */ |
219 | 1 | offset++; |
220 | 1 | bytes_remaining--; |
221 | 1 | goto NXT_BYTE; |
222 | 1 | } |
223 | | |
224 | | /* Valid EOF check */ |
225 | 1 | if (tvb_bytes_exist (tvb, offset+(frame_len-1)*4, 4)) { |
226 | 0 | eof = (fcip_eof_t)tvb_get_uint8 (tvb, offset+(frame_len-1)*4); |
227 | 0 | eofc = (fcip_eof_t)tvb_get_uint8 (tvb, offset+(frame_len-1)*4+2); |
228 | |
|
229 | 0 | if ((eof != FCIP_EOFn) && (eof != FCIP_EOFt) && (eof != FCIP_EOFrt) |
230 | 0 | && (eof != FCIP_EOFdt) && (eof != FCIP_EOFni) && |
231 | 0 | (eof != FCIP_EOFdti) && (eof != FCIP_EOFrti) && |
232 | 0 | (eof != FCIP_EOFa)) { |
233 | 0 | offset++; |
234 | 0 | bytes_remaining--; |
235 | 0 | goto NXT_BYTE; |
236 | 0 | } |
237 | | |
238 | 0 | if ((eof != ~eofc) || |
239 | 0 | (eof != tvb_get_uint8 (tvb, offset+(frame_len-1)*4+1)) || |
240 | 0 | (eofc != tvb_get_uint8 (tvb, offset+(frame_len-1)*4+3))) { |
241 | 0 | offset++; |
242 | 0 | bytes_remaining--; |
243 | 0 | goto NXT_BYTE; |
244 | 0 | } |
245 | 0 | } |
246 | | |
247 | | /* Test d */ |
248 | 1 | if ((tvb_get_uint8 (tvb, offset+9) != 0) || |
249 | 0 | (tvb_get_uint8 (tvb, offset+11) != 0xFF)) { |
250 | | /* Failed */ |
251 | 0 | offset++; |
252 | 0 | bytes_remaining--; |
253 | 0 | goto NXT_BYTE; |
254 | 0 | } |
255 | | |
256 | | /* Test e */ |
257 | | |
258 | | |
259 | | /* Test f |
260 | | * We don't test this since some implementations actually provide |
261 | | * a CRC here. |
262 | | */ |
263 | | |
264 | 1 | if (bytes_remaining >= (frame_len)) { |
265 | 0 | if (tvb_bytes_exist (tvb, offset+frame_len, 8)) { |
266 | | /* The start of the next header matches what we wish to see */ |
267 | 0 | if (tvb_memeql (tvb, offset+frame_len, fcip_header_8_bytes, |
268 | 0 | 8) == 0) { |
269 | 0 | return (offset); |
270 | 0 | } |
271 | 0 | else { |
272 | 0 | offset++; |
273 | 0 | bytes_remaining--; |
274 | 0 | goto NXT_BYTE; |
275 | 0 | } |
276 | 0 | } |
277 | 0 | else { |
278 | 0 | return (offset); |
279 | 0 | } |
280 | 0 | } |
281 | 1 | else { |
282 | 1 | if(fcip_desegment && pinfo->can_desegment) { |
283 | | /* |
284 | | * This frame doesn't have all of the data for |
285 | | * this message, but we can do reassembly on it. |
286 | | * |
287 | | * Tell the TCP dissector where the data for this |
288 | | * message starts in the data it handed us, and |
289 | | * how many more bytes we need, and return. |
290 | | */ |
291 | 0 | pinfo->desegment_offset = offset; |
292 | 0 | pinfo->desegment_len = frame_len - bytes_remaining; |
293 | 0 | return -2; |
294 | 0 | } |
295 | 1 | else { |
296 | 1 | return (offset); |
297 | 1 | } |
298 | 1 | } |
299 | 1 | } |
300 | | |
301 | 18 | return (-1); /* Unable to find FCIP header */ |
302 | 3.17k | } |
303 | | |
304 | | static void |
305 | | dissect_fcencap_header (tvbuff_t *tvb, proto_tree *tree, int offset) |
306 | 0 | { |
307 | 0 | uint8_t protocol = tvb_get_uint8 (tvb, offset); |
308 | |
|
309 | 0 | if (tree) { |
310 | 0 | proto_tree_add_uint (tree, hf_fcip_protocol, tvb, offset, 1, protocol); |
311 | 0 | proto_tree_add_item (tree, hf_fcip_version, tvb, offset+1, 1, ENC_BIG_ENDIAN); |
312 | 0 | proto_tree_add_item (tree, hf_fcip_protocol_c, tvb, offset+2, 1, ENC_BIG_ENDIAN); |
313 | 0 | proto_tree_add_item (tree, hf_fcip_version_c, tvb, offset+3, 1, ENC_BIG_ENDIAN); |
314 | |
|
315 | 0 | if (protocol == FCENCAP_PROTO_FCIP) { |
316 | 0 | proto_tree_add_item (tree, hf_fcip_encap_word1, tvb, offset+4, |
317 | 0 | 4, ENC_BIG_ENDIAN); |
318 | 0 | proto_tree_add_item (tree, hf_fcip_pflags_changed, tvb, offset+8, |
319 | 0 | 1, ENC_BIG_ENDIAN); |
320 | 0 | proto_tree_add_item (tree, hf_fcip_pflags_special, tvb, offset+8, |
321 | 0 | 1, ENC_BIG_ENDIAN); |
322 | 0 | proto_tree_add_item (tree, hf_fcip_pflags_c, tvb, offset+10, 1, ENC_BIG_ENDIAN); |
323 | 0 | } |
324 | | |
325 | | /* XXX - break out CRCV flag. */ |
326 | 0 | proto_tree_add_item (tree, hf_fcip_flags, tvb, offset+12, 1, ENC_BIG_ENDIAN); |
327 | 0 | proto_tree_add_item (tree, hf_fcip_framelen, tvb, offset+12, 2, ENC_BIG_ENDIAN); |
328 | 0 | proto_tree_add_item (tree, hf_fcip_flags_c, tvb, offset+14, 1, ENC_BIG_ENDIAN); |
329 | 0 | proto_tree_add_item (tree, hf_fcip_framelen_c, tvb, offset+14, 2, ENC_BIG_ENDIAN); |
330 | 0 | proto_tree_add_item (tree, hf_fcip_tsec, tvb, offset+16, 4, ENC_BIG_ENDIAN); |
331 | 0 | proto_tree_add_item (tree, hf_fcip_tusec, tvb, offset+20, 4, ENC_BIG_ENDIAN); |
332 | | /* XXX - check CRC if CRCV is set? */ |
333 | 0 | proto_tree_add_item (tree, hf_fcip_encap_crc, tvb, offset+24, 4, ENC_BIG_ENDIAN); |
334 | 0 | } |
335 | 0 | } |
336 | | |
337 | | static void |
338 | | dissect_fcip_sf (tvbuff_t *tvb, proto_tree *tree, int offset) |
339 | 0 | { |
340 | 0 | if (tree) { |
341 | 0 | proto_tree_add_item (tree, hf_fcip_src_wwn, tvb, offset, 8, ENC_NA); |
342 | 0 | proto_tree_add_item (tree, hf_fcip_src_entity_id, tvb, offset+8, 8, |
343 | 0 | ENC_NA); |
344 | 0 | proto_tree_add_item (tree, hf_fcip_conn_nonce, tvb, offset+16, 8, |
345 | 0 | ENC_NA); |
346 | | /* XXX - break out these flags */ |
347 | 0 | proto_tree_add_item (tree, hf_fcip_conn_flags, tvb, offset+24, 1, ENC_BIG_ENDIAN); |
348 | 0 | proto_tree_add_item (tree, hf_fcip_conn_code, tvb, offset+26, 2, ENC_BIG_ENDIAN); |
349 | 0 | proto_tree_add_item (tree, hf_fcip_dst_wwn, tvb, offset+30, 8, ENC_NA); |
350 | 0 | proto_tree_add_item (tree, hf_fcip_katov, tvb, offset+38, 4, ENC_BIG_ENDIAN); |
351 | 0 | } |
352 | 0 | } |
353 | | |
354 | | static bool |
355 | | dissect_fcip (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
356 | | bool check_port) |
357 | 2.27k | { |
358 | 2.27k | int offset = 0, |
359 | 2.27k | start = 0, |
360 | 2.27k | frame_len = 0; |
361 | 2.27k | int bytes_remaining = tvb_captured_length (tvb); |
362 | 2.27k | uint8_t pflags, sof = 0, eof = 0; |
363 | | /* Set up structures needed to add the protocol subtree and manage it */ |
364 | 2.27k | proto_item *ti; |
365 | 2.27k | proto_tree *fcip_tree = NULL; |
366 | 2.27k | tvbuff_t *next_tvb; |
367 | 2.27k | fc_data_t fc_data; |
368 | | |
369 | 2.27k | if (bytes_remaining < FCIP_ENCAP_HEADER_LEN) { |
370 | 920 | return false; |
371 | 920 | } |
372 | | |
373 | 1.35k | if (check_port && |
374 | 1.35k | ((pinfo->srcport != fcip_port) && (pinfo->destport != fcip_port))) { |
375 | 1.33k | return false; |
376 | 1.33k | } |
377 | | |
378 | 20 | while (bytes_remaining > FCIP_ENCAP_HEADER_LEN) { |
379 | 19 | if ((offset = get_next_fcip_header_offset (tvb, pinfo, offset)) == -1) { |
380 | 18 | return false; |
381 | 18 | } |
382 | 1 | else if (offset == -2) { |
383 | | /* We need more data to desegment */ |
384 | 0 | return true; |
385 | 0 | } |
386 | | |
387 | 1 | start = offset; |
388 | 1 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "FCIP"); |
389 | | |
390 | 1 | frame_len = (tvb_get_ntohs (tvb, offset+12) & 0x03FF)*4; |
391 | | |
392 | 1 | if (bytes_remaining < frame_len) { |
393 | 0 | if(fcip_desegment && pinfo->can_desegment) { |
394 | | /* |
395 | | * This frame doesn't have all of the data for |
396 | | * this message, but we can do reassembly on it. |
397 | | * |
398 | | * Tell the TCP dissector where the data for this |
399 | | * message starts in the data it handed us, and |
400 | | * how many more bytes we need, and return. |
401 | | */ |
402 | 0 | pinfo->desegment_offset = offset; |
403 | 0 | pinfo->desegment_len = frame_len - bytes_remaining; |
404 | 0 | return true; |
405 | 0 | } |
406 | 0 | } |
407 | | |
408 | 1 | pflags = tvb_get_uint8 (tvb, start+8); |
409 | | |
410 | 1 | if (tree) { |
411 | 0 | if (FCIP_IS_SF (pflags)) { |
412 | 0 | ti = proto_tree_add_protocol_format (tree, proto_fcip, tvb, 0, |
413 | 0 | FCIP_ENCAP_HEADER_LEN, |
414 | 0 | "FCIP"); |
415 | 0 | } |
416 | 0 | else if (tvb_bytes_exist (tvb, offset, offset+frame_len-4)) { |
417 | 0 | sof = tvb_get_uint8 (tvb, offset+FCIP_ENCAP_HEADER_LEN); |
418 | 0 | eof = tvb_get_uint8 (tvb, offset+frame_len - 4); |
419 | |
|
420 | 0 | ti = proto_tree_add_protocol_format (tree, proto_fcip, tvb, 0, |
421 | 0 | FCIP_ENCAP_HEADER_LEN, |
422 | 0 | "FCIP (%s/%s)", |
423 | 0 | val_to_str(pinfo->pool, sof, fcip_sof_vals, |
424 | 0 | "0x%x"), |
425 | 0 | val_to_str(pinfo->pool, eof, fcip_eof_vals, |
426 | 0 | "0x%x")); |
427 | 0 | } |
428 | 0 | else { |
429 | 0 | sof = tvb_get_uint8 (tvb, offset+FCIP_ENCAP_HEADER_LEN); |
430 | |
|
431 | 0 | ti = proto_tree_add_protocol_format (tree, proto_fcip, tvb, 0, |
432 | 0 | FCIP_ENCAP_HEADER_LEN, |
433 | 0 | "FCIP (%s/%s)", |
434 | 0 | val_to_str(pinfo->pool, sof, fcip_sof_vals, |
435 | 0 | "0x%x"), |
436 | 0 | "NA"); |
437 | 0 | } |
438 | 0 | fcip_tree = proto_item_add_subtree (ti, ett_fcip); |
439 | | /* Dissect the Common FC Encap header */ |
440 | 0 | dissect_fcencap_header (tvb, fcip_tree, offset); |
441 | |
|
442 | 0 | offset += FCIP_ENCAP_HEADER_LEN; |
443 | |
|
444 | 0 | if (!FCIP_IS_SF (pflags)) { |
445 | | /* print SOF */ |
446 | 0 | proto_tree_add_item (fcip_tree, hf_fcip_sof, tvb, offset, 1, ENC_BIG_ENDIAN); |
447 | 0 | proto_tree_add_item (fcip_tree, hf_fcip_sof_c, tvb, offset+2, 1, ENC_BIG_ENDIAN); |
448 | | /* print EOF */ |
449 | |
|
450 | 0 | offset += (frame_len-FCIP_ENCAP_HEADER_LEN-4); |
451 | 0 | if (tvb_bytes_exist (tvb, offset, 4)) { |
452 | 0 | proto_tree_add_item (fcip_tree, hf_fcip_eof, tvb, offset, 1, ENC_BIG_ENDIAN); |
453 | 0 | proto_tree_add_item (fcip_tree, hf_fcip_eof_c, tvb, offset+2, 1, ENC_BIG_ENDIAN); |
454 | 0 | } |
455 | 0 | } |
456 | 0 | } |
457 | | |
458 | | /* Call the FC Dissector if this is carrying an FC frame */ |
459 | 1 | if (!FCIP_IS_SF(pflags)) { |
460 | | /* Set the SOF/EOF flags in the packet_info header */ |
461 | 0 | fc_data.sof_eof = 0; |
462 | |
|
463 | 0 | if (sof) { |
464 | 0 | if ((sof == FCIP_SOFi3) || (sof == FCIP_SOFi2) || (sof == FCIP_SOFi4)) { |
465 | 0 | fc_data.sof_eof = FC_DATA_SOF_FIRST_FRAME; |
466 | 0 | } |
467 | 0 | else if (sof == FCIP_SOFf) { |
468 | 0 | fc_data.sof_eof = FC_DATA_SOF_SOFF; |
469 | 0 | } |
470 | |
|
471 | 0 | if (eof != FCIP_EOFn) { |
472 | 0 | fc_data.sof_eof |= FC_DATA_EOF_LAST_FRAME; |
473 | 0 | } |
474 | 0 | else if (eof != FCIP_EOFt) { |
475 | 0 | fc_data.sof_eof |= FC_DATA_EOF_INVALID; |
476 | 0 | } |
477 | 0 | } |
478 | | |
479 | | /* Special frame bit is not set */ |
480 | 0 | next_tvb = tvb_new_subset_remaining (tvb, FCIP_ENCAP_HEADER_LEN+4); |
481 | 0 | if (fc_handle) { |
482 | 0 | fc_data.ethertype = ETHERTYPE_UNK; |
483 | 0 | call_dissector_with_data(fc_handle, next_tvb, pinfo, tree, &fc_data); |
484 | 0 | } |
485 | 0 | else { |
486 | 0 | call_data_dissector(next_tvb, pinfo, tree); |
487 | 0 | } |
488 | 0 | } |
489 | 1 | else { |
490 | 1 | col_set_str(pinfo->cinfo, COL_INFO, "Special Frame"); |
491 | 1 | if (FCIP_IS_CH (pflags)) { |
492 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "(Changed)"); |
493 | 0 | } |
494 | | |
495 | 1 | dissect_fcip_sf (tvb, fcip_tree, offset+4); |
496 | 1 | } |
497 | | |
498 | 1 | bytes_remaining -= frame_len; |
499 | 1 | } |
500 | | |
501 | 1 | return true; |
502 | 19 | } |
503 | | |
504 | | /* This is called for those sessions where we have explicitly said |
505 | | this to be FCIP using "Decode As..." |
506 | | In this case we will not check the port number for sanity and just |
507 | | do as the user said. |
508 | | */ |
509 | | static int |
510 | | dissect_fcip_handle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
511 | 0 | { |
512 | 0 | dissect_fcip (tvb, pinfo, tree, false); |
513 | 0 | return tvb_captured_length(tvb); |
514 | 0 | } |
515 | | |
516 | | static bool |
517 | | dissect_fcip_heur (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
518 | 2.27k | { |
519 | 2.27k | return (dissect_fcip (tvb, pinfo, tree, true)); |
520 | 2.27k | } |
521 | | |
522 | | void |
523 | | proto_register_fcip (void) |
524 | 16 | { |
525 | | |
526 | | /* Setup list of header fields See Section 1.6.1 for details*/ |
527 | 16 | static hf_register_info hf[] = { |
528 | 16 | { &hf_fcip_protocol, |
529 | 16 | { "Protocol", "fcip.proto", FT_UINT8, BASE_DEC, |
530 | 16 | VALS(fcencap_proto_vals), 0, NULL, HFILL }}, |
531 | 16 | { &hf_fcip_protocol_c, |
532 | 16 | {"Protocol (1's Complement)", "fcip.protoc", FT_UINT8, BASE_DEC, |
533 | 16 | NULL, 0, NULL, HFILL}}, |
534 | 16 | { &hf_fcip_version, |
535 | 16 | {"Version", "fcip.version", FT_UINT8, BASE_DEC, |
536 | 16 | NULL, 0, NULL, HFILL}}, |
537 | 16 | { &hf_fcip_version_c, |
538 | 16 | {"Version (1's Complement)", "fcip.versionc", FT_UINT8, BASE_DEC, |
539 | 16 | NULL, 0, NULL, HFILL}}, |
540 | 16 | { &hf_fcip_encap_word1, |
541 | 16 | {"FCIP Encapsulation Word1", "fcip.encap_word1", FT_UINT32, BASE_HEX, |
542 | 16 | NULL, 0, NULL, HFILL}}, |
543 | 16 | { &hf_fcip_flags, |
544 | 16 | {"Flags", "fcip.flags", FT_UINT8, BASE_HEX, |
545 | 16 | NULL, 0xFC, NULL, HFILL}}, |
546 | 16 | { &hf_fcip_flags_c, |
547 | 16 | {"Flags (1's Complement)", "fcip.flagsc", FT_UINT8, BASE_HEX, |
548 | 16 | NULL, 0xFC, NULL, HFILL}}, |
549 | 16 | { &hf_fcip_framelen, |
550 | 16 | {"Frame Length (in Words)", "fcip.framelen", FT_UINT16, BASE_DEC, |
551 | 16 | NULL, 0x03FF, NULL, HFILL}}, |
552 | 16 | { &hf_fcip_framelen_c, |
553 | 16 | {"Frame Length (1's Complement)", "fcip.framelenc", FT_UINT16, BASE_DEC, |
554 | 16 | NULL, 0x03FF, NULL, HFILL}}, |
555 | 16 | { &hf_fcip_tsec, |
556 | 16 | {"Time (secs)", "fcip.tsec", FT_UINT32, BASE_DEC, |
557 | 16 | NULL, 0, NULL, HFILL}}, |
558 | 16 | { &hf_fcip_tusec, |
559 | 16 | {"Time (fraction)", "fcip.tusec", FT_UINT32, BASE_DEC, |
560 | 16 | NULL, 0, NULL, HFILL}}, |
561 | 16 | { &hf_fcip_encap_crc, |
562 | 16 | {"CRC", "fcip.encap_crc", FT_UINT32, BASE_HEX, |
563 | 16 | NULL, 0, NULL, HFILL}}, |
564 | 16 | { &hf_fcip_sof, |
565 | 16 | {"SOF", "fcip.sof", FT_UINT8, BASE_HEX, |
566 | 16 | VALS (fcip_sof_vals), 0, NULL, HFILL}}, |
567 | 16 | { &hf_fcip_sof_c, |
568 | 16 | {"SOF (1's Complement)", "fcip.sofc", FT_UINT8, BASE_HEX, |
569 | 16 | NULL, 0, NULL, HFILL}}, |
570 | 16 | { &hf_fcip_eof, |
571 | 16 | {"EOF", "fcip.eof", FT_UINT8, BASE_HEX, |
572 | 16 | VALS (fcip_eof_vals), 0, NULL, HFILL}}, |
573 | 16 | { &hf_fcip_eof_c, |
574 | 16 | {"EOF (1's Complement)", "fcip.eofc", FT_UINT8, BASE_HEX, |
575 | 16 | NULL, 0, NULL, HFILL}}, |
576 | 16 | { &hf_fcip_pflags_changed, |
577 | 16 | {"Changed Flag", "fcip.pflags.ch", FT_BOOLEAN, 8, |
578 | 16 | NULL, 0x80, NULL, HFILL}}, |
579 | 16 | { &hf_fcip_pflags_special, |
580 | 16 | {"Special Frame Flag", "fcip.pflags.sf", FT_BOOLEAN, 8, |
581 | 16 | NULL, 0x1, NULL, HFILL}}, |
582 | 16 | { &hf_fcip_pflags_c, |
583 | 16 | {"Pflags (1's Complement)", "fcip.pflagsc", FT_UINT8, BASE_HEX, |
584 | 16 | NULL, 0x0, NULL, HFILL}}, |
585 | 16 | { &hf_fcip_src_wwn, |
586 | 16 | {"Source Fabric WWN", "fcip.srcwwn", FT_FCWWN, BASE_NONE, |
587 | 16 | NULL, 0x0, NULL, HFILL}}, |
588 | 16 | { &hf_fcip_dst_wwn, |
589 | 16 | {"Destination Fabric WWN", "fcip.dstwwn", FT_FCWWN, BASE_NONE, |
590 | 16 | NULL, 0x0, NULL, HFILL}}, |
591 | 16 | { &hf_fcip_src_entity_id, |
592 | 16 | {"FC/FCIP Entity Id", "fcip.srcid", FT_BYTES, BASE_NONE, |
593 | 16 | NULL, 0x0, NULL, HFILL}}, |
594 | 16 | { &hf_fcip_conn_flags, |
595 | 16 | {"Connection Usage Flags", "fcip.connflags", FT_UINT8, BASE_HEX, |
596 | 16 | NULL, 0x0, NULL, HFILL}}, |
597 | 16 | { &hf_fcip_conn_code, |
598 | 16 | {"Connection Usage Code", "fcip.conncode", FT_UINT16, BASE_HEX, |
599 | 16 | NULL, 0x0, NULL, HFILL}}, |
600 | 16 | { &hf_fcip_katov, |
601 | 16 | {"K_A_TOV", "fcip.katov", FT_UINT32, BASE_DEC, |
602 | 16 | NULL, 0x0, NULL, HFILL}}, |
603 | 16 | { &hf_fcip_conn_nonce, |
604 | 16 | {"Connection Nonce", "fcip.nonce", FT_BYTES, BASE_NONE, |
605 | 16 | NULL, 0x0, NULL, HFILL}}, |
606 | 16 | }; |
607 | | |
608 | 16 | static int *ett[] = { |
609 | 16 | &ett_fcip, |
610 | 16 | }; |
611 | | |
612 | 16 | module_t *fcip_module; |
613 | | |
614 | | /* Register the protocol name and description */ |
615 | 16 | proto_fcip = proto_register_protocol("FCIP", "Fibre Channel over IP", "fcip"); |
616 | 16 | fcip_handle = register_dissector("fcip", dissect_fcip_handle, proto_fcip); |
617 | | |
618 | 16 | proto_register_field_array(proto_fcip, hf, array_length(hf)); |
619 | 16 | proto_register_subtree_array(ett, array_length(ett)); |
620 | | |
621 | 16 | fcip_module = prefs_register_protocol(proto_fcip, NULL); |
622 | 16 | prefs_register_bool_preference(fcip_module, |
623 | 16 | "desegment", |
624 | 16 | "Reassemble FCIP messages spanning multiple TCP segments", |
625 | 16 | "Whether the FCIP dissector should reassemble messages spanning multiple TCP segments." |
626 | 16 | " To use this option, you must also enable" |
627 | 16 | " \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.", |
628 | 16 | &fcip_desegment); |
629 | 16 | prefs_register_uint_preference(fcip_module, |
630 | 16 | "target_port", |
631 | 16 | "Target port", |
632 | 16 | "Port number used for FCIP", |
633 | 16 | 10, |
634 | 16 | &fcip_port); |
635 | 16 | } |
636 | | |
637 | | void |
638 | | proto_reg_handoff_fcip (void) |
639 | 16 | { |
640 | 16 | heur_dissector_add("tcp", dissect_fcip_heur, "FCIP over TCP", "fcip_tcp", proto_fcip, HEURISTIC_ENABLE); |
641 | | |
642 | 16 | dissector_add_for_decode_as_with_preference("tcp.port", fcip_handle); |
643 | | |
644 | 16 | fc_handle = find_dissector_add_dependency("fc", proto_fcip); |
645 | 16 | } |
646 | | |
647 | | /* |
648 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
649 | | * |
650 | | * Local variables: |
651 | | * c-basic-offset: 4 |
652 | | * tab-width: 8 |
653 | | * indent-tabs-mode: nil |
654 | | * End: |
655 | | * |
656 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
657 | | * :indentSize=4:tabSize=8:noTabs=true: |
658 | | */ |