/* packet-fcswils.c
 * Routines for FC Inter-switch link services
 * Copyright 2001, Dinesh G Dutt <ddutt@cisco.com>
 *
 * Wireshark - Network traffic analyzer
 * By Gerald Combs <gerald@wireshark.org>
 * Copyright 1998 Gerald Combs
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

#include "config.h"

#include <epan/packet.h>
#include <epan/expert.h>
#include <epan/to_str.h>
#include "packet-fc.h"
#include "packet-fcswils.h"
#include "packet-fcct.h"

void proto_register_fcswils(void);
void proto_reg_handoff_fcswils(void);

/*
 * See the FC-SW specifications.
 */

#define FC_SWILS_RPLY               0x0
#define FC_SWILS_REQ                0x1
#define FC_SWILS_RSCN_DEVENTRY_SIZE 20

/* 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_record_len        = -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_mbrid_fcwwn      = -1;
static int hf_swils_zone_mbrid_fc         = -1;
static int hf_swils_zone_mbrid_uint       = -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;
static int hf_swils_ess_rev               = -1;
static int hf_swils_ess_len               = -1;
static int hf_swils_ess_numobj            = -1;
static int hf_swils_interconnect_list_len = -1;
static int hf_swils_ess_vendorname        = -1;
static int hf_swils_ess_modelname         = -1;
static int hf_swils_ess_relcode           = -1;
static int hf_swils_ess_vendorspecific    = -1;
static int hf_swils_ess_cap_type          = -1;
static int hf_swils_ess_cap_subtype       = -1;
static int hf_swils_ess_cap_numentries    = -1;
static int hf_swils_ess_cap_svc           = -1;
static int hf_swils_ess_dns_obj0h         = -1;
static int hf_swils_ess_dns_obj1h         = -1;
static int hf_swils_ess_dns_obj2h         = -1;
static int hf_swils_ess_dns_obj3h         = -1;
static int hf_swils_ess_dns_zlacc         = -1;
static int hf_swils_ess_dns_vendor        = -1;
static int hf_swils_ess_fctlr_rscn        = -1;
static int hf_swils_ess_fctlr_vendor      = -1;
static int hf_swils_ess_fcs_basic         = -1;
static int hf_swils_ess_fcs_platform      = -1;
static int hf_swils_ess_fcs_topology      = -1;
static int hf_swils_ess_fcs_enhanced      = -1;
static int hf_swils_ess_fzs_enh_supp      = -1;
static int hf_swils_ess_fzs_enh_ena       = -1;
static int hf_swils_ess_fzs_mr            = -1;
static int hf_swils_ess_fzs_zsdb_supp     = -1;
static int hf_swils_ess_fzs_zsdb_ena      = -1;
static int hf_swils_ess_fzs_adc_supp      = -1;
static int hf_swils_ess_fzs_hardzone      = -1;
static int hf_swils_mrra_rev              = -1;
static int hf_swils_mrra_size             = -1;
static int hf_swils_mrra_vendorid         = -1;
static int hf_swils_mrra_reply            = -1;
static int hf_swils_mrra_reply_size       = -1;
static int hf_swils_mrra_waittime         = -1;
static int hf_swils_ess_cap_t10           = -1;
static int hf_swils_ess_cap_vendorobj     = -1;
static int hf_swils_ess_fzs_defzone       = -1;
static int hf_swils_ess_cap_len           = -1;
static int hf_swils_mrra_vendorinfo       = -1;

/* Generated from convert_proto_tree_add_text.pl */
static int hf_swils_lsrh_lsr_age = -1;
static int hf_swils_zone_full_zone_set_length = -1;
static int hf_swils_zone_num_zoning_objects = -1;
static int hf_swils_lsrec_number_of_links = -1;
static int hf_swils_sfc_zoneset_length = -1;
static int hf_swils_zone_vendor_unique = -1;
static int hf_swils_zone_num_members = -1;
static int hf_swils_zone_active_zoneset_length = -1;
static int hf_swils_lsack_num_of_lsr_headers = -1;
static int hf_swils_lsrh_lsr_length = -1;
static int hf_swils_esc_payload_length = -1;
static int hf_swils_lsupdate_num_of_lsrs = -1;
static int hf_swils_zone_mbr_identifier_length = -1;
static int hf_swils_zone_mbrflags = -1;
static int hf_swils_lsrh_options = -1;
static int hf_swils_domain_id_list_length = -1;
static int hf_swils_lsack_flags = -1;
static int hf_swils_rscn_num_entries = -1;
static int hf_swils_requested_domain_id = -1;
static int hf_swils_lsrh_checksum = -1;
static int hf_swils_granted_domain_id = -1;
static int hf_swils_lsupdate_flags = -1;


static expert_field ei_swils_efp_record_len = EI_INIT;
static expert_field ei_swils_no_exchange = EI_INIT;
static expert_field ei_swils_zone_mbrid = EI_INIT;

/* 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;
static gint ett_fcswils_ieinfo      = -1;
static gint ett_fcswils_capinfo     = -1;

static const value_string fc_swils_opcode_key_val[] = {
    {FC_SWILS_SWRJT   , "SW_RJT"},
    {FC_SWILS_SWACC   , "SW_ACC"},
    {FC_SWILS_ELP     , "ELP"},
    {FC_SWILS_EFP     , "EFP"},
    {FC_SWILS_DIA     , "DIA"},
    {FC_SWILS_RDI     , "RDI"},
    {FC_SWILS_HLO     , "HLO"},
    {FC_SWILS_LSU     , "LSU"},
    {FC_SWILS_LSA     , "LSA"},
    {FC_SWILS_BF      , "BF"},
    {FC_SWILS_RCF     , "RCF"},
    {FC_SWILS_RSCN    , "SW_RSCN"},
    {FC_SWILS_DRLIR   , "DRLIR"},
    {FC_SWILS_DSCN    , "DSCN"},
    {FC_SWILS_LOOPD   , "LOOPD"},
    {FC_SWILS_MR      , "MR"},
    {FC_SWILS_ACA     , "ACA"},
    {FC_SWILS_RCA     , "RCA"},
    {FC_SWILS_SFC     , "SFC"},
    {FC_SWILS_UFC     , "UFC"},
    {FC_SWILS_ESC     , "ESC"},
    {FC_SWILS_ESS     , "ESS"},
    {FC_SWILS_MRRA    , "MRRA"},
    {FC_SWILS_AUTH_ILS, "AUTH_ILS"},
    {0, NULL},
};

static const value_string fc_swils_rjt_val [] = {
    {FC_SWILS_RJT_INVCODE   , "Invalid Cmd Code"},
    {FC_SWILS_RJT_INVVER    , "Invalid Revision"},
    {FC_SWILS_RJT_LOGERR    , "Logical Error"},
    {FC_SWILS_RJT_INVSIZE   , "Invalid Size"},
    {FC_SWILS_RJT_LOGBSY    , "Logical Busy"},
    {FC_SWILS_RJT_PROTERR   , "Protocol Error"},
    {FC_SWILS_RJT_GENFAIL   , "Unable to Perform"},
    {FC_SWILS_RJT_CMDNOTSUPP, "Unsupported Cmd"},
    {FC_SWILS_RJT_VENDUNIQ  , "Vendor Unique Err"},
    {0, NULL},
};

static const value_string fc_swils_deterr_val [] = {
    {FC_SWILS_RJT_NODET     , "No Additional Details"},
    {FC_SWILS_RJT_CLSF_ERR  , "Class F Svc Param Err"},
    {FC_SWILS_RJT_CLSN_ERR  , "Class N Svc Param Err"},
    {FC_SWILS_RJT_INVFC_CODE, "Unknown Flow Ctrl Code"},
    {FC_SWILS_RJT_INVFC_PARM, "Invalid Flow Ctrl Parm"},
    {FC_SWILS_RJT_INV_PNAME , "Invalid Port Name"},
    {FC_SWILS_RJT_INV_SNAME , "Invalid Switch Name"},
    {FC_SWILS_RJT_TOV_MSMTCH, "R_A_/E_D_TOV Mismatch"},
    {FC_SWILS_RJT_INV_DIDLST, "Invalid Domain ID List"},
    {FC_SWILS_RJT_CMD_INPROG, "Cmd Already in Progress"},
    {FC_SWILS_RJT_OORSRC    , "Insufficient Resources"},
    {FC_SWILS_RJT_NO_DID    , "Domain ID Unavailable"},
    {FC_SWILS_RJT_INV_DID   , "Invalid Domain ID"},
    {FC_SWILS_RJT_NO_REQ    , "Request Not Supported"},
    {FC_SWILS_RJT_NOLNK_PARM, "Link Parm Not Estd."},
    {FC_SWILS_RJT_NO_REQDID , "Group of Domain IDs Unavail"},
    {FC_SWILS_RJT_EP_ISOL   , "E_Port Isolated"},
    {0, NULL}
};

static const value_string fcswils_elp_fc_val[] = {
    {FC_SWILS_ELP_FC_VENDOR, "Vendor Unique"},
    {FC_SWILS_ELP_FC_RRDY  , "R_RDY Flow Ctrl"},
    {0, NULL},
};

static const value_string fcswils_rectype_val[] = {
    {FC_SWILS_LRECTYPE_DOMAIN, "Domain ID Record"},
    {FC_SWILS_LRECTYPE_MCAST , "Multicast ID Record"},
    {0, NULL},
};

static const value_string fc_swils_link_type_val[] = {
    {0x01, "P2P Link"},
    {0xF0, "Vendor Specific"},
    {0xF1, "Vendor Specific"},
    {0xF2, "Vendor Specific"},
    {0xF3, "Vendor Specific"},
    {0xF4, "Vendor Specific"},
    {0xF5, "Vendor Specific"},
    {0xF6, "Vendor Specific"},
    {0xF7, "Vendor Specific"},
    {0xF8, "Vendor Specific"},
    {0xF9, "Vendor Specific"},
    {0xFA, "Vendor Specific"},
    {0xFB, "Vendor Specific"},
    {0xFC, "Vendor Specific"},
    {0xFD, "Vendor Specific"},
    {0xFE, "Vendor Specific"},
    {0xFF, "Vendor Specific"},
    {0, NULL},
};

static const value_string fc_swils_fspf_linkrec_val[] = {
    {FC_SWILS_LSR_SLR, "Switch Link Record"},
    {FC_SWILS_LSR_ARS, "AR Summary Record"},
    {0, NULL},
};

static const value_string fc_swils_fspf_lsrflags_val[] = {
    {0x0, "LSR is for a Topology Update"},
    {0x1, "LSR is for Initial DB Sync | Not the last seq in DB sync"},
    {0x2, "Last Seq in DB Sync. LSU has no LSRs"},
    {0x3, "LSR is for Initial DB Sync | Last Seq in DB Sync"},
    {0, NULL},
};

static const value_string fc_swils_rscn_portstate_val[] = {
    {0, "No Additional Info"},
    {1, "Port is online"},
    {2, "Port is offline"},
    {0, NULL},
};

static const value_string fc_swils_rscn_addrfmt_val[] = {
    {0, "Port Addr Format"},
    {1, "Area Addr Format"},
    {2, "Domain Addr Format"},
    {3, "Fabric Addr Format"},
    {0, NULL},
};

static const value_string fc_swils_rscn_detectfn_val[] = {
    {1, "Fabric Detected"},
    {2, "N_Port Detected"},
    {0, NULL},
};

static const value_string fc_swils_esc_protocol_val[] = {
    {0, "Reserved"},
    {1, "FSPF-Backbone Protocol"},
    {2, "FSPF Protocol"},
    {0, NULL},
};

static const value_string fc_swils_zoneobj_type_val[] = {
    {0, "Reserved"},
    {FC_SWILS_ZONEOBJ_ZONESET  , "Zone Set"},
    {FC_SWILS_ZONEOBJ_ZONE     , "Zone"},
    {FC_SWILS_ZONEOBJ_ZONEALIAS, "Zone Alias"},
    {0, NULL},
};

const value_string fc_swils_zonembr_type_val[] = {
    {0                        , "Reserved"},
    {FC_SWILS_ZONEMBR_WWN     , "WWN"},
    {FC_SWILS_ZONEMBR_DP      , "Domain/Physical Port (0x00ddpppp)"},
    {FC_SWILS_ZONEMBR_FCID    , "FC Address"},
    {FC_SWILS_ZONEMBR_ALIAS   , "Zone Alias"},
    {FC_SWILS_ZONEMBR_WWN_LUN , "WWN+LUN"},
    {FC_SWILS_ZONEMBR_DP_LUN  , "Domain/Physical Port+LUN"},
    {FC_SWILS_ZONEMBR_FCID_LUN, "FCID+LUN"},
    {0, NULL},
};

static const value_string fc_swils_mr_rsp_val[] = {
    {0, "Successful"},
    {1, "Fabric Busy"},
    {2, "Failed"},
    {0, NULL},
};

static const value_string fc_swils_mr_reason_val[] = {
    {0x0, "No Reason"},
    {0x1, "Invalid Data Length"},
    {0x2, "Unsupported Command"},
    {0x3, "Reserved"},
    {0x4, "Not Authorized"},
    {0x5, "Invalid Request"},
    {0x6, "Fabric Changing"},
    {0x7, "Update Not Staged"},
    {0x8, "Invalid Zone Set Format"},
    {0x9, "Invalid Data"},
    {0xA, "Cannot Merge"},
    {0, NULL},
};

static const value_string fc_swils_sfc_op_val[] = {
    {0, "Reserved"},
    {1, "Reserved"},
    {2, "Reserved"},
    {3, "Activate Zone Set"},
    {4, "Deactivate Zone Set"},
    {0, NULL},
};

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;

static wmem_map_t *fcswils_req_hash = NULL;

/* list of commands for each commandset */
typedef void (*fcswils_dissector_t)(tvbuff_t *tvb, packet_info* pinfo, proto_tree *tree, guint8 isreq);

