Move 3 ASN1 dissectors to 'clean' group; move 1 PIDL dissector to 'dirty' group.
[metze/wireshark/wip.git] / epan / dissectors / packet-ifcp.c
1 /* packet-ifcp.c
2  * Routines for iFCP dissection
3  * RFC 3821, RFC 3643
4  *
5  * Copyright 2005   Aboo Valappil     (valappil_aboo@emc.com)
6  *           2006 ronnie sahlberg   major refactoring
7  *
8  *
9  * Significantly based on packet-fcip.c by
10  *       Copyright 2001, Dinesh G Dutt (ddutt@cisco.com)
11  *
12  * $Id$
13  *
14  * Wireshark - Network traffic analyzer
15  * By Gerald Combs <gerald@wireshark.org>
16  * Copyright 1998 Gerald Combs
17  *
18  * This program is free software; you can redistribute it and/or
19  * modify it under the terms of the GNU General Public License
20  * as published by the Free Software Foundation; either version 2
21  * of the License, or (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  * GNU General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License
29  * along with this program; if not, write to the Free Software
30  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31  */
32
33 #include "config.h"
34
35 #include <glib.h>
36
37 #include <epan/packet.h>
38 #include <epan/prefs.h>
39 #include <epan/conversation.h>
40 #include "packet-tcp.h"
41
42 #define iFCP_ENCAP_HEADER_LEN                    28
43 #define iFCP_MIN_HEADER_LEN                      16 /* upto frame len field */
44
45 typedef enum {
46     iFCP_EOFn    = 0x41,
47     iFCP_EOFt    = 0x42,
48     iFCP_EOFrt   = 0x44,
49     iFCP_EOFdt   = 0x46,
50     iFCP_EOFni   = 0x49,
51     iFCP_EOFdti  = 0x4E,
52     iFCP_EOFrti  = 0x4F,
53     iFCP_EOFa    = 0x50
54 } ifcp_eof_t;
55
56 typedef enum {
57     iFCP_SOFf    = 0x28,
58     iFCP_SOFi4   = 0x29,
59     iFCP_SOFi2   = 0x2D,
60     iFCP_SOFi3   = 0x2E,
61     iFCP_SOFn4   = 0x31,
62     iFCP_SOFn2   = 0x35,
63     iFCP_SOFn3   = 0x36,
64     iFCP_SOFc4   = 0x39
65 } ifcp_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 ifcp_eof_vals[] = {
73     {iFCP_EOFn, "EOFn" },
74     {iFCP_EOFt, "EOFt" },
75     {iFCP_EOFrt, "EOFrt" },
76     {iFCP_EOFdt, "EOFdt" },
77     {iFCP_EOFni, "EOFni" },
78     {iFCP_EOFdti, "EOFdti" },
79     {iFCP_EOFrti, "EOFrti" },
80     {iFCP_EOFa, "EOFa" },
81     {0, NULL},
82 };
83
84 static const value_string ifcp_sof_vals[] = {
85     {iFCP_SOFf, "SOFf" },
86     {iFCP_SOFi4, "SOFi4" },
87     {iFCP_SOFi2, "SOFi2" },
88     {iFCP_SOFi3, "SOFi3" },
89     {iFCP_SOFn4, "SOFn4" },
90     {iFCP_SOFn2, "SOFn2" },
91     {iFCP_SOFn3, "SOFn3" },
92     {iFCP_SOFc4, "SOFc4" },
93     {0, NULL},
94 };
95
96 static const value_string fcencap_proto_vals[] = {
97     {FCENCAP_PROTO_iFCP, "iFCP"},
98     {FCENCAP_PROTO_iFCP, "iFCP"},
99     {0, NULL},
100 };
101
102 /* RFC 4172 section 5.3.1 shows a chart of the iFCP encapsulated Header Format.
103  * It says that bytes 4-7 MUST be zeros.  In reality most vendors are putting
104  * some information in these 4 bytes, particularly Nishon.
105  */
106 static const guint8 ifcp_header_4_bytes[4] = {
107     0x02, 0x01, 0xFD, 0xFE
108 };
109
110 static int proto_ifcp          = -1;
111
112 static int hf_ifcp_protocol    = -1;
113 static int hf_ifcp_protocol_c  = -1;
114 static int hf_ifcp_version     = -1;
115 static int hf_ifcp_version_c   = -1;
116 static int hf_ifcp_encap_flags_c=-1;
117 static int hf_ifcp_framelen    = -1;
118 static int hf_ifcp_framelen_c  = -1;
119 static int hf_ifcp_tsec        = -1;
120 static int hf_ifcp_tusec       = -1;
121 static int hf_ifcp_encap_crc   = -1;
122 static int hf_ifcp_sof         = -1;
123 static int hf_ifcp_sof_c       = -1;
124 static int hf_ifcp_eof         = -1;
125 static int hf_ifcp_eof_c       = -1;
126 static int hf_ifcp_ls_command_acc = -1;
127 static int hf_ifcp_flags     = -1;
128 static int hf_ifcp_flags_ses = -1;
129 static int hf_ifcp_flags_trp = -1;
130 static int hf_ifcp_flags_spc = -1;
131 static int hf_ifcp_common_flags    = -1;
132 static int hf_ifcp_common_flags_crcv = -1;
133
134 static int ett_ifcp              = -1;
135 static int ett_ifcp_sof          = -1;
136 static int ett_ifcp_eof          = -1;
137 static int ett_ifcp_flags        = -1;
138 static int ett_ifcp_common_flags = -1;
139 static int ett_ifcp_protocol     = -1;
140 static int ett_ifcp_version      = -1;
141 static int ett_ifcp_frame_len    = -1;
142
143 static gboolean ifcp_desegment    = TRUE;
144
145 static dissector_handle_t ifcp_handle=NULL;
146 static dissector_handle_t data_handle=NULL;
147 static dissector_handle_t fc_handle=NULL;
148
149
150 /* This function checks the first 16 bytes of the "header" that it looks sane
151  * and returns TRUE if this looks like iFCP and FALSE if it doesnt.
152  */
153 static gboolean
154 ifcp_header_test(tvbuff_t *tvb, int offset)
155 {
156         guint16 flen, flen1;
157
158         /* we can only do this test if we have 16 bytes or more */
159         if(tvb_length_remaining(tvb, offset)<iFCP_MIN_HEADER_LEN){
160                 return FALSE;
161         }
162
163         /*
164         * As per the iFCP standard, the following tests must PASS:
165         * 1)  Frame Length field validation -- 15 < Frame Length < 545;
166         * 2)  Comparison of Frame Length field to its ones complement; and
167         * 3)  A valid EOF is found in the word preceding the start of the next
168         *     iFCP header as indicated by the Frame Length field, to be tested
169         *     as follows:
170         *     1)  Bits 24-31 and 16-23 contain identical legal EOF values (the
171         *         list of legal EOF values is in the FC Frame Encapsulation
172         *         [21]); and
173         *     2)  Bits 8-15 and 0-7 contain the ones complement of the EOF
174         *         value found in bits 24-31.
175         *
176         * As per the iFCP standard, in addition, at least 3 of the following
177         * set of tests must be performed to identify that we've located the
178         * start of an iFCP frame.
179         * a)  Protocol# ones complement field (1 test);
180         * b)  Version ones complement field (1 test);
181         * c)  Replication of encapsulation word 0 in word 1 (1 test);
182         * d)  Reserved field and its ones complement (2 tests);
183         * e)  Flags field and its ones complement (2 tests);
184         *    f)  CRC field is equal to zero (1 test); (DONT DO THIS TEST!)
185         * g)  SOF fields and ones complement fields (4 tests);
186         * h)  Format and values of FC header (1 test);
187         * i)  CRC of FC Frame (2 tests);
188         * j)  FC Frame Encapsulation header information in the next iFCP Frame
189         *     (1 test).
190         *
191         * At least 3 of the 16 tests listed above SHALL be performed. Failure
192         * of any of the above tests actually performed SHALL indicate an
193         * encapsulation error and the FC Frame SHALL NOT be forwarded on to
194         * the FC Entity.
195         */
196
197
198         /*
199          * Tests a, b and c
200          */
201         if(tvb_memeql(tvb, offset, ifcp_header_4_bytes, 4) != 0){
202                 return FALSE;
203         }
204
205         /* check the frame length */
206         flen=tvb_get_ntohs(tvb, offset+12)&0x03FF;
207         if((flen < 15) || (flen > 545)){
208                 return FALSE;
209         }
210
211         /* check the complement of the frame length */
212         flen1=tvb_get_ntohs(tvb, offset+14)&0x03FF;
213         if(flen!=((~flen1)&0x03FF)){
214                 return FALSE;
215         }
216
217
218         /* this should be good enough for our heuristics */
219         return TRUE;
220 }
221
222
223 #define IFCP_FLAGS_SES          0x04
224 #define IFCP_FLAGS_TRP          0x02
225 #define IFCP_FLAGS_SPC          0x01
226
227 static const true_false_string ifcp_flags_ses_tfs = {
228         "This is a SESSION CONTROL FRAME",
229         "This is a normal frame"
230 };
231
232 static const true_false_string ifcp_flags_trp_tfs = {
233         "Address TRANSPARENT Mode Enabled",
234         "Address TRANSLATION Mode Enabled"
235 };
236
237 static const true_false_string ifcp_flags_spc_tfs = {
238         "This frame requires SPECIAL PROCESSING",
239         "This is a normal frame"
240 };
241
242 static int
243 dissect_ifcpflags(tvbuff_t *tvb, int offset, proto_tree *parent_tree)
244 {
245         proto_item *item=NULL;
246         proto_tree *tree=NULL;
247         guint8 flags;
248
249         if(parent_tree){
250                 item=proto_tree_add_item(parent_tree, hf_ifcp_flags, tvb, offset, 1, ENC_BIG_ENDIAN);
251                 tree=proto_item_add_subtree (item, ett_ifcp_flags);
252         }
253
254         flags=tvb_get_guint8(tvb, offset);
255
256         /* SES */
257         proto_tree_add_boolean(tree, hf_ifcp_flags_ses, tvb, offset, 1, flags);
258         if(flags&IFCP_FLAGS_SES){
259                 proto_item_append_text(item, "  SES");
260         }
261         flags&=(~IFCP_FLAGS_SES);
262
263         /* TRP */
264         proto_tree_add_boolean(tree, hf_ifcp_flags_trp, tvb, offset, 1, flags);
265         if(flags&IFCP_FLAGS_TRP){
266                 proto_item_append_text(item, "  TRP");
267         }
268         flags&=(~IFCP_FLAGS_TRP);
269
270         /* SPC */
271         proto_tree_add_boolean(tree, hf_ifcp_flags_spc, tvb, offset, 1, flags);
272         if(flags&IFCP_FLAGS_SPC){
273                 proto_item_append_text(item, "  SPC");
274         }
275
276
277         offset++;
278         return offset;
279 }
280
281
282 #define IFCP_COMMON_FLAGS_CRCV          0x04
283
284 static const true_false_string ifcp_common_flags_crcv_tfs = {
285         "CRC is VALID",
286         "Crc is NOT valid"
287 };
288
289 static void
290 dissect_commonflags(tvbuff_t *tvb, int offset, proto_tree *parent_tree)
291 {
292         proto_item *item=NULL;
293         proto_tree *tree=NULL;
294         guint8 flags;
295
296         if(parent_tree){
297                 item=proto_tree_add_item(parent_tree, hf_ifcp_common_flags, tvb, offset, 1, ENC_BIG_ENDIAN);
298                 tree=proto_item_add_subtree (item, ett_ifcp_common_flags);
299         }
300
301         flags=tvb_get_guint8(tvb, offset);
302
303         /* CRCV */
304         proto_tree_add_boolean(tree, hf_ifcp_common_flags_crcv, tvb, offset, 1, flags);
305         if(flags&IFCP_COMMON_FLAGS_CRCV){
306                 proto_item_append_text(item, "  CRCV");
307         }
308 }
309
310 static void
311 dissect_ifcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
312 {
313         gint offset = 0, frame_len = 0;
314         guint8 sof = 0, eof = 0;
315         proto_item *ti;
316         proto_tree *tree = NULL;
317         tvbuff_t *next_tvb;
318         guint8 protocol;
319         proto_tree *protocol_tree=NULL;
320         proto_tree *version_tree=NULL;
321         proto_tree *frame_len_tree=NULL;
322         proto_tree *sof_tree=NULL;
323         proto_tree *eof_tree=NULL;
324
325         /* verify we have a full header  (do we need to do this? */
326         if(tvb_length(tvb)<iFCP_ENCAP_HEADER_LEN){
327                 return;
328         }
329
330         col_set_str(pinfo->cinfo, COL_PROTOCOL, "iFCP");
331
332         frame_len = (tvb_get_ntohs (tvb, offset+12) & 0x03FF)*4;
333
334
335         if (parent_tree) {
336             if (tvb_bytes_exist (tvb, offset, frame_len-4)) {
337                 sof = tvb_get_guint8 (tvb, offset+iFCP_ENCAP_HEADER_LEN);
338                 eof = tvb_get_guint8 (tvb, offset+frame_len - 4);
339
340                 ti = proto_tree_add_protocol_format (parent_tree, proto_ifcp, tvb, offset,
341                                                      iFCP_ENCAP_HEADER_LEN,
342                                                      "iFCP (%s/%s)",
343                                                      val_to_str (sof, ifcp_sof_vals,
344                                                                  "0x%x"),
345                                                      val_to_str (eof, ifcp_eof_vals,
346                                                                  "0x%x"));
347             } else {
348                 sof = tvb_get_guint8 (tvb, offset+iFCP_ENCAP_HEADER_LEN);
349
350                 ti = proto_tree_add_protocol_format (parent_tree, proto_ifcp, tvb, offset,
351                                                      iFCP_ENCAP_HEADER_LEN,
352                                                      "iFCP (%s/%s)",
353                                                      val_to_str (sof, ifcp_sof_vals,
354                                                                  "0x%x"),
355                                                      "NA");
356             }
357             tree = proto_item_add_subtree (ti, ett_ifcp);
358         }
359
360
361
362         /* The Common FC Encap header */
363         /* protocol */
364         protocol = tvb_get_guint8 (tvb, offset);
365         ti=proto_tree_add_item(tree, hf_ifcp_protocol, tvb, offset, 1, ENC_BIG_ENDIAN);
366         if(ti){
367                 protocol_tree=proto_item_add_subtree(ti, ett_ifcp_protocol);
368         }
369         offset++;
370
371         /* version */
372         ti=proto_tree_add_item(tree, hf_ifcp_version, tvb, offset, 1, ENC_BIG_ENDIAN);
373         if(ti){
374                 version_tree=proto_item_add_subtree(ti, ett_ifcp_version);
375         }
376         offset++;
377
378         /* protocol complement */
379         proto_tree_add_item(protocol_tree, hf_ifcp_protocol_c, tvb, offset, 1, ENC_BIG_ENDIAN);
380         offset++;
381
382         /* version complement */
383         proto_tree_add_item(version_tree, hf_ifcp_version_c, tvb, offset, 1, ENC_BIG_ENDIAN);
384         offset++;
385
386         /* 4 reserved bytes */
387         offset+=4;
388
389         /* iFCP specific fields */
390         if(protocol==FCENCAP_PROTO_iFCP){
391                 /* LS_COMMAND_ACC */
392                 proto_tree_add_item(tree, hf_ifcp_ls_command_acc, tvb, offset, 1, ENC_BIG_ENDIAN);
393                 offset++;
394
395                 /* iFCP Flags */
396                 offset=dissect_ifcpflags(tvb, offset, tree);
397
398                 /* SOF */
399                 ti=proto_tree_add_item(tree, hf_ifcp_sof, tvb, offset, 1, ENC_BIG_ENDIAN);
400                 if(ti){
401                         sof_tree=proto_item_add_subtree(ti, ett_ifcp_sof);
402                 }
403                 offset++;
404
405                 /* EOF */
406                 ti=proto_tree_add_item(tree, hf_ifcp_eof, tvb, offset, 1, ENC_BIG_ENDIAN);
407                 if(ti){
408                         eof_tree=proto_item_add_subtree(ti, ett_ifcp_eof);
409                 }
410                 offset++;
411         } else {
412                 offset+=4;
413                 sof_tree=tree; /* better than nothing */
414                 eof_tree=tree;
415         }
416
417         /* Common Flags */
418         dissect_commonflags(tvb, offset, tree);
419
420         /* frame len */
421         ti=proto_tree_add_item(tree, hf_ifcp_framelen, tvb, offset, 2, ENC_BIG_ENDIAN);
422         if(ti){
423                 frame_len_tree=proto_item_add_subtree(ti, ett_ifcp_frame_len);
424         }
425         offset+=2;
426
427         /* complement of flags and frame len */
428         proto_tree_add_item(frame_len_tree, hf_ifcp_encap_flags_c, tvb, offset, 1, ENC_BIG_ENDIAN);
429         proto_tree_add_item(frame_len_tree, hf_ifcp_framelen_c, tvb, offset, 2, ENC_BIG_ENDIAN);
430         offset+=2;
431
432         /* timestamp seconds */
433         proto_tree_add_item(tree, hf_ifcp_tsec, tvb, offset, 4, ENC_BIG_ENDIAN);
434         offset+=4;
435
436         /* timestamp fractions */
437         proto_tree_add_item(tree, hf_ifcp_tusec, tvb, offset, 4, ENC_BIG_ENDIAN);
438         offset+=4;
439
440         /* crc */
441         proto_tree_add_item(tree, hf_ifcp_encap_crc, tvb, offset, 4, ENC_BIG_ENDIAN);
442         offset+=4;
443
444
445         /* FC SOF/-SOF */
446         proto_tree_add_item(sof_tree, hf_ifcp_sof, tvb, offset, 1, ENC_BIG_ENDIAN);
447         offset++;
448         proto_tree_add_item(sof_tree, hf_ifcp_sof, tvb, offset, 1, ENC_BIG_ENDIAN);
449         offset++;
450         proto_tree_add_item(sof_tree, hf_ifcp_sof_c, tvb, offset, 1, ENC_BIG_ENDIAN);
451         offset++;
452         proto_tree_add_item(sof_tree, hf_ifcp_sof_c, tvb, offset, 1, ENC_BIG_ENDIAN);
453         offset++;
454
455         /* FC EOF/-EOF */
456         if(tvb_bytes_exist(tvb, frame_len-4, 4)) {
457                 proto_tree_add_item(eof_tree, hf_ifcp_eof, tvb, frame_len-4, 1, ENC_BIG_ENDIAN);
458                 proto_tree_add_item(eof_tree, hf_ifcp_eof, tvb, frame_len-3, 1, ENC_BIG_ENDIAN);
459                 proto_tree_add_item(eof_tree, hf_ifcp_eof_c, tvb, frame_len-2, 1, ENC_BIG_ENDIAN);
460                 proto_tree_add_item(eof_tree, hf_ifcp_eof_c, tvb, frame_len-1, 1, ENC_BIG_ENDIAN);
461         }
462
463
464         /* Call the FC Dissector if this is carrying an FC frame */
465         /* Set the SOF/EOF flags in the packet_info header */
466         pinfo->sof_eof = 0;
467
468         switch(sof){
469         case iFCP_SOFi3:
470         case iFCP_SOFi2:
471         case iFCP_SOFi4:
472                 pinfo->sof_eof = PINFO_SOF_FIRST_FRAME;
473                 break;
474         case iFCP_SOFf:
475                 pinfo->sof_eof = PINFO_SOF_SOFF;
476                 break;
477         default:
478                 if(sof){
479                         if (eof != iFCP_EOFn) {
480                                 pinfo->sof_eof |= PINFO_EOF_LAST_FRAME;
481                         } else if (eof != iFCP_EOFt) {
482                                 pinfo->sof_eof |= PINFO_EOF_INVALID;
483                         }
484                 }
485         }
486
487         next_tvb=tvb_new_subset(tvb, offset, frame_len-offset-4, frame_len-offset-4);
488
489         if(fc_handle){
490                 call_dissector(fc_handle, next_tvb, pinfo, parent_tree);
491         } else if(data_handle){
492                 call_dissector(data_handle, next_tvb, pinfo, parent_tree);
493         }
494
495         return;
496 }
497
498 static guint
499 get_ifcp_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
500 {
501         guint pdu_len;
502
503         if(!ifcp_header_test(tvb, offset)){
504                 return 0;
505         }
506
507         pdu_len=(tvb_get_ntohs(tvb, offset+12)&0x03FF)*4;
508         return pdu_len;
509 }
510
511 static void
512 dissect_ifcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
513 {
514         tcp_dissect_pdus(tvb, pinfo, parent_tree, ifcp_desegment, iFCP_MIN_HEADER_LEN, get_ifcp_pdu_len, dissect_ifcp_pdu);
515 }
516
517
518 /* This is called for those sessions where we have explicitely said
519  * this to be iFCP using "Decode As..."
520  * In this case we will not check the port number for sanity and just
521  * do as the user said.
522  */
523 static void
524 dissect_ifcp_handle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
525 {
526         dissect_ifcp(tvb, pinfo, tree);
527 }
528
529 static gboolean
530 dissect_ifcp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
531 {
532         if(!ifcp_header_test(tvb, 0)){
533                 return FALSE;
534         }
535
536         dissect_ifcp(tvb, pinfo, tree);
537
538         /* our heuristics are so strong that if the heuristics above passed
539          * and the dissection of the pdu did not cause any exceptions
540          * then we can set this as our conversation dissector
541          */
542         if(ifcp_handle){
543                 conversation_t* ifcp_conv;
544
545                 ifcp_conv=find_or_create_conversation(pinfo);
546                 /* XXX why does this not work? it doesnt result in dissect_ifcp_handle being called    look into later*/
547                 conversation_set_dissector(ifcp_conv, ifcp_handle);
548         }
549
550         return TRUE;
551 }
552
553 void
554 proto_register_ifcp (void)
555 {
556
557     /* Setup list of header fields  See Section 1.6.1 for details*/
558     static hf_register_info hf[] = {
559         { &hf_ifcp_protocol,
560           { "Protocol", "ifcp.encap.proto", FT_UINT8, BASE_DEC,
561              VALS(fcencap_proto_vals), 0, NULL, HFILL }},
562         { &hf_ifcp_protocol_c,
563           {"Protocol (1's Complement)", "ifcp.encap.protoc", FT_UINT8, BASE_DEC, NULL,
564            0, NULL, HFILL}},
565         { &hf_ifcp_version,
566           {"Version", "ifcp.encap.version", FT_UINT8, BASE_DEC, NULL, 0, NULL,
567            HFILL}},
568         { &hf_ifcp_version_c,
569           {"Version (1's Complement)", "ifcp.encap.versionc", FT_UINT8, BASE_DEC,
570            NULL, 0, NULL, HFILL}},
571         { &hf_ifcp_encap_flags_c,
572           {"iFCP Encapsulation Flags (1's Complement)", "ifcp.encap_flagsc", FT_UINT8, BASE_HEX,
573            NULL, 0xFC, NULL, HFILL}},
574         { &hf_ifcp_framelen,
575           {"Frame Length (in Words)", "ifcp.encap.framelen", FT_UINT16, BASE_DEC,
576            NULL, 0x03FF, NULL, HFILL}},
577         { &hf_ifcp_framelen_c,
578           {"Frame Length (1's Complement)", "ifcp.encap.framelenc", FT_UINT16,
579            BASE_DEC, NULL, 0x03FF, NULL, HFILL}},
580         { &hf_ifcp_tsec,
581           {"Time (secs)", "ifcp.encap.tsec", FT_UINT32, BASE_DEC, NULL, 0, NULL,
582            HFILL}},
583         { &hf_ifcp_tusec,
584           {"Time (fraction)", "ifcp.encap.tusec", FT_UINT32, BASE_DEC, NULL, 0,
585            NULL, HFILL}},
586         { &hf_ifcp_encap_crc,
587           {"CRC", "ifcp.encap.crc", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL}},
588         { &hf_ifcp_sof,
589           {"SOF", "ifcp.sof", FT_UINT8, BASE_HEX, VALS (&ifcp_sof_vals), 0,
590            NULL, HFILL}},
591         { &hf_ifcp_eof,
592           {"EOF", "ifcp.eof", FT_UINT8, BASE_HEX, VALS (&ifcp_eof_vals), 0,
593            NULL, HFILL}},
594         { &hf_ifcp_sof_c,
595           {"SOF Compliment", "ifcp.sof_c", FT_UINT8, BASE_HEX, NULL , 0,
596            NULL, HFILL}},
597         { &hf_ifcp_eof_c,
598           {"EOF Compliment", "ifcp.eof_c", FT_UINT8, BASE_HEX, NULL , 0,
599            NULL, HFILL}},
600         { &hf_ifcp_ls_command_acc,
601           {"Ls Command Acc", "ifcp.ls_command_acc", FT_UINT8, BASE_HEX, NULL, 0,
602            NULL, HFILL}},
603         { &hf_ifcp_common_flags,
604           {"Flags", "ifcp.common_flags", FT_UINT8, BASE_HEX , NULL, 0xfc, NULL, HFILL }},
605         { &hf_ifcp_common_flags_crcv,
606           {"CRCV", "ifcp.common_flags.crcv", FT_BOOLEAN, 8, TFS(&ifcp_common_flags_crcv_tfs), IFCP_COMMON_FLAGS_CRCV, "Is the CRC field valid?", HFILL }},
607         { &hf_ifcp_flags,
608           {"iFCP Flags", "ifcp.flags", FT_UINT8, BASE_HEX , NULL, 0, NULL, HFILL }},
609         { &hf_ifcp_flags_ses,
610           {"SES", "ifcp.flags.ses", FT_BOOLEAN, 8, TFS(&ifcp_flags_ses_tfs), IFCP_FLAGS_SES, "Is this a Session control frame", HFILL }},
611         { &hf_ifcp_flags_trp,
612           {"TRP", "ifcp.flags.trp", FT_BOOLEAN, 8, TFS(&ifcp_flags_trp_tfs), IFCP_FLAGS_TRP, "Is address transparent mode enabled", HFILL }},
613         { &hf_ifcp_flags_spc,
614           {"SPC", "ifcp.flags.spc", FT_BOOLEAN, 8, TFS(&ifcp_flags_spc_tfs), IFCP_FLAGS_SPC, "Is frame part of link service", HFILL }},
615     };
616
617     static gint *ett[] = {
618         &ett_ifcp,
619         &ett_ifcp_sof,
620         &ett_ifcp_eof,
621         &ett_ifcp_protocol,
622         &ett_ifcp_version,
623         &ett_ifcp_frame_len,
624         &ett_ifcp_flags,
625         &ett_ifcp_common_flags,
626     };
627
628     module_t *ifcp_module;
629
630     /* Register the protocol name and description */
631     proto_ifcp = proto_register_protocol("iFCP", "iFCP", "ifcp");
632
633     /* Required function calls to register the header fields and
634      * subtrees used */
635     proto_register_field_array(proto_ifcp, hf, array_length(hf));
636     proto_register_subtree_array(ett, array_length(ett));
637
638     ifcp_module = prefs_register_protocol(proto_ifcp, NULL);
639     prefs_register_bool_preference(ifcp_module,
640                                    "desegment",
641                                    "Reassemble iFCP messages spanning multiple TCP segments",
642                                    "Whether the iFCP 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                                    &ifcp_desegment);
645     prefs_register_obsolete_preference(ifcp_module, "target_port");
646 }
647
648
649 /*
650  * If this dissector uses sub-dissector registration add a
651  * registration routine.
652  */
653
654 /*
655  * This format is required because a script is used to find these
656  * routines and create the code that calls these routines.
657  */
658 void
659 proto_reg_handoff_ifcp (void)
660 {
661     heur_dissector_add("tcp", dissect_ifcp_heur, proto_ifcp);
662
663     ifcp_handle = create_dissector_handle(dissect_ifcp_handle, proto_ifcp);
664     dissector_add_handle("tcp.port", ifcp_handle);
665
666     data_handle = find_dissector("data");
667     fc_handle = find_dissector("fc_ifcp");
668 }