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