typedef struct _fcswils_func_table_t {
    fcswils_dissector_t func;
} fcswils_func_table_t;

static dissector_handle_t fcsp_handle;

static gint get_zoneobj_len(tvbuff_t *tvb, gint offset);

/*
 * Hash Functions
 */
static gint
fcswils_equal(gconstpointer v, gconstpointer w)
{
    const fcswils_conv_key_t *v1 = (const fcswils_conv_key_t *)v;
    const fcswils_conv_key_t *v2 = (const fcswils_conv_key_t *)w;

    return (v1->conv_idx == v2->conv_idx);
}

static guint
fcswils_hash(gconstpointer v)
{
    const fcswils_conv_key_t *key = (const fcswils_conv_key_t *)v;
    guint val;

    val = key->conv_idx;

    return val;
}

static guint8 *
zonenm_to_str(tvbuff_t *tvb, gint offset)
{
    int len = tvb_get_guint8(tvb, offset);
    return tvb_get_string_enc(wmem_packet_scope(), tvb, offset+4, len, ENC_ASCII);
}

/* 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 {
            len += 4 + tvb_get_guint8(tvb, offset+3+len);
        }
    }

    return len;
}

#define MAX_INTERCONNECT_ELEMENT_INFO_LEN  252
static int
dissect_swils_interconnect_element_info(tvbuff_t *tvb, proto_tree *tree, int offset)
{

    int len, max_len = MAX_INTERCONNECT_ELEMENT_INFO_LEN;

    if (tree) {
        proto_tree_add_item(tree, hf_swils_interconnect_list_len, tvb, offset+3, 1, ENC_BIG_ENDIAN);
        len = tvb_strsize(tvb, offset+4);
        proto_tree_add_item(tree, hf_swils_ess_vendorname, tvb, offset+4, len, ENC_ASCII|ENC_NA);
        offset += (4 + len);
        max_len -= len;
        len = tvb_strsize(tvb, offset);
        proto_tree_add_item(tree, hf_swils_ess_modelname, tvb, offset, len, ENC_ASCII|ENC_NA);
        offset += len;
        max_len -= len;
        len = tvb_strsize(tvb, offset);
        proto_tree_add_item(tree, hf_swils_ess_relcode, tvb, offset, len, ENC_ASCII|ENC_NA);
        offset += len;
        max_len -= len;
        while (max_len > 0) {
            /* Vendor specific field is a set of one or more null-terminated
             * strings
             */
            len = tvb_strsize(tvb, offset);
            proto_tree_add_item(tree, hf_swils_ess_vendorspecific, tvb, offset, len, ENC_ASCII|ENC_NA);
            offset += len;
            max_len -= len;
        }
    }

    return TRUE;
}

