remove offset and len from the signature of dissect_scsi_payload()
[obnox/wireshark/wip.git] / epan / dissectors / packet-fcp.c
1 /* packet-fcp.c
2  * Routines for Fibre Channel Protocol for SCSI (FCP)
3  * Copyright 2001, Dinesh G Dutt <ddutt@cisco.com>
4  *
5  * $Id$
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #ifdef HAVE_SYS_TYPES_H
35 # include <sys/types.h>
36 #endif
37
38 #ifdef HAVE_NETINET_IN_H
39 # include <netinet/in.h>
40 #endif
41
42 #include <glib.h>
43
44 #ifdef NEED_SNPRINTF_H
45 # include "snprintf.h"
46 #endif
47
48 #include <epan/prefs.h>
49 #include <epan/packet.h>
50 #include <epan/conversation.h>
51 #include "etypes.h"
52 #include "packet-fc.h"
53 #include "packet-fcp.h"
54 #include "packet-scsi.h"
55
56 /* Initialize the protocol and registered fields */
57 static int proto_fcp         = -1;
58 static int hf_fcp_multilun   = -1;
59 static int hf_fcp_singlelun  = -1;
60 static int hf_fcp_crn        = -1;
61 static int hf_fcp_taskattr   = -1;
62 static int hf_fcp_taskmgmt   = -1;
63 static int hf_fcp_addlcdblen = -1;
64 static int hf_fcp_rddata     = -1;
65 static int hf_fcp_wrdata     = -1;
66 static int hf_fcp_dl         = -1;
67 static int hf_fcp_data_ro    = -1;
68 static int hf_fcp_burstlen   = -1;
69 static int hf_fcp_rspflags   = -1;
70 static int hf_fcp_resid      = -1;
71 static int hf_fcp_snslen     = -1;
72 static int hf_fcp_rsplen     = -1;
73 static int hf_fcp_rspcode    = -1;
74 static int hf_fcp_scsistatus = -1;
75 static int hf_fcp_type = -1;
76
77
78 /* Initialize the subtree pointers */
79 static gint ett_fcp = -1;
80 static dissector_table_t fcp_dissector;
81 static dissector_handle_t data_handle;
82
83 typedef struct _fcp_conv_key {
84     guint32 conv_idx;
85 } fcp_conv_key_t;
86
87 typedef struct _fcp_conv_data {
88     guint32 fcp_dl;
89     gint32 fcp_lun;
90     guint32 abs_secs;
91     guint32 abs_usecs;
92 } fcp_conv_data_t;
93
94 GHashTable *fcp_req_hash = NULL;
95 GMemChunk *fcp_req_keys = NULL;
96 GMemChunk *fcp_req_vals = NULL;
97 guint32 fcp_init_count = 25;
98
99 /*
100  * Hash Functions
101  */
102 static gint
103 fcp_equal(gconstpointer v, gconstpointer w)
104 {
105   const fcp_conv_key_t *v1 = v;
106   const fcp_conv_key_t *v2 = w;
107
108   return (v1->conv_idx == v2->conv_idx);
109 }
110
111 static guint
112 fcp_hash (gconstpointer v)
113 {
114         const fcp_conv_key_t *key = v;
115         guint val;
116
117         val = key->conv_idx;
118
119         return val;
120 }
121
122 /*
123  * Protocol initialization
124  */
125 static void
126 fcp_init_protocol(void)
127 {
128     if (fcp_req_keys)
129         g_mem_chunk_destroy(fcp_req_keys);
130     if (fcp_req_vals)
131         g_mem_chunk_destroy(fcp_req_vals);
132     if (fcp_req_hash)
133         g_hash_table_destroy(fcp_req_hash);
134
135     fcp_req_hash = g_hash_table_new(fcp_hash, fcp_equal);
136     fcp_req_keys = g_mem_chunk_new("fcp_req_keys",
137                                    sizeof(fcp_conv_key_t),
138                                    fcp_init_count * sizeof(fcp_conv_key_t),
139                                    G_ALLOC_AND_FREE);
140     fcp_req_vals = g_mem_chunk_new("fcp_req_vals",
141                                    sizeof(fcp_conv_data_t),
142                                    fcp_init_count * sizeof(fcp_conv_data_t),
143                                    G_ALLOC_AND_FREE);
144 }
145
146 static gchar *
147 task_mgmt_flags_to_str (guint8 flags, gchar *str)
148 {
149     int stroff = 0;
150     
151     if (str == NULL)
152         return str;
153
154     *str = '\0';
155     
156     if (flags & 0x80) {
157         strcpy (str, "Obsolete, ");
158         stroff += 10;
159     }
160
161     if (flags & 0x40) {
162         strcpy (&str[stroff], "Clear ACA, ");
163         stroff += 11;
164     }
165
166     if (flags & 0x20) {
167         strcpy (&str[stroff], "Target Reset, ");
168         stroff += 14;
169     }
170
171     if (flags & 0x10) {
172         strcpy (&str[stroff], "LU Reset, ");
173         stroff += 10;
174     }
175
176     if (flags & 0x08) {
177         strcpy (&str[stroff], "Rsvd, ");
178         stroff += 6;
179     }
180
181     if (flags & 0x04) {
182         strcpy (&str[stroff], "Clear Task Set, ");
183         stroff += 16;
184     }
185
186     if (flags & 0x02) {
187         strcpy (&str[stroff], "Abort Task Set");
188         stroff += 14;
189     }
190
191     return (str);
192 }
193
194 static gchar *
195 rspflags_to_str (guint8 flags, gchar *str)
196 {
197     int stroff = 0;
198
199     if (str == NULL)
200         return (str);
201
202     *str = '\0';
203     
204     if (flags & 0x10) {
205         strcpy (str, "FCP_CONF_REQ | ");
206         stroff += 15;
207     }
208     if (flags & 0x08) {
209         strcpy (&str[stroff], "FCP_RESID_UNDER | ");
210         stroff += 18;
211     }
212     if (flags & 0x04) {
213         strcpy (&str[stroff], "FCP_RESID_OVER | ");
214         stroff += 17;
215     }
216     if (flags & 0x02) {
217         strcpy (&str[stroff], "FCP_SNS_LEN_VLD | ");
218         stroff += 18;
219     }
220     if (flags & 0x01) {
221         strcpy (&str[stroff], "FCP_RSP_LEN_VLD | ");
222     }
223
224     return (str);
225 }
226
227 /* Code to actually dissect the packets */
228 static void
229 dissect_fcp_cmnd (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
230 {
231     int offset = 0;
232     int len,
233         add_len = 0;
234     gchar str[128];
235     guint8 flags, lun0;
236     proto_item *ti;
237     proto_tree *fcp_tree = NULL;
238     conversation_t *conversation;
239     fcp_conv_data_t *cdata;
240     fcp_conv_key_t ckey, *req_key;
241     scsi_task_id_t task_key;
242     guint16 lun=0xffff;
243     tvbuff_t *cdb_tvb;
244     int tvb_len, tvb_rlen;
245
246     /* Determine the length of the FCP part of the packet */
247     flags = tvb_get_guint8 (tvb, offset+10);
248     if (flags) {
249         add_len = tvb_get_guint8 (tvb, offset+11) & 0x7C;
250         add_len = add_len >> 2;
251         
252         len = FCP_DEF_CMND_LEN + add_len;
253     }
254     else {
255         len = FCP_DEF_CMND_LEN;
256     }
257
258     /* We track the conversation to determine how many bytes is required */
259     /* by the data that is sent back or sent next by the initiator as part */
260     /* of this command. The state is destroyed in the response dissector */
261     
262     conversation = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst,
263                                       pinfo->ptype, pinfo->oxid,
264                                       pinfo->rxid, NO_PORT2);
265     if (!conversation) {
266         conversation = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst,
267                                          pinfo->ptype, pinfo->oxid,
268                                          pinfo->rxid, NO_PORT2);
269     }
270     
271     ckey.conv_idx = conversation->index;
272     task_key.conv_id = conversation->index;
273     task_key.task_id = conversation->index;
274     pinfo->private_data = (void *)&task_key;
275     
276     cdata = (fcp_conv_data_t *)g_hash_table_lookup (fcp_req_hash,
277                                                     &ckey);
278     /*
279      * XXX - the fetch of the fcp_dl value will throw an exception on
280      * a short frame before we get a chance to dissect the stuff before
281      * it.
282      *
283      * XXX - this doesn't appear to store the data length with the
284      * FCP packet with the data, so this might not work correctly
285      * if you select a command packet, select the corresponding data
286      * packet, and then select another data packet with a different
287      * length.
288      */
289     if (cdata) {
290         /* Since we never free the memory used by an exchange, this maybe a
291          * case of another request using the same exchange as a previous
292          * req. 
293          */
294         cdata->fcp_dl = tvb_get_ntohl (tvb, offset+12+16+add_len);
295         cdata->abs_usecs = pinfo->fd->abs_usecs;
296         cdata->abs_secs = pinfo->fd->abs_secs;
297     }
298     else {
299         req_key = g_mem_chunk_alloc (fcp_req_keys);
300         req_key->conv_idx = conversation->index;
301         
302         cdata = g_mem_chunk_alloc (fcp_req_vals);
303         cdata->fcp_dl = tvb_get_ntohl (tvb, offset+12+16+add_len);
304         cdata->abs_usecs = pinfo->fd->abs_usecs;
305         cdata->abs_secs = pinfo->fd->abs_secs;
306         
307         g_hash_table_insert (fcp_req_hash, req_key, cdata);
308     }
309     
310     /* XXX this one is redundant  right?  ronnie
311     dissect_scsi_cdb (tvb, pinfo, fcp_tree, offset+12, 16+add_len,
312                       SCSI_DEV_UNKNOWN, lun);
313     */
314
315     if (tree) {
316         ti = proto_tree_add_protocol_format (tree, proto_fcp, tvb, 0, len,
317                                              "FCP_CMND");
318         fcp_tree = proto_item_add_subtree (ti, ett_fcp);
319     }    
320     proto_tree_add_uint_hidden (fcp_tree, hf_fcp_type, tvb, offset, 0, 0);
321     
322     lun0 = tvb_get_guint8 (tvb, offset);
323     
324     /* Display single-level LUNs in decimal for clarity */
325     /* I'm taking a shortcut here by assuming that if the first byte of the
326      * LUN field is 0, it is a single-level LUN. This is not true. For a
327      * real single-level LUN, all 8 bytes except byte 1 must be 0.
328      */
329     if (lun0) {
330       cdata->fcp_lun = -1;
331       proto_tree_add_item (fcp_tree, hf_fcp_multilun, tvb, offset, 8, 0);
332       lun=tvb_get_guint8(tvb, offset)&0x3f;
333       lun<<=8;
334       lun|=tvb_get_guint8(tvb, offset+1);
335     }
336     else {
337       cdata->fcp_lun = tvb_get_guint8 (tvb, offset+1);
338       proto_tree_add_item (fcp_tree, hf_fcp_singlelun, tvb, offset+1,
339                            1, 0);
340       lun=tvb_get_guint8(tvb, offset+1);
341     }
342
343     proto_tree_add_item (fcp_tree, hf_fcp_crn, tvb, offset+8, 1, 0);
344     proto_tree_add_item (fcp_tree, hf_fcp_taskattr, tvb, offset+9, 1, 0);
345     proto_tree_add_uint_format (fcp_tree, hf_fcp_taskmgmt, tvb, offset+10,
346                                 1, flags,
347                                 "Task Management Flags: 0x%x (%s)",
348                                 flags,
349                                 task_mgmt_flags_to_str (flags, str));
350     proto_tree_add_item (fcp_tree, hf_fcp_addlcdblen, tvb, offset+11, 1, 0);
351     proto_tree_add_item (fcp_tree, hf_fcp_rddata, tvb, offset+11, 1, 0);
352     proto_tree_add_item (fcp_tree, hf_fcp_wrdata, tvb, offset+11, 1, 0);
353
354     tvb_len=tvb_length_remaining(tvb, offset+12);
355     if(tvb_len>(16+add_len))
356       tvb_len=16+add_len;
357     tvb_rlen=tvb_reported_length_remaining(tvb, offset+12);
358     if(tvb_rlen>(16+add_len))
359       tvb_rlen=16+add_len;
360     cdb_tvb=tvb_new_subset(tvb, offset+12, tvb_len, tvb_rlen);
361     dissect_scsi_cdb (cdb_tvb, pinfo, tree, SCSI_DEV_UNKNOWN, lun);
362
363     proto_tree_add_item (fcp_tree, hf_fcp_dl, tvb, offset+12+16+add_len,
364                          4, 0);
365 }
366
367 static void
368 dissect_fcp_data (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
369 {
370     conversation_t *conversation;
371     fcp_conv_data_t *cdata = NULL;
372     fcp_conv_key_t ckey;
373     proto_item *ti;
374     proto_tree *fcp_tree;
375     scsi_task_id_t task_key;
376
377     /* Retrieve conversation state to determine expected payload */
378     conversation = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst,
379                                       pinfo->ptype, pinfo->oxid,
380                                       pinfo->rxid, NO_PORT2);
381     if (conversation) {
382         ckey.conv_idx = conversation->index;
383     
384         cdata = (fcp_conv_data_t *)g_hash_table_lookup (fcp_req_hash,
385                                                         &ckey);
386         task_key.conv_id = conversation->index;
387         task_key.task_id = conversation->index;
388         pinfo->private_data = (void *)&task_key;
389     }
390     else {
391         pinfo->private_data = NULL;
392     }
393     if (cdata) {
394         ti = proto_tree_add_protocol_format (tree, proto_fcp, tvb, 0, 0,
395                                              "FCP_DATA");
396         fcp_tree = proto_item_add_subtree (ti, ett_fcp);
397
398         if (cdata->fcp_lun >= 0)
399             proto_tree_add_uint_hidden (fcp_tree, hf_fcp_singlelun, tvb,
400                                         0, 0, cdata->fcp_lun);
401
402         dissect_scsi_payload (tvb, pinfo, tree, FALSE, (guint16) cdata->fcp_lun);
403     }
404     else {
405         dissect_scsi_payload (tvb, pinfo, tree, FALSE, 0xffff);
406     }
407 }
408
409 static void
410 dissect_fcp_rsp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
411 {
412     guint32 offset = 0,
413         del_usecs = 0;
414     guint32 snslen = 0,
415            rsplen = 0;
416     gchar str[128];
417     guint8 flags;
418     proto_item *ti;
419     proto_tree *fcp_tree;
420     guint8 status;
421     conversation_t *conversation;
422     fcp_conv_data_t *cdata = NULL;
423     fcp_conv_key_t ckey;
424     scsi_task_id_t task_key;
425
426     status = tvb_get_guint8 (tvb, offset+11);
427     
428     if (check_col (pinfo->cinfo, COL_INFO)) {
429         col_append_fstr (pinfo->cinfo, COL_INFO, " , %s",
430                          val_to_str (status, scsi_status_val, "0x%x"));
431     }
432
433     /* Response marks the end of the conversation. So destroy state */
434     conversation = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst,
435                                       pinfo->ptype, pinfo->oxid,
436                                       pinfo->rxid, NO_PORT2);
437     if (conversation) {
438         ckey.conv_idx = conversation->index;
439     
440         cdata = (fcp_conv_data_t *)g_hash_table_lookup (fcp_req_hash,
441                                                         &ckey);
442         task_key.conv_id = task_key.task_id = conversation->index;
443         pinfo->private_data = (void *)&task_key;
444     }
445     
446     if (tree) {
447         ti = proto_tree_add_protocol_format (tree, proto_fcp, tvb, 0, -1,
448                                              "FCP_RSP");
449         fcp_tree = proto_item_add_subtree (ti, ett_fcp);
450         proto_tree_add_uint_hidden (fcp_tree, hf_fcp_type, tvb, offset, 0, 0);
451
452         if (cdata) {
453             del_usecs = (pinfo->fd->abs_secs - cdata->abs_secs)* 1000000 +
454                 (pinfo->fd->abs_usecs - cdata->abs_usecs);
455             if (del_usecs > 1000)
456                 proto_tree_add_text (fcp_tree, tvb, offset, 0,
457                                      "Cmd Response Time: %d msecs",
458                                      del_usecs/1000);
459             else
460                 proto_tree_add_text (fcp_tree, tvb, offset, 0,
461                                      "Cmd Response Time: %d usecs",
462                                      del_usecs);
463             if (cdata->fcp_lun >= 0)
464                 proto_tree_add_uint_hidden (fcp_tree, hf_fcp_singlelun, tvb,
465                                             offset, 0, cdata->fcp_lun);
466         }
467         flags = tvb_get_guint8 (tvb, offset+10);
468         proto_tree_add_uint_format (fcp_tree, hf_fcp_rspflags, tvb, offset+10,
469                                     1, flags, "Flags: 0x%02x (%s)", flags,
470                                     rspflags_to_str (flags, str));
471         proto_tree_add_item (fcp_tree, hf_fcp_scsistatus, tvb, offset+11, 1, 0);
472         if (flags & 0xC)
473             proto_tree_add_item (fcp_tree, hf_fcp_resid, tvb, offset+12, 4, 0);
474         if (flags & 0x2) {
475             snslen = tvb_get_ntohl (tvb, offset+16);
476             proto_tree_add_uint (fcp_tree, hf_fcp_snslen, tvb, offset+16, 4,
477                                  snslen);
478         }
479         if (flags & 0x1) {
480             rsplen = tvb_get_ntohl (tvb, offset+20);
481             proto_tree_add_uint (fcp_tree, hf_fcp_rsplen, tvb, offset+20, 4,
482                                  rsplen);
483             /* XXX - must rsplen be >= 4?  What other than the code is there? */
484             proto_tree_add_item (fcp_tree, hf_fcp_rspcode, tvb, offset+27, 1,
485                                  0);
486         }
487         /* This handles too-large rsplen values (including ones > 2^31-1) */
488         tvb_ensure_bytes_exist (tvb, offset+24, rsplen);
489         offset += 24+rsplen;
490         if (flags & 0x2) {
491             dissect_scsi_snsinfo (tvb, pinfo, tree, offset,
492                                   snslen,
493                                   (guint16) (cdata?cdata->fcp_lun:0xffff) );
494         }
495         /* This handles too-large snslen values (including ones > 2^31-1) */
496         tvb_ensure_bytes_exist (tvb, offset, snslen);
497         offset += snslen;
498         proto_item_set_end (ti, tvb, offset);
499         if (cdata) {
500             /*
501              * XXX - this isn't done if an exception is thrown.
502              */
503             g_mem_chunk_free (fcp_req_vals, cdata);
504             g_hash_table_remove (fcp_req_hash, &ckey);
505         }
506     }
507 }
508
509 static void
510 dissect_fcp_xfer_rdy (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
511 {
512     int offset = 0;
513     proto_item *ti;
514     proto_tree *fcp_tree;
515     guint del_usecs;
516
517     conversation_t *conversation;
518     fcp_conv_data_t *cdata = NULL;
519     fcp_conv_key_t ckey, *req_key;
520
521     /* Retrieve conversation state to determine expected payload */
522     conversation = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst,
523                                       pinfo->ptype, pinfo->oxid,
524                                       pinfo->rxid, NO_PORT2);
525     if (!conversation) {
526         conversation = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst,
527                                          pinfo->ptype, pinfo->oxid,
528                                          pinfo->rxid, NO_PORT2);
529     }
530     
531     if (conversation) {
532         ckey.conv_idx = conversation->index;
533     
534         cdata = (fcp_conv_data_t *)g_hash_table_lookup (fcp_req_hash,
535                                                         &ckey);
536         if (cdata != NULL) {
537             cdata->fcp_dl = tvb_get_ntohl (tvb, offset+4);
538         }
539         else {
540             req_key = g_mem_chunk_alloc (fcp_req_keys);
541             req_key->conv_idx = conversation->index;
542             
543             cdata = g_mem_chunk_alloc (fcp_req_vals);
544             cdata->fcp_dl = tvb_get_ntohl (tvb, offset+4);
545             cdata->fcp_lun = -1;
546             
547             g_hash_table_insert (fcp_req_hash, req_key, cdata);
548         }
549     }
550
551     if (tree) {
552         ti = proto_tree_add_protocol_format (tree, proto_fcp, tvb, 0, 12,
553                                              "FCP_XFER_RDY");
554         fcp_tree = proto_item_add_subtree (ti, ett_fcp);
555         proto_tree_add_uint_hidden (fcp_tree, hf_fcp_type, tvb, offset, 0, 0);
556
557         if (cdata) {
558             del_usecs = (pinfo->fd->abs_secs - cdata->abs_secs)* 1000000 +
559                 (pinfo->fd->abs_usecs - cdata->abs_usecs);
560             if (del_usecs > 1000)
561                 proto_tree_add_text (fcp_tree, tvb, offset, 0,
562                                      "Cmd Response Time: %d msecs",
563                                      del_usecs/1000);
564             else
565                 proto_tree_add_text (fcp_tree, tvb, offset, 0,
566                                      "Cmd Response Time: %d usecs",
567                                      del_usecs);
568             if (cdata->fcp_lun >= 0)
569                 proto_tree_add_uint_hidden (fcp_tree, hf_fcp_singlelun, tvb,
570                                             offset, 0, cdata->fcp_lun);
571         }
572         proto_tree_add_item (fcp_tree, hf_fcp_data_ro, tvb, offset, 4, 0);
573         proto_tree_add_item (fcp_tree, hf_fcp_burstlen, tvb, offset+4, 4, 0);
574     }
575 }
576
577 static void
578 dissect_fcp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
579 {
580
581 /* Set up structures needed to add the protocol subtree and manage it */
582     guint8 r_ctl;
583
584     /* Make entries in Protocol column and Info column on summary display */
585     if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
586         col_set_str(pinfo->cinfo, COL_PROTOCOL, "FCP");
587
588     r_ctl = pinfo->r_ctl;
589
590     r_ctl &= 0xF;
591
592     if (check_col (pinfo->cinfo, COL_INFO)) {
593         col_set_str (pinfo->cinfo, COL_INFO, val_to_str (r_ctl, fcp_iu_val,
594                                                       "0x%x"));
595     }
596     
597     switch (r_ctl) {
598     case FCP_IU_DATA:
599         dissect_fcp_data (tvb, pinfo, tree);
600         break;
601     case FCP_IU_CONFIRM:
602         /* Nothing to be done here */
603         break;
604     case FCP_IU_XFER_RDY:
605         dissect_fcp_xfer_rdy (tvb, pinfo, tree);
606         break;
607     case FCP_IU_CMD:
608         dissect_fcp_cmnd (tvb, pinfo, tree);
609         break;
610     case FCP_IU_RSP:
611         dissect_fcp_rsp (tvb, pinfo, tree);
612         break;
613     default:
614         call_dissector (data_handle, tvb, pinfo, tree);
615         break;
616     }
617 }
618
619 /* Register the protocol with Ethereal */
620
621 /* this format is require because a script is used to build the C function
622    that calls all the protocol registration.
623 */
624
625 void
626 proto_register_fcp (void)
627 {                 
628
629     /* Setup list of header fields  See Section 1.6.1 for details*/
630     static hf_register_info hf[] = {
631         { &hf_fcp_type,
632           {"Field to branch off to SCSI", "fcp.type", FT_UINT8, BASE_HEX, NULL,
633            0x0, "", HFILL}},
634         {&hf_fcp_multilun,
635          {"Multi-Level LUN", "fcp.multilun", FT_BYTES, BASE_HEX, NULL, 0x0,
636           "", HFILL}},
637         { &hf_fcp_singlelun,
638           {"LUN", "fcp.lun", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL}},
639         { &hf_fcp_crn,
640           {"Command Ref Num", "fcp.crn", FT_UINT8, BASE_DEC, NULL, 0x0, "",
641            HFILL}},
642         { &hf_fcp_taskattr,
643           {"Task Attribute", "fcp.taskattr", FT_UINT8, BASE_HEX,
644            VALS (fcp_task_attr_val), 0x7, "", HFILL}},
645         { &hf_fcp_taskmgmt,
646           {"Task Management Flags", "fcp.taskmgmt", FT_UINT8, BASE_HEX, NULL,
647            0x0, "", HFILL}},
648         { &hf_fcp_addlcdblen,
649           {"Additional CDB Length", "fcp.addlcdblen", FT_UINT8, BASE_DEC, NULL,
650            0xFC, "", HFILL}},
651         { &hf_fcp_rddata,
652           {"RDDATA", "fcp.rddata", FT_BOOLEAN, 8, NULL, 0x02, "", HFILL}},
653         { &hf_fcp_wrdata,
654           {"WRDATA", "fcp.wrdata", FT_BOOLEAN, 8, NULL, 0x01, "", HFILL}},
655         { &hf_fcp_dl,
656           {"FCP_DL", "fcp.dl", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL}},
657         { &hf_fcp_data_ro,
658           {"FCP_DATA_RO", "fcp.data_ro", FT_UINT32, BASE_DEC, NULL, 0x0, "",
659            HFILL}},
660         { &hf_fcp_burstlen,
661           {"Burst Length", "fcp.burstlen", FT_UINT32, BASE_DEC, NULL, 0x0, "",
662            HFILL}},
663         { &hf_fcp_rspflags,
664           {"FCP_RSP Flags", "fcp.rspflags", FT_UINT8, BASE_HEX, NULL, 0x0, "",
665            HFILL}},
666         { &hf_fcp_resid,
667           {"FCP_RESID", "fcp.resid", FT_UINT32, BASE_DEC, NULL, 0x0, "",
668            HFILL}},
669         { &hf_fcp_snslen,
670           {"FCP_SNS_LEN", "fcp.snslen", FT_UINT32, BASE_DEC, NULL, 0x0, "",
671            HFILL}},
672         { &hf_fcp_rsplen,
673           {"FCP_RSP_LEN", "fcp.rsplen", FT_UINT32, BASE_DEC, NULL, 0x0, "",
674            HFILL}},
675         { &hf_fcp_rspcode,
676           {"RSP_CODE", "fcp.rspcode", FT_UINT8, BASE_HEX,
677            VALS (fcp_rsp_code_val), 0x0, "", HFILL}},
678         { &hf_fcp_scsistatus,
679           {"SCSI Status", "fcp.status", FT_UINT8, BASE_HEX,
680            VALS (scsi_status_val), 0x0, "", HFILL}},
681     };
682
683     /* Setup protocol subtree array */
684     static gint *ett[] = {
685         &ett_fcp,
686     };
687
688     /* Register the protocol name and description */
689     proto_fcp = proto_register_protocol("Fibre Channel Protocol for SCSI",
690                                         "FCP", "fcp");
691
692     /* Required function calls to register the header fields and subtrees used */
693     proto_register_field_array(proto_fcp, hf, array_length(hf));
694     proto_register_subtree_array(ett, array_length(ett));
695     fcp_dissector = register_dissector_table ("fcp.type", "FCP Type", FT_UINT8,
696                                               BASE_HEX);
697     register_init_routine (&fcp_init_protocol);
698 }
699
700 /* If this dissector uses sub-dissector registration add a registration routine.
701    This format is required because a script is used to find these routines and
702    create the code that calls these routines.
703 */
704 void
705 proto_reg_handoff_fcp (void)
706 {
707     dissector_handle_t fcp_handle;
708
709     fcp_handle = create_dissector_handle (dissect_fcp, proto_fcp);
710     dissector_add("fc.ftype", FC_FTYPE_SCSI, fcp_handle);
711
712     data_handle = find_dissector ("data");
713 }
714
715