Fix up a bunch of arguments to "dissect_ber_identifier()" to match its
[obnox/wireshark/wip.git] / epan / dissectors / packet-fcsb3.c
1 /* packet-fc-sb3.c
2  * Routines for Fibre Channel Single Byte Protocol (SBCCS); used in FICON.
3  * This decoder is for FC-SB3 version 1.4
4  * Copyright 2003, Dinesh G Dutt <ddutt@cisco.com>
5  *
6  * $Id$
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@ethereal.com>
10  * Copyright 1998 Gerald Combs
11  *
12  * Copied from WHATEVER_FILE_YOU_USED (where "WHATEVER_FILE_YOU_USED"
13  * is a dissector file; if you just copied this from README.developer,
14  * don't bother with the "Copied from" - you don't even need to put
15  * in a "Copied from" if you copied an existing dissector, especially
16  * if the bulk of the code in the new dissector is your code)
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 #ifdef HAVE_SYS_TYPES_H
42 # include <sys/types.h>
43 #endif
44
45 #ifdef HAVE_NETINET_IN_H
46 # include <netinet/in.h>
47 #endif
48
49 #include <glib.h>
50
51 #ifdef NEED_SNPRINTF_H
52 # include "snprintf.h"
53 #endif
54
55 #include <epan/prefs.h>
56 #include <epan/packet.h>
57 #include <epan/conversation.h>
58 #include "etypes.h"
59 #include "packet-fc.h"
60 #include "packet-fcsb3.h"
61
62 /* Initialize the protocol and registered fields */
63 static int proto_fc_sbccs             = -1;
64 static int hf_sbccs_chid              = -1;
65 static int hf_sbccs_cuid              = -1;
66 static int hf_sbccs_devaddr           = -1;
67 static int hf_sbccs_iui               = -1;
68 static int hf_sbccs_dhflags           = -1;
69 static int hf_sbccs_ccw               = -1;
70 static int hf_sbccs_token             = -1;
71 static int hf_sbccs_dib_iucnt         = -1;
72 static int hf_sbccs_dib_datacnt       = -1;
73 static int hf_sbccs_dib_ccw_cmd       = -1;
74 static int hf_sbccs_dib_ccw_flags     = -1;
75 static int hf_sbccs_dib_ccw_cnt       = -1;
76 static int hf_sbccs_dib_statusflags   = -1;
77 static int hf_sbccs_dib_status        = -1;
78 static int hf_sbccs_dib_residualcnt   = -1;
79 static int hf_sbccs_dib_qtuf          = -1;
80 static int hf_sbccs_dib_qtu           = -1;
81 static int hf_sbccs_dib_dtuf          = -1;
82 static int hf_sbccs_dib_dtu           = -1;
83 static int hf_sbccs_dib_ctlfn         = -1;
84 static int hf_sbccs_dib_ctlparam      = -1;
85 static int hf_sbccs_lrc               = -1;
86 static int hf_sbccs_dib_iupacing      = -1;
87 static int hf_sbccs_dev_xcp_code      = -1;
88 static int hf_sbccs_prg_pth_errcode   = -1;
89 static int hf_sbccs_prg_rsp_errcode   = -1;
90 static int hf_sbccs_dib_ctccntr       = -1;
91 static int hf_sbccs_dib_lprcode       = -1;
92 static int hf_sbccs_dib_tin_imgid_cnt = -1;
93 static int hf_sbccs_dib_lrjcode       = -1;
94 static int hf_sbccs_dib_ioprio        = -1;
95 static int hf_sbccs_dib_cmdflags      = -1;
96 static int hf_sbccs_dib_linkctlfn     = -1;
97 static int hf_sbccs_dib_linkctlinfo   = -1;
98
99 /* Initialize the subtree pointers */
100 static gint ett_fc_sbccs = -1;
101
102 static dissector_handle_t data_handle;
103
104 typedef struct {
105     guint32 conv_id;
106     guint32 task_id;
107 } sb3_task_id_t;
108
109 static const value_string fc_sbccs_iu_val[] = {
110     {FC_SBCCS_IU_DATA,            "Data"},
111     {FC_SBCCS_IU_CMD_HDR,         "Command Header"},
112     {FC_SBCCS_IU_STATUS,          "Status"},
113     {FC_SBCCS_IU_CTL,             "Control"},
114     {FC_SBCCS_IU_CMD_DATA,        "Command Header & Data"},
115     {FC_SBCCS_IU_CMD_LINK_CTL,    "Link Control"},
116     {0x6,                         "Reserved"},
117     {0x7,                         "Reserved"},
118     {0x0,                         NULL},
119 };
120
121 static const value_string fc_sbccs_dib_cmd_val[] = {
122     {0,  "Reserved"},
123     {1,  "Write"},
124     {2,  "Read"},
125     {3,  "Control"},
126     {4,  "Sense"},
127     {5,  "Write (Modifier)"},
128     {6,  "Read (Modifier)"},
129     {7,  "Control (Modifier)"},
130     {8,  "Reserved"},
131     {9,  "Write (Modifier)"},
132     {10, "Read (Modifier)"},
133     {11, "Control (Modifier)"},
134     {12, "Read Backward"},
135     {13, "Write (Modifier)"},
136     {14, "Read (Modifier)"},
137     {15, "Control (Modifier)"},
138     {0, NULL},
139 };
140
141 static const value_string fc_sbccs_dib_ctl_fn_val[] = {
142     {FC_SBCCS_CTL_FN_CTL_END,   "Control End"},
143     {FC_SBCCS_CTL_FN_CMD_RSP,   "Command Response"},
144     {FC_SBCCS_CTL_FN_STK_STS,   "Stack Status"},
145     {FC_SBCCS_CTL_FN_CANCEL,    "Cancel"},
146     {FC_SBCCS_CTL_FN_SYS_RST,   "System Reset"},
147     {FC_SBCCS_CTL_FN_SEL_RST,   "Selective Reset"},
148     {FC_SBCCS_CTL_FN_REQ_STS,   "Request Status"},
149     {FC_SBCCS_CTL_FN_DEV_XCP,   "Device Level Exception"},
150     {FC_SBCCS_CTL_FN_STS_ACC,   "Status Accepted"},
151     {FC_SBCCS_CTL_FN_DEV_ACK,   "Device-Level Ack"},
152     {FC_SBCCS_CTL_FN_PRG_PTH,   "Purge Path"},
153     {FC_SBCCS_CTL_FN_PRG_RSP,   "Purge Path Response"},
154     {0, NULL},
155 };
156
157 static const value_string fc_sbccs_dib_dev_xcpcode_val[] = {
158     {1, "Address Exception"},
159     {0, NULL},
160 };
161
162 static const value_string fc_sbccs_dib_purge_path_err_val[] = {
163     {0, "Error Code Xfer Not Supported"},
164     {1, "SB-3 Protocol Timeout"},
165     {2, "SB-3 Link Failure"},
166     {3, "Reserved"},
167     {4, "SB-3 Offline Condition"},
168     {5, "FC-PH Link Failure"},
169     {6, "SB-3 Length Error"},
170     {7, "LRC Error"},
171     {8, "SB-3 CRC Error"},
172     {9, "IU Count Error"},
173     {10, "SB-3 Link Level Protocol Error"},
174     {11, "SB-3 Device Level Protocol Error"},
175     {12, "Receive ABTS"},
176     {13, "Cancel Function Timeout"},
177     {14, "Abnormal Termination of Xchg"},
178     {15, "Reserved"},
179     {0,  NULL},
180 };
181
182 static const value_string fc_sbccs_dib_purge_path_rsp_err_val[] = {
183     {0, "No Errors"},
184     {1, "SB-3 Protocol Timeout"},
185     {2, "SB-3 Link Failure"},
186     {3, "Logical Path Timeout Error"},
187     {4, "SB-3 Offline Condition"},
188     {5, "FC-PH Link Failure"},
189     {6, "SB-3 Length Error"},
190     {7, "LRC Error"},
191     {8, "SB-3 CRC Error"},
192     {9, "IU Count Error"},
193     {10, "SB-3 Link Level Protocol Error"},
194     {11, "SB-3 Device Level Protocol Error"},
195     {12, "Receive ABTS"},
196     {13, "Reserved"},
197     {14, "Abnormal Termination of Xchg"},
198     {15, "Logical Path Not Estd"},
199     {16, "Test Init Result Error"},
200     {0,  NULL},
201 };
202
203 static const value_string fc_sbccs_dib_link_ctl_fn_val[] = {
204     {FC_SBCCS_LINK_CTL_FN_ELP, "ELP"},
205     {FC_SBCCS_LINK_CTL_FN_RLP, "RLP"},
206     {FC_SBCCS_LINK_CTL_FN_TIN, "TIN"},
207     {FC_SBCCS_LINK_CTL_FN_LPE, "LPE"},
208     {FC_SBCCS_LINK_CTL_FN_LPR, "LPR"},
209     {FC_SBCCS_LINK_CTL_FN_TIR, "TIR"},
210     {FC_SBCCS_LINK_CTL_FN_LRJ, "LRJ"},
211     {FC_SBCCS_LINK_CTL_FN_LBY, "LBY"},
212     {FC_SBCCS_LINK_CTL_FN_LACK, "LACK"},
213     {0, NULL},
214 };
215
216 static const value_string fc_sbccs_dib_lpr_errcode_val[] = {
217     {0x0, "Response to RLP"},
218     {0x1, "Optional Features Conflict"},
219     {0x2, "Out of Resources"},
220     {0x3, "Device Init In Progress"},
221     {0x4, "No CU Image"},
222     {0x0, NULL},
223 };
224
225 static const value_string fc_sbccs_dib_lrj_errcode_val[] = {
226     {0x6, "Logical Path Not Estd"},
227     {0x9, "Protocol Error"},
228     {0x0, NULL},
229 };
230
231 static gchar *get_iui_string (guint8 iui, gchar *buffer)
232 {
233     guint pos = 0;
234     buffer[0] = '\0';
235
236     if (iui & 0x10) {
237         strcpy (&buffer[pos], "AS, ");
238         pos += 4;
239     }
240
241     if (iui & 0x8) {
242         strcpy (&buffer[pos], "ES, ");
243         pos += 4;
244     }
245
246     strcpy (&buffer[pos], val_to_str (iui & 0x7, fc_sbccs_iu_val, "0x%x"));
247
248     return (buffer);
249 }
250
251 static gchar *get_dhflags_string (guint8 dhflags, gchar *buffer)
252 {
253     guint pos = 0;
254     buffer[0] = '\0';
255
256     if (dhflags & 0x80) {
257         strcpy (&buffer[pos], "End, ");
258         pos += 5;
259     }
260
261     if (dhflags & 0x10) {
262         strcpy (&buffer[pos], "Chaining, ");
263         pos += 10;
264     }
265
266     if (dhflags & 0x8) {
267         strcpy (&buffer[pos], "Early End, ");
268         pos += 11;
269     }
270
271     if (dhflags & 0x4) {
272         strcpy (&buffer[pos], "No CRC");
273     }
274
275     return (buffer);
276 }
277
278 static gchar *get_ccw_flags_string (guint8 ccw_flags, gchar *buffer)
279 {
280     guint pos = 0;
281     
282     buffer[0] = '\0';
283
284     if (ccw_flags & 0x80) {
285         strcpy (&buffer[pos], "CD, ");
286         pos += 4;
287     }
288
289     if (ccw_flags & 0x40) {
290         strcpy (&buffer[pos], "CC, ");
291         pos += 4;
292     }
293
294     if (ccw_flags & 0x20) {
295         strcpy (&buffer[pos], "SLI, ");
296         pos += 5;
297     }
298
299     if (ccw_flags & 0x8) {
300         strcpy (&buffer[pos], "CRR");
301         pos += 5;
302     }
303
304     return (buffer);
305 }
306
307 static gchar *get_cmd_flag_string (guint8 cmd_flag, gchar *buffer)
308 {
309     guint pos = 0;
310
311     buffer[0] = '\0';
312
313     if (cmd_flag & 0x10) {
314         strcpy (&buffer[pos], "DU, ");
315         pos += 4;
316     }
317
318     if (cmd_flag & 0x8) {
319         strcpy (&buffer[pos], "COC, ");
320         pos += 4;
321     }
322
323     if (cmd_flag & 0x4) {
324         strcpy (&buffer[pos], "SYR, ");
325         pos += 5;
326     }
327
328     if (cmd_flag & 0x2) {
329         strcpy (&buffer[pos], "REX, ");
330         pos += 5;
331     }
332
333     if (cmd_flag & 0x1) {
334         strcpy (&buffer[pos], "SSS");
335         pos += 5;
336     }
337
338     return (buffer);
339 }
340
341 static gchar *get_status_flag_string (guint8 status_flag, gchar *buffer)
342 {
343     guint pos = 0;
344     guint8 ffc = (status_flag & 0xD0) >> 5;
345
346     buffer[0] = '\0';
347
348     switch (ffc) {
349     case 0:
350         break;                  /* to avoid the catch clause below */
351     case 1:
352         strcpy (&buffer[pos], "FFC:Queuing Information Valid, ");
353         pos += 31;
354         break;
355     case 2:
356         strcpy (&buffer[pos], "FFC:Resetting Event, ");
357         pos += 21;
358         break;
359     default:
360         strcpy (&buffer[pos], "Reserved");
361         break;
362     }
363
364     if (status_flag & 10) {
365         strcpy (&buffer[pos], "CI, ");
366         pos += 4;
367     }
368
369     if (status_flag & 0x4) {
370         strcpy (&buffer[pos], "CR, ");
371         pos += 4;
372     }
373
374     if (status_flag & 0x2) {
375         strcpy (&buffer[pos], "LRI, ");
376         pos += 5;
377     }
378
379     if (status_flag & 0x1) {
380         strcpy (&buffer[pos], "RV");
381     }
382
383     return (buffer);
384 }
385
386 static gchar *get_status_string (guint8 status, gchar *buffer)
387 {
388     guint pos = 0;
389
390     buffer[0] = '\0';
391
392     if (status & 0x80) {
393         strcpy (&buffer[pos], "Attention, ");
394         pos += 11;
395     }
396
397     if (status & 0x40) {
398         strcpy (&buffer[pos], "Status Modifier, ");
399         pos += 17;
400     }
401
402     if (status & 0x20) {
403         strcpy (&buffer[pos], "Control-Unit End, ");
404         pos += 18;
405     }
406
407     if (status & 0x10) {
408         strcpy (&buffer[pos], "Busy, ");
409         pos += 6;
410     }
411
412     if (status & 0x8) {
413         strcpy (&buffer[pos], "Channel End, ");
414         pos += 12;
415     }
416
417     if (status & 0x4) {
418         strcpy (&buffer[pos], "Device End, ");
419         pos += 12;
420     }
421
422     if (status & 0x2) {
423         strcpy (&buffer[pos], "Unit Check, ");
424         pos += 12;
425     }
426
427     if (status & 0x1) {
428         strcpy (&buffer[pos], "Unit Exception");
429     }
430
431     return (buffer);
432 }
433
434 static gchar *get_sel_rst_param_string (guint8 ctlparam, gchar *buffer)
435 {
436     guint pos = 0;
437
438     buffer[0] = '\0';
439
440     if (ctlparam & 0x80) {
441         strcpy (&buffer[pos], "RC, ");
442         pos += 4;
443     }
444     if (ctlparam & 0x10) {
445         strcpy (&buffer[pos], "RU, ");
446         pos += 4;
447     }
448     if (ctlparam & 0x8) {
449         strcpy (&buffer[pos], "RO");
450     }
451
452     return (buffer);
453 }
454
455 static void get_fc_sbccs_conv_data (tvbuff_t *tvb, guint offset,
456                                     guint16 *ch_cu_id, guint16 *dev_addr,
457                                     guint16 *ccw)
458 {
459     *ch_cu_id = *dev_addr = *ccw = 0;
460
461     *ch_cu_id = (tvb_get_guint8 (tvb, offset+1)) << 8;
462     *ch_cu_id |= tvb_get_guint8 (tvb, offset+3);
463     *dev_addr = tvb_get_ntohs (tvb, offset+4);
464     *ccw = tvb_get_ntohs (tvb, offset+10);
465 }
466
467 /* Decode both the SB-3 and basic IU header */
468 static void
469 dissect_fc_sbccs_sb3_iu_hdr (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
470                              guint offset)
471 {
472     proto_item *subti;
473     proto_tree *sb3hdr_tree;
474     proto_tree *iuhdr_tree;
475     gchar buffer[256];
476     guint8 iui, dhflags;
477     guint type;
478     
479     /* Decode the basic SB3 and IU header and determine type of frame */
480     type = get_fc_sbccs_iu_type (tvb, offset);
481
482     if (check_col (pinfo->cinfo, COL_INFO)) {
483         col_set_str (pinfo->cinfo, COL_INFO, val_to_str (type, fc_sbccs_iu_val,
484                                                          "0x%x"));
485     }
486     
487     if (tree) {
488         /* Dissect SB3 header first */
489         subti = proto_tree_add_text (tree, tvb, offset, FC_SBCCS_SB3_HDR_SIZE,
490                                      "SB-3 Header");
491         sb3hdr_tree = proto_item_add_subtree (subti, ett_fc_sbccs);
492
493         proto_tree_add_item (sb3hdr_tree, hf_sbccs_chid, tvb, offset+1, 1, 0);
494         proto_tree_add_item (sb3hdr_tree, hf_sbccs_cuid, tvb, offset+3, 1, 0);
495         proto_tree_add_item (sb3hdr_tree, hf_sbccs_devaddr, tvb, offset+4, 2, 0);
496
497         /* Dissect IU Header */
498         subti = proto_tree_add_text (tree, tvb, offset + FC_SBCCS_SB3_HDR_SIZE,
499                                      FC_SBCCS_IU_HDR_SIZE, "IU Header");
500         iuhdr_tree = proto_item_add_subtree (subti, ett_fc_sbccs);
501         offset += FC_SBCCS_SB3_HDR_SIZE;
502
503         iui = tvb_get_guint8 (tvb, offset);
504         proto_tree_add_uint_format (iuhdr_tree, hf_sbccs_iui, tvb, offset, 1,
505                                     iui, "Information Unit Identifier: 0x%x (%s)",
506                                     iui, get_iui_string (iui, buffer));
507         dhflags = tvb_get_guint8 (tvb, offset+1);
508         proto_tree_add_uint_format (iuhdr_tree, hf_sbccs_dhflags, tvb, offset, 1,
509                                     dhflags, "DH Flags: 0x%x (%s)",
510                                     dhflags, get_dhflags_string (dhflags, buffer));
511         
512         proto_tree_add_item (iuhdr_tree, hf_sbccs_ccw, tvb, offset+2, 2, 0);
513         proto_tree_add_item (iuhdr_tree, hf_sbccs_token, tvb, offset+5, 3, 0);
514     }
515 }
516
517 static void dissect_fc_sbccs_dib_data_hdr (tvbuff_t *tvb,
518                                            packet_info *pinfo _U_,
519                                            proto_tree *tree, guint offset)
520 {
521     if (tree) {
522         proto_tree_add_item (tree, hf_sbccs_dib_iucnt, tvb, offset+9, 1, 0);
523         proto_tree_add_item (tree, hf_sbccs_dib_datacnt, tvb, offset+10, 2, 0);
524         proto_tree_add_item (tree, hf_sbccs_lrc, tvb, offset+12, 4, 0);
525     }
526 }
527
528 static void dissect_fc_sbccs_dib_cmd_hdr (tvbuff_t *tvb, packet_info *pinfo,
529                                           proto_tree *tree, guint offset)
530 {
531     guint8 flags;
532     gchar buffer[64];
533
534     if (check_col (pinfo->cinfo, COL_INFO)) {
535         col_append_fstr (pinfo->cinfo, COL_INFO,
536                          ": %s", val_to_str (tvb_get_guint8 (tvb, offset),
537                                              fc_sbccs_dib_cmd_val,
538                                              "0x%x"));
539     }
540     
541     if (tree) {
542         proto_tree_add_item (tree, hf_sbccs_dib_ccw_cmd, tvb, offset, 1, 0);
543
544         flags = tvb_get_guint8 (tvb, offset+1);
545         proto_tree_add_uint_format (tree, hf_sbccs_dib_ccw_flags, tvb,
546                                     offset+1, 1, flags,
547                                     "CCW Control Flags: 0x%x(%s)", flags,
548                                     get_ccw_flags_string (flags, buffer));
549         proto_tree_add_item (tree, hf_sbccs_dib_ccw_cnt, tvb, offset+2, 2, 0);
550         proto_tree_add_item (tree, hf_sbccs_dib_ioprio, tvb, offset+5, 1, 0);
551
552         flags = tvb_get_guint8 (tvb, offset+7);
553         proto_tree_add_uint_format (tree, hf_sbccs_dib_cmdflags, tvb, offset+7,
554                                     1, flags, "Command Flags: 0x%x(%s)", flags,
555                                     get_cmd_flag_string (flags, buffer));
556         proto_tree_add_item (tree, hf_sbccs_dib_iucnt, tvb, offset+9, 1, 0);
557         proto_tree_add_item (tree, hf_sbccs_dib_datacnt, tvb, offset+10, 2, 0);
558         proto_tree_add_item (tree, hf_sbccs_lrc, tvb, offset+12, 4, 0);
559
560     }
561 }
562
563 static void dissect_fc_sbccs_dib_status_hdr (tvbuff_t *tvb, packet_info *pinfo,
564                                              proto_tree *tree, guint offset)
565 {
566     guint8 flags;
567     gboolean rv_valid, qparam_valid;
568     gchar buffer[128];
569     tvbuff_t *next_tvb;
570     guint16 supp_status_cnt = 0;
571
572     if (check_col (pinfo->cinfo, COL_INFO)) {
573         col_append_fstr (pinfo->cinfo, COL_INFO,
574                          ": %s",
575                          get_status_string (tvb_get_guint8 (tvb, offset+1),
576                                             buffer));
577     }
578     
579     if (tree) {
580         flags = tvb_get_guint8 (tvb, offset);
581         rv_valid = flags & 0x1; /* if residual count is valid */
582         qparam_valid = (((flags & 0xD0) >> 5) == 0x1); /* From the FFC field */
583         proto_tree_add_uint_format (tree, hf_sbccs_dib_statusflags, tvb, offset,
584                                     1, flags, "Status Flags: 0x%x(%s)",
585                                     flags, get_status_flag_string (flags,
586                                                                    buffer));
587         
588         flags = tvb_get_guint8 (tvb, offset+1);
589         proto_tree_add_uint_format (tree, hf_sbccs_dib_status, tvb, offset+1,
590                                     1, flags, "Status: 0x%x(%s)", flags,
591                                     get_status_string (flags, buffer));
592         if (rv_valid) {
593             proto_tree_add_item (tree, hf_sbccs_dib_residualcnt, tvb, offset+2,
594                                  2, 0);
595         }
596         else {
597             proto_tree_add_item (tree, hf_sbccs_dib_iupacing, tvb, offset+3,
598                                  1, 0);
599         }
600         
601         if (qparam_valid) {
602             proto_tree_add_item (tree, hf_sbccs_dib_qtuf, tvb, offset+4, 1, 0);
603             proto_tree_add_item (tree, hf_sbccs_dib_qtu, tvb, offset+4, 2, 0);
604         }
605
606         proto_tree_add_item (tree, hf_sbccs_dib_dtuf, tvb, offset+6, 1, 0);
607         proto_tree_add_item (tree, hf_sbccs_dib_dtu, tvb, offset+6, 2, 0);
608
609         proto_tree_add_item (tree, hf_sbccs_dib_iucnt, tvb, offset+9, 1, 0);
610         proto_tree_add_item (tree, hf_sbccs_dib_datacnt, tvb, offset+10, 2, 0);
611         supp_status_cnt = tvb_get_ntohs (tvb, offset+10);
612         proto_tree_add_item (tree, hf_sbccs_lrc, tvb, offset+12, 4, 0);
613
614         if (supp_status_cnt) {
615             next_tvb = tvb_new_subset (tvb, offset+FC_SBCCS_DIB_LRC_HDR_SIZE,
616                                        -1, -1);
617             call_dissector (data_handle, next_tvb, pinfo, tree);
618         }
619     }
620 }
621
622 static void dissect_fc_sbccs_dib_ctl_hdr (tvbuff_t *tvb, packet_info *pinfo,
623                                           proto_tree *tree, guint offset)
624 {
625     guint8 ctlfn;
626     gchar buffer[128];
627
628     ctlfn = tvb_get_guint8 (tvb, offset);
629     if (check_col (pinfo->cinfo, COL_INFO)) {
630         col_append_fstr (pinfo->cinfo, COL_INFO,
631                          ": %s",
632                          val_to_str (ctlfn, 
633                                      fc_sbccs_dib_ctl_fn_val,
634                                      "0x%x"));
635     }
636     if (tree) {
637         proto_tree_add_item (tree, hf_sbccs_dib_ctlfn, tvb, offset, 1, 0);
638
639         /* Control Function Parameter is to be interpreted in some cases */
640         switch (ctlfn) {
641         case FC_SBCCS_CTL_FN_SEL_RST:
642             proto_tree_add_uint_format (tree, hf_sbccs_dib_ctlparam, tvb,
643                                         offset+1, 3,
644                                         tvb_get_ntoh24 (tvb, offset+1),
645                                         "Control Parameter: 0x%x(%s)",
646                                         tvb_get_ntoh24 (tvb, offset+1),
647                                         get_sel_rst_param_string (ctlfn,
648                                                                   buffer));
649             break;
650         case FC_SBCCS_CTL_FN_DEV_XCP:
651             proto_tree_add_item (tree, hf_sbccs_dev_xcp_code, tvb, offset+1,
652                                  1, 0);
653             break;
654         case FC_SBCCS_CTL_FN_PRG_PTH:
655             proto_tree_add_item (tree, hf_sbccs_prg_pth_errcode, tvb, offset+1,
656                                  1, 0);
657             break;
658         default:
659             proto_tree_add_item (tree, hf_sbccs_dib_ctlparam, tvb, offset+1,
660                                  3, 0);
661             break;
662         }
663         
664         proto_tree_add_item (tree, hf_sbccs_dib_iucnt, tvb, offset+9, 1, 0);
665         proto_tree_add_item (tree, hf_sbccs_dib_datacnt, tvb, offset+10, 2, 0);
666         proto_tree_add_item (tree, hf_sbccs_lrc, tvb, offset+12, 4, 0);
667
668         if (ctlfn == FC_SBCCS_CTL_FN_PRG_RSP) {
669             /* Need to decode the LESBs */
670             proto_tree_add_item (tree, hf_sbccs_prg_rsp_errcode, tvb, offset+60,
671                                  1, 0);
672         }
673     }
674 }
675
676 static void dissect_fc_sbccs_dib_link_hdr (tvbuff_t *tvb, packet_info *pinfo,
677                                            proto_tree *tree, guint offset)
678 {
679     guint8 link_ctl;
680     guint16 ctl_info;
681     gchar buffer[128];
682     guint link_payload_len, i;
683
684     if (check_col (pinfo->cinfo, COL_INFO)) {
685         col_append_fstr (pinfo->cinfo, COL_INFO,
686                          ": %s",
687                          val_to_str (tvb_get_guint8 (tvb, offset+1),
688                                      fc_sbccs_dib_link_ctl_fn_val,
689                                      "0x%x"));
690     }
691
692     if (tree) {
693         link_ctl = tvb_get_guint8 (tvb, offset+1);
694         proto_tree_add_item (tree, hf_sbccs_dib_linkctlfn, tvb, offset+1, 1, 0);
695
696         ctl_info = tvb_get_ntohs (tvb, offset+2);
697         switch (link_ctl) {
698         case FC_SBCCS_LINK_CTL_FN_ELP:
699         case FC_SBCCS_LINK_CTL_FN_LPE:
700             buffer[0] = '\0';
701             if (ctl_info & 0x1) {
702                 strcpy (buffer, "Enhanced CRC Gen, ");
703             }
704             if (ctl_info & 0x80) {
705                 strcpy (&buffer[18], "CTC Conn");
706             }
707
708             proto_tree_add_uint_format (tree, hf_sbccs_dib_linkctlinfo, tvb,
709                                         offset+2, 2, ctl_info,
710                                         "Link Control Info: 0x%x(%s)", ctl_info,
711                                         buffer);
712             break;
713         case FC_SBCCS_LINK_CTL_FN_LPR:
714             proto_tree_add_item (tree, hf_sbccs_dib_lprcode, tvb, offset+2, 1,
715                                  0);
716             break;
717         case FC_SBCCS_LINK_CTL_FN_TIN:
718             proto_tree_add_item (tree, hf_sbccs_dib_tin_imgid_cnt, tvb,
719                                  offset+3, 1, 0);
720             break;
721         case FC_SBCCS_LINK_CTL_FN_TIR:
722             proto_tree_add_item (tree, hf_sbccs_dib_tin_imgid_cnt, tvb,
723                                  offset+3, 1, 0);
724             break;
725         case FC_SBCCS_LINK_CTL_FN_LRJ:
726             proto_tree_add_item (tree, hf_sbccs_dib_lrjcode, tvb, offset+2,
727                                  1, 0);
728             break;
729         default:
730             /* Do Nothing */
731             break;
732         }
733
734         proto_tree_add_item (tree, hf_sbccs_dib_ctccntr, tvb, offset+4, 2, 0);
735         proto_tree_add_item (tree, hf_sbccs_dib_iucnt, tvb, offset+9, 1, 0);
736         proto_tree_add_item (tree, hf_sbccs_dib_datacnt, tvb, offset+10, 2, 0);
737         proto_tree_add_item (tree, hf_sbccs_lrc, tvb, offset+12, 4, 0);
738
739         if (link_ctl == FC_SBCCS_LINK_CTL_FN_TIR) {
740             link_payload_len = tvb_get_ntohs (tvb, offset+10);
741             i = 0;
742             offset += 16;
743             
744             while (i < link_payload_len) {
745                 proto_tree_add_text (tree, tvb, offset, 4,
746                                      "Logical Paths %d-%d: %s",
747                                      i*8, ((i+4)*8) - 1,
748                                      tvb_bytes_to_str_punct (tvb, offset, 4, ':'));
749                 i += 4;
750                 offset += 4;
751             }
752         }
753     }
754 }
755
756 static void dissect_fc_sbccs (tvbuff_t *tvb, packet_info *pinfo,
757                               proto_tree *tree)
758 {
759     guint8 type;
760     guint16 ch_cu_id, dev_addr, ccw;
761     guint offset = 0; 
762     proto_item *ti;
763     proto_tree *sb3_tree = NULL,
764                *dib_tree = NULL;
765     tvbuff_t *next_tvb;
766     conversation_t *conversation;
767     sb3_task_id_t task_key;
768         
769     /* Make entries in Protocol column and Info column on summary display */
770     if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
771         col_set_str(pinfo->cinfo, COL_PROTOCOL, "FC-SB3");
772
773     /* Decode the basic SB3 and IU header and determine type of frame */
774     type = get_fc_sbccs_iu_type (tvb, offset);
775     get_fc_sbccs_conv_data (tvb, offset, &ch_cu_id, &dev_addr, &ccw);
776
777     if (check_col (pinfo->cinfo, COL_INFO)) {
778         col_set_str (pinfo->cinfo, COL_INFO, val_to_str (type, fc_sbccs_iu_val,
779                                                          "0x%x"));
780     }
781     
782     /* Retrieve conversation state to determine expected payload */
783     conversation = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst,
784                                       PT_SBCCS, ch_cu_id, dev_addr, 0);
785                                       
786     if (conversation) {
787         task_key.conv_id = conversation->index;
788         task_key.task_id = ccw;
789         pinfo->private_data = (void *)&task_key;
790
791     }
792     else if ((type == FC_SBCCS_IU_CMD_HDR) || 
793              (type != FC_SBCCS_IU_CMD_DATA)) {
794         conversation = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst,
795                                          PT_SBCCS, ch_cu_id, dev_addr, 0);
796         task_key.conv_id = conversation->index;
797         task_key.task_id = ccw;
798         pinfo->private_data = (void *)&task_key;
799     }
800     else {
801         pinfo->private_data = NULL;
802     }
803     
804     if (tree) {
805         ti = proto_tree_add_protocol_format (tree, proto_fc_sbccs, tvb, 0, -1,
806                                              "FC-SB3");
807         sb3_tree = proto_item_add_subtree (ti, ett_fc_sbccs);
808
809         dissect_fc_sbccs_sb3_iu_hdr (tvb, pinfo, sb3_tree, offset);
810         offset += (FC_SBCCS_SB3_HDR_SIZE + FC_SBCCS_IU_HDR_SIZE);
811
812         ti = proto_tree_add_text (sb3_tree, tvb, offset,
813                                   FC_SBCCS_DIB_LRC_HDR_SIZE, "DIB Header");
814         dib_tree = proto_item_add_subtree (ti, ett_fc_sbccs);
815     }
816     else {
817         offset += (FC_SBCCS_SB3_HDR_SIZE + FC_SBCCS_IU_HDR_SIZE);
818     }
819     
820     switch (type) {
821     case FC_SBCCS_IU_DATA:
822         dissect_fc_sbccs_dib_data_hdr (tvb, pinfo, dib_tree, offset);
823         break;
824     case FC_SBCCS_IU_CMD_HDR:
825     case FC_SBCCS_IU_CMD_DATA:
826         dissect_fc_sbccs_dib_cmd_hdr (tvb, pinfo, dib_tree, offset);
827         break;
828     case FC_SBCCS_IU_STATUS:
829         dissect_fc_sbccs_dib_status_hdr (tvb, pinfo, dib_tree, offset);
830         break;
831     case FC_SBCCS_IU_CTL:
832         dissect_fc_sbccs_dib_ctl_hdr (tvb, pinfo, dib_tree, offset);
833         break;
834     case FC_SBCCS_IU_CMD_LINK_CTL:
835         dissect_fc_sbccs_dib_link_hdr (tvb, pinfo, dib_tree, offset);
836         break;
837     default:
838         next_tvb = tvb_new_subset (tvb, offset, -1, -1);
839         call_dissector (data_handle, next_tvb, pinfo, dib_tree);
840         break;
841     }
842
843     if ((get_fc_sbccs_iu_type (tvb, 0) != FC_SBCCS_IU_CTL) &&
844         (get_fc_sbccs_iu_type (tvb, 0) != FC_SBCCS_IU_CMD_LINK_CTL))  {
845         next_tvb = tvb_new_subset (tvb, offset+FC_SBCCS_DIB_LRC_HDR_SIZE,
846                                    -1, -1);
847         call_dissector (data_handle, next_tvb, pinfo, tree);
848     }
849 }
850
851 /* Register the protocol with Ethereal */
852
853 /* this format is required because a script is used to build the C function
854    that calls all the protocol registration.
855 */
856
857 void
858 proto_register_fcsbccs (void)
859 {                 
860     /* Setup list of header fields  See Section 1.6.1 for details*/
861     static hf_register_info hf[] = {
862         { &hf_sbccs_chid,
863           {"Channel Image ID", "sbccs.chid", FT_UINT8, BASE_DEC, NULL, 0x0,
864            "", HFILL}},
865         { &hf_sbccs_cuid,
866           {"Control Unit Image ID", "sbccs.cuid", FT_UINT8, BASE_DEC, NULL,
867            0x0, "", HFILL}},
868         { &hf_sbccs_devaddr,
869           {"Device Address", "sbccs.devaddr", FT_UINT16, BASE_DEC, NULL, 0x0,
870            "", HFILL}},
871         { &hf_sbccs_iui,
872           {"Information Unit Identifier", "sbccs.iui", FT_UINT8, BASE_HEX,
873            NULL, 0x0, "", HFILL}},
874         { &hf_sbccs_dhflags,
875           {"DH Flags", "sbccs.dhflags", FT_UINT8, BASE_HEX, NULL, 0x0, "",
876            HFILL}},
877         { &hf_sbccs_ccw,
878           {"CCW Number", "sbccs.ccw", FT_UINT16, BASE_HEX, NULL, 0x0, "",
879            HFILL}},
880         { &hf_sbccs_token,
881           {"Token", "sbccs.token", FT_UINT24, BASE_DEC, NULL, 0x0, "",
882            HFILL}},
883         { &hf_sbccs_dib_iucnt,
884           {"DIB IU Count", "sbccs.iucnt", FT_UINT8, BASE_DEC, NULL, 0x0,
885            "", HFILL}},
886         { &hf_sbccs_dib_datacnt,
887           {"DIB Data Byte Count", "sbccs.databytecnt", FT_UINT16, BASE_DEC,
888            NULL, 0x0, "", HFILL}},
889         { &hf_sbccs_dib_ccw_cmd,
890           {"CCW Command", "sbccs.ccwcmd", FT_UINT8, BASE_HEX,
891            VALS (fc_sbccs_dib_cmd_val), 0x0, "", HFILL}},
892         { &hf_sbccs_dib_ccw_flags,
893           {"CCW Control Flags", "sbccs.ccwflags", FT_UINT8, BASE_HEX, NULL,
894            0x0, "", HFILL}},
895         { &hf_sbccs_dib_ccw_cnt,
896           {"CCW Count", "sbccs.ccwcnt", FT_UINT16, BASE_DEC, NULL, 0x0, "",
897            HFILL}},
898         { &hf_sbccs_dib_ioprio,
899           {"I/O Priority", "sbccs.ioprio", FT_UINT8, BASE_DEC, NULL, 0x0,
900            "", HFILL}},
901         { &hf_sbccs_dib_cmdflags,
902           {"Command Flags", "sbccs.cmdflags", FT_UINT8, BASE_HEX, NULL, 0x0,
903            "", HFILL}},
904         { &hf_sbccs_dib_statusflags,
905           {"Status Flags", "sbccs.statusflags", FT_UINT8, BASE_HEX, NULL,
906            0x0, "", HFILL}},
907         { &hf_sbccs_dib_status,
908           {"Status", "sbccs.status", FT_UINT8, BASE_DEC, NULL, 0x0, "",
909            HFILL}},
910         { &hf_sbccs_dib_residualcnt,
911           {"Residual Count", "sbccs.residualcnt", FT_UINT8, BASE_DEC,
912            NULL, 0x0, "", HFILL}},
913         { &hf_sbccs_dib_iupacing,
914           {"IU Pacing", "sbccs.iupacing", FT_UINT8, BASE_DEC, NULL, 0x0,
915            "", HFILL}},
916         { &hf_sbccs_dib_qtuf,
917           {"Queue-Time Unit Factor", "sbccs.qtuf", FT_UINT8, BASE_DEC,
918            NULL, 0xF0, "", HFILL}},
919         { &hf_sbccs_dib_qtu,
920           {"Queue-Time Unit", "sbccs.qtu", FT_UINT16, BASE_DEC, NULL, 0xFFF,
921            "", HFILL}},
922         { &hf_sbccs_dib_dtuf,
923           {"Defer-Time Unit Function", "sbccs.dtuf", FT_UINT8, BASE_DEC,
924            NULL, 0xF0, "", HFILL}},
925         { &hf_sbccs_dib_dtu,
926           {"Defer-Time Unit", "sbccs.dtu", FT_UINT16, BASE_DEC, NULL, 0xFFF,
927            "", HFILL}},
928         { &hf_sbccs_dib_ctlfn,
929           {"Control Function", "sbccs.ctlfn", FT_UINT8, BASE_HEX,
930            VALS (fc_sbccs_dib_ctl_fn_val), 0x0, "", HFILL}},
931         { &hf_sbccs_dib_ctlparam,
932           {"Control Parameters", "sbccs.ctlparam", FT_UINT24, BASE_HEX,
933            NULL, 0x0, "", HFILL}},
934         { &hf_sbccs_dib_linkctlfn,
935           {"Link Control Function", "sbccs.linkctlfn", FT_UINT8, BASE_HEX,
936            VALS (fc_sbccs_dib_link_ctl_fn_val), 0x0, "", HFILL}},
937         { &hf_sbccs_dib_linkctlinfo,
938           {"Link Control Information", "sbccs.linkctlinfo", FT_UINT16,
939            BASE_HEX, NULL, 0x0, "", HFILL}},
940         { &hf_sbccs_dib_ctccntr,
941           {"CTC Counter", "sbccs.ctccntr", FT_UINT16, BASE_DEC, NULL, 0x0,
942            "", HFILL}},
943         { &hf_sbccs_lrc,
944           {"LRC", "sbccs.lrc", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL}},
945         { &hf_sbccs_dev_xcp_code,
946           {"Device Level Exception Code", "sbccs.dip.xcpcode", FT_UINT8,
947            BASE_DEC, VALS (fc_sbccs_dib_dev_xcpcode_val), 0x0, "", HFILL}},
948         { &hf_sbccs_prg_pth_errcode,
949           {"Purge Path Error Code", "sbccs.purgepathcode", FT_UINT8,
950            BASE_DEC, VALS (fc_sbccs_dib_purge_path_err_val), 0x0, "", HFILL}},
951         { &hf_sbccs_prg_rsp_errcode,
952           {"Purge Path Response Error Code", "sbccs.purgepathrspcode",
953            FT_UINT8, BASE_DEC, VALS (fc_sbccs_dib_purge_path_rsp_err_val),
954            0x0, "", HFILL}},
955         { &hf_sbccs_dib_lprcode,
956           {"LPR Reason Code", "sbccs.lprcode", FT_UINT8, BASE_DEC,
957            VALS (fc_sbccs_dib_lpr_errcode_val), 0xF, "", HFILL}},
958         { &hf_sbccs_dib_tin_imgid_cnt,
959           {"TIN Image ID", "sbccs.tinimageidcnt", FT_UINT8, BASE_DEC, NULL,
960            0x0, "", HFILL}},
961         { &hf_sbccs_dib_lrjcode,
962           {"LRJ Reaspn Code", "sbccs.lrjcode", FT_UINT8, BASE_HEX,
963            VALS (fc_sbccs_dib_lrj_errcode_val), 0x7F, "", HFILL}},
964     };
965
966
967     /* Setup protocol subtree array */
968     static gint *ett[] = {
969         &ett_fc_sbccs,
970     };
971
972     /* Register the protocol name and description */
973     proto_fc_sbccs = proto_register_protocol ("Fibre Channel Single Byte Command",
974                                               "FC-SB3", "sb3");
975
976     /* Required function calls to register the header fields and subtrees used */
977     proto_register_field_array(proto_fc_sbccs, hf, array_length(hf));
978     proto_register_subtree_array(ett, array_length(ett));
979 }
980
981 /* If this dissector uses sub-dissector registration add a registration routine.
982    This format is required because a script is used to find these routines and
983    create the code that calls these routines.
984 */
985 void
986 proto_reg_handoff_fcsbccs (void)
987 {
988     dissector_handle_t fc_sbccs_handle;
989
990     fc_sbccs_handle = create_dissector_handle (dissect_fc_sbccs,
991                                                proto_fc_sbccs);
992
993     dissector_add("fc.ftype", FC_FTYPE_SBCCS, fc_sbccs_handle);
994
995     data_handle = find_dissector ("data");
996 }
997
998