static void
dissect_swils_ess_capability(tvbuff_t *tvb, proto_tree *tree, int offset,
                             guint8 srvr_type)
{
    if (tree) {
        switch (srvr_type) {
        case FCCT_GSRVR_DNS:
            proto_tree_add_item(tree, hf_swils_ess_dns_zlacc, tvb, offset+3,
                                1, ENC_BIG_ENDIAN);
            proto_tree_add_item(tree, hf_swils_ess_dns_obj3h, tvb, offset+3,
                                1, ENC_BIG_ENDIAN);
            proto_tree_add_item(tree, hf_swils_ess_dns_obj2h, tvb, offset+3,
                                1, ENC_BIG_ENDIAN);
            proto_tree_add_item(tree, hf_swils_ess_dns_obj1h, tvb, offset+3,
                                1, ENC_BIG_ENDIAN);
            proto_tree_add_item(tree, hf_swils_ess_dns_obj0h, tvb, offset+3,
                                1, ENC_BIG_ENDIAN);
            proto_tree_add_item(tree, hf_swils_ess_dns_vendor, tvb,
                                offset+4, 4, ENC_BIG_ENDIAN);
            break;
        case FCCT_GSRVR_FCTLR:
            proto_tree_add_item(tree, hf_swils_ess_fctlr_rscn, tvb,
                                offset+3, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(tree, hf_swils_ess_fctlr_vendor, tvb,
                                offset+4, 4, ENC_BIG_ENDIAN);
            break;
        case FCCT_GSRVR_FCS:
            proto_tree_add_item(tree, hf_swils_ess_fcs_basic, tvb,
                                offset+3, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(tree, hf_swils_ess_fcs_platform, tvb,
                                offset+3, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(tree, hf_swils_ess_fcs_topology, tvb,
                                offset+3, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(tree, hf_swils_ess_fcs_enhanced, tvb,
                                offset+3, 1, ENC_BIG_ENDIAN);
            break;
        case FCCT_GSRVR_FZS:
            proto_tree_add_item(tree, hf_swils_ess_fzs_enh_supp, tvb,
                                offset+3, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(tree, hf_swils_ess_fzs_enh_ena, tvb,
                                offset+3, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(tree, hf_swils_ess_fzs_mr, tvb, offset+3,
                                1, ENC_BIG_ENDIAN);
            proto_tree_add_item(tree, hf_swils_ess_fzs_defzone, tvb,
                                offset+3, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(tree, hf_swils_ess_fzs_zsdb_supp, tvb,
                                offset+3, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(tree, hf_swils_ess_fzs_zsdb_ena, tvb,
                                offset+3, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(tree, hf_swils_ess_fzs_adc_supp, tvb,
                                offset+3, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(tree, hf_swils_ess_fzs_hardzone, tvb,
                                offset+3, 1, ENC_BIG_ENDIAN);
            break;
        default:
            break;
        }
    }

    return;
}

static int
dissect_swils_ess_capability_obj(tvbuff_t *tvb, proto_tree *tree, int offset)
{
    int         i = 0, num_entries = 0, len = 0, total_len = 0;
    guint8      type, subtype, srvr_type;
    proto_tree *capinfo_tree = NULL;

    if (tree) {
        /*
         * Structure of capability object is: WK type (1B), WK subtype(1),
         * rsvd (1), num_cap_entries (1), entry_1 (8) ... entry_n (8)
         */
        /* Compute length first to create subtree of cap object */
        type = tvb_get_guint8(tvb, offset);
        if (type != FCCT_GSTYPE_VENDOR) {
            num_entries = tvb_get_guint8(tvb, offset+3);
            total_len = 4 + (num_entries*8);
            capinfo_tree = proto_tree_add_subtree_format(tree, tvb, offset,
                                     total_len, ett_fcswils_capinfo, NULL, "Capability Object (%s)",
                                     val_to_str(type, fc_ct_gstype_vals,
                                                "Unknown (0x%x)"));
        } else {
            i = tvb_get_guint8(tvb, offset+3);
            i += 12;

            capinfo_tree = proto_tree_add_subtree_format(tree, tvb, offset,
                                     i, ett_fcswils_capinfo, NULL, "Capability Object (Vendor-specific 0x%x)",
                                     type);
        }

        proto_tree_add_item(capinfo_tree, hf_swils_ess_cap_type, tvb, offset, 1, ENC_BIG_ENDIAN);
        proto_tree_add_item(capinfo_tree, hf_swils_ess_cap_subtype, tvb, offset+1,
                            1, ENC_BIG_ENDIAN);
        subtype = tvb_get_guint8(tvb, offset+1);

        if (type != FCCT_GSTYPE_VENDOR) {
            srvr_type = get_gs_server(type, subtype);
            proto_tree_add_uint(capinfo_tree, hf_swils_ess_cap_svc, tvb, offset, 2,
                                srvr_type);
            proto_tree_add_item(capinfo_tree, hf_swils_ess_cap_numentries, tvb,
                                offset+3, 1, ENC_BIG_ENDIAN);
            offset += 4;
            len += 4;

            while ((num_entries > 0) && tvb_bytes_exist(tvb, offset, 8)) {
                dissect_swils_ess_capability(tvb, capinfo_tree, offset, srvr_type);
                num_entries--;
                offset += 8;
                len += 8;
            }
        } else {
            /* Those damn T11 guys defined another format for
             * Vendor-specific objects.
             */
            proto_tree_add_item(capinfo_tree, hf_swils_ess_cap_len, tvb, offset+3,
                                1, ENC_BIG_ENDIAN);
            proto_tree_add_item(capinfo_tree, hf_swils_ess_cap_t10, tvb, offset+4,
                                8, ENC_ASCII|ENC_NA);
            i -= 8;          /* reduce length by t10 object size */
            offset += 12;
            len += 12;

            while ((i > 0) && tvb_bytes_exist(tvb, offset, 8)) {
                proto_tree_add_item(capinfo_tree, hf_swils_ess_cap_vendorobj,
                                    tvb, offset, 8, ENC_NA);
                i -= 8;
                offset += 8;
                len += 12;
            }
        }
    }
    return len;
}

static void
dissect_swils_nullpayload(tvbuff_t *tvb _U_, packet_info* pinfo _U_, proto_tree *tree _U_,
                          guint8 isreq _U_)
{
    /* Common dissector for those ILSs without a payload */
    return;
}

static void
dissect_swils_elp(tvbuff_t *tvb, packet_info* pinfo _U_, proto_tree *elp_tree, guint8 isreq _U_)
{

    /* Set up structures needed to add the protocol subtree and manage it */
    /* 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 */
    int          offset = 4;
    const gchar *flags;
    guint16 isl_flwctrl_mode;
    guint8  clsf_svcparm[6], cls1_svcparm[2], cls2_svcparm[2], cls3_svcparm[2];

    if (elp_tree) {
        offset += 4;
        proto_tree_add_item(elp_tree, hf_swils_elp_rev, tvb, offset++, 1, ENC_BIG_ENDIAN);
        proto_tree_add_item(elp_tree, hf_swils_elp_flags, tvb, offset, 2, ENC_NA);
        offset += 3;
        proto_tree_add_item(elp_tree, hf_swils_elp_r_a_tov, tvb, offset, 4, ENC_BIG_ENDIAN);
        offset += 4;
        proto_tree_add_item(elp_tree, hf_swils_elp_e_d_tov, tvb, offset, 4, ENC_BIG_ENDIAN);
        offset += 4;
        proto_tree_add_item(elp_tree, hf_swils_elp_req_epn, tvb, offset, 8, ENC_NA);
        offset += 8;
        proto_tree_add_item(elp_tree, hf_swils_elp_req_esn, tvb, offset, 8, ENC_NA);
        offset += 8;

        tvb_memcpy(tvb, clsf_svcparm, offset, 6);
        if (clsf_svcparm[0] & 0x80) {
            if (clsf_svcparm[4] & 0x20) {
                flags="Class F Valid | X_ID Interlock";
            } else {
                flags="Class F Valid | No X_ID Interlk";
            }
        } else {
            flags="Class F Invld";
        }
        proto_tree_add_bytes_format_value(elp_tree, hf_swils_elp_clsf_svcp, tvb, offset, 6,
                                    clsf_svcparm, "(%s)", flags);
        offset += 6;

        proto_tree_add_item(elp_tree, hf_swils_elp_clsf_rcvsz, tvb, offset, 2, ENC_BIG_ENDIAN);
        offset += 2;
        proto_tree_add_item(elp_tree, hf_swils_elp_clsf_conseq, tvb, offset, 2, ENC_BIG_ENDIAN);
        offset += 2;
        proto_tree_add_item(elp_tree, hf_swils_elp_clsf_e2e, tvb, offset, 2, ENC_BIG_ENDIAN);
        offset += 2;
        proto_tree_add_item(elp_tree, hf_swils_elp_clsf_openseq, tvb, offset, 2, ENC_BIG_ENDIAN);
        offset += 4;

        tvb_memcpy(tvb, cls1_svcparm, offset, 2);
        if (cls1_svcparm[0] & 0x80) {
#define MAX_FLAGS_LEN 40
            char *flagsbuf;
            gint stroff, returned_length;

            flagsbuf=(char *)wmem_alloc(wmem_packet_scope(), MAX_FLAGS_LEN);
            stroff = 0;

            returned_length = g_snprintf(flagsbuf+stroff, MAX_FLAGS_LEN-stroff,
                                         "Class 1 Valid");
            stroff += MIN(returned_length, MAX_FLAGS_LEN-stroff);
            if (cls1_svcparm[0] & 0x40) {
                returned_length = g_snprintf(flagsbuf+stroff, MAX_FLAGS_LEN-stroff, " | IMX");
                stroff += MIN(returned_length, MAX_FLAGS_LEN-stroff);
            }
            if (cls1_svcparm[0] & 0x20) {
                returned_length = g_snprintf(flagsbuf+stroff, MAX_FLAGS_LEN-stroff, " | IPS");
                stroff += MIN(returned_length, MAX_FLAGS_LEN-stroff);
            }
            if (cls1_svcparm[0] & 0x10) {
                /*returned_length =*/ g_snprintf(flagsbuf+stroff, MAX_FLAGS_LEN-stroff, " | LKS");
            }
            flags=flagsbuf;
        }
        else {
            flags="Class 1 Invalid";
        }

        proto_tree_add_bytes_format_value(elp_tree, hf_swils_elp_cls1_svcp, tvb, offset, 2,
                                    NULL, "(%s)", flags);
        offset += 2;
        if (cls1_svcparm[0] & 0x80) {
            proto_tree_add_item(elp_tree, hf_swils_elp_cls1_rcvsz, tvb, offset, 2, ENC_BIG_ENDIAN);
        }
        offset += 2;

        tvb_memcpy(tvb, cls2_svcparm, offset, 2);
        if (cls2_svcparm[0] & 0x80) {
            if (cls2_svcparm[0] & 0x08) {
                flags="Class 2 Valid | Seq Delivery";
            }
            else {
                flags="Class 2 Valid | No Seq Delivery";
            }
        }
        else {
            flags="Class 2 Invld";
        }

        proto_tree_add_bytes_format_value(elp_tree, hf_swils_elp_cls2_svcp, tvb, offset, 2,
                                    cls2_svcparm,
                                    "(%s)", flags);
        offset += 2;

        if (cls2_svcparm[0] & 0x80) {
            proto_tree_add_item(elp_tree, hf_swils_elp_cls2_rcvsz, tvb, offset, 2, ENC_BIG_ENDIAN);
        }
        offset += 2;

        tvb_memcpy(tvb, cls3_svcparm, offset, 2);
        if (cls3_svcparm[0] & 0x80) {
            if (cls3_svcparm[0] & 0x08) {
                flags="Class 3 Valid | Seq Delivery";
            }
            else {
                flags="Class 3 Valid | No Seq Delivery";
            }
        }
        else {
            flags="Class 3 Invld";
        }
        proto_tree_add_bytes_format_value(elp_tree, hf_swils_elp_cls3_svcp, tvb, offset, 2,
                                    cls3_svcparm,
                                    "(%s)", flags);
        offset += 2;

        if (cls3_svcparm[0] & 0x80) {
            proto_tree_add_item(elp_tree, hf_swils_elp_cls3_rcvsz, tvb, offset, 2, ENC_BIG_ENDIAN);
        }
        offset += 22;

        isl_flwctrl_mode = tvb_get_ntohs(tvb, offset);
        proto_tree_add_string(elp_tree, hf_swils_elp_isl_fc_mode, tvb, offset, 2,
                              val_to_str_const(isl_flwctrl_mode, fcswils_elp_fc_val, "Vendor Unique"));
        offset += 2;
        proto_tree_add_item(elp_tree, hf_swils_elp_fcplen, tvb, offset, 2, ENC_BIG_ENDIAN);
        offset += 2;
        proto_tree_add_item(elp_tree, hf_swils_elp_b2bcredit, tvb, offset, 4, ENC_BIG_ENDIAN);
        offset += 4;
        proto_tree_add_item(elp_tree, hf_swils_elp_compat1, tvb, offset, 4, ENC_BIG_ENDIAN);
        offset += 4;
        proto_tree_add_item(elp_tree, hf_swils_elp_compat2, tvb, offset, 4, ENC_BIG_ENDIAN);
        offset += 4;
        proto_tree_add_item(elp_tree, hf_swils_elp_compat3, tvb, offset, 4, ENC_BIG_ENDIAN);
        offset += 4;
        proto_tree_add_item(elp_tree, hf_swils_elp_compat4, tvb, offset, 4, ENC_BIG_ENDIAN);
    }

}

static void
dissect_swils_efp(tvbuff_t *tvb, packet_info* pinfo, proto_tree *efp_tree, guint8 isreq _U_)
{

/* Set up structures needed to add the protocol subtree and manage it */
    proto_tree  *lrec_tree;
    proto_item  *rec_item;
    int          num_listrec = 0;
    int          offset      = 1; /* Skip opcode */
    guint8       reclen;
    guint16      payload_len;
    guint8       rec_type;

    reclen = tvb_get_guint8(tvb, offset);
    rec_item = proto_tree_add_uint(efp_tree, hf_swils_efp_record_len, tvb, offset, 1, reclen);
    offset += 1;
    payload_len = tvb_get_ntohs(tvb, offset);
    if (payload_len < FC_SWILS_EFP_SIZE) {
        proto_tree_add_uint_format_value(efp_tree, hf_swils_efp_payload_len,
                                       tvb, offset, 2, payload_len,
                                       "%u (bogus, must be >= %u)",
                                       payload_len, FC_SWILS_EFP_SIZE);
        return;
    }
    proto_tree_add_item(efp_tree, hf_swils_efp_payload_len, tvb, offset, 2, ENC_BIG_ENDIAN);
    offset += 5;       /* skip 3 reserved bytes, too */
    proto_tree_add_item(efp_tree, hf_swils_efp_pswitch_pri, tvb,
                            offset, 1, ENC_BIG_ENDIAN);
    offset += 1;
    proto_tree_add_item(efp_tree, hf_swils_efp_pswitch_name, tvb, offset, 8, ENC_NA);
    offset += 8;

    if (reclen == 0) {
        expert_add_info(pinfo, rec_item, &ei_swils_efp_record_len);
        return;
    }
    /* Add List Records now */
    if (efp_tree) {
        num_listrec = (payload_len - FC_SWILS_EFP_SIZE)/reclen;
        while (num_listrec-- > 0) {
            rec_type = tvb_get_guint8(tvb, offset);
            lrec_tree = proto_tree_add_subtree(efp_tree, tvb, offset, -1,
                                        ett_fcswils_efplist, NULL,
                                        val_to_str(rec_type,
                                                   fcswils_rectype_val,
                                                   "Unknown record type (0x%02x)"));
            proto_tree_add_uint(lrec_tree, hf_swils_efp_rec_type, tvb, offset, 1,
                                rec_type);
            switch (rec_type) {

            case FC_SWILS_LRECTYPE_DOMAIN:
                proto_tree_add_item(lrec_tree, hf_swils_efp_dom_id, tvb, offset+1, 1, ENC_BIG_ENDIAN);
                proto_tree_add_item(lrec_tree, hf_swils_efp_switch_name, tvb, offset+8, 8, ENC_NA);
                break;

            case FC_SWILS_LRECTYPE_MCAST:
                proto_tree_add_item(lrec_tree, hf_swils_efp_mcast_grpno, tvb, offset+1, 1, ENC_BIG_ENDIAN);
                break;
            }
            offset += reclen;
        }
    }
}

static void
dissect_swils_dia(tvbuff_t *tvb, packet_info* pinfo _U_, 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_item(dia_tree, hf_swils_dia_switch_name, tvb, offset+4,
                              8, ENC_NA);
    }
}

static void
dissect_swils_rdi(tvbuff_t *tvb, packet_info* pinfo _U_, 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, ENC_BIG_ENDIAN);
        proto_tree_add_item(rdi_tree, hf_swils_rdi_req_sname, tvb, offset+4, 8, ENC_NA);

        /* 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_item(rdi_tree, hf_swils_requested_domain_id, tvb, offset+3, 1, ENC_BIG_ENDIAN);
            }
            else {
                proto_tree_add_item(rdi_tree, hf_swils_granted_domain_id, tvb, offset+3, 1, ENC_BIG_ENDIAN);
            }
            offset += 4;
        }
    }
}

static void
dissect_swils_fspf_hdr(tvbuff_t *tvb, proto_tree *tree, int offset)
{
    proto_tree *fspfh_tree;

    if (tree) {
        /* 20 is the size of FSPF header */
        fspfh_tree = proto_tree_add_subtree(tree, tvb, offset, 20, ett_fcswils_fspfhdr, NULL, "FSPF Header");

        proto_tree_add_item(fspfh_tree, hf_swils_fspfh_rev, tvb, offset+4,
                            1, ENC_BIG_ENDIAN);
        proto_tree_add_item(fspfh_tree, hf_swils_fspfh_ar_num, tvb,
                            offset+5, 1, ENC_BIG_ENDIAN);
        proto_tree_add_item(fspfh_tree, hf_swils_fspfh_auth_type, tvb,
                            offset+6, 1, ENC_BIG_ENDIAN);
        proto_tree_add_item(fspfh_tree, hf_swils_fspfh_dom_id, tvb, offset+11,
                            1, ENC_BIG_ENDIAN);
        proto_tree_add_item(fspfh_tree, hf_swils_fspfh_auth, tvb, offset+12,
                            8, ENC_NA);
    }
}

static void
dissect_swils_fspf_lsrechdr(tvbuff_t *tvb, proto_tree *tree, int offset)
{
    proto_tree_add_item(tree, hf_swils_lsrh_lsr_type, tvb, offset, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_swils_lsrh_lsr_age, tvb, offset+2, 2, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_swils_lsrh_options, tvb, offset+4, 4, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_swils_lsrh_lsid, tvb, offset+11, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_swils_lsrh_adv_domid, tvb, offset+15, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_swils_lsrh_ls_incid, tvb, offset+16, 4, ENC_BIG_ENDIAN);
    proto_tree_add_checksum(tree, tvb, offset+20, hf_swils_lsrh_checksum, -1, NULL, NULL, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
    proto_tree_add_item(tree, hf_swils_lsrh_lsr_length, tvb, offset+22, 2, ENC_BIG_ENDIAN);
}

static void
dissect_swils_fspf_ldrec(tvbuff_t *tvb, proto_tree *tree, int offset)
{
    proto_tree_add_item(tree, hf_swils_ldrec_linkid, tvb, offset+1, 3, ENC_NA);
    proto_tree_add_item(tree, hf_swils_ldrec_out_pidx, tvb, offset+5, 3, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_swils_ldrec_nbr_pidx, tvb, offset+9, 3, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_swils_ldrec_link_type, tvb, offset+12, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_swils_ldrec_link_cost, tvb, offset+14, 2, ENC_BIG_ENDIAN);
}

static void
dissect_swils_fspf_lsrec(tvbuff_t *tvb, proto_tree *tree, int offset,
                         int num_lsrec)
{
    int         i, j, num_ldrec;
    proto_tree *lsrec_tree, *ldrec_tree, *lsrechdr_tree;

    if (tree) {
        for (j = 0; j < num_lsrec; j++) {
            num_ldrec = tvb_get_ntohs(tvb, offset+26);
            lsrec_tree = proto_tree_add_subtree_format(tree, tvb, offset, (28+num_ldrec*16),
                                        ett_fcswils_lsrec, NULL, "Link State Record %d (Domain %d)", j,
                                        tvb_get_guint8(tvb, offset+15));

            lsrechdr_tree = proto_tree_add_subtree(lsrec_tree, tvb, offset, 24,
                                        ett_fcswils_lsrechdr, NULL, "Link State Record Header");

            dissect_swils_fspf_lsrechdr(tvb, lsrechdr_tree, offset);
            proto_tree_add_item(tree, hf_swils_lsrec_number_of_links, tvb, offset+26, 2, ENC_BIG_ENDIAN);
            offset += 28;

            for (i = 0; i < num_ldrec; i++) {
                ldrec_tree = proto_tree_add_subtree_format(lsrec_tree, tvb, offset, 16,
                                             ett_fcswils_ldrec, NULL, "Link Descriptor %d "
                                             "(Neighbor domain %d)", i,
                                             tvb_get_guint8(tvb, offset+3));
                dissect_swils_fspf_ldrec(tvb, ldrec_tree, offset);
                offset += 16;
            }
        }
    }
}

static void
dissect_swils_hello(tvbuff_t *tvb, packet_info* pinfo _U_, 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, ENC_NA);
        proto_tree_add_item(hlo_tree, hf_swils_hlo_hloint, tvb, offset+24, 4, ENC_BIG_ENDIAN);
        proto_tree_add_item(hlo_tree, hf_swils_hlo_deadint, tvb, offset+28, 4, ENC_BIG_ENDIAN);
        proto_tree_add_item(hlo_tree, hf_swils_hlo_rcv_domid, tvb, offset+35, 1, ENC_BIG_ENDIAN);
        proto_tree_add_item(hlo_tree, hf_swils_hlo_orig_pidx, tvb, offset+37, 3, ENC_BIG_ENDIAN);
    }
}

static void
dissect_swils_lsupdate(tvbuff_t *tvb, packet_info* pinfo _U_, 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_item(lsu_tree, hf_swils_lsupdate_flags, tvb, offset+23, 1, ENC_BIG_ENDIAN);
        num_lsrec = tvb_get_ntohl(tvb, offset+24);

        proto_tree_add_item(lsu_tree, hf_swils_lsupdate_num_of_lsrs, tvb, offset+24, 4, ENC_BIG_ENDIAN);

        offset = 28;
        dissect_swils_fspf_lsrec(tvb, lsu_tree, offset, num_lsrec);
    }
}

static void
dissect_swils_lsack(tvbuff_t *tvb, packet_info* pinfo _U_, 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;
    proto_tree *lsrechdr_tree;

    if (lsa_tree) {
        dissect_swils_fspf_hdr(tvb, lsa_tree, offset);

        proto_tree_add_item(lsa_tree, hf_swils_lsack_flags, tvb, offset+23, 1, ENC_BIG_ENDIAN);
        num_lsrechdr = tvb_get_ntohl(tvb, offset+24);

        proto_tree_add_item(lsa_tree, hf_swils_lsack_num_of_lsr_headers, tvb, offset+24, 4, ENC_BIG_ENDIAN);

        offset = 28;

        for (i = 0; i < num_lsrechdr; i++) {
            lsrechdr_tree = proto_tree_add_subtree_format(lsa_tree, tvb, offset, 24,
                                        ett_fcswils_lsrechdr, NULL, "Link State Record Header (Domain %d)",
                                        tvb_get_guint8(tvb, offset+15));
            dissect_swils_fspf_lsrechdr(tvb, lsrechdr_tree, offset);
            offset += 24;
        }
    }
}

static void
dissect_swils_rscn(tvbuff_t *tvb, packet_info* pinfo _U_, 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         numrec, i;

    if (rscn_tree) {
        if (!isreq)
            return;

        proto_tree_add_item(rscn_tree, hf_swils_rscn_evtype, tvb, offset+4,
                            1, ENC_BIG_ENDIAN);
        proto_tree_add_item(rscn_tree, hf_swils_rscn_addrfmt, tvb, offset+4,
                            1, ENC_BIG_ENDIAN);
        proto_tree_add_item(rscn_tree, hf_swils_rscn_affectedport, tvb,
                              offset+5, 3, ENC_NA);
        proto_tree_add_item(rscn_tree, hf_swils_rscn_detectfn, tvb,
                            offset+8, 4, ENC_BIG_ENDIAN);
        numrec = tvb_get_ntohl(tvb, offset+12);

        if (!tvb_bytes_exist(tvb, offset+16, FC_SWILS_RSCN_DEVENTRY_SIZE*numrec)) {
            /* Some older devices do not include device entry information. */
            return;
        }

        proto_tree_add_item(rscn_tree, hf_swils_rscn_num_entries, tvb, offset+12, 4, ENC_BIG_ENDIAN);

        offset = 16;
        for (i = 0; i < numrec; i++) {
            dev_tree = proto_tree_add_subtree_format(rscn_tree, tvb, offset, 20,
                                        ett_fcswils_rscn_dev, NULL, "Device Entry %d", i);

            proto_tree_add_item(dev_tree, hf_swils_rscn_portstate, tvb, offset, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(dev_tree, hf_swils_rscn_portid, tvb, offset+1, 3, ENC_NA);
            proto_tree_add_item(dev_tree, hf_swils_rscn_pwwn, tvb, offset+4, 8, ENC_NA);
            proto_tree_add_item(dev_tree, hf_swils_rscn_nwwn, tvb, offset+12, 8, ENC_NA);
            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, packet_info* pinfo, proto_tree *zmbr_tree, int offset)
{
    guint8  mbrtype;
    int     idlen;
    proto_item* ti;

    mbrtype = tvb_get_guint8(tvb, offset);
    ti = proto_tree_add_uint(zmbr_tree, hf_swils_zone_mbrtype, tvb,
                        offset, 1, mbrtype);
    proto_tree_add_item(zmbr_tree, hf_swils_zone_mbrflags, tvb, offset+2, 1, ENC_BIG_ENDIAN);
    idlen = tvb_get_guint8(tvb, offset+3);
    proto_tree_add_item(zmbr_tree, hf_swils_zone_mbr_identifier_length, tvb, offset+3, 1, ENC_BIG_ENDIAN);
    switch (mbrtype) {
    case FC_SWILS_ZONEMBR_WWN:
        proto_tree_add_item(zmbr_tree, hf_swils_zone_mbrid_fcwwn, tvb,
                              offset+4, 8, ENC_NA);
        break;
    case FC_SWILS_ZONEMBR_DP:
        proto_tree_add_item(zmbr_tree, hf_swils_zone_mbrid_uint, tvb,
                              offset+4, 4, ENC_BIG_ENDIAN);
        break;
    case FC_SWILS_ZONEMBR_FCID:
        proto_tree_add_item(zmbr_tree, hf_swils_zone_mbrid_fc, tvb,
                              offset+4, 3, ENC_NA);
        break;
    case FC_SWILS_ZONEMBR_ALIAS:
        proto_tree_add_string(zmbr_tree, hf_swils_zone_mbrid, tvb,
                              offset+4, idlen, zonenm_to_str(tvb, offset+4));
        break;
    case FC_SWILS_ZONEMBR_WWN_LUN:
        proto_tree_add_item(zmbr_tree, hf_swils_zone_mbrid_fcwwn, tvb,
                              offset+4, 8, ENC_NA);
        proto_tree_add_item(zmbr_tree, hf_swils_zone_mbrid_lun, tvb,
                            offset+12, 8, ENC_NA);
        break;
    case FC_SWILS_ZONEMBR_DP_LUN:
        proto_tree_add_item(zmbr_tree, hf_swils_zone_mbrid_uint, tvb,
                              offset+4, 4, ENC_BIG_ENDIAN);
        proto_tree_add_item(zmbr_tree, hf_swils_zone_mbrid_lun, tvb,
                            offset+8, 8, ENC_NA);
        break;
    case FC_SWILS_ZONEMBR_FCID_LUN:
        proto_tree_add_item(zmbr_tree, hf_swils_zone_mbrid_fc, tvb,
                              offset+4, 3, ENC_NA);
        proto_tree_add_item(zmbr_tree, hf_swils_zone_mbrid_lun, tvb,
                            offset+8, 8, ENC_NA);
        break;
    default:
        expert_add_info(pinfo, ti, &ei_swils_zone_mbrid);

    }
}

static void
dissect_swils_zone_obj(tvbuff_t *tvb, packet_info* pinfo, proto_tree *zobj_tree, int offset)
{
    proto_tree *zmbr_tree;
    int         mbrlen, numrec, i, objtype;
    char       *str;

    objtype = tvb_get_guint8(tvb, offset);

    proto_tree_add_item(zobj_tree, hf_swils_zone_objtype, tvb, offset,
                        1, ENC_BIG_ENDIAN);
    proto_tree_add_item(zobj_tree, hf_swils_zone_protocol, tvb,
                        offset+1, 1, ENC_BIG_ENDIAN);
    str = zonenm_to_str(tvb, offset+4);
    proto_tree_add_string(zobj_tree, hf_swils_zone_objname, tvb,
                          offset+4, ZONENAME_LEN(tvb, offset+4), str);

    numrec = tvb_get_ntohl(tvb, offset+4+ZONENAME_LEN(tvb, offset+4));
    proto_tree_add_item(zobj_tree, hf_swils_zone_num_members, tvb, offset+4+ZONENAME_LEN(tvb,offset+4), 4, ENC_BIG_ENDIAN);

    offset += 8 + ZONENAME_LEN(tvb, offset+4);
    for (i = 0; i < numrec; i++) {
        if (objtype == FC_SWILS_ZONEOBJ_ZONESET) {
            dissect_swils_zone_obj(tvb, pinfo, zobj_tree, offset);
            offset += get_zoneobj_len(tvb, offset);
        }
        else {
            mbrlen = 4 + tvb_get_guint8(tvb, offset+3);
            zmbr_tree = proto_tree_add_subtree_format(zobj_tree, tvb, offset, mbrlen,
                                        ett_fcswils_zonembr, NULL, "Zone Member %d", i);
            dissect_swils_zone_mbr(tvb, pinfo, zmbr_tree, offset);
            offset += mbrlen;
        }
    }
}

static void
dissect_swils_mergereq(tvbuff_t *tvb, packet_info* pinfo, 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;
    char       *str;

        if (isreq) {
            /* zonesetlen is the size of the zoneset including the zone name */
            zonesetlen = tvb_get_ntohs(tvb, offset+2);
            proto_tree_add_item(mr_tree, hf_swils_zone_active_zoneset_length, tvb, offset+2, 2, ENC_BIG_ENDIAN);

            if (zonesetlen) {
                str = zonenm_to_str(tvb, offset+4);
                proto_tree_add_string(mr_tree, hf_swils_zone_activezonenm, tvb,
                                      offset+4, ZONENAME_LEN(tvb, offset+4),
                                      str);

                /* 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);

                zobjlist_tree = proto_tree_add_subtree(mr_tree, tvb, offset, objlistlen,
                                            ett_fcswils_zoneobjlist, NULL, "Active Zone Set");

                proto_tree_add_item(zobjlist_tree, hf_swils_zone_num_zoning_objects, tvb, offset, 4, ENC_BIG_ENDIAN);

                offset += 4;
                for (i = 0; i < numrec; i++) {
                    objlen = get_zoneobj_len(tvb, offset);
                    zobj_tree = proto_tree_add_subtree_format(zobjlist_tree, tvb, offset+4, objlen,
                                                ett_fcswils_zoneobj, NULL, "Zone Object %d", i);
                    dissect_swils_zone_obj(tvb, pinfo, zobj_tree, offset);
                    offset += objlen;
                }
            }
            else {
                offset += 4;
            }

            zonesetlen = tvb_get_ntohl(tvb, offset);
            proto_tree_add_item(mr_tree, hf_swils_zone_full_zone_set_length, tvb, offset, 4, ENC_BIG_ENDIAN);

            if (zonesetlen) {
                objlistlen = zonesetlen;
                /* Offset = start of the active zoneset zoning object list */
                offset += 4;
                numrec = tvb_get_ntohl(tvb, offset);

                zobjlist_tree = proto_tree_add_subtree(mr_tree, tvb, offset, objlistlen,
                                            ett_fcswils_zoneobjlist, NULL, "Full Zone Set");

                proto_tree_add_item(zobjlist_tree, hf_swils_zone_num_zoning_objects, tvb, offset, 4, ENC_BIG_ENDIAN);
                offset += 4;
                for (i = 0; i < numrec; i++) {
                    objlen = get_zoneobj_len(tvb, offset);
                    zobj_tree = proto_tree_add_subtree_format(zobjlist_tree, tvb, offset,
                                                objlen, ett_fcswils_zoneobj, NULL, "Zone Object %d", i);
                    dissect_swils_zone_obj(tvb, pinfo, zobj_tree, offset);
                    offset += objlen;
                }
            }
        }
        else {
            proto_tree_add_item(mr_tree, hf_swils_zone_status, tvb,
                                offset+5, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(mr_tree, hf_swils_zone_reason, tvb,
                                offset+6, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(mr_tree, hf_swils_zone_vendor_unique, tvb, offset+7, 1, ENC_BIG_ENDIAN);
        }
}

static void
dissect_swils_aca(tvbuff_t *tvb, packet_info* pinfo _U_, 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_item(aca_tree, hf_swils_domain_id_list_length, tvb, offset+2, 2, ENC_BIG_ENDIAN);
            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, ENC_BIG_ENDIAN);
            proto_tree_add_item(aca_tree, hf_swils_zone_reason, tvb,
                                offset+6, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(aca_tree, hf_swils_zone_vendor_unique, tvb, offset+7, 1, ENC_BIG_ENDIAN);
        }
    }
}

static void
dissect_swils_rca(tvbuff_t *tvb, packet_info* pinfo _U_, 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, ENC_BIG_ENDIAN);
            proto_tree_add_item(rca_tree, hf_swils_zone_reason, tvb,
                                offset+6, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(rca_tree, hf_swils_zone_vendor_unique, tvb, offset+7, 1, ENC_BIG_ENDIAN);
        }
    }
}

static void
dissect_swils_sfc(tvbuff_t *tvb, packet_info* pinfo, 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;
    char       *str;

        if (isreq) {
            proto_tree_add_item(sfc_tree, hf_swils_sfc_opcode, tvb, offset+1, 1, ENC_BIG_ENDIAN);

            zonesetlen = tvb_get_ntohs(tvb, offset+2);
            proto_tree_add_item(sfc_tree, hf_swils_sfc_zoneset_length, tvb, offset+2, 2, ENC_BIG_ENDIAN);

            if (zonesetlen) {
                str = zonenm_to_str(tvb, offset+4);
                proto_tree_add_string(sfc_tree, hf_swils_sfc_zonenm, tvb,
                                      offset+4, ZONENAME_LEN(tvb, offset+4),
                                      str);

                /* 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);

                zobjlist_tree = proto_tree_add_subtree(sfc_tree, tvb, offset, objlistlen,
                                            ett_fcswils_zoneobjlist, NULL, "Zone Set");

                proto_tree_add_item(zobjlist_tree, hf_swils_zone_num_zoning_objects, tvb, offset, 4, ENC_BIG_ENDIAN);

                offset += 4;
                for (i = 0; i < numrec; i++) {
                    objlen = get_zoneobj_len(tvb, offset);
                    zobj_tree = proto_tree_add_subtree_format(zobjlist_tree, tvb, offset, objlen,
                                                ett_fcswils_zoneobj, NULL, "Zone Object %d", i);
                    dissect_swils_zone_obj(tvb, pinfo, zobj_tree, offset);
                    offset += objlen;
                }
            }
            else {
                offset += 4;
            }

            zonesetlen = tvb_get_ntohl(tvb, offset);
            proto_tree_add_item(sfc_tree, hf_swils_zone_full_zone_set_length, tvb, offset, 4, ENC_BIG_ENDIAN);

            if (zonesetlen) {
                objlistlen = zonesetlen;
                /* Offset = start of the active zoneset zoning object list */
                offset += 4;
                numrec = tvb_get_ntohl(tvb, offset);

                zobjlist_tree = proto_tree_add_subtree(sfc_tree, tvb, offset, objlistlen,
                                            ett_fcswils_zoneobjlist, NULL, "Full Zone Set");

                proto_tree_add_item(zobjlist_tree, hf_swils_zone_num_zoning_objects, tvb, offset, 4, ENC_BIG_ENDIAN);
                offset += 4;
                for (i = 0; i < numrec; i++) {
                    objlen = get_zoneobj_len(tvb, offset);
                    zobj_tree = proto_tree_add_subtree_format(zobjlist_tree, tvb, offset, objlen,
                                                ett_fcswils_zoneobj, NULL, "Zone Object %d", i);
                    dissect_swils_zone_obj(tvb, pinfo, zobj_tree, offset);
                    offset += objlen;
                }
            }
        }
        else {
            proto_tree_add_item(sfc_tree, hf_swils_zone_status, tvb,
                                offset+5, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(sfc_tree, hf_swils_zone_reason, tvb,
                                offset+6, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(sfc_tree, hf_swils_zone_vendor_unique, tvb, offset+7, 1, ENC_BIG_ENDIAN);
        }
}

static void
dissect_swils_ufc(tvbuff_t *tvb, packet_info* pinfo _U_, 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, ENC_BIG_ENDIAN);
            proto_tree_add_item(ufc_tree, hf_swils_zone_reason, tvb,
                                offset+6, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(ufc_tree, hf_swils_zone_vendor_unique, tvb, offset+7, 1, ENC_BIG_ENDIAN);
        }
    }
}

static void
dissect_swils_esc(tvbuff_t *tvb, packet_info* pinfo _U_, 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;

    if (esc_tree) {
        if (isreq) {
            plen = tvb_get_ntohs(tvb, offset+2);
            proto_tree_add_item(esc_tree, hf_swils_esc_payload_length, tvb, offset+2, 2, ENC_BIG_ENDIAN);
            proto_tree_add_item(esc_tree, hf_swils_esc_swvendorid, tvb,
                                offset+4, 8, ENC_ASCII|ENC_NA);
            numrec = (plen - 12)/12;
            offset = 12;

            for (i = 0; i < numrec; i++) {
                pdesc_tree = proto_tree_add_subtree_format(esc_tree, tvb, offset, 12,
                                            ett_fcswils_esc_pdesc, NULL, "Protocol Descriptor %d", i);
                proto_tree_add_item(pdesc_tree, hf_swils_esc_pdesc_vendorid, tvb,
                                    offset, 8, ENC_ASCII|ENC_NA);
                proto_tree_add_item(pdesc_tree, hf_swils_esc_protocolid,
                                    tvb, offset+10, 2, ENC_BIG_ENDIAN);
                offset += 12;
            }
        }
        else {
            proto_tree_add_item(esc_tree, hf_swils_esc_swvendorid, tvb,
                                offset+4, 8, ENC_ASCII|ENC_NA);
            pdesc_tree = proto_tree_add_subtree(esc_tree, tvb, offset+12, 12,
                                        ett_fcswils_esc_pdesc, NULL, "Accepted Protocol Descriptor");

            proto_tree_add_item(pdesc_tree, hf_swils_esc_pdesc_vendorid, tvb,
                                offset+12, 8, ENC_ASCII|ENC_NA);
            proto_tree_add_item(pdesc_tree, hf_swils_esc_protocolid,
                                tvb, offset+22, 2, ENC_BIG_ENDIAN);
        }
    }
}

static void
dissect_swils_drlir(tvbuff_t *tvb _U_, packet_info* pinfo _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, packet_info* pinfo _U_, proto_tree *swrjt_tree, guint8 isreq _U_)
{
    /* 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, ENC_BIG_ENDIAN);
        proto_tree_add_item(swrjt_tree, hf_swils_rjtdet, tvb, offset+6, 1, ENC_BIG_ENDIAN);
        proto_tree_add_item(swrjt_tree, hf_swils_rjtvendor, tvb, offset+7,
                            1, ENC_BIG_ENDIAN);
    }
}

static void
dissect_swils_ess(tvbuff_t *tvb, packet_info* pinfo _U_, proto_tree *ess_tree, guint8 isreq _U_)
{
    int         offset      = 0;
    gint16      numcapobj   = 0;
    gint        len         = 0;
    gint        capobjlen   = 0;
    proto_tree *ieinfo_tree;

    if (!ess_tree) {
        return;
    }

    proto_tree_add_item(ess_tree, hf_swils_ess_rev, tvb, offset+4, 4, ENC_BIG_ENDIAN);
    proto_tree_add_item(ess_tree, hf_swils_ess_len, tvb, offset+8, 4, ENC_BIG_ENDIAN);
    len = tvb_get_ntohl(tvb, offset+8);

    ieinfo_tree = proto_tree_add_subtree(ess_tree, tvb, offset+12,
                             MAX_INTERCONNECT_ELEMENT_INFO_LEN+4,
                             ett_fcswils_ieinfo, NULL, "Interconnect Element Info");
    dissect_swils_interconnect_element_info(tvb, ieinfo_tree, offset+12);
    len -= 256;                /* the interconnect obj above is 256 bytes */
    offset += 268;

    proto_tree_add_item(ess_tree, hf_swils_ess_numobj, tvb, offset, 2, ENC_BIG_ENDIAN);
    numcapobj = tvb_get_ntohs(tvb, offset);

    len -= 4;                  /* 2B numcapobj + 2B rsvd */
    offset += 4;

    while ((len > 0) && (numcapobj > 0)) {
        capobjlen = dissect_swils_ess_capability_obj(tvb, ess_tree, offset);
        numcapobj--;
        len -= capobjlen;
        offset += capobjlen;
    }
}

static void
dissect_swils_mrra(tvbuff_t *tvb, packet_info* pinfo _U_, proto_tree *tree, guint8 isreq)
{

    int offset = 0;

    if (!tree) {
        return;
    }

    if (isreq) {
        proto_tree_add_item(tree, hf_swils_mrra_rev, tvb, offset+4, 4, ENC_BIG_ENDIAN);
        proto_tree_add_item(tree, hf_swils_mrra_size, tvb, offset+8, 4, ENC_BIG_ENDIAN);
        proto_tree_add_item(tree, hf_swils_mrra_vendorid, tvb, offset+12, 8, ENC_ASCII|ENC_NA);
        proto_tree_add_item(tree, hf_swils_mrra_vendorinfo, tvb, offset+20,
                            8, ENC_NA);
    } else {
        proto_tree_add_item(tree, hf_swils_mrra_vendorid, tvb, offset+4,
                            8, ENC_ASCII|ENC_NA);
        proto_tree_add_item(tree, hf_swils_mrra_reply, tvb, offset+12,
                            4, ENC_BIG_ENDIAN);
        proto_tree_add_item(tree, hf_swils_mrra_reply_size, tvb, offset+16,
                            4, ENC_BIG_ENDIAN);
        proto_tree_add_item(tree, hf_swils_mrra_waittime, tvb, offset+20,
                            4, ENC_BIG_ENDIAN);
    }


}

static fcswils_func_table_t fcswils_func_table[FC_SWILS_MAXCODE] = {
    /* 0x00 */ {NULL},
    /* 0x01 */ {dissect_swils_swrjt},
    /* 0x02 */ {NULL},
    /* 0x03 */ {NULL},
    /* 0x04 */ {NULL},
    /* 0x05 */ {NULL},
    /* 0x06 */ {NULL},
    /* 0x07 */ {NULL},
    /* 0x08 */ {NULL},
    /* 0x09 */ {NULL},
    /* 0x0a */ {NULL},
    /* 0x0b */ {NULL},
    /* 0x0c */ {NULL},
    /* 0x0d */ {NULL},
    /* 0x0e */ {NULL},
    /* 0x0f */ {NULL},
    /* 0x10 */ {dissect_swils_elp},
    /* 0x11 */ {dissect_swils_efp},
    /* 0x12 */ {dissect_swils_dia},
    /* 0x13 */ {dissect_swils_rdi},
    /* 0x14 */ {dissect_swils_hello},
    /* 0x15 */ {dissect_swils_lsupdate},
    /* 0x16 */ {dissect_swils_lsack},
    /* 0x17 */ {dissect_swils_nullpayload},
    /* 0x18 */ {dissect_swils_nullpayload},
    /* 0x19 */ {NULL},
    /* 0x1a */ {NULL},
    /* 0x1b */ {dissect_swils_rscn},
    /* 0x1c */ {NULL},
    /* 0x1d */ {NULL},
    /* 0x1e */ {dissect_swils_drlir},
    /* 0x1f */ {NULL},
    /* 0x20 */ {NULL /*dissect_swils_dscn*/},
    /* 0x21 */ {NULL /*dissect_swils_loopd*/},
    /* 0x22 */ {dissect_swils_mergereq},
    /* 0x23 */ {dissect_swils_aca},
    /* 0x24 */ {dissect_swils_rca},
    /* 0x25 */ {dissect_swils_sfc},
    /* 0x26 */ {dissect_swils_ufc},
    /* 0x27 */ {NULL},
    /* 0x28 */ {NULL},
    /* 0x29 */ {NULL},
    /* 0x2a */ {NULL},
    /* 0x2b */ {NULL},
    /* 0x2c */ {NULL},
    /* 0x2d */ {NULL},
    /* 0x2e */ {NULL},
    /* 0x2f */ {NULL},
    /* 0x30 */ {dissect_swils_esc},
    /* 0x31 */ {dissect_swils_ess},
    /* 0x32 */ {NULL},
    /* 0x33 */ {NULL},
    /* 0x34 */ {dissect_swils_mrra}
};

/* Code to actually dissect the packets */
static int
dissect_fcswils(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
{
    proto_item          *ti            = NULL;
    guint8               opcode;
    guint8               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;
    tvbuff_t            *next_tvb;
    fc_hdr *fchdr;

    /* Reject the packet if data is NULL */
    if (data == NULL)
        return 0;
    fchdr = (fc_hdr *)data;

    /* Make entries in Protocol column and Info column on summary display */
    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);

    ti = proto_tree_add_protocol_format(tree, proto_fcswils, tvb, 0, -1, "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->num, &pinfo->src, &pinfo->dst,
                                         conversation_pt_to_endpoint_type(pinfo->ptype), fchdr->oxid,
                                         fchdr->rxid, NO_PORT2);
        if (!conversation) {
            conversation = conversation_new(pinfo->num, &pinfo->src, &pinfo->dst,
                                            conversation_pt_to_endpoint_type(pinfo->ptype), fchdr->oxid,
                                            fchdr->rxid, NO_PORT2);
        }

        ckey.conv_idx = conversation->conv_index;

        cdata = (fcswils_conv_data_t *)wmem_map_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 = wmem_new(wmem_file_scope(), fcswils_conv_key_t);
            req_key->conv_idx = conversation->conv_index;

            cdata = wmem_new(wmem_file_scope(), fcswils_conv_data_t);
            cdata->opcode = opcode;

            wmem_map_insert(fcswils_req_hash, req_key, cdata);
        }
    }
    else {
        /* Opcode is ACC or RJT */
        conversation = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst,
                                         conversation_pt_to_endpoint_type(pinfo->ptype), fchdr->oxid,
                                         fchdr->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_expert_format(swils_tree, pinfo, &ei_swils_no_exchange, tvb, 0, -1, "No record of Exchg. Unable to decode SW_ACC");
                return 0;
            }
        }
        else {
            ckey.conv_idx = conversation->conv_index;

            cdata = (fcswils_conv_data_t *)wmem_map_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_expert_format(swils_tree, pinfo, &ei_swils_no_exchange, tvb, 0, -1, "No record of SW_ILS Req. Unable to decode SW_ACC");
                    return 0;
                }
            }
        }
    }

    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"));
    }

    proto_tree_add_item(swils_tree, hf_swils_opcode, tvb, offset, 1, ENC_BIG_ENDIAN);

    if ((opcode < FC_SWILS_MAXCODE) && fcswils_func_table[opcode].func) {
        fcswils_func_table[opcode].func(tvb, pinfo, swils_tree, isreq);
    } else if (opcode == FC_SWILS_AUTH_ILS) {
        /* This is treated differently */
        if (isreq && fcsp_handle)
            call_dissector(fcsp_handle, tvb, pinfo, swils_tree);
    } else {
        /* data dissector */
        next_tvb = tvb_new_subset_remaining(tvb, offset+4);
        call_data_dissector(next_tvb, pinfo, tree);
    }

    return tvb_captured_length(tvb);
}

