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