diff options
author | Gerald Combs <gerald@wireshark.org> | 2002-12-08 02:32:36 +0000 |
---|---|---|
committer | Gerald Combs <gerald@wireshark.org> | 2002-12-08 02:32:36 +0000 |
commit | b60b1414c39e902281dd7c819cb2deb5083d6bcc (patch) | |
tree | 0eb50f10825095cede74b16fe654c9e89ca64281 /packet-fcswils.c | |
parent | c2ecb0daa5c959f4c0bcc36443b90eb545d294db (diff) | |
download | wireshark-b60b1414c39e902281dd7c819cb2deb5083d6bcc.tar.gz wireshark-b60b1414c39e902281dd7c819cb2deb5083d6bcc.tar.bz2 wireshark-b60b1414c39e902281dd7c819cb2deb5083d6bcc.zip |
From Dinesh Dutt: Add Fibre Channel support, including FCIP, Basic FC
header, Extended Link Service, Interswitch Link Service, FCP, and IPFC.
svn path=/trunk/; revision=6757
Diffstat (limited to 'packet-fcswils.c')
-rw-r--r-- | packet-fcswils.c | 1727 |
1 files changed, 1727 insertions, 0 deletions
diff --git a/packet-fcswils.c b/packet-fcswils.c new file mode 100644 index 0000000000..cbf45aafbf --- /dev/null +++ b/packet-fcswils.c @@ -0,0 +1,1727 @@ +/* packet-fcswils + * Routines for FC Inter-switch link services + * Copyright 2001, Dinesh G Dutt <ddutt@cisco.com> + * + * $Id: packet-fcswils.c,v 1.1 2002/12/08 02:32:17 gerald Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@ethereal.com> + * Copyright 1998 Gerald Combs + * + * Copied from WHATEVER_FILE_YOU_USED (where "WHATEVER_FILE_YOU_USED" + * is a dissector file; if you just copied this from README.developer, + * don't bother with the "Copied from" - you don't even need to put + * in a "Copied from" if you copied an existing dissector, especially + * if the bulk of the code in the new dissector is your code) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +#ifdef HAVE_NETINET_IN_H +# include <netinet/in.h> +#endif + +#include <glib.h> + +#ifdef NEED_SNPRINTF_H +# include "snprintf.h" +#endif + +#include <epan/packet.h> +#include <epan/conversation.h> +#include "etypes.h" +#include "packet-fc.h" +#include "packet-fcswils.h" + +#define FC_SWILS_RPLY 0x0 +#define FC_SWILS_REQ 0x1 + +/* Zone name has the structure: + * name_len (1 byte), rsvd (3 bytes), name (m bytes), fill (n bytes) + * name_len excludes the 4 initial bytes before the name + */ +#define ZONENAME_LEN(x, y) (tvb_get_guint8(x, y)+4) + +/* Initialize the protocol and registered fields */ +static int proto_fcswils = -1; +static int hf_swils_opcode = -1; +static int hf_swils_elp_rev = -1; +static int hf_swils_elp_flags = -1; +static int hf_swils_elp_r_a_tov = -1; +static int hf_swils_elp_e_d_tov = -1; +static int hf_swils_elp_req_epn = -1; +static int hf_swils_elp_req_esn = -1; +static int hf_swils_elp_clsf_svcp = -1; +static int hf_swils_elp_clsf_rcvsz = -1; +static int hf_swils_elp_clsf_conseq = -1; +static int hf_swils_elp_clsf_e2e = -1; +static int hf_swils_elp_clsf_openseq = -1; +static int hf_swils_elp_cls1_svcp = -1; +static int hf_swils_elp_cls1_rcvsz = -1; +static int hf_swils_elp_cls2_svcp = -1; +static int hf_swils_elp_cls2_rcvsz = -1; +static int hf_swils_elp_cls3_svcp = -1; +static int hf_swils_elp_cls3_rcvsz = -1; +static int hf_swils_elp_isl_fc_mode = -1; +static int hf_swils_elp_fcplen = -1; +static int hf_swils_elp_b2bcredit = -1; +static int hf_swils_elp_compat1 = -1; +static int hf_swils_elp_compat2 = -1; +static int hf_swils_elp_compat3 = -1; +static int hf_swils_elp_compat4 = -1; +static int hf_swils_efp_rec_type = -1; +static int hf_swils_efp_dom_id = -1; +static int hf_swils_efp_switch_name = -1; +static int hf_swils_efp_mcast_grpno = -1; +static int hf_swils_efp_alias_token = -1; +static int hf_swils_efp_payload_len = -1; +static int hf_swils_efp_pswitch_pri = -1; +static int hf_swils_efp_pswitch_name = -1; +static int hf_swils_dia_switch_name = -1; +static int hf_swils_rdi_payload_len = -1; +static int hf_swils_rdi_req_sname = -1; +static int hf_swils_fspfh_cmd = -1; +static int hf_swils_fspfh_rev = -1; +static int hf_swils_fspfh_ar_num = -1; +static int hf_swils_fspfh_auth_type = -1; +static int hf_swils_fspfh_dom_id = -1; +static int hf_swils_fspfh_auth = -1; +static int hf_swils_hlo_options = -1; +static int hf_swils_hlo_hloint = -1; +static int hf_swils_hlo_deadint = -1; +static int hf_swils_hlo_rcv_domid = -1; +static int hf_swils_hlo_orig_pidx = -1; +static int hf_swils_ldrec_linkid = -1; +static int hf_swils_ldrec_out_pidx = -1; +static int hf_swils_ldrec_nbr_pidx = -1; +static int hf_swils_ldrec_link_type = -1; +static int hf_swils_ldrec_link_cost = -1; +static int hf_swils_lsrh_lsr_type = -1; +static int hf_swils_lsrh_lsid = -1; +static int hf_swils_lsrh_adv_domid = -1; +static int hf_swils_lsrh_ls_incid = -1; +static int hf_swils_esc_pdesc_vendorid = -1; +static int hf_swils_esc_swvendorid = -1; +static int hf_swils_esc_protocolid = -1; +static int hf_swils_rscn_evtype = -1; +static int hf_swils_rscn_addrfmt = -1; +static int hf_swils_rscn_detectfn = -1; +static int hf_swils_rscn_affectedport = -1; +static int hf_swils_rscn_portstate = -1; +static int hf_swils_rscn_portid = -1; +static int hf_swils_rscn_pwwn = -1; +static int hf_swils_rscn_nwwn = -1; +static int hf_swils_zone_activezonenm = -1; +static int hf_swils_zone_objname = -1; +static int hf_swils_zone_objtype = -1; +static int hf_swils_zone_mbrtype = -1; +static int hf_swils_zone_protocol = -1; +static int hf_swils_zone_mbrid = -1; +static int hf_swils_zone_status = -1; +static int hf_swils_zone_reason = -1; +static int hf_swils_aca_domainid = -1; +static int hf_swils_sfc_opcode = -1; +static int hf_swils_sfc_zonenm = -1; +static int hf_swils_rjt = -1; +static int hf_swils_rjtdet = -1; +static int hf_swils_rjtvendor = -1; +static int hf_swils_zone_mbrid_lun = -1; + +/* Initialize the subtree pointers */ +static gint ett_fcswils = -1; +static gint ett_fcswils_swacc = -1; +static gint ett_fcswils_swrjt = -1; +static gint ett_fcswils_elp = -1; +static gint ett_fcswils_efp = -1; +static gint ett_fcswils_efplist = -1; +static gint ett_fcswils_dia = -1; +static gint ett_fcswils_rdi = -1; +static gint ett_fcswils_fspfhdr = -1; +static gint ett_fcswils_hlo = -1; +static gint ett_fcswils_lsrec = -1; +static gint ett_fcswils_lsrechdr = -1; +static gint ett_fcswils_ldrec = -1; +static gint ett_fcswils_lsu = -1; +static gint ett_fcswils_lsa = -1; +static gint ett_fcswils_bf = -1; +static gint ett_fcswils_rcf = -1; +static gint ett_fcswils_rscn = -1; +static gint ett_fcswils_rscn_dev = -1; +static gint ett_fcswils_drlir = -1; +static gint ett_fcswils_mr = -1; +static gint ett_fcswils_zoneobjlist = -1; +static gint ett_fcswils_zoneobj = -1; +static gint ett_fcswils_zonembr = -1; +static gint ett_fcswils_aca = -1; +static gint ett_fcswils_rca = -1; +static gint ett_fcswils_sfc = -1; +static gint ett_fcswils_ufc = -1; +static gint ett_fcswils_esc = -1; +static gint ett_fcswils_esc_pdesc = -1; + +typedef struct _zonename { + guint32 namelen:8, + rsvd:24; + gchar *name; + gchar *pad; +} zonename_t; + +typedef struct _fcswils_conv_key { + guint32 conv_idx; +} fcswils_conv_key_t; + +typedef struct _fcswils_conv_data { + guint32 opcode; +} fcswils_conv_data_t; + +#ifndef WIN32 +#define PACKED __attribute__((__packed__)) +#else +#define PACKED +#endif + +GHashTable *fcswils_req_hash = NULL; +GMemChunk *fcswils_req_keys = NULL; +GMemChunk *fcswils_req_vals = NULL; +guint32 fcswils_init_count = 25; + +static dissector_handle_t data_handle; + +static gint get_zoneobj_len (tvbuff_t *tvb, gint offset); + +/* + * Hash Functions + */ +static gint +fcswils_equal(gconstpointer v, gconstpointer w) +{ + fcswils_conv_key_t *v1 = (fcswils_conv_key_t *)v; + fcswils_conv_key_t *v2 = (fcswils_conv_key_t *)w; + + return (v1->conv_idx == v2->conv_idx); +} + +static guint +fcswils_hash (gconstpointer v) +{ + fcswils_conv_key_t *key = (fcswils_conv_key_t *)v; + guint val; + + val = key->conv_idx; + + return val; +} + +/* + * Protocol initialization + */ +static void +fcswils_init_protocol(void) +{ + if (fcswils_req_keys) + g_mem_chunk_destroy (fcswils_req_keys); + if (fcswils_req_vals) + g_mem_chunk_destroy (fcswils_req_vals); + if (fcswils_req_hash) + g_hash_table_destroy (fcswils_req_hash); + + fcswils_req_hash = g_hash_table_new(fcswils_hash, fcswils_equal); + fcswils_req_keys = g_mem_chunk_new("fcswils_req_keys", + sizeof(fcswils_conv_key_t), + fcswils_init_count * sizeof(fcswils_conv_key_t), + G_ALLOC_AND_FREE); + fcswils_req_vals = g_mem_chunk_new("fcswils_req_vals", + sizeof(fcswils_conv_data_t), + fcswils_init_count * sizeof(fcswils_conv_data_t), + G_ALLOC_AND_FREE); +} + +static gchar * +zonenm_to_str (tvbuff_t *tvb, gint offset) +{ + int len = tvb_get_guint8 (tvb, offset); + return ((gchar *)tvb_get_ptr (tvb, offset+4, len)); +} + +/* Offset points to the start of the zone object */ +static gint +get_zoneobj_len (tvbuff_t *tvb, gint offset) +{ + gint numrec, numrec1; + guint8 objtype; + gint i, j, len; + + /* zone object structure is: + * type (1 byte), protocol (1 byte), rsvd (2 bytes), obj name (x bytes), + * num of zone mbrs (4 bytes ), list of zone members (each member if of + * variable length). + * + * zone member structure is: + * type (1 byte), rsvd (1 byte), flags (1 byte), id_len (1 byte), + * id (id_len bytes) + */ + objtype = tvb_get_guint8 (tvb, offset); + len = 4 + ZONENAME_LEN (tvb, offset+4); /* length upto num_of_mbrs field */ + numrec = tvb_get_ntohl (tvb, offset+len); /* gets us num of zone mbrs */ + + len += 4; /* + num_mbrs */ + for (i = 0; i < numrec; i++) { + if (objtype == FC_SWILS_ZONEOBJ_ZONESET) { + len += 4 + ZONENAME_LEN (tvb, offset+4+len); /* length upto num_of_mbrs field */ + numrec1 = tvb_get_ntohl (tvb, offset+len); + + len += 4; + for (j = 0; j < numrec1; j++) { + len += 4 + tvb_get_guint8 (tvb, offset+3+len); + } + } + else if (objtype == FC_SWILS_ZONEOBJ_ZONE) { + len += 4 + tvb_get_guint8 (tvb, offset+3+len); + } + } + + return len; +} + +static void +dissect_swils_elp (tvbuff_t *tvb, proto_tree *elp_tree, guint8 isreq _U_) +{ + + /* Set up structures needed to add the protocol subtree and manage it */ + int offset = 0, + stroff = 0; + gchar flags[40]; + fcswils_elp elp; + + /* Response i.e. SW_ACC for an ELP has the same format as the request */ + /* We skip the initial 4 bytes as we don't care about the opcode */ + tvb_memcpy (tvb, (guint8 *)&elp, 4, FC_SWILS_ELP_SIZE); + + elp.r_a_tov = ntohl (elp.r_a_tov); + elp.e_d_tov = ntohl (elp.e_d_tov); + elp.isl_flwctrl_mode = ntohs (elp.isl_flwctrl_mode); + elp.flw_ctrl_parmlen = ntohs (elp.flw_ctrl_parmlen); + + if (elp_tree) { + offset += 4; + proto_tree_add_item (elp_tree, hf_swils_elp_rev, tvb, offset++, 1, 0); + proto_tree_add_item (elp_tree, hf_swils_elp_flags, tvb, offset, 2, 0); + offset += 3; + proto_tree_add_uint_format (elp_tree, hf_swils_elp_r_a_tov, tvb, offset, 4, + elp.r_a_tov, "R_A_TOV: %d msecs", elp.r_a_tov); + offset += 4; + proto_tree_add_uint_format (elp_tree, hf_swils_elp_e_d_tov, tvb, offset, 4, + elp.e_d_tov, "E_D_TOV: %d msecs", elp.e_d_tov); + offset += 4; + proto_tree_add_string (elp_tree, hf_swils_elp_req_epn, tvb, offset, 8, + fcwwn_to_str (elp.req_epname)); + offset += 8; + proto_tree_add_string (elp_tree, hf_swils_elp_req_esn, tvb, offset, 8, + fcwwn_to_str (elp.req_sname)); + offset += 8; + + flags[0] = '\0'; + if (elp.clsf_svcparm[0] & 0x80) { + strcpy (flags, "Class F Valid"); + + if (elp.clsf_svcparm[4] & 0x20) { + strcpy (&flags[13], " | X_ID Interlock"); + } + else { + strcpy (&flags[13], " | No X_ID Interlk"); + } + } + else { + strcpy (flags, "Class F Invld"); + } + proto_tree_add_bytes_format (elp_tree, hf_swils_elp_clsf_svcp, tvb, offset, 6, + &elp.clsf_svcparm[0], "Class F Svc Parameters: (%s)", flags); + offset += 6; + + proto_tree_add_item (elp_tree, hf_swils_elp_clsf_rcvsz, tvb, offset, 2, 0); + offset += 2; + proto_tree_add_item (elp_tree, hf_swils_elp_clsf_conseq, tvb, offset, 2, 0); + offset += 2; + proto_tree_add_item (elp_tree, hf_swils_elp_clsf_e2e, tvb, offset, 2, 0); + offset += 2; + proto_tree_add_item (elp_tree, hf_swils_elp_clsf_openseq, tvb, offset, 2, 0); + offset += 4; + + flags[0] = '\0'; + stroff = 0; + if (elp.cls1_svcparm[0] & 0x80) { + strcpy (&flags[stroff], "Class 1 Valid"); + stroff += 13; + if (elp.cls1_svcparm[0] & 0x40) { + strcpy (&flags[stroff], " | IMX"); + stroff += 6; + } + if (elp.cls1_svcparm[0] & 0x20) { + strcpy (&flags[stroff], " | XPS"); + stroff += 6; + } + if (elp.cls1_svcparm[0] & 0x10) { + strcpy (&flags[stroff], " | LKS"); + } + } + else { + strcpy (&flags[0], "Class 1 Invalid"); + } + + proto_tree_add_bytes_format (elp_tree, hf_swils_elp_cls1_svcp, tvb, offset, 2, + tvb_get_ptr (tvb, offset, 2), + "Class 1 Svc Parameters: (%s)", flags); + offset += 2; + if (elp.cls1_svcparm[0] & 0x80) { + proto_tree_add_item (elp_tree, hf_swils_elp_cls1_rcvsz, tvb, offset, 2, 0); + } + offset += 2; + + flags[0] = '\0'; + if (elp.cls2_svcparm[0] & 0x80) { + strcpy (flags, "Class 2 Valid"); + + if (elp.cls2_svcparm[0] & 0x08) { + strcpy (&flags[13], " | Seq Delivery"); + } + else { + strcpy (&flags[13], " | No Seq Delivery"); + } + } + else { + strcpy (flags, "Class 2 Invld"); + } + + proto_tree_add_bytes_format (elp_tree, hf_swils_elp_cls2_svcp, tvb, offset, 2, + &elp.cls2_svcparm[0], + "Class 2 Svc Parameters: (%s)", flags); + offset += 2; + + if (elp.cls2_svcparm[0] & 0x80) { + proto_tree_add_item (elp_tree, hf_swils_elp_cls2_rcvsz, tvb, offset, 2, 0); + } + offset += 2; + + flags[0] = '\0'; + if (elp.cls3_svcparm[0] & 0x80) { + strcpy (flags, "Class 3 Valid"); + + if (elp.cls3_svcparm[0] & 0x08) { + strcpy (&flags[13], " | Seq Delivery"); + } + else { + strcpy (&flags[13], " | No Seq Delivery"); + } + } + else { + strcpy (flags, "Class 3 Invld"); + } + proto_tree_add_bytes_format (elp_tree, hf_swils_elp_cls3_svcp, tvb, offset, 2, + &elp.cls3_svcparm[0], + "Class 3 Svc Parameters: (%s)", flags); + offset += 2; + + if (elp.cls3_svcparm[0] & 0x80) { + proto_tree_add_item (elp_tree, hf_swils_elp_cls3_rcvsz, tvb, offset, 2, 0); + } + offset += 22; + + proto_tree_add_string (elp_tree, hf_swils_elp_isl_fc_mode, tvb, offset, 2, + val_to_str (elp.isl_flwctrl_mode, fcswils_elp_fc_val, "Vendor Unique")); + offset += 2; + proto_tree_add_item (elp_tree, hf_swils_elp_fcplen, tvb, offset, 2, 0); + offset += 2; + proto_tree_add_item (elp_tree, hf_swils_elp_b2bcredit, tvb, offset, 4, 0); + offset += 4; + proto_tree_add_item (elp_tree, hf_swils_elp_compat1, tvb, offset, 4, 0); + offset += 4; + proto_tree_add_item (elp_tree, hf_swils_elp_compat2, tvb, offset, 4, 0); + offset += 4; + proto_tree_add_item (elp_tree, hf_swils_elp_compat3, tvb, offset, 4, 0); + offset += 4; + proto_tree_add_item (elp_tree, hf_swils_elp_compat4, tvb, offset, 4, 0); + } + +} + +static void +dissect_swils_efp (tvbuff_t *tvb, proto_tree *efp_tree, guint8 isreq _U_) +{ + +/* Set up structures needed to add the protocol subtree and manage it */ + proto_item *subti; + proto_tree *lrec_tree; + int num_listrec = 0, + offset = 0; + fcswils_efp efp; + fcswils_efp_listrec *lrec; + + tvb_memcpy (tvb, (guint8 *)&efp, offset, FC_SWILS_EFP_SIZE); + efp.payload_len = ntohs (efp.payload_len); + efp.listrec = (fcswils_efp_listrec *)tvb_get_ptr (tvb, FC_SWILS_EFP_SIZE, + efp.payload_len - FC_SWILS_EFP_SIZE); + + if (efp_tree) { + offset += 2; + proto_tree_add_item (efp_tree, hf_swils_efp_payload_len, tvb, offset, 2, 0); + offset += 5; + proto_tree_add_item (efp_tree, hf_swils_efp_pswitch_pri, tvb, + offset++, 1, 0); + proto_tree_add_string (efp_tree, hf_swils_efp_pswitch_name, tvb, offset, + 8, fcwwn_to_str (efp.pswitch_name)); + offset += 8; + + /* Add List Records now */ + if (efp.reclen) { + num_listrec = (efp.payload_len - FC_SWILS_EFP_SIZE)/efp.reclen; + } + else { + num_listrec = 0; + } + + while (num_listrec--) { + lrec = (fcswils_efp_listrec *)tvb_get_ptr (tvb, offset, efp.reclen); + if (lrec != NULL) { + if (lrec->didrec.rec_type == FC_SWILS_LRECTYPE_DOMAIN) { + subti = proto_tree_add_text (efp_tree, tvb, offset, + (efp.payload_len - FC_SWILS_EFP_SIZE), + "Domain ID Record"); + lrec_tree = proto_item_add_subtree (subti, ett_fcswils_efplist); + proto_tree_add_item (lrec_tree, hf_swils_efp_dom_id, tvb, offset+1, 1, 0); + proto_tree_add_string (lrec_tree, hf_swils_efp_switch_name, tvb, offset+8, 8, + fcwwn_to_str (lrec->didrec.sname)); + } + else if (lrec->didrec.rec_type == FC_SWILS_LRECTYPE_MCAST) { + subti = proto_tree_add_text (efp_tree, tvb, offset, + (efp.payload_len - FC_SWILS_EFP_SIZE), + "Multicast ID Record"); + lrec_tree = proto_item_add_subtree (subti, ett_fcswils_efplist); + proto_tree_add_item (lrec_tree, hf_swils_efp_mcast_grpno, tvb, offset+1, 1, 0); + } + offset += efp.reclen; + } + } + } +} + +static void +dissect_swils_dia (tvbuff_t *tvb, proto_tree *dia_tree, guint8 isreq _U_) +{ + /* Set up structures needed to add the protocol subtree and manage it */ + int offset = 0; + + if (dia_tree) { + proto_tree_add_string (dia_tree, hf_swils_dia_switch_name, tvb, offset+4, + 8, fcwwn_to_str (tvb_get_ptr (tvb, offset+4, 8))); + } +} + +static void +dissect_swils_rdi (tvbuff_t *tvb, proto_tree *rdi_tree, guint8 isreq) +{ + /* Set up structures needed to add the protocol subtree and manage it */ + int offset = 0; + int i, plen, numrec; + + if (rdi_tree) { + plen = tvb_get_ntohs (tvb, offset+2); + + proto_tree_add_item (rdi_tree, hf_swils_rdi_payload_len, tvb, offset+2, 2, 0); + proto_tree_add_string (rdi_tree, hf_swils_rdi_req_sname, tvb, offset+4, + 8, fcwwn_to_str (tvb_get_ptr (tvb, offset+4, 8))); + + /* 12 is the length of the initial header and 4 is the size of each + * domain request record. + */ + numrec = (plen - 12)/4; + offset = 12; + for (i = 0; i < numrec; i++) { + if (isreq) { + proto_tree_add_text (rdi_tree, tvb, offset+3, 1, + "Requested Domain ID: %d", + tvb_get_guint8 (tvb, offset+3)); + } + else { + proto_tree_add_text (rdi_tree, tvb, offset+3, 1, + "Granted Domain ID: %d", + tvb_get_guint8 (tvb, offset+3)); + } + offset += 4; + } + } +} + +static void +dissect_swils_fspf_hdr (tvbuff_t *tvb, proto_tree *tree, int offset) +{ + proto_item *subti; + proto_tree *fspfh_tree; + + if (tree) { + /* 20 is the size of FSPF header */ + subti = proto_tree_add_text (tree, tvb, offset, 20, "FSPF Header"); + fspfh_tree = proto_item_add_subtree (subti, ett_fcswils_fspfhdr); + + proto_tree_add_item (fspfh_tree, hf_swils_fspfh_rev, tvb, offset+4, + 1, 0); + proto_tree_add_item (fspfh_tree, hf_swils_fspfh_ar_num, tvb, + offset+5, 1, 0); + proto_tree_add_item (fspfh_tree, hf_swils_fspfh_auth_type, tvb, + offset+6, 1, 0); + proto_tree_add_item (fspfh_tree, hf_swils_fspfh_dom_id, tvb, offset+11, + 1, 0); + proto_tree_add_item (fspfh_tree, hf_swils_fspfh_auth, tvb, offset+12, + 8, 0); + } +} + +static void +dissect_swils_fspf_lsrechdr (tvbuff_t *tvb, proto_tree *lsrec_tree, int offset) +{ + proto_tree *tree; + proto_item *subti; + + subti = proto_tree_add_text (lsrec_tree, tvb, offset, 24, + "Link State Record Header"); + tree = proto_item_add_subtree (subti, ett_fcswils_lsrechdr); + + proto_tree_add_item (tree, hf_swils_lsrh_lsr_type, tvb, offset, 1, 0); + proto_tree_add_text (tree, tvb, offset+2, 2, "LSR Age: %d secs", + tvb_get_ntohs (tvb, offset+2)); + proto_tree_add_text (tree, tvb, offset+4, 4, "Options : 0x%x", + tvb_get_ntohl (tvb, offset+4)); + proto_tree_add_item (tree, hf_swils_lsrh_lsid, tvb, offset+11, 1, 0); + proto_tree_add_item (tree, hf_swils_lsrh_adv_domid, tvb, offset+15, 1, 0); + proto_tree_add_item (tree, hf_swils_lsrh_ls_incid, tvb, offset+16, 4, 0); + proto_tree_add_text (tree, tvb, offset+20, 2, "Checksum: 0x%x", + tvb_get_ntohs (tvb, offset+20)); + proto_tree_add_text (tree, tvb, offset+22, 2, "LSR Length: %d", + tvb_get_ntohs (tvb, offset+22)); +} + +static void +dissect_swils_fspf_ldrec (tvbuff_t *tvb, proto_tree *tree, int offset) +{ + proto_tree_add_string (tree, hf_swils_ldrec_linkid, tvb, offset, 4, + fc_to_str (tvb_get_ptr (tvb, offset+1, 3))); + proto_tree_add_item (tree, hf_swils_ldrec_out_pidx, tvb, offset+5, 3, 0); + proto_tree_add_item (tree, hf_swils_ldrec_nbr_pidx, tvb, offset+9, 3, 0); + proto_tree_add_item (tree, hf_swils_ldrec_link_type, tvb, offset+12, 1, 0); + proto_tree_add_item (tree, hf_swils_ldrec_link_cost, tvb, offset+14, 2, 0); +} + +static void +dissect_swils_fspf_lsrec (tvbuff_t *tvb, proto_tree *tree, int offset, + int num_lsrec) +{ + int i, j, num_ldrec; + proto_item *subti1, *subti; + proto_tree *lsrec_tree, *ldrec_tree; + + if (tree) { + for (j = 0; j < num_lsrec; j++) { + num_ldrec = tvb_get_ntohs (tvb, offset+26); + subti = proto_tree_add_text (tree, tvb, offset, (28+num_ldrec*16), + "Link State Record %d", j); + lsrec_tree = proto_item_add_subtree (subti, ett_fcswils_lsrec); + + dissect_swils_fspf_lsrechdr (tvb, lsrec_tree, offset); + proto_tree_add_text (tree, tvb, offset+26, 2, "Number of Links: %d", + num_ldrec); + offset += 28; + + for (i = 0; i < num_ldrec; i++) { + subti1 = proto_tree_add_text (tree, tvb, offset, 16, + "Link Descriptor %d", i); + ldrec_tree = proto_item_add_subtree (subti1, ett_fcswils_ldrec); + dissect_swils_fspf_ldrec (tvb, ldrec_tree, offset); + offset += 16; + } + } + } +} + +static void +dissect_swils_hello (tvbuff_t *tvb, proto_tree *hlo_tree, guint8 isreq _U_) +{ + /* Set up structures needed to add the protocol subtree and manage it */ + int offset = 0; + + if (hlo_tree) { + dissect_swils_fspf_hdr (tvb, hlo_tree, offset); + + proto_tree_add_item (hlo_tree, hf_swils_hlo_options, tvb, offset+20, 4, 0); + proto_tree_add_item (hlo_tree, hf_swils_hlo_hloint, tvb, offset+24, 4, 0); + proto_tree_add_item (hlo_tree, hf_swils_hlo_deadint, tvb, offset+28, 4, 0); + proto_tree_add_item (hlo_tree, hf_swils_hlo_rcv_domid, tvb, offset+35, 1, 0); + proto_tree_add_item (hlo_tree, hf_swils_hlo_orig_pidx, tvb, offset+37, 3, 0); + } +} + +static void +dissect_swils_lsupdate (tvbuff_t *tvb, proto_tree *lsu_tree, guint8 isreq _U_) +{ + /* Set up structures needed to add the protocol subtree and manage it */ + int offset = 0; + int num_lsrec; + + if (lsu_tree) { + dissect_swils_fspf_hdr (tvb, lsu_tree, offset); + + proto_tree_add_text (lsu_tree, tvb, offset+23, 1, "Flags : %s", + val_to_str (tvb_get_guint8 (tvb, offset+23), + fc_swils_fspf_lsrflags_val, "0x%x")); + num_lsrec = tvb_get_ntohl (tvb, offset+24); + + proto_tree_add_text (lsu_tree, tvb, offset+24, 4, "Num of LSRs: %d", + num_lsrec); + + offset = 28; + dissect_swils_fspf_lsrec (tvb, lsu_tree, offset, num_lsrec); + } +} + +static void +dissect_swils_lsack (tvbuff_t *tvb, proto_tree *lsa_tree, guint8 isreq _U_) +{ + /* Set up structures needed to add the protocol subtree and manage it */ + int offset = 0; + int num_lsrechdr, i; + + if (lsa_tree) { + dissect_swils_fspf_hdr (tvb, lsa_tree, offset); + + proto_tree_add_text (lsa_tree, tvb, offset+23, 1, "Flags : %s", + val_to_str (tvb_get_guint8 (tvb, offset+23), + fc_swils_fspf_lsrflags_val, "0x%x")); + num_lsrechdr = tvb_get_ntohl (tvb, offset+24); + + proto_tree_add_text (lsa_tree, tvb, offset+24, 4, "Num of LSR Headers: %d", + num_lsrechdr); + + offset = 28; + + for (i = 0; i < num_lsrechdr; i++) { + dissect_swils_fspf_lsrechdr (tvb, lsa_tree, offset); + offset += 24; + } + } +} + +static void +dissect_swils_rscn (tvbuff_t *tvb, proto_tree *rscn_tree, guint8 isreq) +{ + /* Set up structures needed to add the protocol subtree and manage it */ + int offset = 0; + proto_tree *dev_tree; + int addrfmt, evtype; + int numrec, i; + proto_item *subti; + + if (rscn_tree) { + if (!isreq) + return; + + evtype = tvb_get_guint8 (tvb, offset+4); + addrfmt = evtype & 0x0F; + evtype = evtype >> 4; + + proto_tree_add_item (rscn_tree, hf_swils_rscn_evtype, tvb, offset+4, + 1, 0); + proto_tree_add_item (rscn_tree, hf_swils_rscn_addrfmt, tvb, offset+4, + 1, 0); + proto_tree_add_string (rscn_tree, hf_swils_rscn_affectedport, tvb, + offset+5, 3, fc_to_str (tvb_get_ptr (tvb, + offset+5, 3))); + proto_tree_add_item (rscn_tree, hf_swils_rscn_detectfn, tvb, + offset+8, 4, 0); + numrec = tvb_get_ntohl (tvb, offset+12); + proto_tree_add_text (rscn_tree, tvb, offset+12, 4, "Num Entries: %d", + numrec); + + offset = 16; + for (i = 0; i < numrec; i++) { + subti = proto_tree_add_text (rscn_tree, tvb, offset, 20, + "Device Entry %d", i); + dev_tree = proto_item_add_subtree (rscn_tree, ett_fcswils_rscn_dev); + + proto_tree_add_item (dev_tree, hf_swils_rscn_portstate, tvb, offset, 1, 0); + proto_tree_add_string (dev_tree, hf_swils_rscn_portid, tvb, offset+1, 3, + fc_to_str (tvb_get_ptr (tvb, offset+1, 3))); + proto_tree_add_string (dev_tree, hf_swils_rscn_pwwn, tvb, offset+4, 8, + fcwwn_to_str (tvb_get_ptr (tvb, offset+4, 8))); + proto_tree_add_string (dev_tree, hf_swils_rscn_nwwn, tvb, offset+4, 8, + fcwwn_to_str (tvb_get_ptr (tvb, offset+4, 8))); + offset += 20; + } + } +} + +/* + * Merge Request contains zoning objects organized in the following format: + * + * Zone Set Object + * | + * +---------------- Zone Object + * | | + * +-- +---------------- Zone Member + * | | | + * +-- +---- +----- + * + * So the decoding of the zone merge request is based on this structure + */ + +static void +dissect_swils_zone_mbr (tvbuff_t *tvb, proto_tree *zmbr_tree, int offset) +{ + int mbrlen = 4 + tvb_get_guint8 (tvb, offset+3); + + proto_tree_add_item (zmbr_tree, hf_swils_zone_mbrtype, tvb, + offset, 1, 0); + proto_tree_add_text (zmbr_tree, tvb, offset+2, 1, "Flags: 0x%x", + tvb_get_guint8 (tvb, offset+2)); + proto_tree_add_text (zmbr_tree, tvb, offset+3, 1, + "Identifier Length: %d", + tvb_get_guint8 (tvb, offset+3)); + switch (tvb_get_guint8 (tvb, offset)) { + case FC_SWILS_ZONEMBR_WWN: + proto_tree_add_string (zmbr_tree, hf_swils_zone_mbrid, tvb, + offset+4, 8, + fcwwn_to_str (tvb_get_ptr (tvb, + offset+4, + 8))); + break; + case FC_SWILS_ZONEMBR_DP: + proto_tree_add_string_format (zmbr_tree, + hf_swils_zone_mbrid, + tvb, offset+4, 4, " ", + "0x%x", + tvb_get_ntohl (tvb, + offset+4)); + break; + case FC_SWILS_ZONEMBR_FCID: + proto_tree_add_string (zmbr_tree, hf_swils_zone_mbrid, tvb, + offset+4, 4, + fc_to_str (tvb_get_ptr (tvb, + offset+5, + 3))); + break; + case FC_SWILS_ZONEMBR_ALIAS: + proto_tree_add_string (zmbr_tree, hf_swils_zone_mbrid, tvb, + offset+4, + tvb_get_guint8 (tvb, offset+3), + zonenm_to_str (tvb, offset+4)); + break; + case FC_SWILS_ZONEMBR_WWN_LUN: + proto_tree_add_string (zmbr_tree, hf_swils_zone_mbrid, tvb, + offset+4, 8, + fcwwn_to_str (tvb_get_ptr (tvb, + offset+4, + 8))); + proto_tree_add_item (zmbr_tree, hf_swils_zone_mbrid_lun, tvb, + offset+12, 8, 0); + break; + case FC_SWILS_ZONEMBR_DP_LUN: + proto_tree_add_string_format (zmbr_tree, + hf_swils_zone_mbrid, + tvb, offset+4, 4, " ", + "0x%x", + tvb_get_ntohl (tvb, + offset+4)); + proto_tree_add_item (zmbr_tree, hf_swils_zone_mbrid_lun, tvb, + offset+8, 8, 0); + break; + case FC_SWILS_ZONEMBR_FCID_LUN: + proto_tree_add_string (zmbr_tree, hf_swils_zone_mbrid, tvb, + offset+4, 4, + fc_to_str (tvb_get_ptr (tvb, + offset+5, + 3))); + proto_tree_add_item (zmbr_tree, hf_swils_zone_mbrid_lun, tvb, + offset+8, 8, 0); + break; + default: + proto_tree_add_string (zmbr_tree, hf_swils_zone_mbrid, tvb, + offset+4, mbrlen, + "Unknown member type format"); + + } +} + +static void +dissect_swils_zone_obj (tvbuff_t *tvb, proto_tree *zobj_tree, int offset) +{ + proto_tree *zmbr_tree; + int mbrlen, numrec, i, objtype; + proto_item *subti; + + objtype = tvb_get_guint8 (tvb, offset); + + proto_tree_add_item (zobj_tree, hf_swils_zone_objtype, tvb, offset, + 1, 0); + proto_tree_add_item (zobj_tree, hf_swils_zone_protocol, tvb, + offset+1, 1, 0); + proto_tree_add_string (zobj_tree, hf_swils_zone_objname, tvb, + offset+4, ZONENAME_LEN (tvb, offset+4), + zonenm_to_str (tvb, offset+4)); + + numrec = tvb_get_ntohl (tvb, offset+4+ZONENAME_LEN (tvb, offset+4)); + proto_tree_add_text (zobj_tree, tvb, + offset+4+ZONENAME_LEN (tvb, offset+4), 4, + "Number of Zone Members: %d", numrec); + + offset += 8 + ZONENAME_LEN (tvb, offset+4); + for (i = 0; i < numrec; i++) { + if (objtype == FC_SWILS_ZONEOBJ_ZONESET) { + dissect_swils_zone_obj (tvb, zobj_tree, offset); + offset += get_zoneobj_len (tvb, offset); + } + else { + mbrlen = 4 + tvb_get_guint8 (tvb, offset+3); + subti = proto_tree_add_text (zobj_tree, tvb, offset, mbrlen, + "Zone Member %d", i); + zmbr_tree = proto_item_add_subtree (zobj_tree, + ett_fcswils_zonembr); + dissect_swils_zone_mbr (tvb, zmbr_tree, offset); + offset += mbrlen; + } + } +} + +static void +dissect_swils_mergereq (tvbuff_t *tvb, proto_tree *mr_tree, guint8 isreq) +{ + /* Set up structures needed to add the protocol subtree and manage it */ + int offset = 0; + proto_tree *zobjlist_tree, *zobj_tree; + int numrec, i, zonesetlen, objlistlen, objlen; + proto_item *subti; + + if (mr_tree) { + if (isreq) { + /* zonesetlen is the size of the zoneset including the zone name */ + zonesetlen = tvb_get_ntohs (tvb, offset+2); + proto_tree_add_text (mr_tree, tvb, offset+2, 2, + "Active ZoneSet Length: %d", zonesetlen); + + if (zonesetlen) { + proto_tree_add_string (mr_tree, hf_swils_zone_activezonenm, tvb, + offset+4, ZONENAME_LEN (tvb, offset+4), + zonenm_to_str (tvb, offset+4)); + + /* objlistlen gives the size of the active zoneset object list */ + objlistlen = zonesetlen - ZONENAME_LEN (tvb, offset+4); + /* Offset = start of the active zoneset zoning object list */ + offset = offset + (4 + ZONENAME_LEN (tvb, offset+4)); + numrec = tvb_get_ntohl (tvb, offset); + + subti = proto_tree_add_text (mr_tree, tvb, offset, objlistlen, + "Active Zone Set"); + zobjlist_tree = proto_item_add_subtree (subti, + ett_fcswils_zoneobjlist); + + proto_tree_add_text (zobjlist_tree, tvb, offset, 4, + "Number of zoning objects: %d", numrec); + + offset += 4; + for (i = 0; i < numrec; i++) { + objlen = get_zoneobj_len (tvb, offset); + subti = proto_tree_add_text (zobjlist_tree, tvb, offset+4, + objlen, "Zone Object %d", i); + zobj_tree = proto_item_add_subtree (subti, ett_fcswils_zoneobj); + dissect_swils_zone_obj (tvb, zobj_tree, offset); + offset += objlen; + } + } + else { + offset += 4; + } + + zonesetlen = tvb_get_ntohl (tvb, offset); + proto_tree_add_text (mr_tree, tvb, offset, 4, + "Full Zone Set Length: %d", zonesetlen); + + if (zonesetlen) { + objlistlen = zonesetlen; + /* Offset = start of the active zoneset zoning object list */ + offset += 4; + numrec = tvb_get_ntohl (tvb, offset); + + subti = proto_tree_add_text (mr_tree, tvb, offset, objlistlen, + "Full Zone Set"); + + zobjlist_tree = proto_item_add_subtree (subti, + ett_fcswils_zoneobjlist); + proto_tree_add_text (zobjlist_tree, tvb, offset, 4, + "Number of zoning objects: %d", numrec); + offset += 4; + for (i = 0; i < numrec; i++) { + objlen = get_zoneobj_len (tvb, offset); + subti = proto_tree_add_text (zobjlist_tree, tvb, offset, + objlen, "Zone Object %d", i); + zobj_tree = proto_item_add_subtree (subti, ett_fcswils_zoneobj); + dissect_swils_zone_obj (tvb, zobj_tree, offset); + offset += objlen; + } + } + } + else { + proto_tree_add_item (mr_tree, hf_swils_zone_status, tvb, + offset+5, 1, 0); + proto_tree_add_item (mr_tree, hf_swils_zone_reason, tvb, + offset+6, 1, 0); + proto_tree_add_text (mr_tree, tvb, offset+7, 1, + "Vendor Unique: 0x%x", + tvb_get_guint8 (tvb, offset+7)); + } + } +} + +static void +dissect_swils_aca (tvbuff_t *tvb, proto_tree *aca_tree, guint8 isreq) +{ + /* Set up structures needed to add the protocol subtree and manage it */ + int offset = 0; + int numrec, plen, i; + + if (aca_tree) { + if (isreq) { + plen = tvb_get_ntohs (tvb, offset+2); + proto_tree_add_text (aca_tree, tvb, offset+2, 2, + "Domain ID List Length: %d", plen); + numrec = plen/4; + offset = 4; + + for (i = 0; i < numrec; i++) { + proto_tree_add_uint_format (aca_tree, hf_swils_aca_domainid, + tvb, offset+3, 1, + tvb_get_guint8 (tvb, offset+3), + "Domain ID %d: %d", i, + tvb_get_guint8 (tvb, offset+3)); + offset += 4; + } + } + else { + proto_tree_add_item (aca_tree, hf_swils_zone_status, tvb, + offset+5, 1, 0); + proto_tree_add_item (aca_tree, hf_swils_zone_reason, tvb, + offset+6, 1, 0); + proto_tree_add_text (aca_tree, tvb, offset+7, 1, + "Vendor Unique: 0x%x", + tvb_get_guint8 (tvb, offset+7)); + } + } +} + +static void +dissect_swils_rca (tvbuff_t *tvb, proto_tree *rca_tree, guint8 isreq) +{ + /* Set up structures needed to add the protocol subtree and manage it */ + int offset = 0; + + if (rca_tree) { + if (!isreq) { + proto_tree_add_item (rca_tree, hf_swils_zone_status, tvb, + offset+5, 1, 0); + proto_tree_add_item (rca_tree, hf_swils_zone_reason, tvb, + offset+6, 1, 0); + proto_tree_add_text (rca_tree, tvb, offset+7, 1, + "Vendor Unique: 0x%x", + tvb_get_guint8 (tvb, offset+7)); + } + } +} + +static void +dissect_swils_sfc (tvbuff_t *tvb, proto_tree *sfc_tree, guint8 isreq) +{ + /* Set up structures needed to add the protocol subtree and manage it */ + int offset = 0; + proto_tree *zobjlist_tree, *zobj_tree; + int numrec, i, zonesetlen, objlistlen, objlen; + proto_item *subti; + + if (sfc_tree) { + if (isreq) { + proto_tree_add_item (sfc_tree, hf_swils_sfc_opcode, tvb, offset+1, 1, 0); + + zonesetlen = tvb_get_ntohs (tvb, offset+2); + proto_tree_add_text (sfc_tree, tvb, offset+2, 2, + "ZoneSet Length: %d", zonesetlen); + + if (zonesetlen) { + proto_tree_add_string (sfc_tree, hf_swils_sfc_zonenm, tvb, + offset+4, ZONENAME_LEN (tvb, offset+4), + zonenm_to_str (tvb, offset+4)); + + /* objlistlen gives the size of the active zoneset object list */ + objlistlen = zonesetlen - ZONENAME_LEN (tvb, offset+4); + /* Offset = start of the active zoneset zoning object list */ + offset = offset + (4 + ZONENAME_LEN (tvb, offset+4)); + numrec = tvb_get_ntohl (tvb, offset); + + subti = proto_tree_add_text (sfc_tree, tvb, offset, objlistlen, + "Zone Set"); + zobjlist_tree = proto_item_add_subtree (subti, + ett_fcswils_zoneobjlist); + + proto_tree_add_text (zobjlist_tree, tvb, offset, 4, + "Number of zoning objects: %d", numrec); + + offset += 4; + for (i = 0; i < numrec; i++) { + objlen = get_zoneobj_len (tvb, offset); + subti = proto_tree_add_text (zobjlist_tree, tvb, offset, + objlen, "Zone Object %d", i); + zobj_tree = proto_item_add_subtree (subti, ett_fcswils_zoneobj); + dissect_swils_zone_obj (tvb, zobj_tree, offset); + offset += objlen; + } + } + else { + offset += 4; + } + + zonesetlen = tvb_get_ntohl (tvb, offset); + proto_tree_add_text (sfc_tree, tvb, offset, 4, + "Full Zone Set Length: %d", zonesetlen); + + if (zonesetlen) { + objlistlen = zonesetlen; + /* Offset = start of the active zoneset zoning object list */ + offset += 4; + numrec = tvb_get_ntohl (tvb, offset); + + subti = proto_tree_add_text (sfc_tree, tvb, offset, objlistlen, + "Full Zone Set"); + + zobjlist_tree = proto_item_add_subtree (subti, + ett_fcswils_zoneobjlist); + proto_tree_add_text (zobjlist_tree, tvb, offset, 4, + "Number of zoning objects: %d", numrec); + offset += 4; + for (i = 0; i < numrec; i++) { + objlen = get_zoneobj_len (tvb, offset); + subti = proto_tree_add_text (zobjlist_tree, tvb, offset, + objlen, "Zone Object %d", i); + zobj_tree = proto_item_add_subtree (subti, ett_fcswils_zoneobj); + dissect_swils_zone_obj (tvb, zobj_tree, offset); + offset += objlen; + } + } + } + else { + proto_tree_add_item (sfc_tree, hf_swils_zone_status, tvb, + offset+5, 1, 0); + proto_tree_add_item (sfc_tree, hf_swils_zone_reason, tvb, + offset+6, 1, 0); + proto_tree_add_text (sfc_tree, tvb, offset+7, 1, + "Vendor Unique: 0x%x", + tvb_get_guint8 (tvb, offset+7)); + } + } +} + +static void +dissect_swils_ufc (tvbuff_t *tvb, proto_tree *ufc_tree, guint8 isreq) +{ + /* Set up structures needed to add the protocol subtree and manage it */ + int offset = 0; + + if (ufc_tree) { + if (!isreq) { + proto_tree_add_item (ufc_tree, hf_swils_zone_status, tvb, + offset+5, 1, 0); + proto_tree_add_item (ufc_tree, hf_swils_zone_reason, tvb, + offset+6, 1, 0); + proto_tree_add_text (ufc_tree, tvb, offset+7, 1, + "Vendor Unique: 0x%x", + tvb_get_guint8 (tvb, offset+7)); + } + } +} + +static void +dissect_swils_esc (tvbuff_t *tvb, proto_tree *esc_tree, guint8 isreq) +{ + /* Set up structures needed to add the protocol subtree and manage it */ + int offset = 0; + int i, numrec, plen; + proto_tree *pdesc_tree; + proto_item *subti; + + if (esc_tree) { + if (isreq) { + plen = tvb_get_ntohs (tvb, offset+2); + proto_tree_add_text (esc_tree, tvb, offset+2, 2, + "Payload Length: %d", plen); + proto_tree_add_item (esc_tree, hf_swils_esc_swvendorid, tvb, + offset+4, 8, 0); + numrec = (plen - 12)/12; + offset = 12; + + for (i = 0; i < numrec; i++) { + subti = proto_tree_add_text (esc_tree, tvb, offset, 12, + "Protocol Descriptor %d", i); + pdesc_tree = proto_item_add_subtree (subti, + ett_fcswils_esc_pdesc); + proto_tree_add_item (pdesc_tree, hf_swils_esc_pdesc_vendorid, tvb, + offset, 8, 0); + proto_tree_add_item (pdesc_tree, hf_swils_esc_protocolid, + tvb, offset+10, 2, 0); + offset += 12; + } + } + else { + proto_tree_add_item (esc_tree, hf_swils_esc_swvendorid, tvb, + offset+4, 8, 0); + subti = proto_tree_add_text (esc_tree, tvb, offset+12, 12, + "Accepted Protocol Descriptor"); + pdesc_tree = proto_item_add_subtree (subti, ett_fcswils_esc_pdesc); + + proto_tree_add_item (pdesc_tree, hf_swils_esc_pdesc_vendorid, tvb, + offset+12, 8, 0); + proto_tree_add_item (pdesc_tree, hf_swils_esc_protocolid, + tvb, offset+22, 2, 0); + } + } +} + +static void +dissect_swils_drlir (tvbuff_t *tvb _U_, proto_tree *drlir_tree _U_, + guint8 isreq _U_) +{ + /* Set up structures needed to add the protocol subtree and manage it */ + return; +} + +static void +dissect_swils_swrjt (tvbuff_t *tvb, proto_tree *swrjt_tree) +{ + /* Set up structures needed to add the protocol subtree and manage it */ + int offset = 0; + + if (swrjt_tree) { + proto_tree_add_item (swrjt_tree, hf_swils_rjt, tvb, offset+5, 1, 0); + proto_tree_add_item (swrjt_tree, hf_swils_rjtdet, tvb, offset+6, 1, 0); + proto_tree_add_item (swrjt_tree, hf_swils_rjtvendor, tvb, offset+7, + 1, 0); + } +} + +/* Code to actually dissect the packets */ +static void +dissect_fcswils (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + proto_item *ti = NULL; + guint8 opcode, + failed_opcode = 0; + int offset = 0; + conversation_t *conversation; + fcswils_conv_data_t *cdata; + fcswils_conv_key_t ckey, *req_key; + proto_tree *swils_tree = NULL; + guint8 isreq = FC_SWILS_REQ; + + /* Make entries in Protocol column and Info column on summary display */ + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + col_set_str(pinfo->cinfo, COL_PROTOCOL, "SW_ILS"); + + /* decoding of this is done by each individual opcode handler */ + opcode = tvb_get_guint8 (tvb, 0); + + if (tree) { + ti = proto_tree_add_protocol_format (tree, proto_fcswils, tvb, 0, + tvb_length (tvb), "SW_ILS"); + swils_tree = proto_item_add_subtree (ti, ett_fcswils); + } + + /* Register conversation if this is not a response */ + if ((opcode != FC_SWILS_SWACC) && (opcode != FC_SWILS_SWRJT)) { + conversation = find_conversation (&pinfo->src, &pinfo->dst, + pinfo->ptype, pinfo->oxid, + pinfo->rxid, NO_PORT2); + if (!conversation) { + conversation = conversation_new (&pinfo->src, &pinfo->dst, + pinfo->ptype, pinfo->oxid, + pinfo->rxid, NO_PORT2); + } + + ckey.conv_idx = conversation->index; + + cdata = (fcswils_conv_data_t *)g_hash_table_lookup (fcswils_req_hash, + &ckey); + if (cdata) { + /* Since we never free the memory used by an exchange, this maybe a + * case of another request using the same exchange as a previous + * req. + */ + cdata->opcode = opcode; + } + else { + req_key = g_mem_chunk_alloc (fcswils_req_keys); + req_key->conv_idx = conversation->index; + + cdata = g_mem_chunk_alloc (fcswils_req_vals); + cdata->opcode = opcode; + + g_hash_table_insert (fcswils_req_hash, req_key, cdata); + } + } + else { + /* Opcode is ACC or RJT */ + conversation = find_conversation (&pinfo->src, &pinfo->dst, + pinfo->ptype, pinfo->oxid, + pinfo->rxid, NO_PORT2); + isreq = FC_SWILS_RPLY; + if (!conversation) { + if (tree && (opcode == FC_SWILS_SWACC)) { + /* No record of what this accept is for. Can't decode */ + proto_tree_add_text (swils_tree, tvb, 0, tvb_length (tvb), + "No record of Exchg. Unable to decode SW_ACC"); + return; + } + } + else { + ckey.conv_idx = conversation->index; + + cdata = (fcswils_conv_data_t *)g_hash_table_lookup (fcswils_req_hash, &ckey); + + if (cdata != NULL) { + if (opcode == FC_SWILS_SWACC) + opcode = cdata->opcode; + else + failed_opcode = cdata->opcode; + } + + if (tree) { + if ((cdata == NULL) && (opcode != FC_SWILS_SWRJT)) { + /* No record of what this accept is for. Can't decode */ + proto_tree_add_text (swils_tree, tvb, 0, tvb_length (tvb), + "No record of SW_ILS Req. Unable to decode SW_ACC"); + return; + } + } + } + } + + if (check_col (pinfo->cinfo, COL_INFO)) { + if (isreq == FC_SWILS_REQ) { + col_add_str (pinfo->cinfo, COL_INFO, + val_to_str (opcode, fc_swils_opcode_key_val, "0x%x")); + } + else if (opcode == FC_SWILS_SWRJT) { + col_add_fstr (pinfo->cinfo, COL_INFO, "SW_RJT (%s)", + val_to_str (failed_opcode, fc_swils_opcode_key_val, "0x%x")); + } + else { + col_add_fstr (pinfo->cinfo, COL_INFO, "SW_ACC (%s)", + val_to_str (opcode, fc_swils_opcode_key_val, "0x%x")); + } + } + + if (tree) { + proto_tree_add_item (swils_tree, hf_swils_opcode, tvb, offset, 1, 0); + } + + switch (opcode) { + case FC_SWILS_SWRJT: + dissect_swils_swrjt (tvb, swils_tree); + break; + case FC_SWILS_ELP: + dissect_swils_elp (tvb, swils_tree, isreq); + break; + case FC_SWILS_EFP: + dissect_swils_efp (tvb, swils_tree, isreq); + break; + case FC_SWILS_DIA: + dissect_swils_dia (tvb, swils_tree, isreq); + break; + case FC_SWILS_RDI: + dissect_swils_rdi (tvb, swils_tree, isreq); + break; + case FC_SWILS_HLO: + dissect_swils_hello (tvb, swils_tree, isreq); + break; + case FC_SWILS_LSU: + dissect_swils_lsupdate (tvb, swils_tree, isreq); + break; + case FC_SWILS_LSA: + dissect_swils_lsack (tvb, swils_tree, isreq); + break; + case FC_SWILS_BF: + case FC_SWILS_RCF: + /* Nothing to be displayed for these two commands */ + break; + case FC_SWILS_RSCN: + dissect_swils_rscn (tvb, swils_tree, isreq); + break; + case FC_SWILS_DRLIR: + dissect_swils_drlir (tvb, swils_tree, isreq); + break; + case FC_SWILS_MR: + dissect_swils_mergereq (tvb, swils_tree, isreq); + break; + case FC_SWILS_ACA: + dissect_swils_aca (tvb, swils_tree, isreq); + break; + case FC_SWILS_RCA: + dissect_swils_rca (tvb, swils_tree, isreq); + break; + case FC_SWILS_SFC: + dissect_swils_sfc (tvb, swils_tree, isreq); + break; + case FC_SWILS_UFC: + dissect_swils_ufc (tvb, swils_tree, isreq); + break; + case FC_SWILS_ESC: + dissect_swils_esc (tvb, swils_tree, isreq); + break; + default: + call_dissector (data_handle, tvb, pinfo, tree); + } + +} + +/* Register the protocol with Ethereal */ + +/* this format is require because a script is used to build the C function + that calls all the protocol registration. +*/ + +void +proto_register_fcswils (void) +{ +/* Setup list of header fields See Section 1.6.1 for details*/ + static hf_register_info hf[] = { + { &hf_swils_opcode, + {"Cmd Code", "swils.opcode", FT_UINT8, BASE_HEX, + VALS (fc_swils_opcode_key_val), 0x0, "", HFILL}}, + { &hf_swils_elp_rev, + {"Revision", "swils.elp.rev", FT_UINT8, BASE_DEC, NULL, + 0x0, "", HFILL}}, + { &hf_swils_elp_flags, + {"Flag", "swils.elp.flag", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL}}, + { &hf_swils_elp_r_a_tov, + {"R_A_TOV", "swils.elp.ratov", FT_UINT32, BASE_DEC, NULL, + 0x0, "", HFILL}}, + { &hf_swils_elp_e_d_tov, + {"E_D_TOV", "swils.elp.edtov", FT_UINT32, BASE_DEC, NULL, 0x0, "", + HFILL}}, + { &hf_swils_elp_req_epn, + {"Req Eport Name", "swils.elp.reqepn", FT_STRING, BASE_HEX, NULL, 0x0, + "", HFILL}}, + { &hf_swils_elp_req_esn, + {"Req Switch Name", "swils.elp.reqesn", FT_STRING, BASE_HEX, NULL, 0x0, + "", HFILL}}, + { &hf_swils_elp_clsf_svcp, + {"Class F Svc Param", "swils.elp.clsfp", FT_BYTES, BASE_NONE, NULL, 0x0, + "", HFILL}}, + { &hf_swils_elp_clsf_rcvsz, + {"Max Class F Frame Size", "swils.elp.clsfrsz", FT_UINT16, BASE_DEC, + NULL, 0x0, "", HFILL}}, + { &hf_swils_elp_clsf_conseq, + {"Class F Max Concurrent Seq", "swils.elp.clsfcs", FT_UINT16, BASE_DEC, + NULL, 0x0, "", HFILL}}, + { &hf_swils_elp_clsf_e2e, + {"Class F E2E Credit", "swils.elp.cfe2e", FT_UINT16, BASE_DEC, NULL, + 0x0, "", HFILL}}, + { &hf_swils_elp_clsf_openseq, + {"Class F Max Open Seq", "swils.elp.oseq", FT_UINT16, BASE_DEC, NULL, + 0x0, "", HFILL}}, + { &hf_swils_elp_cls1_svcp, + {"Class 1 Svc Param", "swils.elp.cls1p", FT_BYTES, BASE_NONE, NULL, 0x0, + "", HFILL}}, + { &hf_swils_elp_cls1_rcvsz, + {"Class 1 Frame Size", "swils.elp.cls1rsz", FT_UINT16, BASE_DEC, NULL, + 0x0, "", HFILL}}, + { &hf_swils_elp_cls2_svcp, + {"Class 2 Svc Param", "swils.elp.cls2p", FT_BYTES, BASE_HEX, NULL, 0x0, + "", HFILL}}, + { &hf_swils_elp_cls2_rcvsz, + {"Class 2 Frame Size", "swils.elp.cls1rsz", FT_UINT16, BASE_DEC, NULL, + 0x0, "", HFILL}}, + { &hf_swils_elp_cls3_svcp, + {"Class 3 Svc Param", "swils.elp.cls3p", FT_BYTES, BASE_HEX, NULL, 0x0, + "", HFILL}}, + { &hf_swils_elp_cls3_rcvsz, + {"Class 3 Frame Size", "swils.elp.cls1rsz", FT_UINT16, BASE_DEC, NULL, + 0x0, "", HFILL}}, + { &hf_swils_elp_isl_fc_mode, + {"ISL Flow Ctrl Mode", "swils.elp.fcmode", FT_STRING, BASE_HEX, NULL, + 0x0, "", HFILL}}, + { &hf_swils_elp_fcplen, + {"Flow Ctrl Param Len", "swils.elp.fcplen", FT_UINT16, BASE_DEC, NULL, + 0x0, "", HFILL}}, + { &hf_swils_elp_b2bcredit, + {"B2B Credit", "swils.elp.b2b", FT_UINT32, BASE_DEC, NULL, 0x0, "", + HFILL}}, + { &hf_swils_elp_compat1, + {"Compatability Param 1", "swils.elp.compat1", FT_UINT32, BASE_DEC, NULL, + 0x0, "", HFILL}}, + { &hf_swils_elp_compat2, + {"Compatability Param 2", "swils.elp.compat2", FT_UINT32, BASE_DEC, NULL, + 0x0, "", HFILL}}, + { &hf_swils_elp_compat3, + {"Compatability Param 3", "swils.elp.compat3", FT_UINT32, BASE_DEC, NULL, + 0x0, "", HFILL}}, + { &hf_swils_elp_compat4, + {"Compatability Param 4", "swils.elp.compat4", FT_UINT32, BASE_DEC, NULL, + 0x0, "", HFILL}}, + { &hf_swils_efp_rec_type, + {"Record Type", "swils.efp.rectype", FT_UINT8, BASE_HEX, + VALS (fcswils_rectype_val), 0x0, "", HFILL}}, + { &hf_swils_efp_dom_id, + {"Domain ID", "swils.efp.domid", FT_UINT8, BASE_HEX, NULL, 0x0, + "", HFILL}}, + { &hf_swils_efp_switch_name, + {"Switch Name", "swils.efp.sname", FT_STRING, BASE_HEX, NULL, 0x0, + "", HFILL}}, + { &hf_swils_efp_mcast_grpno, + {"Mcast Grp#", "swils.efp.mcastno", FT_UINT8, BASE_HEX, NULL, 0x0, + "", HFILL}}, + { &hf_swils_efp_alias_token, + {"Alias Token", "swils.efp.aliastok", FT_BYTES, BASE_HEX, NULL, 0x0, + "", HFILL}}, + { &hf_swils_efp_payload_len, + {"Payload Len", "swils.efp.payloadlen", FT_UINT16, BASE_DEC, NULL, 0x0, + "", HFILL}}, + { &hf_swils_efp_pswitch_pri, + {"Principal Switch Priority", "swils.efp.psprio", FT_UINT8, BASE_DEC, + NULL, 0x0, "", HFILL}}, + { &hf_swils_efp_pswitch_name, + {"Principal Switch Name", "swils.efp.psname", FT_STRING, BASE_HEX, NULL, + 0x0, "", HFILL}}, + { &hf_swils_dia_switch_name, + {"Switch Name", "swils.dia.sname", FT_STRING, BASE_HEX, NULL, 0x0, + "", HFILL}}, + { &hf_swils_rdi_payload_len, + {"Payload Len", "swils.rdi.len", FT_UINT16, BASE_DEC, NULL, 0x0, "", + HFILL}}, + { &hf_swils_rdi_req_sname, + {"Req Switch Name", "swils.rdi.reqsn", FT_STRING, BASE_HEX, NULL, 0x0, + "", HFILL}}, + { &hf_swils_fspfh_cmd, + {"Command: ", "swils.fspf.cmd", FT_UINT8, BASE_HEX, NULL, 0x0, + "", HFILL}}, + { &hf_swils_fspfh_rev, + {"Version", "swils.fspf.ver", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL}}, + { &hf_swils_fspfh_ar_num, + {"AR Number", "swils.fspf.arnum", FT_UINT8, BASE_HEX, NULL, 0x0, "", + HFILL}}, + { &hf_swils_fspfh_auth_type, + {"Authentication Type", "swils.fspf.authtype", FT_UINT8, BASE_HEX, NULL, + 0x0, "", HFILL}}, + { &hf_swils_fspfh_dom_id, + {"Originating Domain ID", "swils.fspf.origdomid", FT_UINT8, BASE_DEC, + NULL, 0x0, "", HFILL}}, + { &hf_swils_fspfh_auth, + {"Authentication", "swils.fspf.auth", FT_BYTES, BASE_HEX, NULL, 0x0, + "", HFILL}}, + { &hf_swils_hlo_options, + {"Options", "swils.hlo.options", FT_BYTES, BASE_HEX, NULL, 0x0, + "", HFILL}}, + { &hf_swils_hlo_hloint, + {"Hello Interval (secs)", "swils.hlo.hloint", FT_UINT32, BASE_DEC, + NULL, 0x0, "", HFILL}}, + { &hf_swils_hlo_deadint, + {"Dead Interval (secs)", "swils.hlo.deadint", FT_UINT32, BASE_DEC, + NULL, 0x0, "", HFILL}}, + { &hf_swils_hlo_rcv_domid, + {"Recipient Domain ID", "swils.hlo.rcvdomid", FT_UINT8, BASE_DEC, + NULL, 0x0, "", HFILL}}, + { &hf_swils_hlo_orig_pidx, + {"Originating Port Idx", "swils.hlo.origpidx", FT_UINT24, BASE_HEX, + NULL, 0x0, "", HFILL}}, + { &hf_swils_lsrh_lsr_type, + {"LSR Type", "swils.lsr.type", FT_UINT8, BASE_HEX, + VALS (fc_swils_fspf_linkrec_val), 0x0, "", HFILL}}, + { &hf_swils_lsrh_lsid, + {"Link State Id", "swils.ls.id", FT_UINT8, BASE_DEC, NULL, 0x0, + "", HFILL}}, + { &hf_swils_lsrh_adv_domid, + {"Advertising Domain Id", "swils.lsr.advdomid", FT_UINT8, BASE_DEC, + NULL, 0x0, "", HFILL}}, + { &hf_swils_lsrh_ls_incid, + {"LS Incarnation Number", "swils.lsr.incid", FT_UINT32, BASE_DEC, + NULL, 0x0, "", HFILL}}, + { &hf_swils_ldrec_linkid, + {"Link ID", "swils.ldr.linkid", FT_STRING, BASE_HEX, NULL, 0x0, + "", HFILL}}, + { &hf_swils_ldrec_out_pidx, + {"Output Port Idx", "swils.ldr.out_portidx", FT_UINT24, BASE_HEX, NULL, + 0x0, "", HFILL}}, + { &hf_swils_ldrec_nbr_pidx, + {"Neighbor Port Idx", "swils.ldr.nbr_portidx", FT_UINT24, BASE_HEX, + NULL, 0x0, "", HFILL}}, + { &hf_swils_ldrec_link_type, + {"Link Type", "swils.ldr.linktype", FT_UINT8, BASE_HEX, + VALS (fc_swils_link_type_val), 0x0, "", HFILL}}, + { &hf_swils_ldrec_link_cost, + {"Link Cost", "swils.ldr.linkcost", FT_UINT16, BASE_DEC, NULL, 0x0, + "", HFILL}}, + { &hf_swils_rscn_evtype, + {"Event Type", "swils.rscn.evtype", FT_UINT8, BASE_DEC, + VALS (fc_swils_rscn_portstate_val), 0xF0, "", HFILL}}, + { &hf_swils_rscn_addrfmt, + {"Address Format", "swils.rscn.addrfmt", FT_UINT8, BASE_DEC, + VALS (fc_swils_rscn_addrfmt_val), 0x0F, "", HFILL}}, + { &hf_swils_rscn_affectedport, + {"Affected Port ID", "swils.rscn.affectedport", FT_STRING, BASE_HEX, + NULL, 0x0, "", HFILL}}, + { &hf_swils_rscn_detectfn, + {"Detection Function", "swils.rscn.detectfn", FT_UINT32, BASE_HEX, + VALS (fc_swils_rscn_detectfn_val), 0x0, "", HFILL}}, + { &hf_swils_rscn_portstate, + {"Port State", "swils.rscn.portstate", FT_UINT8, BASE_HEX, NULL, 0x0, + "", HFILL}}, + { &hf_swils_rscn_portid, + {"Port Id", "swils.rscn.portid", FT_STRING, BASE_HEX, NULL, 0x0, "", + HFILL}}, + { &hf_swils_rscn_pwwn, + {"Port WWN", "swils.rscn.pwwn", FT_STRING, BASE_HEX, NULL, 0x0, "", + HFILL}}, + { &hf_swils_rscn_nwwn, + {"Node WWN", "swils.rscn.nwwn", FT_STRING, BASE_HEX, NULL, 0x0, "", + HFILL}}, + { &hf_swils_esc_swvendorid, + {"Switch Vendor ID", "swils.esc.swvendor", FT_STRING, BASE_HEX, NULL, + 0x0, "", HFILL}}, + { &hf_swils_esc_pdesc_vendorid, + {"Vendor ID", "swils.esc.vendorid", FT_STRING, BASE_HEX, NULL, 0x0, + "", HFILL}}, + { &hf_swils_esc_protocolid, + {"Protocol ID", "swils.esc.protocol", FT_UINT16, BASE_HEX, + VALS (fc_swils_esc_protocol_val), 0x0, "", HFILL}}, + { &hf_swils_zone_activezonenm, + {"Active Zoneset Name", "swils.mr.activezonesetname", FT_STRING, + BASE_HEX, NULL, 0x0, "", HFILL}}, + { &hf_swils_zone_objname, + {"Zone Object Name", "swils.zone.zoneobjname", FT_STRING, BASE_HEX, + NULL, 0x0, "", HFILL}}, + { &hf_swils_zone_objtype, + {"Zone Object Type", "swils.zone.zoneobjtype", FT_UINT8, BASE_HEX, + VALS (fc_swils_zoneobj_type_val), 0x0, "", HFILL}}, + { &hf_swils_zone_mbrtype, + {"Zone Member Type", "swils.zone.mbrtype", FT_UINT8, BASE_HEX, + VALS (fc_swils_zonembr_type_val), 0x0, "", HFILL}}, + { &hf_swils_zone_protocol, + {"Zone Protocol", "swils.zone.protocol", FT_UINT8, BASE_HEX, NULL, + 0x0, "", HFILL}}, + { &hf_swils_zone_mbrid, + {"Member Identifier", "swils.zone.mbrid", FT_STRING, BASE_HEX, NULL, + 0x0, "", HFILL}}, + { &hf_swils_zone_status, + {"Zone Command Status", "swils.zone.status", FT_UINT8, BASE_HEX, + VALS (fc_swils_mr_rsp_val), 0x0, "Applies to MR, ACA, RCA, SFC, UFC", + HFILL}}, + { &hf_swils_zone_reason, + {"Zone Command Reason Code", "swils.zone.reason", FT_UINT8, BASE_HEX, + VALS (fc_swils_mr_reason_val), 0x0, "Applies to MR, ACA, RCA, SFC, UFC", + HFILL}}, + { &hf_swils_aca_domainid, + {"Known Domain ID", "swils.aca.domainid", FT_UINT8, BASE_HEX, NULL, + 0x0, "", HFILL}}, + { &hf_swils_sfc_opcode, + {"Operation Request", "swils.sfc.opcode", FT_UINT8, BASE_HEX, + VALS (fc_swils_sfc_op_val), 0x0, "", HFILL}}, + { &hf_swils_sfc_zonenm, + {"Zone Set Name", "swils.sfc.zonename", FT_STRING, BASE_HEX, NULL, + 0x0, "", HFILL}}, + { &hf_swils_rjt, + {"Reason Code", "swils.rjt.reason", FT_UINT8, BASE_HEX, + VALS (fc_swils_rjt_val), 0x0, "", HFILL}}, + { &hf_swils_rjtdet, + {"Reason Code Explanantion", "swils.rjt.reasonexpl", FT_UINT8, + BASE_HEX, VALS (fc_swils_deterr_val), 0x0, "", HFILL}}, + { &hf_swils_rjtvendor, + {"Vendor Unique Error Code", "swils.rjt.vendor", FT_UINT8, BASE_HEX, + NULL, 0x0, "", HFILL}}, + { &hf_swils_zone_mbrid_lun, + {"LUN", "swils.zone.lun", FT_BYTES, BASE_HEX, NULL, 0x0, "", + HFILL}}, + }; + + /* Setup protocol subtree array */ + static gint *ett[] = { + &ett_fcswils, + &ett_fcswils_swacc, + &ett_fcswils_swrjt, + &ett_fcswils_elp, + &ett_fcswils_efp, + &ett_fcswils_efplist, + &ett_fcswils_dia, + &ett_fcswils_rdi, + &ett_fcswils_fspfhdr, + &ett_fcswils_hlo, + &ett_fcswils_lsrec, + &ett_fcswils_lsrechdr, + &ett_fcswils_ldrec, + &ett_fcswils_lsu, + &ett_fcswils_lsa, + &ett_fcswils_bf, + &ett_fcswils_rcf, + &ett_fcswils_rscn, + &ett_fcswils_rscn_dev, + &ett_fcswils_drlir, + &ett_fcswils_mr, + &ett_fcswils_zoneobjlist, + &ett_fcswils_zoneobj, + &ett_fcswils_zonembr, + &ett_fcswils_aca, + &ett_fcswils_rca, + &ett_fcswils_sfc, + &ett_fcswils_ufc, + &ett_fcswils_esc, + &ett_fcswils_esc_pdesc, + }; + + /* Register the protocol name and description */ + proto_fcswils = proto_register_protocol("Fibre Channel SW_ILS", "FC-SWILS", "swils"); + + /* Required function calls to register the header fields and subtrees used */ + proto_register_field_array(proto_fcswils, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + register_init_routine(&fcswils_init_protocol); +} + +/* If this dissector uses sub-dissector registration add a registration routine. + This format is required because a script is used to find these routines and + create the code that calls these routines. +*/ +void +proto_reg_handoff_fcswils (void) +{ + dissector_handle_t swils_handle; + + swils_handle = create_dissector_handle (dissect_fcswils, proto_fcswils); + dissector_add("fc.ftype", FC_FTYPE_SWILS, swils_handle); + + data_handle = find_dissector ("data"); +} + + |