/* Register the protocol with Wireshark */

void
proto_register_fcswils(void)
{
    static hf_register_info hf[] = {
        { &hf_swils_opcode,
          {"Cmd Code", "swils.opcode",
           FT_UINT8, BASE_HEX, VALS(fc_swils_opcode_key_val), 0x0,
           NULL, HFILL}},

        { &hf_swils_elp_rev,
          {"Revision", "swils.elp.rev",
           FT_UINT8, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_elp_flags,
          {"Flag", "swils.elp.flag",
           FT_BYTES, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_elp_r_a_tov,
          {"R_A_TOV", "swils.elp.ratov",
           FT_UINT32, BASE_DEC|BASE_UNIT_STRING, &units_milliseconds, 0x0,
           NULL, HFILL}},

        { &hf_swils_elp_e_d_tov,
          {"E_D_TOV", "swils.elp.edtov",
           FT_UINT32, BASE_DEC|BASE_UNIT_STRING, &units_milliseconds, 0x0,
           NULL, HFILL}},

        { &hf_swils_elp_req_epn,
          {"Req Eport Name", "swils.elp.reqepn",
           FT_FCWWN, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_elp_req_esn,
          {"Req Switch Name", "swils.elp.reqesn",
           FT_FCWWN, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_elp_clsf_svcp,
          {"Class F Svc Parameters", "swils.elp.clsfp",
           FT_BYTES, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_elp_clsf_rcvsz,
          {"Max Class F Frame Size", "swils.elp.clsfrsz",
           FT_UINT16, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_elp_clsf_conseq,
          {"Class F Max Concurrent Seq", "swils.elp.clsfcs",
           FT_UINT16, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_elp_clsf_e2e,
          {"Class F E2E Credit", "swils.elp.cfe2e",
           FT_UINT16, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_elp_clsf_openseq,
          {"Class F Max Open Seq", "swils.elp.oseq",
           FT_UINT16, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_elp_cls1_svcp,
          {"Class 1 Svc Parameters", "swils.elp.cls1p",
           FT_BYTES, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_elp_cls1_rcvsz,
          {"Class 1 Frame Size", "swils.elp.cls1rsz",
           FT_UINT16, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_elp_cls2_svcp,
          {"Class 2 Svc Parameters", "swils.elp.cls2p",
           FT_BYTES, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_elp_cls2_rcvsz,
          {"Class 2 Frame Size", "swils.elp.cls2rsz",
           FT_UINT16, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_elp_cls3_svcp,
          {"Class 3 Svc Parameters", "swils.elp.cls3p",
           FT_BYTES, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_elp_cls3_rcvsz,
          {"Class 3 Frame Size", "swils.elp.cls3rsz",
           FT_UINT16, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_elp_isl_fc_mode,
          {"ISL Flow Ctrl Mode", "swils.elp.fcmode",
           FT_STRING, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_elp_fcplen,
          {"Flow Ctrl Param Len", "swils.elp.fcplen",
           FT_UINT16, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_elp_b2bcredit,
          {"B2B Credit", "swils.elp.b2b",
           FT_UINT32, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_elp_compat1,
          {"Compatibility Param 1", "swils.elp.compat1",
           FT_UINT32, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_elp_compat2,
          {"Compatibility Param 2", "swils.elp.compat2",
           FT_UINT32, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_elp_compat3,
          {"Compatibility Param 3", "swils.elp.compat3",
           FT_UINT32, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_elp_compat4,
          {"Compatibility Param 4", "swils.elp.compat4",
           FT_UINT32, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_efp_rec_type,
          {"Record Type", "swils.efp.rectype",
           FT_UINT8, BASE_HEX, VALS(fcswils_rectype_val), 0x0,
           NULL, HFILL}},

        { &hf_swils_efp_dom_id,
          {"Domain ID", "swils.efp.domid",
           FT_UINT8, BASE_HEX, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_efp_switch_name,
          {"Switch Name", "swils.efp.sname",
           FT_FCWWN, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_efp_mcast_grpno,
          {"Mcast Grp#", "swils.efp.mcastno",
           FT_UINT8, BASE_HEX, NULL, 0x0,
           NULL, HFILL}},

#if 0
        { &hf_swils_efp_alias_token,
          {"Alias Token", "swils.efp.aliastok",
           FT_BYTES, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},
#endif

        { &hf_swils_efp_record_len,
          {"Record Len", "swils.efp.recordlen",
           FT_UINT8, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_efp_payload_len,
          {"Payload Len", "swils.efp.payloadlen",
           FT_UINT16, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_efp_pswitch_pri,
          {"Principal Switch Priority", "swils.efp.psprio",
           FT_UINT8, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_efp_pswitch_name,
          {"Principal Switch Name", "swils.efp.psname",
           FT_FCWWN, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_dia_switch_name,
          {"Switch Name", "swils.dia.sname",
           FT_FCWWN, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_rdi_payload_len,
          {"Payload Len", "swils.rdi.len",
           FT_UINT16, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_rdi_req_sname,
          {"Req Switch Name", "swils.rdi.reqsn",
           FT_FCWWN, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

#if 0
        { &hf_swils_fspfh_cmd,
          {"Command:", "swils.fspf.cmd",
           FT_UINT8, BASE_HEX, NULL, 0x0,
           NULL, HFILL}},
#endif

        { &hf_swils_fspfh_rev,
          {"Version", "swils.fspf.ver",
           FT_UINT8, BASE_HEX, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_fspfh_ar_num,
          {"AR Number", "swils.fspf.arnum",
           FT_UINT8, BASE_HEX, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_fspfh_auth_type,
          {"Authentication Type", "swils.fspf.authtype",
           FT_UINT8, BASE_HEX, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_fspfh_dom_id,
          {"Originating Domain ID", "swils.fspf.origdomid",
           FT_UINT8, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_fspfh_auth,
          {"Authentication", "swils.fspf.auth",
           FT_BYTES, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_hlo_options,
          {"Options", "swils.hlo.options",
           FT_BYTES, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_hlo_hloint,
          {"Hello Interval (secs)", "swils.hlo.hloint",
           FT_UINT32, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_hlo_deadint,
          {"Dead Interval (secs)", "swils.hlo.deadint",
           FT_UINT32, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_hlo_rcv_domid,
          {"Recipient Domain ID", "swils.hlo.rcvdomid",
           FT_UINT8, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_hlo_orig_pidx,
          {"Originating Port Idx", "swils.hlo.origpidx",
           FT_UINT24, BASE_HEX, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_lsrh_lsr_type,
          {"LSR Type", "swils.lsr.type",
           FT_UINT8, BASE_HEX, VALS(fc_swils_fspf_linkrec_val), 0x0,
           NULL, HFILL}},

        { &hf_swils_lsrh_lsid,
          {"Link State Id", "swils.ls.id",
           FT_UINT8, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_lsrh_adv_domid,
          {"Advertising Domain Id", "swils.lsr.advdomid",
           FT_UINT8, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_lsrh_ls_incid,
          {"LS Incarnation Number", "swils.lsr.incid",
           FT_UINT32, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_ldrec_linkid,
          {"Link ID", "swils.ldr.linkid",
           FT_BYTES, SEP_DOT, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_ldrec_out_pidx,
          {"Output Port Idx", "swils.ldr.out_portidx",
           FT_UINT24, BASE_HEX, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_ldrec_nbr_pidx,
          {"Neighbor Port Idx", "swils.ldr.nbr_portidx",
           FT_UINT24, BASE_HEX, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_ldrec_link_type,
          {"Link Type", "swils.ldr.linktype",
           FT_UINT8, BASE_HEX, VALS(fc_swils_link_type_val), 0x0,
           NULL, HFILL}},

        { &hf_swils_ldrec_link_cost,
          {"Link Cost", "swils.ldr.linkcost",
           FT_UINT16, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_rscn_evtype,
          {"Event Type", "swils.rscn.evtype",
           FT_UINT8, BASE_DEC, VALS(fc_swils_rscn_portstate_val), 0xF0,
           NULL, HFILL}},

        { &hf_swils_rscn_addrfmt,
          {"Address Format", "swils.rscn.addrfmt",
           FT_UINT8, BASE_DEC, VALS(fc_swils_rscn_addrfmt_val), 0x0F,
           NULL, HFILL}},

        { &hf_swils_rscn_affectedport,
          {"Affected Port ID", "swils.rscn.affectedport",
           FT_BYTES, SEP_DOT, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_rscn_detectfn,
          {"Detection Function", "swils.rscn.detectfn",
           FT_UINT32, BASE_HEX, VALS(fc_swils_rscn_detectfn_val), 0x0,
           NULL, HFILL}},

        { &hf_swils_rscn_portstate,
          {"Port State", "swils.rscn.portstate",
           FT_UINT8, BASE_HEX, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_rscn_portid,
          {"Port Id", "swils.rscn.portid",
           FT_BYTES, SEP_DOT, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_rscn_pwwn,
          {"Port WWN", "swils.rscn.pwwn",
           FT_FCWWN, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_rscn_nwwn,
          {"Node WWN", "swils.rscn.nwwn",
           FT_FCWWN, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_esc_swvendorid,
          {"Switch Vendor ID", "swils.esc.swvendor",
           FT_STRING, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_esc_pdesc_vendorid,
          {"Vendor ID", "swils.esc.vendorid",
           FT_STRING, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_esc_protocolid,
          {"Protocol ID", "swils.esc.protocol",
           FT_UINT16, BASE_HEX, VALS(fc_swils_esc_protocol_val), 0x0,
           NULL, HFILL}},

        { &hf_swils_zone_activezonenm,
          {"Active Zoneset Name", "swils.mr.activezonesetname",
           FT_STRING, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_zone_objname,
          {"Zone Object Name", "swils.zone.zoneobjname",
           FT_STRING, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_zone_objtype,
          {"Zone Object Type", "swils.zone.zoneobjtype",
           FT_UINT8, BASE_HEX, VALS(fc_swils_zoneobj_type_val), 0x0,
           NULL, HFILL}},

        { &hf_swils_zone_mbrtype,
          {"Zone Member Type", "swils.zone.mbrtype",
           FT_UINT8, BASE_HEX, VALS(fc_swils_zonembr_type_val), 0x0,
           NULL, HFILL}},

        { &hf_swils_zone_protocol,
          {"Zone Protocol", "swils.zone.protocol",
           FT_UINT8, BASE_HEX, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_zone_mbrid,
          {"Member Identifier", "swils.zone.mbrid",
           FT_STRING, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_zone_mbrid_fcwwn,
          {"Member Identifier", "swils.zone.mbrid.fcwwn",
           FT_FCWWN, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_zone_mbrid_fc,
          {"Member Identifier", "swils.zone.mbrid.fc",
           FT_BYTES, SEP_DOT, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_zone_mbrid_uint,
          {"Member Identifier", "swils.zone.mbrid.uint",
           FT_UINT32, BASE_HEX, NULL, 0x0,
           NULL, 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,
           NULL, HFILL}},

        { &hf_swils_sfc_opcode,
          {"Operation Request", "swils.sfc.opcode",
           FT_UINT8, BASE_HEX, VALS(fc_swils_sfc_op_val), 0x0,
           NULL, HFILL}},

        { &hf_swils_sfc_zonenm,
          {"Zone Set Name", "swils.sfc.zonename",
           FT_STRING, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_rjt,
          {"Reason Code", "swils.rjt.reason",
           FT_UINT8, BASE_HEX, VALS(fc_swils_rjt_val), 0x0,
           NULL, HFILL}},

        { &hf_swils_rjtdet,
          {"Reason Code Explanation", "swils.rjt.reasonexpl",
           FT_UINT8, BASE_HEX, VALS(fc_swils_deterr_val), 0x0,
           NULL, HFILL}},

        { &hf_swils_rjtvendor,
          {"Vendor Unique Error Code", "swils.rjt.vendor",
           FT_UINT8, BASE_HEX, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_zone_mbrid_lun,
          {"LUN", "swils.zone.lun",
           FT_BYTES, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_ess_rev,
          {"Revision", "swils.ess.revision",
           FT_UINT32, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_ess_len,
          {"Payload Length", "swils.ess.leb",
           FT_UINT32, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_ess_numobj,
          {"Number of Capability Objects", "swils.ess.numobj",
           FT_UINT16, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_interconnect_list_len,
          {"List Length", "swils.ess.listlen",
           FT_UINT8, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_ess_vendorname,
          {"Vendor Name", "swils.ess.vendorname",
           FT_STRING, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_ess_modelname,
          {"Model Name", "swils.ess.modelname",
           FT_STRING, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_ess_relcode,
          {"Release Code", "swils.ess.relcode",
           FT_STRING, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_ess_vendorspecific,
          {"Vendor Specific", "swils.ess.vendorspecific",
           FT_STRING, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_ess_cap_type,
          {"Type", "swils.ess.capability.type",
           FT_UINT8, BASE_DEC, VALS(fc_ct_gstype_vals), 0x0,
           NULL, HFILL}},

        { &hf_swils_ess_cap_subtype,
          {"Subtype", "swils.ess.capability.subtype",
           FT_UINT8, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_ess_cap_numentries,
          {"Number of Entries", "swils.ess.capability.numentries",
           FT_UINT8, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_ess_cap_svc,
          {"Service Name", "swils.ess.capability.service",
           FT_UINT8, BASE_DEC, VALS(fc_ct_gsserver_vals), 0x0,
           NULL, HFILL}},

        { &hf_swils_ess_dns_obj0h,
          {"Name Server Entry Object 00h Support", "swils.ess.capability.dns.obj0h",
           FT_BOOLEAN, 8, NULL, 0x1,
           NULL, HFILL}},

        { &hf_swils_ess_dns_obj1h,
          {"Name Server Entry Object 01h Support", "swils.ess.capability.dns.obj1h",
           FT_BOOLEAN, 8, NULL, 0x2,
           NULL, HFILL}},

        { &hf_swils_ess_dns_obj2h,
          {"Name Server Entry Object 02h Support", "swils.ess.capability.dns.obj2h",
           FT_BOOLEAN, 8, NULL, 0x4,
           NULL, HFILL}},

        { &hf_swils_ess_dns_obj3h,
          {"Name Server Entry Object 03h Support", "swils.ess.capability.dns.obj3h",
           FT_BOOLEAN, 8, NULL, 0x8,
           NULL, HFILL}},

        { &hf_swils_ess_dns_zlacc,
          {"GE_PT Zero Length Accepted", "swils.ess.capability.dns.zlacc",
           FT_BOOLEAN, 8, NULL, 0x10,
           NULL, HFILL}},

        { &hf_swils_ess_dns_vendor,
          {"Vendor Specific Flags", "swils.ess.capability.dns.vendor",
           FT_UINT32, BASE_HEX, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_ess_fctlr_rscn,
          {"SW_RSCN Supported", "swils.ess.capability.fctlr.rscn",
           FT_BOOLEAN, 8, NULL, 0x1,
           NULL, HFILL}},

        { &hf_swils_ess_fctlr_vendor,
          {"Vendor Specific Flags", "swils.ess.capability.fctlr.vendor",
           FT_UINT32, BASE_HEX, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_ess_fcs_basic,
          {"Basic Configuration Services", "swils.ess.capability.fcs.basic",
           FT_BOOLEAN, 8, NULL, 0x1,
           NULL, HFILL}},

        { &hf_swils_ess_fcs_platform,
          {"Platform Configuration Services", "swils.ess.capability.fcs.platform",
           FT_BOOLEAN, 8, NULL, 0x2,
           NULL, HFILL}},

        { &hf_swils_ess_fcs_topology,
          {"Topology Discovery Services", "swils.ess.capability.fcs.topology",
           FT_BOOLEAN, 8, NULL, 0x4,
           NULL, HFILL}},

        { &hf_swils_ess_fcs_enhanced,
          {"Enhanced Configuration Services", "swils.ess.capability.fcs.enhanced",
           FT_BOOLEAN, 8, NULL, 0x8,
           NULL, HFILL}},

        { &hf_swils_ess_fzs_enh_supp,
          {"Enhanced Zoning Supported", "swils.ess.capability.fzs.ezonesupp",
           FT_BOOLEAN, 8, NULL, 0x1,
           NULL, HFILL}},

        { &hf_swils_ess_fzs_enh_ena,
          {"Enhanced Zoning Enabled", "swils.ess.capability.fzs.ezoneena",
           FT_BOOLEAN, 8, NULL, 0x2,
           NULL, HFILL}},

        { &hf_swils_ess_fzs_mr,
          {"Merge Control Setting", "swils.ess.capability.fzs.mr",
           FT_BOOLEAN, 8, NULL, 0x4,
           NULL, HFILL}},

        { &hf_swils_ess_fzs_defzone,
          {"Default Zone Setting", "swils.ess.capability.fzs.defzone",
           FT_BOOLEAN, 8, NULL, 0x8,
           NULL, HFILL}},

        { &hf_swils_ess_fzs_zsdb_supp,
          {"Zoneset Database Supported", "swils.ess.capability.fzs.zsdbsupp",
           FT_BOOLEAN, 8, NULL, 0x10,
           NULL, HFILL}},

        { &hf_swils_ess_fzs_zsdb_ena,
          {"Zoneset Database Enabled", "swils.ess.capability.fzs.zsdbena",
           FT_BOOLEAN, 8, NULL, 0x20,
           NULL, HFILL}},

        { &hf_swils_ess_fzs_adc_supp,
          {"Active Direct Command Supported", "swils.ess.capability.fzs.adcsupp",
           FT_BOOLEAN, 8, NULL, 0x40,
           NULL, HFILL}},

        { &hf_swils_ess_fzs_hardzone,
          {"Hard Zoning Supported", "swils.ess.capability.fzs.hardzone",
           FT_BOOLEAN, 8, NULL, 0x80,
           NULL, HFILL}},

        { &hf_swils_ess_cap_len,
          {"Length", "swils.ess.capability.length",
           FT_UINT8, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_ess_cap_t10,
          {"T10 Vendor ID", "swils.ess.capability.t10id",
           FT_STRING, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_ess_cap_vendorobj,
          {"Vendor-Specific Info", "swils.ess.capability.vendorobj",
           FT_BYTES, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_mrra_rev,
          {"Revision", "swils.mrra.revision",
           FT_UINT32, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_mrra_size,
          {"Merge Request Size", "swils.mrra.size",
           FT_UINT32, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_mrra_vendorid,
          {"Vendor ID", "swils.mrra.vendorid",
           FT_STRING, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_mrra_vendorinfo,
          {"Vendor-Specific Info", "swils.mrra.vendorinfo",
           FT_BYTES, BASE_NONE, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_mrra_reply,
          {"MRRA Response", "swils.mrra.reply",
           FT_UINT32, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_mrra_reply_size,
          {"Maximum Resources Available", "swils.mrra.replysize",
           FT_UINT32, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

        { &hf_swils_mrra_waittime,
          {"Waiting Period (secs)", "swils.mrra.waittime",
           FT_UINT32, BASE_DEC, NULL, 0x0,
           NULL, HFILL}},

      /* Generated from convert_proto_tree_add_text.pl */
      { &hf_swils_requested_domain_id, { "Requested Domain ID", "swils.requested_domain_id", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
      { &hf_swils_granted_domain_id, { "Granted Domain ID", "swils.granted_domain_id", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
      { &hf_swils_lsrh_lsr_age, { "LSR Age", "swils.lsr.age", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, &units_seconds, 0x0, NULL, HFILL }},
      { &hf_swils_lsrh_options, { "Options", "swils.lsr.options", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
      { &hf_swils_lsrh_checksum, { "Checksum", "swils.lsr.checksum", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
      { &hf_swils_lsrh_lsr_length, { "LSR Length", "swils.lsr.length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
      { &hf_swils_lsrec_number_of_links, { "Number of Links", "swils.lsr.number_of_links", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
      { &hf_swils_lsupdate_flags, { "Flags", "swils.lsupdate.flags", FT_UINT8, BASE_HEX, VALS(fc_swils_fspf_lsrflags_val), 0x0, NULL, HFILL }},
      { &hf_swils_lsupdate_num_of_lsrs, { "Num of LSRs", "swils.lsupdate.num_of_lsrs", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
      { &hf_swils_lsack_flags, { "Flags", "swils.lsack.flags", FT_UINT8, BASE_HEX, VALS(fc_swils_fspf_lsrflags_val), 0x0, NULL, HFILL }},
      { &hf_swils_lsack_num_of_lsr_headers, { "Num of LSR Headers", "swils.lsack.num_of_lsr_headers", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
      { &hf_swils_rscn_num_entries, { "Num Entries", "swils.rscn.num_entries", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
      { &hf_swils_zone_mbrflags, { "Flags", "swils.zone.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
      { &hf_swils_zone_mbr_identifier_length, { "Identifier Length", "swils.zone.identifier_length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
      { &hf_swils_zone_num_members, { "4", "swils.zone.num_members", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
      { &hf_swils_zone_active_zoneset_length, { "Active ZoneSet Length", "swils.zone.active_zoneset_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
      { &hf_swils_zone_num_zoning_objects, { "Number of zoning objects", "swils.zone.num_zoning_objects", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
      { &hf_swils_zone_full_zone_set_length, { "Full Zone Set Length", "swils.zone.full_zone_set_length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
      { &hf_swils_zone_vendor_unique, { "Vendor Unique", "swils.zone.vendor_unique", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
      { &hf_swils_domain_id_list_length, { "Domain ID List Length", "swils.aca.domain_id_list_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
      { &hf_swils_sfc_zoneset_length, { "ZoneSet Length", "swils.sfc.zoneset_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
      { &hf_swils_esc_payload_length, { "Payload Length", "swils.esc.payload_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
    };

    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,
        &ett_fcswils_ieinfo,
        &ett_fcswils_capinfo
    };

    static ei_register_info ei[] = {
        { &ei_swils_efp_record_len, { "swils.efp.recordlen.zero", PI_UNDECODED, PI_NOTE, "Record length is zero", EXPFILL }},
        { &ei_swils_no_exchange, { "swils.no_exchange", PI_UNDECODED, PI_WARN, "No record of Exchg. Unable to decode", EXPFILL }},
        { &ei_swils_zone_mbrid, { "swils.zone.mbrid.unknown_type", PI_PROTOCOL, PI_WARN, "Unknown member type format", EXPFILL }},
    };

    expert_module_t* expert_fcswils;

    proto_fcswils = proto_register_protocol("Fibre Channel SW_ILS", "FC-SWILS", "swils");

    proto_register_field_array(proto_fcswils, hf, array_length(hf));
    proto_register_subtree_array(ett, array_length(ett));
    expert_fcswils = expert_register_protocol(proto_fcswils);
    expert_register_field_array(expert_fcswils, ei, array_length(ei));

    fcswils_req_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), fcswils_hash, fcswils_equal);
}

void
proto_reg_handoff_fcswils(void)
{
    dissector_handle_t swils_handle;

    swils_handle = create_dissector_handle(dissect_fcswils, proto_fcswils);
    dissector_add_uint("fc.ftype", FC_FTYPE_SWILS, swils_handle);

    fcsp_handle = find_dissector_add_dependency("fcsp", proto_fcswils);
}

/*
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
 *
 * Local variables:
 * c-basic-offset: 4
 * tab-width: 8
 * indent-tabs-mode: nil
 * End:
 *
 * vi: set shiftwidth=4 tabstop=8 expandtab:
 * :indentSize=4:tabSize=8:noTabs=true:
 */
