summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGerald Combs <gerald@wireshark.org>2002-12-08 02:32:36 +0000
committerGerald Combs <gerald@wireshark.org>2002-12-08 02:32:36 +0000
commitb60b1414c39e902281dd7c819cb2deb5083d6bcc (patch)
tree0eb50f10825095cede74b16fe654c9e89ca64281
parentc2ecb0daa5c959f4c0bcc36443b90eb545d294db (diff)
downloadwireshark-b60b1414c39e902281dd7c819cb2deb5083d6bcc.tar.gz
From Dinesh Dutt: Add Fibre Channel support, including FCIP, Basic FC
header, Extended Link Service, Interswitch Link Service, FCP, and IPFC. svn path=/trunk/; revision=6757
-rw-r--r--Makefile.am13
-rw-r--r--Makefile.nmake8
-rw-r--r--column.c38
-rw-r--r--epan/column-utils.c25
-rw-r--r--epan/column_info.h4
-rw-r--r--epan/conversation.c50
-rw-r--r--epan/packet.c5
-rw-r--r--epan/packet_info.h10
-rw-r--r--epan/to_str.c114
-rw-r--r--epan/to_str.h15
-rw-r--r--packet-fc.c786
-rw-r--r--packet-fc.h153
-rw-r--r--packet-fcbls.h87
-rw-r--r--packet-fcels.c1978
-rw-r--r--packet-fcels.h321
-rw-r--r--packet-fcip.c619
-rw-r--r--packet-fclctl.c102
-rw-r--r--packet-fclctl.h174
-rw-r--r--packet-fcp.c690
-rw-r--r--packet-fcp.h69
-rw-r--r--packet-fcswils.c1727
-rw-r--r--packet-fcswils.h389
-rw-r--r--packet-ipfc.c155
-rw-r--r--packet-llc.c3
24 files changed, 7501 insertions, 34 deletions
diff --git a/Makefile.am b/Makefile.am
index 8e6aff81f7..e9c73d4e3d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,7 @@
# Makefile.am
# Automake file for Ethereal
#
-# $Id: Makefile.am,v 1.524 2002/12/07 21:43:27 gerald Exp $
+# $Id: Makefile.am,v 1.525 2002/12/08 02:32:17 gerald Exp $
#
# Ethereal - Network traffic analyzer
# By Gerald Combs <gerald@ethereal.com>
@@ -179,6 +179,12 @@ DISSECTOR_SRC = \
packet-esis.c \
packet-eth.c \
packet-ethertype.c \
+ packet-fc.c \
+ packet-fcels.c \
+ packet-fcip.c \
+ packet-fclctl.c \
+ packet-fcp.c \
+ packet-fcswils.c \
packet-fddi.c \
packet-fix.c \
packet-fr.c \
@@ -505,6 +511,11 @@ noinst_HEADERS = \
packet-dvmrp.h \
packet-esis.h \
packet-eth.h \
+ packet-fc.h \
+ packet-fcels.h \
+ packet-fclctl.h \
+ packet-fcp.h \
+ packet-fcswils.h \
packet-fddi.h \
packet-frame.h \
packet-giop.h \
diff --git a/Makefile.nmake b/Makefile.nmake
index 68e738a897..f75d32c10c 100644
--- a/Makefile.nmake
+++ b/Makefile.nmake
@@ -1,7 +1,7 @@
## Makefile for building ethereal.exe with Microsoft C and nmake
## Use: $(MAKE) /$(MAKEFLAGS) -f makefile.nmake
#
-# $Id: Makefile.nmake,v 1.259 2002/12/03 00:37:27 guy Exp $
+# $Id: Makefile.nmake,v 1.260 2002/12/08 02:32:17 gerald Exp $
include config.nmake
include <win32.mak>
@@ -122,6 +122,12 @@ DISSECTOR_SRC = \
packet-esis.c \
packet-eth.c \
packet-ethertype.c \
+ packet-fc.c \
+ packet-fcels.c \
+ packet-fcip.c \
+ packet-fclctl.c \
+ packet-fcp.c \
+ packet-fcswils.c \
packet-fddi.c \
packet-fix.c \
packet-fr.c \
diff --git a/column.c b/column.c
index 68276740b1..6e295a7e78 100644
--- a/column.c
+++ b/column.c
@@ -1,7 +1,7 @@
/* column.c
* Routines for handling column preferences
*
- * $Id: column.c,v 1.37 2002/08/28 21:00:06 jmayer Exp $
+ * $Id: column.c,v 1.38 2002/12/08 02:32:17 gerald Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -52,8 +52,8 @@ col_format_to_string(gint fmt) {
"%us","%hs", "%rhs", "%uhs", "%ns", "%rns", "%uns", "%d",
"%rd", "%ud", "%hd", "%rhd", "%uhd", "%nd", "%rnd",
"%und", "%S", "%rS", "%uS", "%D", "%rD", "%uD", "%p",
- "%i", "%L" };
-
+ "%i", "%L", "%XO", "%XR" };
+
if (fmt < 0 || fmt > NUM_COL_FMTS)
return NULL;
@@ -79,10 +79,8 @@ col_format_desc(gint fmt) {
"Source port", "Src port (resolved)",
"Src port (unresolved)", "Destination port",
"Dest port (resolved)", "Dest port (unresolved)",
- "Protocol", "Information", "Packet length (bytes)" };
-
- if (fmt < 0 || fmt > NUM_COL_FMTS)
- return NULL;
+ "Protocol", "Information", "Packet length (bytes)" ,
+ "OXID", "RXID", };
return(dlist[fmt]);
}
@@ -140,6 +138,12 @@ get_column_format_matches(gboolean *fmt_list, gint format) {
case COL_DEF_DST_PORT:
fmt_list[COL_RES_DST_PORT] = TRUE;
break;
+ case COL_OXID:
+ fmt_list[COL_OXID] = TRUE;
+ break;
+ case COL_RXID:
+ fmt_list[COL_RXID] = TRUE;
+ break;
default:
break;
}
@@ -216,6 +220,10 @@ get_column_longest_string(gint format)
case COL_PACKET_LENGTH:
return "000000";
break;
+ case COL_RXID:
+ case COL_OXID:
+ return "000000";
+ break;
default: /* COL_INFO */
return "Source port: kerberos-master Destination port: kerberos-master";
break;
@@ -270,6 +278,8 @@ get_column_resize_type(gint format) {
case COL_DEF_NET_DST:
case COL_RES_NET_DST:
case COL_UNRES_NET_DST:
+ case COL_OXID:
+ case COL_RXID:
/* We don't want these to resize dynamically; if they get resolved
to names, those names could be very long, and auto-resizing
columns showing those names may leave too little room for
@@ -313,6 +323,7 @@ gint
get_column_format_from_str(gchar *str) {
gchar *cptr = str;
gint res_off = RES_DEF, addr_off = ADDR_DEF, time_off = TIME_DEF;
+ gint prev_code = -1;
/* To do: Make this parse %-formatted strings "for real" */
while (*cptr != '\0') {
@@ -354,7 +365,12 @@ get_column_format_from_str(gchar *str) {
addr_off = ADDR_NET;
break;
case 'R':
- time_off = TIME_REL;
+ if (prev_code == COL_OXID) {
+ return COL_RXID;
+ }
+ else {
+ time_off = TIME_REL;
+ }
break;
case 'A':
time_off = TIME_ABS;
@@ -368,6 +384,12 @@ get_column_format_from_str(gchar *str) {
case 'L':
return COL_PACKET_LENGTH;
break;
+ case 'X':
+ prev_code = COL_OXID;
+ break;
+ case 'O':
+ return COL_OXID;
+ break;
}
cptr++;
}
diff --git a/epan/column-utils.c b/epan/column-utils.c
index a4aad6d790..6238ab74af 100644
--- a/epan/column-utils.c
+++ b/epan/column-utils.c
@@ -1,7 +1,7 @@
/* column-utils.c
* Routines for column utilities.
*
- * $Id: column-utils.c,v 1.27 2002/12/03 02:38:39 guy Exp $
+ * $Id: column-utils.c,v 1.28 2002/12/08 02:32:35 gerald Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -364,6 +364,8 @@ col_set_addr(packet_info *pinfo, int col, address *addr, gboolean is_res,
struct e_in6_addr ipv6_addr;
struct atalk_ddp_addr ddp_addr;
struct sna_fid_type_4_addr sna_fid_type_4_addr;
+ gchar *fcid;
+ guint32 tmpfc;
pinfo->cinfo->col_expr[col][0] = '\0';
pinfo->cinfo->col_expr_val[col][0] = '\0';
@@ -484,6 +486,15 @@ col_set_addr(packet_info *pinfo, int col, address *addr, gboolean is_res,
strcpy(pinfo->cinfo->col_expr_val[col],pinfo->cinfo->col_buf[col]);
break;
+ case AT_FC:
+ tmpfc = *((guint32 *)addr->data);
+ fcid = fc_to_str ((const guint8 *)&tmpfc);
+
+ strncpy (pinfo->cinfo->col_buf[col], fcid, COL_MAX_LEN);
+ pinfo->cinfo->col_buf[col][COL_MAX_LEN - 1] = '\0';
+ pinfo->cinfo->col_data[col] = pinfo->cinfo->col_buf[col];
+ break;
+
default:
break;
}
@@ -676,6 +687,18 @@ fill_in_columns(packet_info *pinfo)
strcpy(pinfo->cinfo->col_expr_val[i], pinfo->cinfo->col_buf[i]);
break;
+ case COL_OXID:
+ snprintf (pinfo->cinfo->col_buf[i], COL_MAX_LEN, "0x%x", pinfo->oxid);
+ pinfo->cinfo->col_buf[i][COL_MAX_LEN - 1] = '\0';
+ pinfo->cinfo->col_data[i] = pinfo->cinfo->col_buf[i];
+ break;
+
+ case COL_RXID:
+ snprintf (pinfo->cinfo->col_buf[i], COL_MAX_LEN, "0x%x", pinfo->rxid);
+ pinfo->cinfo->col_buf[i][COL_MAX_LEN - 1] = '\0';
+ pinfo->cinfo->col_data[i] = pinfo->cinfo->col_buf[i];
+ break;
+
case NUM_COL_FMTS: /* keep compiler happy - shouldn't get here */
g_assert_not_reached();
break;
diff --git a/epan/column_info.h b/epan/column_info.h
index e645fbb2fd..6aa86964a5 100644
--- a/epan/column_info.h
+++ b/epan/column_info.h
@@ -1,7 +1,7 @@
/* column.h
* Definitions for column structures and routines
*
- * $Id: column_info.h,v 1.3 2002/08/28 20:40:44 jmayer Exp $
+ * $Id: column_info.h,v 1.4 2002/12/08 02:32:36 gerald Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@@ -85,6 +85,8 @@ enum {
COL_PROTOCOL, /* Protocol */
COL_INFO, /* Description */
COL_PACKET_LENGTH, /* Packet length in bytes */
+ COL_OXID, /* Fibre Channel OXID */
+ COL_RXID, /* Fibre Channel RXID */
NUM_COL_FMTS /* Should always be last */
};
diff --git a/epan/conversation.c b/epan/conversation.c
index 09a5f5c240..95e6536999 100644
--- a/epan/conversation.c
+++ b/epan/conversation.c
@@ -1,7 +1,7 @@
/* conversation.c
* Routines for building lists of packets that are part of a "conversation"
*
- * $Id: conversation.c,v 1.22 2002/11/27 22:44:41 guy Exp $
+ * $Id: conversation.c,v 1.23 2002/12/08 02:32:36 gerald Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -621,7 +621,17 @@ find_conversation(address *addr_a, address *addr_b, port_type ptype,
*/
conversation =
conversation_lookup_hashtable(conversation_hashtable_exact,
- addr_a, addr_b, ptype, port_a, port_b);
+ addr_a, addr_b, ptype,
+ port_a, port_b);
+ if ((conversation == NULL) && (addr_a->type == AT_FC)) {
+ /* In Fibre channel, OXID & RXID are never swapped as
+ * TCP/UDP ports are in TCP/IP.
+ */
+ conversation =
+ conversation_lookup_hashtable(conversation_hashtable_exact,
+ addr_b, addr_a, ptype,
+ port_a, port_b);
+ }
if (conversation != NULL)
return conversation;
}
@@ -643,6 +653,15 @@ find_conversation(address *addr_a, address *addr_b, port_type ptype,
conversation =
conversation_lookup_hashtable(conversation_hashtable_no_addr2,
addr_a, addr_b, ptype, port_a, port_b);
+ if ((conversation == NULL) && (addr_a->type == AT_FC)) {
+ /* In Fibre channel, OXID & RXID are never swapped as
+ * TCP/UDP ports are in TCP/IP.
+ */
+ conversation =
+ conversation_lookup_hashtable(conversation_hashtable_no_addr2,
+ addr_b, addr_a, ptype,
+ port_a, port_b);
+ }
if (conversation != NULL) {
/*
* If search address B isn't wildcarded, and this
@@ -673,9 +692,9 @@ find_conversation(address *addr_a, address *addr_b, port_type ptype,
* ("addr_a" doesn't take part in this lookup.)
*/
if (!(options & NO_ADDR_B)) {
- conversation =
- conversation_lookup_hashtable(conversation_hashtable_no_addr2,
- addr_b, addr_a, ptype, port_b, port_a);
+ conversation =
+ conversation_lookup_hashtable(conversation_hashtable_no_addr2,
+ addr_b, addr_a, ptype, port_b, port_a);
if (conversation != NULL) {
/*
* If this is for a connection-oriented
@@ -711,6 +730,14 @@ find_conversation(address *addr_a, address *addr_b, port_type ptype,
conversation =
conversation_lookup_hashtable(conversation_hashtable_no_port2,
addr_a, addr_b, ptype, port_a, port_b);
+ if ((conversation == NULL) && (addr_a->type == AT_FC)) {
+ /* In Fibre channel, OXID & RXID are never swapped as
+ * TCP/UDP ports are in TCP/IP
+ */
+ conversation =
+ conversation_lookup_hashtable(conversation_hashtable_no_port2,
+ addr_b, addr_a, ptype, port_a, port_b);
+ }
if (conversation != NULL) {
/*
* If search port B isn't wildcarded, and this is
@@ -805,9 +832,16 @@ find_conversation(address *addr_a, address *addr_b, port_type ptype,
* first packet in the conversation).
* (Neither "addr_a" nor "port_a" take part in this lookup.)
*/
- conversation =
- conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2,
- addr_b, addr_a, ptype, port_b, port_a);
+ if (addr_a->type == AT_FC)
+ conversation =
+ conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2,
+ addr_b, addr_a, ptype, port_a,
+ port_b);
+ else
+ conversation =
+ conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2,
+ addr_b, addr_a, ptype, port_b,
+ port_a);
if (conversation != NULL) {
/*
* If this is for a connection-oriented protocol, set the
diff --git a/epan/packet.c b/epan/packet.c
index 52bda772ed..ab50d0a614 100644
--- a/epan/packet.c
+++ b/epan/packet.c
@@ -1,7 +1,7 @@
/* packet.c
* Routines for packet disassembly
*
- * $Id: packet.c,v 1.83 2002/11/16 21:36:39 guy Exp $
+ * $Id: packet.c,v 1.84 2002/12/08 02:32:36 gerald Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -286,6 +286,9 @@ dissect_packet(epan_dissect_t *edt, union wtap_pseudo_header *pseudo_header,
edt->pi.can_desegment = 0;
edt->pi.p2p_dir = P2P_DIR_UNKNOWN;
edt->pi.private_data = NULL;
+ edt->pi.oxid = 0;
+ edt->pi.rxid = 0;
+ edt->pi.r_ctl = 0;
TRY {
edt->tvb = tvb_new_real_data(pd, fd->cap_len, fd->pkt_len);
diff --git a/epan/packet_info.h b/epan/packet_info.h
index c7bcd95c7e..99b93f55e4 100644
--- a/epan/packet_info.h
+++ b/epan/packet_info.h
@@ -1,7 +1,7 @@
/* packet_info.h
* Definitions for packet info structures and routines
*
- * $Id: packet_info.h,v 1.25 2002/11/08 01:00:07 guy Exp $
+ * $Id: packet_info.h,v 1.26 2002/12/08 02:32:36 gerald Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -39,7 +39,8 @@ typedef enum {
AT_ATALK, /* Appletalk DDP */
AT_VINES, /* Banyan Vines */
AT_OSI, /* OSI NSAP */
- AT_ARCNET /* ARCNET */
+ AT_ARCNET, /* ARCNET */
+ AT_FC /* Fibre Channel */
} address_type;
typedef struct _address {
@@ -96,6 +97,7 @@ typedef enum {
PT_UDP, /* UDP */
PT_IPX, /* IPX sockets */
PT_NCP, /* NCP connection */
+ PT_EXCHG, /* Fibre Channel exchange */
PT_DDP /* DDP AppleTalk connection */
} port_type;
@@ -146,6 +148,10 @@ typedef struct _packet_info {
int iplen;
int iphdrlen;
int p2p_dir;
+ guint16 oxid; /* next 2 fields reqd to identify fibre */
+ guint16 rxid; /* channel conversations */
+ guint8 r_ctl; /* R_CTL field in Fibre Channel Protocol */
+ guint8 pad;
void *private_data; /* pointer to data passed from one dissector to another */
} packet_info;
diff --git a/epan/to_str.c b/epan/to_str.c
index c8b8f83224..fbd579d9c2 100644
--- a/epan/to_str.c
+++ b/epan/to_str.c
@@ -1,7 +1,7 @@
/* to_str.c
* Routines for utilities to convert various other types to strings.
*
- * $Id: to_str.c,v 1.19 2002/11/28 03:54:50 guy Exp $
+ * $Id: to_str.c,v 1.20 2002/12/08 02:32:36 gerald Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -71,7 +71,7 @@
gchar *
ether_to_str(const guint8 *ad)
{
- return ether_to_str_punct(ad, ':');
+ return ether_to_str_punct(ad, ':', 5);
}
/* Places char punct in the string as the hex-digit separator.
@@ -79,7 +79,7 @@ ether_to_str(const guint8 *ad)
* the resulting string is 5 bytes shorter)
*/
gchar *
-ether_to_str_punct(const guint8 *ad, char punct) {
+ether_to_str_punct(const guint8 *ad, char punct, guint32 len) {
static gchar str[3][18];
static gchar *cur;
gchar *p;
@@ -96,7 +96,7 @@ ether_to_str_punct(const guint8 *ad, char punct) {
}
p = &cur[18];
*--p = '\0';
- i = 5;
+ i = len;
for (;;) {
octet = ad[i];
*--p = hex_digits[octet&0xF];
@@ -194,7 +194,7 @@ ipx_addr_to_str(guint32 net, const guint8 *ad)
sprintf(cur, "%s.%s", get_ipxnet_name(net), name);
}
else {
- sprintf(cur, "%s.%s", get_ipxnet_name(net), ether_to_str_punct(ad, '\0'));
+ sprintf(cur, "%s.%s", get_ipxnet_name(net), ether_to_str_punct(ad, '\0', 5));
}
return cur;
}
@@ -522,6 +522,110 @@ rel_time_to_secs_str(nstime_t *rel_time)
return cur;
}
+gchar *
+fc_to_str(const guint8 *ad) {
+ return ether_to_str_punct (ad, '.', 2);
+}
+
+gchar *
+fcwwn_to_str (const guint8 *ad)
+{
+ int fmt;
+ guint8 oui[6];
+ static gchar ethstr[512];
+
+ if (ad == NULL) return NULL;
+
+ fmt = (ad[0] & 0xF0) >> 4;
+
+ if ((fmt == 1) || (fmt == 2)) {
+ memcpy (oui, &ad[2], 6);
+ sprintf (ethstr, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x (%s)", ad[0],
+ ad[1], ad[2], ad[3], ad[4], ad[5], ad[6], ad[7],
+ get_manuf_name (oui));
+ }
+ else if (fmt == 5) {
+ oui[0] = ((ad[0] & 0x0F) << 4) | ((ad[1] & 0xF0) >> 4);
+ oui[1] = ((ad[1] & 0x0F) << 4) | ((ad[2] & 0xF0) >> 4);
+ oui[2] = ((ad[2] & 0x0F) << 4) | ((ad[3] & 0xF0) >> 4);
+ oui[3] = ((ad[3] & 0x0F) << 4) | ((ad[4] & 0xF0) >> 4);
+ oui[4] = ((ad[4] & 0x0F) << 4) | ((ad[5] & 0xF0) >> 4);
+ oui[5] = ((ad[5] & 0x0F) << 4) | ((ad[6] & 0xF0) >> 4);
+
+ sprintf (ethstr, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x (%s)", ad[0],
+ ad[1], ad[2], ad[3], ad[4], ad[5], ad[6], ad[7],
+ get_manuf_name (oui));
+ }
+ else {
+ sprintf (ethstr, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", ad[0],
+ ad[1], ad[2], ad[3], ad[4], ad[5], ad[6], ad[7]);
+ }
+ return (ethstr);
+}
+
+gchar *
+fc_to_str_buf(const guint8 *ad)
+{
+ static gchar str[3][18];
+ static gchar *cur;
+ gchar *p;
+ int i;
+ guint32 octet;
+ static const gchar hex_digits[16] = "0123456789abcdef";
+
+ if (cur == &str[0][0]) {
+ cur = &str[1][0];
+ } else if (cur == &str[1][0]) {
+ cur = &str[2][0];
+ } else {
+ cur = &str[0][0];
+ }
+ p = &cur[18];
+ *--p = '\0';
+ i = 0;
+ for (;;) {
+ octet = ad[i];
+ *--p = hex_digits[octet&0xF];
+ octet >>= 4;
+ *--p = hex_digits[octet&0xF];
+ if (i == 2)
+ break;
+ *--p = '.';
+ i++;
+ }
+ return p;
+/*
+ gchar *p;
+ int i;
+ guint32 octet;
+ guint32 digit;
+ gboolean saw_nonzero;
+
+ p = buf;
+ i = 0;
+ for (;;) {
+ saw_nonzero = FALSE;
+ octet = ad[i];
+ digit = octet/100;
+ if (digit != 0) {
+ *p++ = digit + '0';
+ saw_nonzero = TRUE;
+ }
+ octet %= 100;
+ digit = octet/10;
+ if (saw_nonzero || digit != 0)
+ *p++ = digit + '0';
+ digit = octet%10;
+ *p++ = digit + '0';
+ if (i == 2)
+ break;
+ *p++ = '.';
+ i++;
+ }
+ *p = '\0';
+ */
+}
+
/* Generate, into "buf", a string showing the bits of a bitfield.
Return a pointer to the character after that string. */
char *
diff --git a/epan/to_str.h b/epan/to_str.h
index 2d6668fade..2fa748af6d 100644
--- a/epan/to_str.h
+++ b/epan/to_str.h
@@ -1,7 +1,7 @@
/* to_str.h
* Definitions for utilities to convert various other types to strings.
*
- * $Id: to_str.h,v 1.9 2002/11/28 03:54:50 guy Exp $
+ * $Id: to_str.h,v 1.10 2002/12/08 02:32:36 gerald Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -43,11 +43,16 @@ typedef enum {
* but for which no more specific module applies.
*/
-extern gchar* ether_to_str(const guint8 *);
-extern gchar* ether_to_str_punct(const guint8 *, char);
-extern gchar* ip_to_str(const guint8 *);
-extern void ip_to_str_buf(const guint8 *, gchar *);
+gchar* ether_to_str(const guint8 *);
+gchar* ether_to_str_punct(const guint8 *, char, guint32);
+gchar* ip_to_str(const guint8 *);
+void ip_to_str_buf(const guint8 *, gchar *);
+
struct e_in6_addr;
+
+gchar* fc_to_str(const guint8 *);
+gchar* fc_to_str_buf(const guint8 *);
+gchar* fcwwn_to_str (const guint8 *);
extern char* ip6_to_str(const struct e_in6_addr *);
extern gchar* ipx_addr_to_str(guint32, const guint8 *);
extern gchar* ipxnet_to_string(const guint8 *ad);
diff --git a/packet-fc.c b/packet-fc.c
new file mode 100644
index 0000000000..9cc0a9c71b
--- /dev/null
+++ b/packet-fc.c
@@ -0,0 +1,786 @@
+/* packet-fc.c
+ * Routines for Fibre Channel Decoding (FC Header, Link Ctl & Basic Link Svc)
+ * Copyright 2001, Dinesh G Dutt <ddutt@cisco.com>
+ *
+ * $Id: packet-fc.c,v 1.1 2002/12/08 02:32:17 gerald Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * Copied from WHATEVER_FILE_YOU_USED (where "WHATEVER_FILE_YOU_USED"
+ * is a dissector file; if you just copied this from README.developer,
+ * don't bother with the "Copied from" - you don't even need to put
+ * in a "Copied from" if you copied an existing dissector, especially
+ * if the bulk of the code in the new dissector is your code)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#include <glib.h>
+
+#ifdef NEED_SNPRINTF_H
+# include "snprintf.h"
+#endif
+
+#include <epan/packet.h>
+#include "prefs.h"
+#include "reassemble.h"
+#include "etypes.h"
+#include "packet-fc.h"
+#include "packet-fclctl.h"
+#include "packet-fcbls.h"
+
+#define FC_HEADER_SIZE 24
+#define FC_RCTL_EISL 0x50
+
+/* Size of various fields in FC header in bytes */
+#define FC_RCTL_SIZE 1
+#define FC_DID_SIZE 3
+#define FC_CSCTL_SIZE 1
+#define FC_SID_SIZE 3
+#define FC_TYPE_SIZE 1
+#define FC_FCTL_SIZE 3
+#define FC_SEQID_SIZE 1
+#define FC_DFCTL_SIZE 1
+#define FC_SEQCNT_SIZE 2
+#define FC_OXID_SIZE 2
+#define FC_RXID_SIZE 2
+#define FC_PARAM_SIZE 4
+
+/* Initialize the protocol and registered fields */
+static int proto_fc = -1;
+static int hf_fc_rctl = -1;
+static int hf_fc_did = -1;
+static int hf_fc_csctl = -1;
+static int hf_fc_sid = -1;
+static int hf_fc_type = -1;
+static int hf_fc_fctl = -1;
+static int hf_fc_seqid = -1;
+static int hf_fc_dfctl = -1;
+static int hf_fc_seqcnt = -1;
+static int hf_fc_oxid = -1;
+static int hf_fc_rxid = -1;
+static int hf_fc_param = -1;
+static int hf_fc_ftype = -1; /* Derived field, non-existent in FC hdr */
+static int hf_fc_exchg_orig = -1;
+static int hf_fc_exchg_resp = -1;
+static int hf_fc_reassembled = -1;
+
+/* For Basic Link Svc */
+static int hf_fc_bls_seqid_vld = -1;
+static int hf_fc_bls_lastvld_seqid = -1;
+static int hf_fc_bls_oxid = -1;
+static int hf_fc_bls_rxid = -1;
+static int hf_fc_bls_lowseqcnt = -1;
+static int hf_fc_bls_hiseqcnt = -1;
+static int hf_fc_bls_rjtcode = -1;
+static int hf_fc_bls_rjtdetail = -1;
+static int hf_fc_bls_vendor = -1;
+
+/* Initialize the subtree pointers */
+static gint ett_fc = -1;
+static gint ett_fcbls = -1;
+
+static dissector_table_t fcftype_dissector_table;
+static dissector_handle_t data_handle;
+
+/* Reassembly stuff */
+static gboolean fc_reassemble = TRUE;
+static guint32 fc_max_frame_size = 1024;
+static GHashTable *fc_fragment_table = NULL;
+
+static void fc_defragment_init(void)
+{
+ fragment_table_init(&fc_fragment_table);
+}
+
+
+static gchar *
+fctl_to_str (const guint8 *fctl, gchar *str, gboolean is_ack)
+{
+ int stroff = 0;
+ guint8 tmp = 0;
+
+ if (str == NULL)
+ return (str);
+
+ if (fctl[0] & 0x80) {
+ strcpy (str, "Exchange Responder, ");
+ stroff += 20;
+ }
+ else {
+ strcpy (str, "Exchange Originator, ");
+ stroff += 21;
+ }
+
+ if (fctl[0] & 0x40) {
+ strcpy (&str[stroff], "Seq Recipient, ");
+ stroff += 15;
+ }
+ else {
+ strcpy (&str[stroff], "Seq Initiator, ");
+ stroff += 15;
+ }
+
+ if (fctl[0] & 0x20) {
+ strcpy (&str[stroff], "Exchg First, ");
+ stroff += 13;
+ }
+
+ if (fctl[0] & 0x10) {
+ strcpy (&str[stroff], "Exchg Last, ");
+ stroff += 12;
+ }
+
+ if (fctl[0] & 0x8) {
+ strcpy (&str[stroff], "Seq Last, ");
+ stroff += 10;
+ }
+
+ if (fctl[0] & 0x2) {
+ strcpy (&str[stroff], "Priority, ");
+ stroff += 10;
+ }
+ else {
+ strcpy (&str[stroff], "CS_CTL, ");
+ stroff += 8;
+ }
+
+ if (fctl[0] & 0x1) {
+ strcpy (&str[stroff], "Transfer Seq Initiative, ");
+ stroff += 25;
+ }
+
+ if (fctl[1] & 0x30) {
+ strcpy (&str[stroff], "ACK_0 Reqd, ");
+ stroff += 12;
+ }
+ else if (fctl[1] & 0x10) {
+ strcpy (&str[stroff], "ACK_1 Reqd, ");
+ stroff += 12;
+ }
+
+ if (fctl[1] & 0x2) {
+ strcpy (&str[stroff], "Rexmitted Seq, ");
+ stroff += 15;
+ }
+
+ tmp = fctl[2] & 0xC0;
+ switch (tmp) {
+ case 0:
+ strcpy (&str[stroff], "Last Data Frame - No Info, ");
+ stroff += 27;
+ break;
+ case 1:
+ strcpy (&str[stroff], "Last Data Frame - Seq Imm, ");
+ stroff += 27;
+ break;
+ case 2:
+ strcpy (&str[stroff], "Last Data Frame - Seq Soon, ");
+ stroff += 28;
+ break;
+ case 3:
+ strcpy (&str[stroff], "Last Data Frame - Seq Delyd, ");
+ stroff += 29;
+ break;
+ }
+
+ tmp = fctl[2] & 0x30;
+ switch (tmp) {
+ case 0:
+ if (is_ack) {
+ strcpy (&str[stroff], "ABTS - Cont, ");
+ stroff += 13;
+ }
+ else {
+ strcpy (&str[stroff], "ABTS - Abort/MS, ");
+ stroff += 17;
+ }
+ break;
+ case 0x10:
+ if (is_ack) {
+ strcpy (&str[stroff], "ABTS - Abort, ");
+ stroff += 14;
+ }
+ else {
+ strcpy (&str[stroff], "ABTS - Abort/SS, ");
+ stroff += 17;
+ }
+ break;
+ case 0x20:
+ if (is_ack) {
+ strcpy (&str[stroff], "ABTS - Stop, ");
+ stroff += 13;
+ }
+ else {
+ strcpy (&str[stroff], "ABTS - Process/IB, ");
+ stroff += 19;
+ }
+ break;
+ case 0x30:
+ if (is_ack) {
+ strcpy (&str[stroff], "ABTS - Imm Seq Retx, ");
+ stroff += 21;
+ }
+ else {
+ strcpy (&str[stroff], "ABTS - Discard/MS/Imm Retx, ");
+ stroff += 28;
+ }
+ break;
+ }
+
+ if (fctl[2] & 0x8) {
+ strcpy (&str[stroff], "Rel Offset = 1");
+ stroff += 14;
+ }
+
+ return (str);
+}
+
+/* BA_ACC & BA_RJT are decoded in this file itself instead of a traditional
+ * dedicated file and dissector format because the dissector would require some
+ * fields of the FC_HDR such as param in some cases, type in some others, the
+ * lower 4 bits of r_ctl in some other cases etc. So, we decode BLS & Link Ctl
+ * in this file itself.
+ */
+static void
+dissect_fc_ba_acc (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ proto_item *ti;
+ proto_tree *acc_tree;
+ int offset = 0;
+
+ /* Make entries in Protocol column and Info column on summary display */
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "BLS");
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "BA_ACC");
+
+ if (tree) {
+ ti = proto_tree_add_text (tree, tvb, 0, tvb_length (tvb), "Basic Link Svc");
+ acc_tree = proto_item_add_subtree (ti, ett_fcbls);
+
+ proto_tree_add_item (acc_tree, hf_fc_bls_seqid_vld, tvb, offset++, 1, 0);
+ proto_tree_add_item (acc_tree, hf_fc_bls_lastvld_seqid, tvb, offset++, 1, 0);
+ offset += 2; /* Skip reserved field */
+ proto_tree_add_item (acc_tree, hf_fc_bls_oxid, tvb, offset, 2, 0);
+ offset += 2;
+ proto_tree_add_item (acc_tree, hf_fc_bls_rxid, tvb, offset, 2, 0);
+ offset += 2;
+ proto_tree_add_item (acc_tree, hf_fc_bls_lowseqcnt, tvb, offset, 2, 0);
+ offset += 2;
+ proto_tree_add_item (acc_tree, hf_fc_bls_hiseqcnt, tvb, offset, 2, 0);
+ }
+}
+
+static void
+dissect_fc_ba_rjt (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ proto_item *ti;
+ proto_tree *rjt_tree;
+ int offset = 0;
+
+ /* Make entries in Protocol column and Info column on summary display */
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "BLS");
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "BA_RJT");
+
+ if (tree) {
+ ti = proto_tree_add_text (tree, tvb, 0, tvb_length (tvb), "Basic Link Svc");
+ rjt_tree = proto_item_add_subtree (ti, ett_fcbls);
+
+ proto_tree_add_item (rjt_tree, hf_fc_bls_rjtcode, tvb, offset+1, 1, 0);
+ proto_tree_add_item (rjt_tree, hf_fc_bls_rjtdetail, tvb, offset+2, 1, 0);
+ proto_tree_add_item (rjt_tree, hf_fc_bls_vendor, tvb, offset+3, 1, 0);
+ }
+}
+
+static guint8
+fc_get_ftype (guint8 r_ctl, guint8 type)
+{
+ /* A simple attempt to determine the upper level protocol based on the
+ * r_ctl & type fields.
+ */
+ switch (r_ctl & 0xF0) {
+ case FC_RCTL_DEV_DATA:
+ switch (type) {
+ case FC_TYPE_SWILS:
+ if ((r_ctl == 0x2) || (r_ctl == 0x3))
+ return FC_FTYPE_SWILS;
+ else
+ return FC_FTYPE_UNDEF;
+ case FC_TYPE_IP:
+ return FC_FTYPE_IP;
+ case FC_TYPE_SCSI:
+ return FC_FTYPE_SCSI;
+ case FC_TYPE_FCCT:
+ return FC_FTYPE_FCCT;
+ default:
+ return FC_FTYPE_UNDEF;
+ }
+ break;
+ case FC_RCTL_ELS:
+ if (((r_ctl & 0x0F) == 0x2) || ((r_ctl & 0x0F) == 0x3))
+ return FC_FTYPE_ELS;
+ else
+ return FC_FTYPE_UNDEF;
+ break;
+ case FC_RCTL_LINK_DATA:
+ return FC_FTYPE_LINKDATA;
+ break;
+ case FC_RCTL_VIDEO:
+ return FC_FTYPE_VDO;
+ break;
+ case FC_RCTL_BLS:
+ if (type == 0)
+ return FC_FTYPE_BLS;
+ else
+ return FC_FTYPE_UNDEF;
+ break;
+ case FC_RCTL_LINK_CTL:
+ return FC_FTYPE_LINKCTL;
+ break;
+ default:
+ return FC_FTYPE_UNDEF;
+ break;
+ }
+}
+/* Code to actually dissect the packets */
+static void
+dissect_fc (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ proto_item *ti;
+ proto_tree *fc_tree = NULL;
+ tvbuff_t *next_tvb;
+ int offset = 0;
+ gboolean is_lastframe_inseq;
+ gboolean is_exchg_resp = 0;
+ fragment_data *fcfrag_head;
+ guint32 frag_id;
+ guint32 frag_size;
+ guint8 r_ctl, type;
+
+ gchar str[256];
+ guint32 param;
+ guint16 seqcnt;
+ guint8 ftype;
+ gboolean is_ack;
+
+ /* Make entries in Protocol column and Info column on summary display */
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "FC");
+
+ r_ctl = tvb_get_guint8 (tvb, offset);
+
+ /* If the R_CTL is the EISL field, skip the first 8 bytes to retrieve the
+ * real FC header. EISL is Cisco-proprietary and is not decoded.
+ */
+ if (r_ctl == FC_RCTL_EISL) {
+ offset += 8;
+ r_ctl = tvb_get_guint8 (tvb, offset);
+ }
+
+ type = tvb_get_guint8 (tvb, offset+8);
+ seqcnt = tvb_get_ntohs (tvb, offset+14);
+ param = tvb_get_ntohl (tvb, offset+20);
+
+ SET_ADDRESS (&pinfo->dst, AT_FC, 3, tvb_get_ptr (tvb, 1, 3));
+ SET_ADDRESS (&pinfo->src, AT_FC, 3, tvb_get_ptr (tvb, 5, 3));
+ pinfo->oxid = tvb_get_ntohs (tvb, offset+16);
+ pinfo->rxid = tvb_get_ntohs (tvb, offset+18);
+ pinfo->ptype = PT_EXCHG;
+ pinfo->r_ctl = r_ctl;
+
+ is_ack = ((r_ctl == 0xC0) || (r_ctl == 0xC1));
+
+ ftype = fc_get_ftype (r_ctl, type);
+
+ if (check_col (pinfo->cinfo, COL_INFO)) {
+ col_add_str (pinfo->cinfo, COL_INFO, match_strval (ftype, fc_ftype_vals));
+
+ if (ftype == FC_FTYPE_LINKCTL)
+ col_append_fstr (pinfo->cinfo, COL_INFO, ", %s",
+ match_strval ((r_ctl & 0x0F),
+ fc_lctl_proto_val));
+ }
+
+ /* In the interest of speed, if "tree" is NULL, don't do any work not
+ necessary to generate protocol tree items. */
+ if (tree) {
+ ti = proto_tree_add_protocol_format (tree, proto_fc, tvb, offset,
+ FC_HEADER_SIZE, "Fibre Channel");
+ fc_tree = proto_item_add_subtree (ti, ett_fc);
+
+ if (ftype == FC_FTYPE_LINKCTL) {
+ /* the lower 4 bits of R_CTL indicate the type of link ctl frame */
+ proto_tree_add_uint_format (fc_tree, hf_fc_rctl, tvb, offset,
+ FC_RCTL_SIZE, r_ctl,
+ "R_CTL: 0x%x(%s)",
+ r_ctl,
+ val_to_str ((r_ctl & 0x0F),
+ fc_lctl_proto_val, "0x%x"));
+ }
+ else if (ftype == FC_FTYPE_BLS) {
+ /* the lower 4 bits of R_CTL indicate the type of BLS frame */
+ proto_tree_add_uint_format (fc_tree, hf_fc_rctl, tvb, offset,
+ FC_RCTL_SIZE, r_ctl,
+ "R_CTL: 0x%x(%s)",
+ r_ctl,
+ val_to_str ((r_ctl & 0x0F),
+ fc_bls_proto_val, "0x%x"));
+ }
+ else {
+ proto_tree_add_item (fc_tree, hf_fc_rctl, tvb, offset, 1, 0);
+ }
+
+ proto_tree_add_uint_hidden (fc_tree, hf_fc_ftype, tvb, offset, 1,
+ ftype);
+ proto_tree_add_string (fc_tree, hf_fc_did, tvb, offset+1, 3,
+ fc_to_str ((guint8 *)tvb_get_ptr (tvb,
+ offset+1, 3)));
+ proto_tree_add_item (fc_tree, hf_fc_csctl, tvb, offset+4, 1, 0);
+
+ proto_tree_add_string (fc_tree, hf_fc_sid, tvb, offset+5, 3,
+ fc_to_str ((guint8 *)tvb_get_ptr (tvb,
+ offset+5, 3)));
+
+ if (ftype == FC_FTYPE_LINKCTL) {
+ if (((r_ctl & 0x0F) == FC_LCTL_FBSYB) ||
+ ((r_ctl & 0x0F) == FC_LCTL_FBSYL)) {
+ /* for F_BSY frames, the upper 4 bits of the type field specify the
+ * reason for the BSY.
+ */
+ proto_tree_add_uint_format (fc_tree, hf_fc_type, tvb,
+ offset+8, FC_TYPE_SIZE,
+ type, "Type: 0x%x(%s)", type,
+ fclctl_get_typestr (r_ctl & 0x0F,
+ type));
+ }
+ else {
+ proto_tree_add_item (fc_tree, hf_fc_type, tvb, offset+8, 1, 0);
+ }
+ }
+ else {
+ proto_tree_add_item (fc_tree, hf_fc_type, tvb, offset+8, 1, 0);
+ }
+
+ proto_tree_add_uint_format (fc_tree, hf_fc_fctl, tvb, offset+9,
+ 3, tvb_get_ntoh24 (tvb, offset+9),
+ "F_CTL: 0x%x (%s)",
+ tvb_get_ntoh24 (tvb, offset+9),
+ fctl_to_str (tvb_get_ptr (tvb, offset+9, 3),
+ str, is_ack));
+
+ /* Bit 23 if set => this frame is from the exchange originator */
+ if (tvb_get_guint8 (tvb, offset+9) & 0x80) {
+ proto_tree_add_boolean_hidden (fc_tree, hf_fc_exchg_orig, tvb,
+ offset+9, 1, 0);
+ proto_tree_add_boolean_hidden (fc_tree, hf_fc_exchg_resp, tvb,
+ offset+9, 1, 1);
+ }
+ else {
+ proto_tree_add_boolean_hidden (fc_tree, hf_fc_exchg_orig, tvb,
+ offset+9, 1, 1);
+ proto_tree_add_boolean_hidden (fc_tree, hf_fc_exchg_resp, tvb,
+ offset+9, 1, 0);
+ }
+
+ proto_tree_add_item (fc_tree, hf_fc_seqid, tvb, offset+12, 1, 0);
+ proto_tree_add_item (fc_tree, hf_fc_dfctl, tvb, offset+13, 1, 0);
+ proto_tree_add_item (fc_tree, hf_fc_seqcnt, tvb, offset+14, 2, 0);
+ proto_tree_add_item (fc_tree, hf_fc_oxid, tvb, offset+16, 2, 0);
+ proto_tree_add_uint (fc_tree, hf_fc_rxid, tvb, offset+18, 2, 0);
+
+ if (ftype == FC_FTYPE_LINKCTL) {
+ if (((r_ctl & 0x0F) == FC_LCTL_FRJT) ||
+ ((r_ctl & 0x0F) == FC_LCTL_PRJT) ||
+ ((r_ctl & 0x0F) == FC_LCTL_PBSY)) {
+ /* In all these cases of Link Ctl frame, the parameter field
+ * encodes the detailed error message
+ */
+ proto_tree_add_uint_format (fc_tree, hf_fc_param, tvb,
+ offset+20, 4, param,
+ "Parameter: 0x%x(%s)", param,
+ fclctl_get_paramstr ((r_ctl & 0x0F),
+ param));
+ }
+ else {
+ proto_tree_add_item (fc_tree, hf_fc_param, tvb, offset+20, 4, 0);
+ }
+ }
+ else if (ftype == FC_FTYPE_BLS) {
+ if ((r_ctl & 0x0F) == FC_BLS_ABTS) {
+ proto_tree_add_uint_format (fc_tree, hf_fc_param, tvb,
+ offset+20, 4, param,
+ "Parameter: 0x%x(%s)", param,
+ ((param & 0x0F) == 1 ? "Abort Sequence" :
+ "Abort Exchange"));
+ }
+ else {
+ proto_tree_add_item (fc_tree, hf_fc_param, tvb, offset+20,
+ 4, 0);
+ }
+ }
+ else {
+ proto_tree_add_item (fc_tree, hf_fc_param, tvb, offset+20, 4, 0);
+ }
+ }
+
+ if (ftype == FC_FTYPE_LINKCTL) {
+ /* ACK_1 frames and other LINK_CTL frames echo the last seq bit if the
+ * packet they're ack'ing did not have it set. So, we'll incorrectly
+ * flag them as being fragmented when they're not. This fixes the
+ * problem
+ */
+ is_lastframe_inseq = TRUE;
+ }
+ else {
+ is_lastframe_inseq = tvb_get_guint8 (tvb, offset+9) & 0x08;
+ is_exchg_resp = ((tvb_get_guint8 (tvb, offset+20) & 0x80) == 0x80);
+ }
+
+ frag_size = tvb_reported_length (tvb)-FC_HEADER_SIZE;
+
+ if (!is_lastframe_inseq) {
+ /* Show this only as a fragmented FC frame */
+ if (check_col (pinfo->cinfo, COL_INFO)) {
+ col_append_str (pinfo->cinfo, COL_INFO, " (Fragmented)");
+ }
+ }
+
+ /* If this is a fragment, attempt to check if fully reassembled frame is
+ * present, if we're configured to reassemble.
+ */
+ if ((ftype != FC_FTYPE_LINKCTL) && (ftype != FC_FTYPE_BLS) &&
+ seqcnt && fc_reassemble) {
+ /* Add this to the list of fragments */
+ frag_id = (pinfo->oxid << 16) | is_exchg_resp;
+
+ /* We assume that all frames are of the same max size */
+ fcfrag_head = fragment_add (tvb, FC_HEADER_SIZE, pinfo, frag_id,
+ fc_fragment_table,
+ seqcnt * fc_max_frame_size,
+ frag_size,
+ TRUE);
+
+ if (fcfrag_head) {
+ next_tvb = tvb_new_real_data (fcfrag_head->data,
+ fcfrag_head->datalen,
+ fcfrag_head->datalen);
+ tvb_set_child_real_data_tvbuff(tvb, next_tvb);
+
+ /* Add the defragmented data to the data source list. */
+ add_new_data_source(pinfo, next_tvb, "Reassembled FC");
+
+ if (tree) {
+ proto_tree_add_boolean_hidden (fc_tree, hf_fc_reassembled,
+ tvb, offset+9, 1, 1);
+ }
+ }
+ else {
+ if (tree) {
+ proto_tree_add_boolean_hidden (fc_tree, hf_fc_reassembled,
+ tvb, offset+9, 1, 0);
+ }
+ next_tvb = tvb_new_subset (tvb, offset+FC_HEADER_SIZE, -1, -1);
+ call_dissector (data_handle, next_tvb, pinfo, tree);
+ return;
+ }
+ }
+ else {
+ if (tree) {
+ proto_tree_add_boolean_hidden (fc_tree, hf_fc_reassembled,
+ tvb, offset+9, 1, 0);
+ }
+ next_tvb = tvb_new_subset (tvb, offset+FC_HEADER_SIZE, -1, -1);
+ }
+
+ if ((ftype != FC_FTYPE_LINKCTL) && (ftype != FC_FTYPE_BLS)) {
+ if (!dissector_try_port (fcftype_dissector_table, ftype, next_tvb,
+ pinfo, tree)) {
+ call_dissector (data_handle, next_tvb, pinfo, tree);
+ }
+ }
+ else if (ftype == FC_FTYPE_BLS) {
+ if ((r_ctl & 0x0F) == FC_BLS_BAACC) {
+ dissect_fc_ba_acc (next_tvb, pinfo, tree);
+ }
+ else if ((r_ctl & 0x0F) == FC_BLS_BARJT) {
+ dissect_fc_ba_rjt (next_tvb, pinfo, tree);
+ }
+ }
+}
+
+
+/* Register the protocol with Ethereal */
+
+/* this format is require because a script is used to build the C function
+ that calls all the protocol registration.
+*/
+
+void
+proto_register_fc(void)
+{
+
+/* Setup list of header fields See Section 1.6.1 for details*/
+ static hf_register_info hf[] = {
+ { &hf_fc_rctl,
+ { "R_CTL", "fc.r_ctl", FT_UINT8, BASE_HEX, NULL, 0x0,
+ "R_CTL", HFILL }},
+ { &hf_fc_ftype,
+ {"Frame type", "fc.ftype", FT_UINT8, BASE_HEX, VALS(fc_ftype_vals),
+ 0x0, "Derived Type", HFILL}},
+ { &hf_fc_did,
+ { "Dest Addr", "fc.d_id", FT_STRING, BASE_HEX, NULL, 0x0,
+ "Destination Address", HFILL}},
+ { &hf_fc_csctl,
+ {"CS_CTL", "fc.cs_ctl", FT_UINT8, BASE_HEX, NULL, 0x0,
+ "CS_CTL", HFILL}},
+ { &hf_fc_sid,
+ {"Src Addr", "fc.s_id", FT_STRING, BASE_HEX, NULL, 0x0,
+ "Source Address", HFILL}},
+ { &hf_fc_type,
+ {"Type", "fc.type", FT_UINT8, BASE_HEX, VALS (fc_fc4_val), 0x0,
+ "", HFILL}},
+ { &hf_fc_fctl,
+ {"F_CTL", "fc.f_ctl", FT_UINT24, BASE_HEX, NULL, 0x0, "", HFILL}},
+ { &hf_fc_seqid,
+ {"SEQ_ID", "fc.seq_id", FT_UINT8, BASE_HEX, NULL, 0x0,
+ "Sequence ID", HFILL}},
+ { &hf_fc_dfctl,
+ {"DF_CTL", "fc.df_ctl", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL}},
+ { &hf_fc_seqcnt,
+ {"SEQ_CNT", "fc.seq_cnt", FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Sequence Count", HFILL}},
+ { &hf_fc_oxid,
+ {"OX_ID", "fc.ox_id", FT_UINT16, BASE_HEX, NULL, 0x0, "Originator ID",
+ HFILL}},
+ { &hf_fc_rxid,
+ {"RX_ID", "fc.rx_id", FT_UINT16, BASE_HEX, NULL, 0x0, "Receiver ID",
+ HFILL}},
+ { &hf_fc_param,
+ {"Parameter", "fc.parameter", FT_UINT32, BASE_HEX, NULL, 0x0, "Parameter",
+ HFILL}},
+
+ /* Basic Link Svc field definitions */
+ { &hf_fc_bls_seqid_vld,
+ {"SEQID Valid", "fc.bls_seqidvld", FT_UINT8, BASE_HEX,
+ VALS (fc_bls_seqid_val), 0x0, "", HFILL}},
+ { &hf_fc_bls_lastvld_seqid,
+ {"Last Valid SEQID", "fc.bls_lastseqid", FT_UINT8, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_fc_bls_oxid,
+ {"OXID", "fc.bls_oxid", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL}},
+ { &hf_fc_bls_rxid,
+ {"RXID", "fc.bls_rxid", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL}},
+ { &hf_fc_bls_lowseqcnt,
+ {"Low SEQCNT", "fc.bls_lseqcnt", FT_UINT16, BASE_HEX, NULL, 0x0, "",
+ HFILL}},
+ { &hf_fc_bls_hiseqcnt,
+ {"High SEQCNT", "fc.bls_hseqcnt", FT_UINT16, BASE_HEX, NULL, 0x0, "",
+ HFILL}},
+ { &hf_fc_bls_rjtcode,
+ {"Reason", "fc.bls_reason", FT_UINT8, BASE_HEX, VALS(fc_bls_barjt_val),
+ 0x0, "", HFILL}},
+ { &hf_fc_bls_rjtdetail,
+ {"Reason Explanantion", "fc.bls_rjtdetail", FT_UINT8, BASE_HEX,
+ VALS (fc_bls_barjt_det_val), 0x0, "", HFILL}},
+ { &hf_fc_bls_vendor,
+ {"Vendor Unique Reason", "fc.bls_vnduniq", FT_UINT8, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_fc_exchg_orig,
+ {"Exchange Originator", "fc.xchg_orig", FT_BOOLEAN, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_fc_exchg_resp,
+ {"Exchange Responder", "fc.xchg_resp", FT_BOOLEAN, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_fc_reassembled,
+ {"Reassembled Frame", "fc.reassembled", FT_BOOLEAN, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ };
+
+ /* Setup protocol subtree array */
+ static gint *ett[] = {
+ &ett_fc,
+ &ett_fcbls,
+ };
+
+ module_t *fc_module;
+
+ /* Register the protocol name and description */
+ proto_fc = proto_register_protocol ("Fibre Channel", "FC", "fc");
+ register_dissector ("fc", dissect_fc, proto_fc);
+
+ /* Required function calls to register the header fields and subtrees used */
+ proto_register_field_array(proto_fc, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+
+ fcftype_dissector_table = register_dissector_table ("fc.ftype",
+ "FC Frame Type",
+ FT_UINT8, BASE_HEX);
+
+ /* Register preferences */
+ fc_module = prefs_register_protocol (proto_fc, NULL);
+ prefs_register_bool_preference (fc_module,
+ "reassemble_fc", "Reassemble FC",
+ "If enabled, reassembly of multi-frame "
+ "sequences is done",
+ &fc_reassemble);
+ prefs_register_uint_preference (fc_module,
+ "fc_max_frame_size", "Max FC Frame Size",
+ "This is the size of non-last frames in a "
+ "multi-frame sequence", 10,
+ &fc_max_frame_size);
+
+ register_init_routine(fc_defragment_init);
+}
+
+
+/* If this dissector uses sub-dissector registration add a registration routine.
+ This format is required because a script is used to find these routines and
+ create the code that calls these routines.
+*/
+void
+proto_reg_handoff_fc (void)
+{
+ dissector_handle_t fc_handle;
+
+ fc_handle = create_dissector_handle (dissect_fc, proto_fc);
+
+ data_handle = find_dissector("data");
+}
diff --git a/packet-fc.h b/packet-fc.h
new file mode 100644
index 0000000000..abfadbb813
--- /dev/null
+++ b/packet-fc.h
@@ -0,0 +1,153 @@
+/* packet-fc.h
+ * Basic Fibre Channel Header definitions
+ * Copyright 2002 Dinesh G Dutt (ddutt@cisco.com)
+ *
+ * $Id: packet-fc.h,v 1.1 2002/12/08 02:32:17 gerald Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PACKET_FC_H_
+#define __PACKET_FC_H_
+
+/* R_CTL upper bits creates a classification tree */
+#define FC_RCTL_DEV_DATA 0x00
+#define FC_RCTL_ELS 0x20
+#define FC_RCTL_LINK_DATA 0x30
+#define FC_RCTL_VIDEO 0x40
+#define FC_RCTL_BLS 0x80
+#define FC_RCTL_LINK_CTL 0xC0
+
+/* TYPE (FC-4) Definitions */
+
+#define FC_TYPE_SCSI 0x8
+#define FC_TYPE_IP 0x5
+#define FC_TYPE_LLCSNAP 0x4
+#define FC_TYPE_ELS 0x1
+#define FC_TYPE_FCCT 0x20
+#define FC_TYPE_SWILS 0x22
+#define FC_TYPE_AL 0x23
+#define FC_TYPE_SNMP 0x24
+#define FC_TYPE_CMNSVC 0x0 /* Used in PRLI Svc Param Page */
+
+static const value_string fc_fc4_val[] = {
+ {FC_TYPE_SCSI , "FCP"},
+ {FC_TYPE_IP , "IP/FC"},
+ {FC_TYPE_LLCSNAP , "LLC_SNAP"},
+ {FC_TYPE_ELS , "Ext Link Svc"},
+ {FC_TYPE_FCCT , "FC_CT"},
+ {FC_TYPE_SWILS , "SW_ILS"},
+ {FC_TYPE_AL , "AL"},
+ {FC_TYPE_SNMP , "SNMP"},
+ {0, NULL},
+};
+
+static const value_string fc_prli_fc4_val[] = {
+ {FC_TYPE_SCSI , "FCP"},
+ {FC_TYPE_IP , "IP/FC"},
+ {FC_TYPE_LLCSNAP , "LLC_SNAP"},
+ {FC_TYPE_ELS , "Ext Link Svc"},
+ {FC_TYPE_FCCT , "FC_CT"},
+ {FC_TYPE_SWILS , "SW_ILS"},
+ {FC_TYPE_AL , "AL"},
+ {FC_TYPE_SNMP , "SNMP"},
+ {FC_TYPE_CMNSVC , "Common to all FC-4 Types"},
+ {0, NULL},
+};
+
+/* Derived Frame types (used for ULP demux) */
+#define FC_FTYPE_UNDEF 0x0
+#define FC_FTYPE_SWILS 0x1
+#define FC_FTYPE_IP 0x2
+#define FC_FTYPE_SCSI 0x3
+#define FC_FTYPE_BLS 0x4
+#define FC_FTYPE_ELS 0x5
+#define FC_FTYPE_FCCT 0x7
+#define FC_FTYPE_LINKDATA 0x8
+#define FC_FTYPE_VDO 0x9
+#define FC_FTYPE_LINKCTL 0xA
+#define FC_FTYPE_SWILS_RSP 0xB
+
+static const value_string fc_ftype_vals [] = {
+ {FC_FTYPE_UNDEF , "Unknown frame"},
+ {FC_FTYPE_SWILS, "SW_ILS"},
+ {FC_FTYPE_IP , "IP/FC"},
+ {FC_FTYPE_SCSI , "FCP"},
+ {FC_FTYPE_BLS , "Basic Link Svc"},
+ {FC_FTYPE_ELS , "ELS"},
+ {FC_FTYPE_FCCT , "FC_CT"},
+ {FC_FTYPE_LINKDATA, "Link Data"},
+ {FC_FTYPE_VDO, "Video Data"},
+ {FC_FTYPE_LINKCTL, "Link Ctl"},
+ {0, NULL},
+};
+
+/* Well-known Address Definitions (in Network order) */
+#define FC_WKA_MULTICAST 0xFFFFF5
+#define FC_WKA_CLKSYNC 0xFFFFF6
+#define FC_WKA_KEYDIST 0xFFFFF7
+#define FC_WKA_ALIAS 0xFFFFF8
+#define FC_WKA_QOSF 0xFFFFF9
+#define FC_WKA_MGMT 0xFFFFFA
+#define FC_WKA_TIME 0xFFFFFB
+#define FC_WKA_DNS 0xFFFFFC
+#define FC_WKA_FABRIC_CTRLR 0xFFFFFD
+#define FC_WKA_FPORT 0xFFFFFE
+#define FC_WKA_BCAST 0xFFFFFF
+
+/* Well-known Address Definitions (in little endian) */
+
+static const value_string fc_wka_vals[] = {
+ {FC_WKA_MULTICAST, "Multicast Server"},
+ {FC_WKA_CLKSYNC, "Clock Sync Server"},
+ {FC_WKA_KEYDIST, "Key Distribution Server"},
+ {FC_WKA_ALIAS, "Alias Server"},
+ {FC_WKA_QOSF, "QoS Facilitator"},
+ {FC_WKA_MGMT, "Management Server"},
+ {FC_WKA_TIME, "Time Server"},
+ {FC_WKA_DNS, "Directory Server"},
+ {FC_WKA_FABRIC_CTRLR, "Fabric Ctlr"},
+ {FC_WKA_FPORT, "F_Port Server"},
+ {FC_WKA_BCAST, "Broadcast ID"},
+ {0, NULL},
+};
+
+/* Information Categories for Link Data & Link Control Frames */
+#define FC_IU_UNCATEGORIZED 0x0
+#define FC_IU_SOLICITED_DATA 0x1
+#define FC_IU_UNSOLICITED_CTL 0x2
+#define FC_IU_SOLICITED_CTL 0x3
+#define FC_IU_UNSOLICITED_DATA 0x4
+#define FC_IU_DATA_DESCRIPTOR 0x5
+#define FC_IU_UNSOLICITED_CMD 0x6
+#define FC_IU_CMD_STATUS 0x7
+
+static const value_string fc_iu_val[] = {
+ {FC_IU_UNCATEGORIZED , "Uncategorized Data"},
+ {FC_IU_SOLICITED_DATA , "Solicited Data"},
+ {FC_IU_UNSOLICITED_CTL , "Unsolicited Control"},
+ {FC_IU_SOLICITED_CTL , "Solicited Control"},
+ {FC_IU_UNSOLICITED_DATA, "Solicited Data"},
+ {FC_IU_DATA_DESCRIPTOR , "Data Descriptor"},
+ {FC_IU_UNSOLICITED_CMD , "Unsolicited Command"},
+ {FC_IU_CMD_STATUS , "Command Status"},
+ {0, NULL},
+};
+
+#endif
diff --git a/packet-fcbls.h b/packet-fcbls.h
new file mode 100644
index 0000000000..cda0ca02cb
--- /dev/null
+++ b/packet-fcbls.h
@@ -0,0 +1,87 @@
+/* packet-fcbls.h
+ * Fibre Channel Basic Link Services header
+ * Copyright 2001, Dinesh G Dutt <ddutt@cisco.com>
+ *
+ * $Id: packet-fcbls.h,v 1.1 2002/12/08 02:32:17 gerald Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PACKET_FCBLS_H_
+#define __PACKET_FCBLS_H_
+
+#define FC_BLS_NOP 0x00
+#define FC_BLS_ABTS 0x01
+#define FC_BLS_RMC 0x02
+#define FC_BLS_BAACC 0x04
+#define FC_BLS_BARJT 0x05
+#define FC_BLS_PRMT 0x06
+
+static const value_string fc_bls_proto_val[] = {
+ {FC_BLS_NOP , "NOP"},
+ {FC_BLS_ABTS , "ABTS"},
+ {FC_BLS_RMC , "RMC"},
+ {FC_BLS_BAACC , "BA_ACC"},
+ {FC_BLS_BARJT , "BA_RJT"},
+ {FC_BLS_PRMT , "PRMT"},
+ {0, NULL},
+};
+
+#define FC_BLS_BARJT_INVCMDCODE 0x01
+#define FC_BLS_BARJT_LOGERR 0x03
+#define FC_BLS_BARJT_LOGBSY 0x05
+#define FC_BLS_BARJT_PROTERR 0x07
+#define FC_BLS_BARJT_GENFAIL 0x09
+#define FC_BLS_BARJT_VENDOR 0xFF
+
+static const value_string fc_bls_barjt_val[] = {
+ {FC_BLS_BARJT_INVCMDCODE, "Invalid Cmd Code"},
+ {FC_BLS_BARJT_LOGERR , "Logical Error"},
+ {FC_BLS_BARJT_LOGBSY , "Logical Busy"},
+ {FC_BLS_BARJT_PROTERR , "Protocol Error"},
+ {FC_BLS_BARJT_GENFAIL , "Unable to Perform Cmd"},
+ {FC_BLS_BARJT_VENDOR , "Vendor Unique Error"},
+ {0, NULL},
+};
+
+#define FC_BLS_BARJT_DET_NODET 0x01
+#define FC_BLS_BARJT_DET_INVEXCHG 0x03
+#define FC_BLS_BARJT_DET_SEQABT 0x05
+
+static const value_string fc_bls_barjt_det_val[] = {
+ {FC_BLS_BARJT_DET_NODET , "No Details"},
+ {FC_BLS_BARJT_DET_INVEXCHG, "Invalid OXID-RXID Combo"},
+ {FC_BLS_BARJT_DET_SEQABT , "Sequence Aborted"},
+ {0, NULL},
+};
+
+static const value_string fc_bls_seqid_val[] = {
+ {0x80, "Yes"},
+ {0x0, "No"},
+ {0, NULL},
+};
+
+typedef struct _fc_bls_ba_rjt {
+ guint8 rsvd;
+ guint8 reason_code;
+ guint8 rjt_detail;
+ guint8 vendor_uniq;
+} fc_bls_ba_rjt;
+
+#endif
diff --git a/packet-fcels.c b/packet-fcels.c
new file mode 100644
index 0000000000..0c57bb10d3
--- /dev/null
+++ b/packet-fcels.c
@@ -0,0 +1,1978 @@
+/* packet-fcels.c
+ * Routines for FC Extended Link Services
+ * Copyright 2001, Dinesh G Dutt <ddutt@cisco.com>
+ *
+ * $Id: packet-fcels.c,v 1.1 2002/12/08 02:32:17 gerald Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * Copied from WHATEVER_FILE_YOU_USED (where "WHATEVER_FILE_YOU_USED"
+ * is a dissector file; if you just copied this from README.developer,
+ * don't bother with the "Copied from" - you don't even need to put
+ * in a "Copied from" if you copied an existing dissector, especially
+ * if the bulk of the code in the new dissector is your code)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * TODO Still (Complete compliance with FC-MI):
+ * - Decode RNID, RLIR
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#include <glib.h>
+
+#ifdef NEED_SNPRINTF_H
+# include "snprintf.h"
+#endif
+
+#include <epan/packet.h>
+#include <epan/conversation.h>
+#include "etypes.h"
+#include "packet-fc.h"
+#include "packet-fcels.h"
+
+#define FC_ELS_RPLY 0
+#define FC_ELS_REQ 1
+
+/* Initialize the protocol and registered fields */
+static int proto_fcels = -1;
+static int hf_fcels_opcode = -1;
+static int hf_fcels_rjtcode = -1;
+static int hf_fcels_rjtdetcode = -1;
+static int hf_fcels_vnduniq = -1;
+static int hf_fcels_b2b = -1;
+static int hf_fcels_cmnfeatures = -1;
+static int hf_fcels_bbscnum = -1;
+static int hf_fcels_rcvsize = -1;
+static int hf_fcels_maxconseq = -1;
+static int hf_fcels_reloffset = -1;
+static int hf_fcels_edtov = -1;
+static int hf_fcels_npname = -1;
+static int hf_fcels_fnname = -1;
+static int hf_fcels_cls1param = -1;
+static int hf_fcels_cls2param = -1;
+static int hf_fcels_cls3param = -1;
+static int hf_fcels_cls4param = -1;
+static int hf_fcels_vendorvers = -1;
+static int hf_fcels_svcavail = -1;
+static int hf_fcels_clsflags = -1;
+static int hf_fcels_initctl = -1;
+static int hf_fcels_rcptctl = -1;
+static int hf_fcels_clsrcvsize = -1;
+static int hf_fcels_conseq = -1;
+static int hf_fcels_e2e = -1;
+static int hf_fcels_openseq = -1;
+static int hf_fcels_nportid = -1;
+static int hf_fcels_oxid = -1;
+static int hf_fcels_rxid = -1;
+static int hf_fcels_recovqual = -1;
+static int hf_fcels_fabricaddr = -1;
+static int hf_fcels_fabricpname = -1;
+static int hf_fcels_failedrcvr = -1;
+static int hf_fcels_flacompliance = -1;
+static int hf_fcels_loopstate = -1;
+static int hf_fcels_publicloop_bmap = -1;
+static int hf_fcels_pvtloop_bmap = -1;
+static int hf_fcels_alpa_map = -1;
+static int hf_fcels_scrregn = -1;
+static int hf_fcels_farp_matchcodept = -1;
+static int hf_fcels_farp_respaction = -1;
+static int hf_fcels_resportid = -1;
+static int hf_fcels_respname = -1;
+static int hf_fcels_respnname = -1;
+static int hf_fcels_reqipaddr = -1;
+static int hf_fcels_respipaddr = -1;
+static int hf_fcels_hardaddr = -1;
+static int hf_fcels_rps_flag = -1;
+static int hf_fcels_rps_portnum = -1;
+static int hf_fcels_rps_portstatus = -1;
+static int hf_fcels_rnft_fc4type = -1;
+static int hf_fcels_rscn_evqual = -1;
+static int hf_fcels_rscn_addrfmt = -1;
+static int hf_fcels_rscn_domain = -1;
+static int hf_fcels_rscn_area = -1;
+static int hf_fcels_rscn_port = -1;
+static int hf_fcels_nodeidfmt = -1;
+static int hf_fcels_spidlen = -1;
+static int hf_fcels_vendoruniq = -1;
+static int hf_fcels_vendorsp = -1;
+static int hf_fcels_asstype = -1;
+static int hf_fcels_physport = -1;
+static int hf_fcels_attnodes = -1;
+static int hf_fcels_nodemgmt = -1;
+static int hf_fcels_ipvers = -1;
+static int hf_fcels_tcpport = -1;
+static int hf_fcels_ip = -1;
+
+static gint ett_fcels;
+static gint ett_fcels_lsrjt;
+static gint ett_fcels_acc;
+static gint ett_fcels_logi;
+static gint ett_fcels_logi_cmnsvc;
+static gint ett_fcels_logi_clssvc;
+static gint ett_fcels_logo;
+static gint ett_fcels_abtx;
+static gint ett_fcels_rsi;
+static gint ett_fcels_rrq;
+static gint ett_fcels_prli;
+static gint ett_fcels_prli_svcpg;
+static gint ett_fcels_adisc;
+static gint ett_fcels_farp;
+static gint ett_fcels_rps;
+static gint ett_fcels_rpl;
+static gint ett_fcels_rplpb;
+static gint ett_fcels_fan;
+static gint ett_fcels_rscn;
+static gint ett_fcels_rscn_rec;
+static gint ett_fcels_scr;
+static gint ett_fcels_rnft;
+static gint ett_fcels_rnft_fc4;
+static gint ett_fcels_lsts;
+static gint ett_fcels_rnid;
+static gint ett_fcels_rlir;
+static gint ett_fcels_lirr;
+static gint ett_fcels_srl;
+static gint ett_fcels_rpsc;
+
+typedef struct _fcels_conv_key {
+ guint32 conv_idx;
+} fcels_conv_key_t;
+
+typedef struct _fcels_conv_data {
+ guint32 opcode;
+} fcels_conv_data_t;
+
+GHashTable *fcels_req_hash = NULL;
+GMemChunk *fcels_req_keys = NULL;
+GMemChunk *fcels_req_vals = NULL;
+guint32 fcels_init_count = 25;
+
+static dissector_handle_t data_handle;
+
+/*
+ * Hash Functions
+ */
+static gint
+fcels_equal(gconstpointer v, gconstpointer w)
+{
+ fcels_conv_key_t *v1 = (fcels_conv_key_t *)v;
+ fcels_conv_key_t *v2 = (fcels_conv_key_t *)w;
+
+ return (v1->conv_idx == v2->conv_idx);
+}
+
+static guint
+fcels_hash (gconstpointer v)
+{
+ fcels_conv_key_t *key = (fcels_conv_key_t *)v;
+ guint val;
+
+ val = key->conv_idx;
+
+ return val;
+}
+
+/*
+ * Protocol initialization
+ */
+static void
+fcels_init_protocol(void)
+{
+ if (fcels_req_keys)
+ g_mem_chunk_destroy(fcels_req_keys);
+ if (fcels_req_vals)
+ g_mem_chunk_destroy(fcels_req_vals);
+ if (fcels_req_hash)
+ g_hash_table_destroy(fcels_req_hash);
+
+ fcels_req_hash = g_hash_table_new(fcels_hash, fcels_equal);
+ fcels_req_keys = g_mem_chunk_new ("fcels_req_keys",
+ sizeof(fcels_conv_key_t),
+ fcels_init_count *
+ sizeof(fcels_conv_key_t),
+ G_ALLOC_AND_FREE);
+ fcels_req_vals = g_mem_chunk_new ("fcels_req_vals",
+ sizeof(fcels_conv_data_t),
+ fcels_init_count *
+ sizeof(fcels_conv_data_t),
+ G_ALLOC_AND_FREE);
+}
+
+static void
+construct_cmnsvc_string (guint16 flag, gchar *flagstr, guint8 opcode)
+{
+ int stroff = 0;
+ gchar punc[3];
+
+ punc[0] = '\0';
+
+ if ((opcode == FC_ELS_PLOGI) || (opcode == FC_ELS_PDISC)) {
+ if (flag & 0x8000) {
+ strcpy (flagstr, "Cont. Incr. Offset Supported");
+ stroff += 28;
+ strcpy (punc, ", ");
+ }
+ if (flag & 0x4000) {
+ sprintf (&flagstr[stroff], "%sRRO Supported", punc);
+ stroff += 15;
+ strcpy (punc, ", ");
+ }
+ }
+
+ if (flag & 0x2000) {
+ sprintf (flagstr, "%sValid Vendor Version Level", punc);
+ strcpy (punc, ", ");
+ stroff += 28;
+ }
+
+ if (flag & 0x0800) {
+ sprintf (&flagstr[stroff], "%sNormal B2B Credit Mgmt", punc);
+ strcpy (punc, ", ");
+ stroff += 24;
+ }
+ else {
+ sprintf (&flagstr[stroff], "%sAlt B2B Credit Mgmt", punc);
+ strcpy (punc, ", ");
+ stroff += 21;
+ }
+
+ if ((opcode == FC_ELS_PLOGI) || (opcode == FC_ELS_PDISC)) {
+ if (flag & 0x0400) {
+ strcpy (&flagstr[stroff], ", E_D_TOV Resolution in ns");
+ }
+ else {
+ strcpy (&flagstr[stroff], ", E_D_TOV Resolution in ms");
+ }
+ stroff += 26;
+
+ if (flag & 0x0040) {
+ strcpy (&flagstr[stroff], ", Simplex Dedicated Conn Supported");
+ stroff += 34;
+ }
+ }
+
+ if (flag & 0x0010) {
+ strcpy (&flagstr[stroff], ", Clk Sync Prim Capable");
+ stroff += 23;
+ }
+ if (flag & 0x0004) {
+ strcpy (&flagstr[stroff], ", DHD Capable");
+ stroff += 13;
+ }
+
+ if ((opcode == FC_ELS_PLOGI) || (opcode == FC_ELS_PDISC)) {
+ if (flag & 0x0002) {
+ strcpy (&flagstr[stroff], ", Cont. Incr SEQCNT rules");
+ stroff += 25;
+ }
+ else {
+ strcpy (&flagstr[stroff], ", Normal SEQCNT rules");
+ stroff += 21;
+ }
+ }
+
+ if (flag & 0x0001) {
+ sprintf (&flagstr[stroff], ", Payload Len=256 bytes");
+ }
+ else {
+ sprintf (&flagstr[stroff], ", Payload Len=116 bytes");
+ }
+}
+
+/* The next 3 routines decode only Class 2 & Class 3 relevant bits */
+static void
+construct_clssvc_string (guint16 flag, gchar *flagstr, guint8 opcode)
+{
+ int stroff = 0;
+
+ if (!(flag & 0x8000)) {
+ strcpy (flagstr, "Class Not Supported");
+ return;
+ }
+
+ if ((opcode == FC_ELS_FLOGI) || (opcode == FC_ELS_FDISC)) {
+ if (flag & 0x0800) {
+ strcpy (flagstr, "Seq Delivery Requested");
+ stroff += 22;
+ }
+ else {
+ strcpy (flagstr, "Out of Order Delivery Requested");
+ stroff += 31;
+ }
+ }
+
+ if (flag & 0x0080) {
+ strcpy (&flagstr[stroff], ", Priority/preemption supported");
+ stroff += 31;
+ }
+
+ if ((opcode == FC_ELS_PLOGI) || (opcode == FC_ELS_PDISC)) {
+ if (flag & 0x0040) {
+ strcpy (&flagstr[stroff], "Non-zero CS_CTL Tolerated");
+ }
+ else {
+ strcpy (&flagstr[stroff], "Non-zero CS_CTL Maybe Tolerated");
+ }
+ }
+}
+
+static void
+construct_initctl_string (guint16 flag, gchar *flagstr, guint8 opcode)
+{
+ int stroff = 0;
+
+ if ((opcode == FC_ELS_PLOGI) || (opcode == FC_ELS_PDISC)) {
+ switch ((flag & 0x3000)) {
+ case 0x0:
+ strcpy (flagstr, "Initial P_A Not Supported");
+ stroff += 25;
+ break;
+ case 0x1000:
+ strcpy (flagstr, "Initial P_A Supported");
+ stroff += 21;
+ break;
+ case 0x3000:
+ strcpy (flagstr, "Initial P_A Required & Supported");
+ stroff += 32;
+ break;
+ }
+
+ if (flag & 0x0800) {
+ strcpy (&flagstr[stroff], ", ACK0 Capable");
+ stroff += 14;
+ }
+
+ if (flag & 0x0200) {
+ strcpy (&flagstr[stroff], ", ACK Generation Assistance Avail");
+ stroff += 33;
+ }
+ if (flag & 0x0010) {
+ strcpy (&flagstr[stroff], ", Clock Sync ELS Supported");
+ }
+ }
+ else {
+ if (flag & 0x0010) {
+ strcpy (&flagstr[stroff], "Clock Sync ELS Supported");
+ }
+ }
+}
+
+static void
+construct_rcptctl_string (guint16 flag, gchar *flagstr, guint8 opcode)
+{
+ int stroff = 0;
+ gchar punc[3];
+
+ punc[0] = '\0';
+
+ if ((opcode == FC_ELS_PLOGI) || (opcode == FC_ELS_PDISC)) {
+ if (flag & 0x8000) {
+ strcpy (flagstr, "ACK_0 Supported");
+ stroff += 15;
+ }
+ else {
+ strcpy (flagstr, "ACK_0 Not Supported");
+ stroff += 19;
+ }
+
+ if (flag & 0x2000) {
+ strcpy (&flagstr[stroff], ", X_ID Interlock Reqd");
+ stroff += 21;
+ }
+
+ switch (flag & 0x1800) {
+ case 0x0:
+ strcpy (&flagstr[stroff], ", Error Policy: Discard Policy only");
+ stroff += 43;
+ break;
+ case 0x1000:
+ strcpy (&flagstr[stroff], ", Error Policy: Both discard and process policies supported");
+ stroff += 52;
+ break;
+ case 0x0800:
+ strcpy (&flagstr[stroff], ", Error Policy: Reserved");
+ stroff += 41;
+ break;
+ case 0x1800:
+ strcpy (&flagstr[stroff], ", Error Policy: Reserved");
+ stroff += 52;
+ break;
+ }
+
+ switch (flag & 0x0030) {
+ case 0:
+ strcpy (&flagstr[stroff], ", 1 Category/Seq");
+ stroff += 16;
+ break;
+ case 0x0010:
+ strcpy (&flagstr[stroff], ", 2 Categories/Seq");
+ stroff += 18;
+ break;
+ case 0x0030:
+ strcpy (&flagstr[stroff], ", More than 2 Categories/Seq");
+ stroff += 28;
+ break;
+ }
+
+ if (flag & 0x0008) {
+ strcpy (&flagstr[stroff], ", Clk Sync ELS Supported");
+ }
+ }
+ else {
+ if (flag & 0x0008) {
+ strcpy (&flagstr[stroff], "Clk Sync ELS Supported");
+ }
+ }
+}
+
+
+static void
+dissect_fcels_logi (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+ proto_item *ti, guint8 opcode)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 0,
+ svcvld = 0,
+ class;
+ proto_tree *logi_tree, *cmnsvc_tree;
+ proto_item *subti;
+ gchar flagstr[256];
+ guint16 flag;
+
+ if (tree) {
+ logi_tree = proto_item_add_subtree (ti, ett_fcels_logi);
+ proto_tree_add_item (logi_tree, hf_fcels_opcode, tvb, offset, 1, 0);
+
+ subti = proto_tree_add_text (logi_tree, tvb, offset+4, 16,
+ "Common Svc Parameters");
+ cmnsvc_tree = proto_item_add_subtree (subti, ett_fcels_logi_cmnsvc);
+ proto_tree_add_item (cmnsvc_tree, hf_fcels_b2b, tvb, offset+6, 2, 0);
+ flag = tvb_get_ntohs (tvb, offset+8);
+
+ if (flag & 0x0001) {
+ svcvld = 1;
+ }
+
+ construct_cmnsvc_string (flag, flagstr, opcode);
+ proto_tree_add_uint_format (cmnsvc_tree, hf_fcels_cmnfeatures, tvb,
+ offset+8, 2, flag,
+ "Common Svc Parameters: 0x%x (%s)",
+ flag, flagstr);
+
+ proto_tree_add_item (cmnsvc_tree, hf_fcels_bbscnum, tvb, offset+10, 1, 0);
+ proto_tree_add_item (cmnsvc_tree, hf_fcels_rcvsize, tvb, offset+10, 2, 0);
+ proto_tree_add_item (cmnsvc_tree, hf_fcels_maxconseq, tvb, offset+12, 2, 0);
+ proto_tree_add_item (cmnsvc_tree, hf_fcels_reloffset, tvb, offset+14, 2, 0);
+ proto_tree_add_item (cmnsvc_tree, hf_fcels_edtov, tvb, offset+16, 4, 0);
+ proto_tree_add_string (cmnsvc_tree, hf_fcels_npname, tvb, offset+20, 8,
+ fcwwn_to_str (tvb_get_ptr (tvb, offset+20, 8)));
+ proto_tree_add_string (cmnsvc_tree, hf_fcels_fnname, tvb, offset+28, 8,
+ fcwwn_to_str (tvb_get_ptr (tvb, offset+28, 8)));
+
+ /* Add subtree for class paramters */
+ offset = 36;
+ for (class = 1; class < 5; class++) {
+ subti = proto_tree_add_text (logi_tree, tvb, offset, 16,
+ "Class %d Svc Parameters", class);
+ cmnsvc_tree = proto_item_add_subtree (subti, ett_fcels_logi_cmnsvc);
+
+ flag = tvb_get_ntohs (tvb, offset);
+ construct_clssvc_string (flag, flagstr, opcode);
+ proto_tree_add_uint_format (cmnsvc_tree, hf_fcels_clsflags, tvb,
+ offset, 2, flag,
+ "Service Options: 0x%x(%s)", flag,
+ flagstr);
+ if (flag & 0x8000) {
+ flag = tvb_get_ntohs (tvb, offset+2);
+ construct_initctl_string (flag, flagstr, opcode);
+ proto_tree_add_uint_format (cmnsvc_tree, hf_fcels_initctl, tvb,
+ offset+2, 2, flag,
+ "Initiator Control: 0x%x(%s)", flag,
+ flagstr);
+
+ flag = tvb_get_ntohs (tvb, offset+4);
+ construct_rcptctl_string (flag, flagstr, opcode);
+ proto_tree_add_uint_format (cmnsvc_tree, hf_fcels_initctl, tvb,
+ offset+4, 2, flag,
+ "Recipient Control: 0x%x(%s)", flag,
+ flagstr);
+
+ proto_tree_add_item (cmnsvc_tree, hf_fcels_clsrcvsize, tvb,
+ offset+6, 2, 0);
+ proto_tree_add_item (cmnsvc_tree, hf_fcels_conseq, tvb,
+ offset+8, 2, 0);
+ proto_tree_add_item (cmnsvc_tree, hf_fcels_e2e, tvb,
+ offset+10, 2, 0);
+ proto_tree_add_item (cmnsvc_tree, hf_fcels_openseq, tvb,
+ offset+12, 2, 0);
+ }
+ offset += 16;
+ }
+ proto_tree_add_item (logi_tree, hf_fcels_vendorvers, tvb, offset, 16, 0);
+ if (svcvld) {
+ proto_tree_add_item (logi_tree, hf_fcels_svcavail, tvb, offset+32, 8, 0);
+ }
+ }
+}
+
+static void
+dissect_fcels_plogi (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ guint8 isreq _U_, proto_item *ti)
+{
+ dissect_fcels_logi (tvb, pinfo, tree, ti, FC_ELS_PLOGI);
+}
+
+static void
+dissect_fcels_flogi (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ guint8 isreq _U_, proto_item *ti)
+{
+ dissect_fcels_logi (tvb, pinfo, tree, ti, FC_ELS_FLOGI);
+}
+
+static void
+dissect_fcels_logout (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+ guint8 isreq, proto_item *ti)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 5; /* bypass opcode+rsvd field */
+ proto_tree *logo_tree;
+
+ if (tree) {
+ logo_tree = proto_item_add_subtree (ti, ett_fcels_logo);
+
+ proto_tree_add_item (logo_tree, hf_fcels_opcode, tvb, offset-5, 1, 0);
+
+ if (!isreq) {
+ /* Accept has no payload */
+ return;
+ }
+
+ proto_tree_add_string (logo_tree, hf_fcels_nportid, tvb, offset, 3,
+ fc_to_str (tvb_get_ptr (tvb, offset, 3)));
+ proto_tree_add_string (logo_tree, hf_fcels_npname, tvb, offset+3, 6,
+ fcwwn_to_str (tvb_get_ptr (tvb, offset+3, 6)));
+ }
+}
+
+static void
+dissect_fcels_abtx (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+ guint8 isreq, proto_item *ti)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 0;
+ proto_tree *abtx_tree;
+
+ if (tree) {
+ abtx_tree = proto_item_add_subtree (ti, ett_fcels_abtx);
+
+ proto_tree_add_item (abtx_tree, hf_fcels_opcode, tvb, offset, 1, 0);
+
+ if (!isreq) {
+ return;
+ }
+
+ proto_tree_add_text (abtx_tree, tvb, offset+4, 1,
+ "Recovery Qualifier Status: 0x%x",
+ tvb_get_guint8 (tvb, offset+4));
+ proto_tree_add_string (abtx_tree, hf_fcels_nportid, tvb, offset+5, 3,
+ fc_to_str (tvb_get_ptr (tvb, offset+5, 3)));
+ proto_tree_add_item (abtx_tree, hf_fcels_oxid, tvb, offset+8, 2, 0);
+ proto_tree_add_item (abtx_tree, hf_fcels_rxid, tvb, offset+10, 2, 0);
+ }
+}
+
+static void
+dissect_fcels_rsi (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+ guint8 isreq, proto_item *ti)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 4;
+ proto_tree *rsi_tree;
+
+ if (tree) {
+ rsi_tree = proto_item_add_subtree (ti, ett_fcels_rsi);
+
+ proto_tree_add_item (rsi_tree, hf_fcels_opcode, tvb, offset-4, 1, 0);
+ if (!isreq)
+ return;
+
+ proto_tree_add_item (rsi_tree, hf_fcels_recovqual, tvb, offset, 1, 0);
+ proto_tree_add_string (rsi_tree, hf_fcels_nportid, tvb, offset+1, 3,
+ fc_to_str (tvb_get_ptr (tvb, offset+1, 3)));
+ proto_tree_add_item (rsi_tree, hf_fcels_rxid, tvb, offset+4, 2, 0);
+ proto_tree_add_item (rsi_tree, hf_fcels_oxid, tvb, offset+6, 2, 0);
+ }
+}
+
+static void
+dissect_fcels_rrq (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+ guint8 isreq, proto_item *ti)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 0;
+ proto_tree *rrq_tree;
+
+ if (tree) {
+ rrq_tree = proto_item_add_subtree (ti, ett_fcels_rrq);
+
+ proto_tree_add_item (rrq_tree, hf_fcels_opcode, tvb, offset, 1, 0);
+ if (!isreq)
+ return;
+
+ proto_tree_add_string (rrq_tree, hf_fcels_nportid, tvb, offset+5, 3,
+ fc_to_str (tvb_get_ptr (tvb, offset+5, 3)));
+ proto_tree_add_item (rrq_tree, hf_fcels_oxid, tvb, offset+8, 2, 0);
+ proto_tree_add_item (rrq_tree, hf_fcels_rxid, tvb, offset+10, 2, 0);
+ }
+}
+
+static void
+dissect_fcels_pdisc (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ guint8 isreq _U_, proto_item *ti)
+{
+ dissect_fcels_logi (tvb, pinfo, tree, ti, FC_ELS_PDISC);
+}
+
+static void
+dissect_fcels_fdisc (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ guint8 isreq _U_, proto_item *ti)
+{
+ dissect_fcels_logi (tvb, pinfo, tree, ti, FC_ELS_FDISC);
+}
+
+static void
+dissect_fcels_adisc (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+ guint8 isreq _U_, proto_item *ti)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 5;
+ proto_tree *adisc_tree;
+
+ if (tree) {
+ adisc_tree = proto_item_add_subtree (ti, ett_fcels_adisc);
+
+ proto_tree_add_item (adisc_tree, hf_fcels_opcode, tvb, offset-5, 1, 0);
+
+ proto_tree_add_string (adisc_tree, hf_fcels_hardaddr, tvb, offset, 3,
+ fc_to_str (tvb_get_ptr (tvb, offset, 3)));
+ proto_tree_add_string (adisc_tree, hf_fcels_npname, tvb, offset+3, 8,
+ fcwwn_to_str (tvb_get_ptr (tvb, offset+3, 8)));
+ proto_tree_add_string (adisc_tree, hf_fcels_fnname, tvb, offset+11, 8,
+ fcwwn_to_str (tvb_get_ptr (tvb, offset+11, 8)));
+ proto_tree_add_string (adisc_tree, hf_fcels_nportid, tvb, offset+20, 3,
+ fc_to_str (tvb_get_ptr (tvb, offset+20, 3)));
+ }
+
+}
+
+static void
+dissect_fcels_farp (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+ proto_item *ti)
+{
+ int offset = 4;
+ proto_tree *farp_tree;
+
+ if (tree) {
+ farp_tree = proto_item_add_subtree (ti, ett_fcels_farp);
+
+ proto_tree_add_item (farp_tree, hf_fcels_opcode, tvb, offset-4, 1, 0);
+
+ proto_tree_add_item (farp_tree, hf_fcels_farp_matchcodept,
+ tvb, offset, 1, 0);
+ proto_tree_add_string (farp_tree, hf_fcels_nportid, tvb, offset+1,
+ 3, fc_to_str (tvb_get_ptr (tvb, offset+1, 3)));
+ proto_tree_add_item (farp_tree, hf_fcels_farp_respaction, tvb,
+ offset+4, 1, 0);
+ proto_tree_add_string (farp_tree, hf_fcels_resportid, tvb, offset+5,
+ 3, fc_to_str (tvb_get_ptr (tvb, offset+5, 3)));
+ proto_tree_add_string (farp_tree, hf_fcels_npname, tvb, offset+8,
+ 8, fcwwn_to_str (tvb_get_ptr (tvb, offset+8, 8)));
+ proto_tree_add_string (farp_tree, hf_fcels_fnname, tvb, offset+16,
+ 8, fcwwn_to_str (tvb_get_ptr (tvb, offset+16, 8)));
+ proto_tree_add_string (farp_tree, hf_fcels_respname, tvb, offset+24,
+ 8, fcwwn_to_str (tvb_get_ptr (tvb, offset+24, 8)));
+ proto_tree_add_string (farp_tree, hf_fcels_respnname, tvb, offset+32,
+ 8, fcwwn_to_str (tvb_get_ptr (tvb, offset+32, 8)));
+ proto_tree_add_item (farp_tree, hf_fcels_reqipaddr, tvb, offset+40,
+ 16, 0);
+ proto_tree_add_item (farp_tree, hf_fcels_respipaddr, tvb, offset+56,
+ 16, 0);
+ }
+}
+
+static void
+dissect_fcels_farp_req (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ guint8 isreq _U_, proto_item *ti)
+{
+ dissect_fcels_farp (tvb, pinfo, tree, ti);
+}
+
+static void
+dissect_fcels_farp_rply (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ guint8 isreq _U_, proto_item *ti)
+{
+ dissect_fcels_farp (tvb, pinfo, tree, ti);
+}
+
+static void
+dissect_fcels_rps (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+ guint8 isreq, proto_item *ti)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 3;
+ guint8 flag;
+ proto_tree *rps_tree;
+
+ flag = tvb_get_guint8 (tvb, offset);
+
+ if (tree) {
+ rps_tree = proto_item_add_subtree (ti, ett_fcels_rps);
+
+ if (isreq) {
+ proto_tree_add_item (rps_tree, hf_fcels_rps_flag, tvb, offset, 1, 0);
+
+ proto_tree_add_item (rps_tree, hf_fcels_opcode, tvb, offset-3, 1, 0);
+
+ if (flag & 0x2) {
+ proto_tree_add_string (rps_tree, hf_fcels_npname, tvb, offset+1,
+ 8, fcwwn_to_str (tvb_get_ptr (tvb,
+ offset+1,
+ 8)));
+ }
+ else if (flag & 0x1) {
+ proto_tree_add_item (rps_tree, hf_fcels_rps_portnum, tvb,
+ offset+5, 3, 0);
+ }
+ }
+ else {
+ proto_tree_add_item (rps_tree, hf_fcels_rps_flag, tvb, offset, 1, 0);
+ proto_tree_add_item (rps_tree, hf_fcels_rps_portstatus, tvb,
+ offset+3, 2, 0);
+ /* Next 6 fields are from Link Error Status Block (LESB) */
+ proto_tree_add_text (rps_tree, tvb, offset+5, 4,
+ "Link Failure Count: %d",
+ tvb_get_ntohl (tvb, offset+5));
+ proto_tree_add_text (rps_tree, tvb, offset+9, 4,
+ "Loss of Sync Count: %d",
+ tvb_get_ntohl (tvb, offset+9));
+ proto_tree_add_text (rps_tree, tvb, offset+13, 4,
+ "Loss of Signal Count: %d",
+ tvb_get_ntohl (tvb, offset+13));
+ proto_tree_add_text (rps_tree, tvb, offset+17, 4,
+ "Primitive Seq Protocol Err: %d",
+ tvb_get_ntohl (tvb, offset+17));
+ proto_tree_add_text (rps_tree, tvb, offset+21, 4,
+ "Invalid Xmission Word: %d",
+ tvb_get_ntohl (tvb, offset+21));
+ proto_tree_add_text (rps_tree, tvb, offset+25, 4,
+ "Invalid CRC Count: %d",
+ tvb_get_ntohl (tvb, offset+25));
+ if (flag & 0x01) {
+ /* Next 6 fields are from L_Port Extension field */
+ proto_tree_add_text (rps_tree, tvb, offset+31, 2,
+ "L_Port Status: 0x%x",
+ tvb_get_ntohs (tvb, offset+31));
+ proto_tree_add_text (rps_tree, tvb, offset+36, 1,
+ "LIP AL_PS: 0x%x",
+ tvb_get_guint8 (tvb, offset+36));
+ proto_tree_add_text (rps_tree, tvb, offset+37, 4,
+ "LIP F7 Initiated Count: %d",
+ tvb_get_ntohl (tvb, offset+37));
+ proto_tree_add_text (rps_tree, tvb, offset+41, 4,
+ "LIP F7 Received Count: %d",
+ tvb_get_ntohl (tvb, offset+41));
+ proto_tree_add_text (rps_tree, tvb, offset+45, 4,
+ "LIP F8 Initiated Count: %d",
+ tvb_get_ntohl (tvb, offset+45));
+ proto_tree_add_text (rps_tree, tvb, offset+49, 4,
+ "LIP F8 Received Count: %d",
+ tvb_get_ntohl (tvb, offset+49));
+ proto_tree_add_text (rps_tree, tvb, offset+53, 4,
+ "LIP Reset Initiated Count: %d",
+ tvb_get_ntohl (tvb, offset+53));
+ proto_tree_add_text (rps_tree, tvb, offset+57, 4,
+ "LIP Reset Received Count: %d",
+ tvb_get_ntohl (tvb, offset+57));
+ }
+ }
+ }
+}
+
+static void
+dissect_fcels_rpl (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+ guint8 isreq, proto_item *ti)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 0;
+ proto_tree *rpl_tree, *pb_tree;
+ proto_item *subti;
+ int loop;
+
+ if (tree) {
+ rpl_tree = proto_item_add_subtree (ti, ett_fcels_rpl);
+
+ proto_tree_add_item (rpl_tree, hf_fcels_opcode, tvb, offset, 1, 0);
+
+ if (isreq) {
+ proto_tree_add_text (rpl_tree, tvb, offset+6, 2,
+ "Max Size: %d",
+ tvb_get_ntohs (tvb, offset+6));
+ proto_tree_add_text (rpl_tree, tvb, offset+9, 3,
+ "Index: %d",
+ tvb_get_ntoh24 (tvb, offset+9));
+ }
+ else {
+ /* Reply consists of a header and a number of port blocks */
+ proto_tree_add_text (rpl_tree, tvb, offset+2, 2,
+ "Payload Length: %d",
+ tvb_get_ntohs (tvb, offset+2));
+ proto_tree_add_text (rpl_tree, tvb, offset+5, 3,
+ "List Length: %d",
+ tvb_get_ntoh24 (tvb, offset+5));
+ proto_tree_add_text (rpl_tree, tvb, offset+9, 3,
+ "Index of I Port Block: %d",
+ tvb_get_ntoh24 (tvb, offset+9));
+ offset = 12;
+ /* The following loop is for dissecting the port blocks */
+ for (loop = tvb_get_ntoh24 (tvb, 5); loop > 0; loop--) {
+ subti = proto_tree_add_text (rpl_tree, tvb, offset+12, 16,
+ "Port Block %d", loop);
+ pb_tree = proto_item_add_subtree (subti, ett_fcels_rplpb);
+
+ proto_tree_add_text (pb_tree, tvb, offset, 4,
+ "Physical Port #: %d",
+ tvb_get_ntohl (tvb, offset));
+ proto_tree_add_text (pb_tree, tvb, offset+5, 3,
+ "Port Identifier: %s",
+ fc_to_str (tvb_get_ptr (tvb, offset+5, 3)));
+ proto_tree_add_text (pb_tree, tvb, offset+8, 8,
+ "Port Name: %s",
+ fcwwn_to_str (tvb_get_ptr (tvb, offset+8, 8)));
+ offset += 16;
+ }
+ }
+ }
+}
+
+static void
+dissect_fcels_fan (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+ guint8 isreq _U_, proto_item *ti)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 5;
+ proto_tree *fan_tree;
+
+ if (tree) {
+ fan_tree = proto_item_add_subtree (ti, ett_fcels_fan);
+
+ proto_tree_add_item (fan_tree, hf_fcels_opcode, tvb, offset-5, 1, 0);
+
+ proto_tree_add_string (fan_tree, hf_fcels_fabricaddr, tvb, offset, 3,
+ fc_to_str (tvb_get_ptr (tvb, offset, 3)));
+ proto_tree_add_string (fan_tree, hf_fcels_fabricpname, tvb, offset+3,
+ 8, fcwwn_to_str (tvb_get_ptr (tvb, offset, 8)));
+ proto_tree_add_string (fan_tree, hf_fcels_fnname, tvb, offset+11, 8,
+ fcwwn_to_str (tvb_get_ptr (tvb, offset+11, 8)));
+ }
+}
+
+static void
+dissect_fcels_rscn (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+ guint8 isreq, proto_item *ti)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 1;
+ proto_tree *rscn_tree, *rectree;
+ proto_item *subti;
+ int numrec, plen, i;
+
+ if (tree) {
+ rscn_tree = proto_item_add_subtree (ti, ett_fcels_rscn);
+
+ proto_tree_add_item (rscn_tree, hf_fcels_opcode, tvb, offset-1, 1, 0);
+ if (!isreq)
+ return;
+
+ proto_tree_add_text (rscn_tree, tvb, offset, 1,
+ "Page Len: %d", tvb_get_guint8 (tvb, offset));
+ plen = tvb_get_ntohs (tvb, offset+1);
+ proto_tree_add_text (rscn_tree, tvb, offset+1, 2,
+ "Payload Len: %d", plen);
+ numrec = (plen - 4)/4;
+
+ offset = 4;
+ for (i = 0; i < numrec; i++) {
+ subti = proto_tree_add_text (rscn_tree, tvb, offset, 4,
+ "Affected N_Port Page %d", i);
+ rectree = proto_item_add_subtree (subti, ett_fcels_rscn_rec);
+
+ proto_tree_add_item (rectree, hf_fcels_rscn_evqual, tvb, offset,
+ 1, 0);
+ proto_tree_add_item (rectree, hf_fcels_rscn_addrfmt, tvb, offset,
+ 1, 0);
+ proto_tree_add_item (rectree, hf_fcels_rscn_domain, tvb, offset+1,
+ 1, 0);
+ proto_tree_add_item (rectree, hf_fcels_rscn_area, tvb, offset+2,
+ 1, 0);
+ proto_tree_add_item (rectree, hf_fcels_rscn_port, tvb, offset+3,
+ 1, 0);
+ offset += 4;
+ }
+ }
+}
+
+static void
+dissect_fcels_scr (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+ guint8 isreq, proto_item *ti)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 7;
+ proto_tree *scr_tree;
+
+ if (tree) {
+ scr_tree = proto_item_add_subtree (ti, ett_fcels_scr);
+ proto_tree_add_item (scr_tree, hf_fcels_opcode, tvb, offset-7, 1, 0);
+ if (isreq)
+ proto_tree_add_item (scr_tree, hf_fcels_scrregn, tvb, offset, 1, 0);
+ }
+}
+
+static void
+dissect_fcels_rnft (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+ guint8 isreq, proto_item *ti)
+{
+ int offset = 0;
+ guint16 numrec, i;
+ proto_tree *rnft_tree, *fc4_tree;
+ proto_item *subti;
+
+ if (tree) {
+ rnft_tree = proto_item_add_subtree (ti, ett_fcels_rnft);
+
+ proto_tree_add_item (rnft_tree, hf_fcels_opcode, tvb, offset, 1, 0);
+
+ if (isreq) {
+ proto_tree_add_text (rnft_tree, tvb, offset+2, 2,
+ "Max Size: %d", tvb_get_ntohs (tvb, offset+2));
+ proto_tree_add_text (rnft_tree, tvb, offset+7, 1,
+ "Index: %d", tvb_get_guint8 (tvb, offset+7));
+ }
+ else {
+ proto_tree_add_text (rnft_tree, tvb, offset+2, 2,
+ "Payload Len: %d",
+ tvb_get_ntohs (tvb, offset+2));
+ numrec = tvb_get_guint8 (tvb, offset+5);
+ proto_tree_add_text (rnft_tree, tvb, offset+5, 1,
+ "List Length: %d", numrec);
+ proto_tree_add_text (rnft_tree, tvb, offset+7, 1,
+ "Index of First Rec in List: %d",
+ tvb_get_guint8 (tvb, offset+7));
+ offset = 8;
+ for (i = 0; i < numrec; i++) {
+ subti = proto_tree_add_text (rnft_tree, tvb, offset, 4,
+ "FC-4 Entry #%d", i);
+ fc4_tree = proto_item_add_subtree (subti, ett_fcels_rnft_fc4);
+
+ proto_tree_add_item (fc4_tree, hf_fcels_rnft_fc4type, tvb,
+ offset, 1, 0);
+ proto_tree_add_text (fc4_tree, tvb, offset+1, 3,
+ "FC-4 Qualifier 0x%x",
+ tvb_get_ntoh24 (tvb, offset+1));
+ offset += 4;
+ }
+ }
+ }
+}
+
+static void
+dissect_fcels_lsts (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+ guint8 isreq, proto_item *ti)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 5;
+ proto_tree *lsts_tree;
+
+ if (tree) {
+ lsts_tree = proto_item_add_subtree (ti, ett_fcels_lsts);
+
+ proto_tree_add_item (lsts_tree, hf_fcels_opcode, tvb, offset-5, 1, 0);
+ if (isreq) {
+ /* In case of LSTS, the reply has the meat */
+ return;
+ }
+ proto_tree_add_item (lsts_tree, hf_fcels_failedrcvr, tvb, offset, 1, 0);
+ proto_tree_add_item (lsts_tree, hf_fcels_flacompliance, tvb, offset+1,
+ 1, 0);
+ proto_tree_add_item (lsts_tree, hf_fcels_loopstate, tvb, offset+2, 1, 0);
+ proto_tree_add_item (lsts_tree, hf_fcels_publicloop_bmap, tvb, offset+3,
+ 16, 0);
+ proto_tree_add_item (lsts_tree, hf_fcels_pvtloop_bmap, tvb, offset+19,
+ 16, 0);
+ proto_tree_add_item (lsts_tree, hf_fcels_alpa_map, tvb, offset+35,
+ 128, 0);
+ }
+}
+
+static void
+dissect_fcels_prlilo_payload (tvbuff_t *tvb, packet_info *pinfo _U_,
+ guint8 isreq, proto_item *ti, guint8 opcode)
+{
+ int offset = 0,
+ stroff = 0;
+ guint8 type;
+ proto_tree *prli_tree, *svcpg_tree;
+ int num_svcpg, payload_len, i, flag;
+ proto_item *subti;
+ gchar flagstr[100];
+
+ /* We're assuming that we're invoked only if tree is not NULL i.e.
+ * we don't do the usual "if (tree)" check here, the caller must.
+ */
+ prli_tree = proto_item_add_subtree (ti, ett_fcels_prli);
+
+ proto_tree_add_item (prli_tree, hf_fcels_opcode, tvb, offset, 1, 0);
+
+ proto_tree_add_text (prli_tree, tvb, offset+1, 1,
+ "Page Length: %d",
+ tvb_get_guint8 (tvb, offset+1));
+ payload_len = tvb_get_ntohs (tvb, offset+2);
+ proto_tree_add_text (prli_tree, tvb, offset+2, 2,
+ "Payload Length: %d", payload_len);
+ num_svcpg = payload_len/16;
+
+ offset = 4;
+ for (i = 0; i < num_svcpg; i++) {
+ subti = proto_tree_add_text (prli_tree, tvb, offset, 16,
+ "Service Parameter Page %d", i);
+ svcpg_tree = proto_item_add_subtree (subti, ett_fcels_prli_svcpg);
+
+ type = tvb_get_guint8 (tvb, offset);
+ proto_tree_add_text (svcpg_tree, tvb, offset, 1,
+ "TYPE: %s",
+ val_to_str (type,
+ fc_prli_fc4_val, "0x%x"));
+ proto_tree_add_text (svcpg_tree, tvb, offset+1, 1,
+ "TYPE Code Extension: %d",
+ tvb_get_guint8 (tvb, offset+1));
+
+ flag = tvb_get_guint8 (tvb, offset+2);
+ flagstr[0] = '\0';
+ stroff = 0;
+ if (opcode != FC_ELS_TPRLO) {
+ if (flag & 0x80) {
+ strcpy (flagstr, "Orig PA Valid, ");
+ stroff += 15;
+ }
+ if (flag & 0x40) {
+ strcpy (&flagstr[stroff], "Resp PA Valid, ");
+ stroff += 15;
+ }
+
+ if (opcode == FC_ELS_PRLI) {
+ if (!isreq) {
+ if (flag & 0x20) {
+ strcpy (&flagstr[stroff], "Image Pair Estd., ");
+ stroff += 18;
+ }
+ else {
+ strcpy (&flagstr[stroff], "Image Pair Not Estd., ");
+ stroff += 22;
+ }
+ }
+ else {
+ if (flag & 0x20) {
+ strcpy (&flagstr[stroff], "Est Image Pair & Exchg Svc Param, ");
+ stroff += 34;
+ }
+ else {
+ strcpy (&flagstr[stroff], "Exchange Svc Param Only, ");
+ stroff += 25;
+ }
+ }
+ }
+ }
+ else { /* Assuming opcode is TPRLO */
+ if (flag & 0x80) {
+ strcpy (flagstr, "3rd Party Orig PA Valid, ");
+ stroff += 25;
+ }
+ if (flag & 0x40) {
+ strcpy (&flagstr[stroff], "Resp PA Valid, ");
+ stroff += 15;
+ }
+ if (flag & 0x20) {
+ strcpy (&flagstr[stroff], "3rd Party N_Port Valid, ");
+ stroff += 24;
+ }
+ if (flag & 0x10) {
+ strcpy (&flagstr[stroff], "Global PRLO, ");
+ stroff += 13;
+ }
+ }
+
+ proto_tree_add_text (svcpg_tree, tvb, offset+2, 1,
+ "Flags: %s", flagstr);
+ if (!isreq && (opcode != FC_ELS_TPRLO)) {
+ /* This is valid only for ACC */
+ proto_tree_add_text (svcpg_tree, tvb, offset+2, 1,
+ "Response Code: 0x%x",
+ (tvb_get_guint8 (tvb, offset+2) & 0x0F));
+ }
+ if (opcode != FC_ELS_TPRLO) {
+ proto_tree_add_text (svcpg_tree, tvb, offset+4, 4,
+ "Originator PA: 0x%x",
+ tvb_get_ntohl (tvb, offset+4));
+ }
+ else {
+ proto_tree_add_text (svcpg_tree, tvb, offset+4, 4,
+ "3rd Party Originator PA: 0x%x",
+ tvb_get_ntohl (tvb, offset+4));
+ }
+ proto_tree_add_text (svcpg_tree, tvb, offset+8, 4,
+ "Responder PA: 0x%x",
+ tvb_get_ntohl (tvb, offset+8));
+
+ if (type == FC_TYPE_SCSI) {
+ flag = tvb_get_ntohs (tvb, offset+14);
+ flagstr[0] = '\0';
+ stroff = 0;
+
+ if (flag & 0x2000) {
+ if (isreq) {
+ strcpy (flagstr, "Task Retry Ident Req, ");
+ stroff += 22;
+ }
+ else {
+ strcpy (flagstr, "Task Retry Ident Acc, ");
+ stroff += 22;
+ }
+ }
+ if (flag & 0x1000) {
+ strcpy (&flagstr[stroff], "Retry Possible, ");
+ stroff += 16;
+ }
+ if (flag & 0x0080) {
+ strcpy (&flagstr[stroff], "Confirmed Comp, ");
+ stroff += 16;
+ }
+ if (flag & 0x0040) {
+ strcpy (&flagstr[stroff], "Data Overlay, ");
+ stroff += 14;
+ }
+ if (flag & 0x0020) {
+ strcpy (&flagstr[stroff], "Initiator, ");
+ stroff += 11;
+ }
+ if (flag & 0x0010) {
+ strcpy (&flagstr[stroff], "Target, ");
+ stroff += 8;
+ }
+ if (flag & 0x0002) {
+ strcpy (&flagstr[stroff], "Rd Xfer_Rdy Dis, ");
+ stroff += 17;
+ }
+ if (flag & 0x0001) {
+ strcpy (&flagstr[stroff], "Wr Xfer_Rdy Dis");
+ stroff += 15;
+ }
+ proto_tree_add_text (svcpg_tree, tvb, offset+12, 4,
+ "FCP Flags: 0x%x (%s)", flag,
+ flagstr);
+ }
+ else if ((opcode == FC_ELS_PRLI) && !isreq) {
+ proto_tree_add_text (svcpg_tree, tvb, offset+12, 4,
+ "Service Parameter Response: 0x%x",
+ tvb_get_ntohl (tvb, offset+12));
+ }
+ else if (opcode == FC_ELS_TPRLO) {
+ proto_tree_add_text (svcpg_tree, tvb, offset+13, 3,
+ "3rd Party N_Port Id: %s",
+ fc_to_str (tvb_get_ptr (tvb, offset+13, 3)));
+ }
+ }
+}
+
+static void
+dissect_fcels_prli (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ guint8 isreq, proto_item *ti)
+{
+ if (tree) {
+ dissect_fcels_prlilo_payload (tvb, pinfo, isreq, ti, FC_ELS_PRLI);
+ }
+}
+
+static void
+dissect_fcels_prlo (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ guint8 isreq, proto_item *ti)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ if (tree) {
+ dissect_fcels_prlilo_payload (tvb, pinfo, isreq, ti, FC_ELS_PRLO);
+ }
+}
+
+static void
+dissect_fcels_tprlo (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ guint8 isreq, proto_item *ti)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+
+ if (tree) {
+ dissect_fcels_prlilo_payload (tvb, pinfo, isreq, ti, FC_ELS_TPRLO);
+ }
+}
+
+static void
+dissect_fcels_lirr (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+ guint8 isreq _U_, proto_item *ti)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 4;
+ proto_tree *lirr_tree;
+ guint8 lirr_fmt;
+
+ if (tree) {
+ lirr_tree = proto_item_add_subtree (ti, ett_fcels_lirr);
+
+ proto_tree_add_item (lirr_tree, hf_fcels_opcode, tvb, offset-4, 1, 0);
+
+ proto_tree_add_text (lirr_tree, tvb, offset, 1,
+ "Regn. Function: %s",
+ val_to_str (tvb_get_guint8 (tvb, offset),
+ fc_els_lirr_regfunc_val,
+ "Reserved (0x%x)"));
+ lirr_fmt = tvb_get_guint8 (tvb, offset+1);
+ if (!lirr_fmt) {
+ /* This scheme is resorted to because the value 0 has a string in
+ * the value_string that is not what we want displayed here.
+ */
+ proto_tree_add_text (lirr_tree, tvb, offset, 1,
+ "Regn. Format: Common Format");
+ }
+ else {
+ proto_tree_add_text (lirr_tree, tvb, offset, 1,
+ "Regn. Format: %s",
+ val_to_str (lirr_fmt, fc_fc4_val, "0x%x"));
+ }
+ }
+}
+
+static void
+dissect_fcels_srl (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+ guint8 isreq, proto_item *ti)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 4,
+ flag = 0;
+ proto_tree *srl_tree;
+
+ if (tree) {
+ srl_tree = proto_item_add_subtree (ti, ett_fcels_srl);
+
+ proto_tree_add_item (srl_tree, hf_fcels_opcode, tvb, offset-4, 1, 0);
+ if (!isreq)
+ return;
+
+ flag = tvb_get_guint8 (tvb, offset);
+ if (flag & 0x1) {
+ proto_tree_add_text (srl_tree, tvb, offset, 1,
+ "Flag: Scan only specified FL Port");
+ }
+ else {
+ proto_tree_add_text (srl_tree, tvb, offset, 1,
+ "Flag: Scan all loops in domain");
+ }
+ proto_tree_add_text (srl_tree, tvb, offset+1, 3,
+ "FL_Port Addr: %s",
+ fc_to_str (tvb_get_ptr (tvb, offset+1, 3)));
+ }
+}
+
+static void
+dissect_fcels_rpsc (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+ guint8 isreq, proto_item *ti)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 2;
+ int num_entries, i, cap;
+ gchar speed_str[40];
+ int stroff = 0;
+ proto_tree *rpsc_tree;
+
+ if (tree) {
+ rpsc_tree = proto_item_add_subtree (ti, ett_fcels_rpsc);
+
+ proto_tree_add_item (rpsc_tree, hf_fcels_opcode, tvb, offset-2, 1, 0);
+ if (isreq)
+ return;
+
+ num_entries = tvb_get_ntohs (tvb, offset);
+ proto_tree_add_text (rpsc_tree, tvb, offset, 2,
+ "Number of Entries: %d", num_entries);
+ offset = 4;
+ for (i = 0; i < num_entries; i++) {
+ cap = tvb_get_ntohs (tvb, offset);
+ speed_str[0] = '\0';
+ stroff = 0;
+ if (cap & 0x8000) {
+ strcpy (speed_str, "1,");
+ stroff += 2;
+ }
+ if (cap & 0x4000) {
+ strcpy (speed_str, "2,");
+ stroff += 2;
+ }
+ if (cap & 0x2000) {
+ strcpy (speed_str, "4,");
+ stroff += 2;
+ }
+ if (cap & 0x1000) {
+ strcpy (speed_str, "10");
+ stroff += 2;
+ }
+ strcpy (&speed_str[stroff], "Gb");
+ proto_tree_add_text (rpsc_tree, tvb, offset, 2,
+ "Port Speed Capabilities (Port %d): %s", i,
+ speed_str);
+ cap = tvb_get_ntohs (tvb, offset+2);
+ proto_tree_add_text (rpsc_tree, tvb, offset+2, 2,
+ "Port Oper Speed: %s",
+ val_to_str (cap, fc_els_portspeed_val,
+ "0x%x"));
+ }
+ }
+}
+
+static void
+dissect_fcels_rnid (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+ guint8 isreq, proto_item *ti)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 0;
+ int clen, slen;
+ proto_tree *rnid_tree;
+
+ if (tree) {
+ rnid_tree = proto_item_add_subtree (ti, ett_fcels_rnid);
+
+ proto_tree_add_item (rnid_tree, hf_fcels_opcode, tvb, offset, 1, 0);
+ if (isreq) {
+ proto_tree_add_item (rnid_tree, hf_fcels_nodeidfmt, tvb, offset+4,
+ 1, 0);
+ }
+ else {
+ /* We only decode responses to nodeid fmt DF */
+ proto_tree_add_item (rnid_tree, hf_fcels_nodeidfmt, tvb, offset+4,
+ 1, 0);
+ clen = tvb_get_guint8 (tvb, offset+5);
+ proto_tree_add_text (rnid_tree, tvb, offset+5, 1,
+ "Common Identification Data Length: %d", clen);
+ slen = tvb_get_guint8 (tvb, offset+7);
+ proto_tree_add_item (rnid_tree, hf_fcels_spidlen, tvb, offset+7,
+ 1, 0);
+ if (clen) {
+ proto_tree_add_string (rnid_tree, hf_fcels_npname, tvb,
+ offset+8, 8,
+ fcwwn_to_str (tvb_get_ptr (tvb, offset+8,
+ 8)));
+ proto_tree_add_string (rnid_tree, hf_fcels_fnname, tvb,
+ offset+16, 8,
+ fcwwn_to_str (tvb_get_ptr (tvb,
+ offset+16,
+ 8)));
+ }
+ if (tvb_get_guint8 (tvb, offset+4) == 0xDF) {
+ /* Decode the Specific Node ID Format as this is known */
+ proto_tree_add_item (rnid_tree, hf_fcels_vendoruniq, tvb,
+ offset+24, 16, 0);
+ proto_tree_add_item (rnid_tree, hf_fcels_asstype, tvb,
+ offset+40, 4, 0);
+ proto_tree_add_item (rnid_tree, hf_fcels_physport, tvb,
+ offset+44, 4, 0);
+ proto_tree_add_item (rnid_tree, hf_fcels_attnodes, tvb,
+ offset+48, 4, 0);
+ proto_tree_add_item (rnid_tree, hf_fcels_nodemgmt, tvb,
+ offset+52, 1, 0);
+ proto_tree_add_item (rnid_tree, hf_fcels_ipvers, tvb,
+ offset+53, 1, 0);
+ proto_tree_add_item (rnid_tree, hf_fcels_tcpport, tvb,
+ offset+54, 2, 0);
+ proto_tree_add_item (rnid_tree, hf_fcels_ip, tvb, offset+56,
+ 16, 0);
+ proto_tree_add_item (rnid_tree, hf_fcels_vendorsp, tvb,
+ offset+74, 2, 0);
+ }
+ }
+ }
+}
+
+static void
+dissect_fcels_rlir (tvbuff_t *tvb _U_, packet_info *pinfo _U_,
+ proto_tree *tree, guint8 isreq _U_,
+ proto_item *ti _U_)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+
+ if (tree) {
+ }
+}
+
+static void
+dissect_fcels_lsrjt (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+ guint8 isreq _U_, proto_item *ti)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 5;
+ proto_tree *lsrjt_tree;
+
+ if (tree) {
+ lsrjt_tree = proto_item_add_subtree (ti, ett_fcels_lsrjt);
+
+ proto_tree_add_item (lsrjt_tree, hf_fcels_opcode, tvb, offset-5, 1, 0);
+
+ proto_tree_add_item (lsrjt_tree, hf_fcels_rjtcode, tvb, offset++, 1, 0);
+ proto_tree_add_item (lsrjt_tree, hf_fcels_rjtdetcode, tvb, offset++, 1, 0);
+ proto_tree_add_item (lsrjt_tree, hf_fcels_vnduniq, tvb, offset, 1, 0);
+ }
+}
+
+static void
+dissect_fcels (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+
+/* Set up structures needed to add the protocol subtree and manage it */
+ proto_item *ti = NULL;
+ proto_tree *acc_tree;
+ guint8 isreq = FC_ELS_REQ;
+ int offset = 0;
+ guint8 opcode,
+ failed_opcode = 0;
+ conversation_t *conversation;
+ fcels_conv_data_t *cdata;
+ fcels_conv_key_t ckey, *req_key;
+ guint options;
+ address dstaddr;
+ guint8 addrdata[3];
+
+ /* Make entries in Protocol column and Info column on summary display */
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "FC ELS");
+
+ /* decoding of this is done by each individual opcode handler */
+ opcode = tvb_get_guint8 (tvb, 0);
+
+ if (tree) {
+ ti = proto_tree_add_protocol_format (tree, proto_fcels, tvb, 0,
+ tvb_length (tvb), "FC ELS");
+ }
+
+ /* Register conversation in case this is not a response */
+ if ((opcode != FC_ELS_LSRJT) && (opcode != FC_ELS_ACC)) {
+ if (opcode == FC_ELS_FLOGI) {
+ if (pinfo->src.data[2]) {
+ /* If it is a loop port, we'll need to remember the ALPA */
+ options = NO_PORT2;
+ }
+ else {
+ options = NO_PORT2 | NO_ADDR2;
+ }
+ }
+ else {
+ options = NO_PORT2;
+ }
+ conversation = find_conversation (&pinfo->dst, &pinfo->src,
+ pinfo->ptype, pinfo->oxid,
+ pinfo->rxid, options);
+
+ if (!conversation) {
+ conversation = conversation_new (&pinfo->dst, &pinfo->src,
+ pinfo->ptype, pinfo->oxid,
+ pinfo->rxid, options);
+ }
+
+ ckey.conv_idx = conversation->index;
+
+ cdata = (fcels_conv_data_t *)g_hash_table_lookup (fcels_req_hash,
+ &ckey);
+ if (cdata) {
+ /* Since we never free the memory used by an exchange, this maybe a
+ * case of another request using the same exchange as a previous
+ * req.
+ */
+ cdata->opcode = opcode;
+ }
+ else {
+ req_key = g_mem_chunk_alloc (fcels_req_keys);
+ req_key->conv_idx = conversation->index;
+
+ cdata = g_mem_chunk_alloc (fcels_req_vals);
+ cdata->opcode = opcode;
+
+ g_hash_table_insert (fcels_req_hash, req_key, cdata);
+ }
+ }
+ else {
+ isreq = FC_ELS_RPLY;
+
+ options = NO_PORT2;
+ conversation = find_conversation (&pinfo->dst, &pinfo->src,
+ pinfo->ptype, pinfo->oxid,
+ pinfo->rxid, options);
+ if (!conversation) {
+ /* FLOGI has two ways to save state: without the src and using just
+ * the port (ALPA) part of the address. Try both.
+ */
+ addrdata[0] = addrdata[1] = 0;
+ addrdata[2] = pinfo->dst.data[2];
+ SET_ADDRESS (&dstaddr, AT_FC, 3, addrdata);
+ conversation = find_conversation (&dstaddr, &pinfo->src,
+ pinfo->ptype, pinfo->oxid,
+ pinfo->rxid, options);
+ }
+
+ if (!conversation) {
+ /* Finally check for FLOGI with both NO_PORT2 and NO_ADDR2 set */
+ options = NO_ADDR2 | NO_PORT2;
+ conversation = find_conversation (&pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->oxid,
+ pinfo->rxid, options);
+ if (!conversation) {
+ if (tree && (opcode == FC_ELS_ACC)) {
+ /* No record of what this accept is for. Can't decode */
+ acc_tree = proto_item_add_subtree (ti, ett_fcels_acc);
+ proto_tree_add_text (acc_tree, tvb, offset, tvb_length (tvb),
+ "No record of Exchange. Unable to decode ACC");
+ return;
+ }
+ failed_opcode = 0;
+ }
+ }
+
+ if (conversation) {
+ ckey.conv_idx = conversation->index;
+
+ cdata = (fcels_conv_data_t *)g_hash_table_lookup (fcels_req_hash, &ckey);
+
+ if (cdata != NULL) {
+ if ((options & NO_ADDR2) && (cdata->opcode != FC_ELS_FLOGI)) {
+ /* only FLOGI can have this special check */
+ if (tree && (opcode == FC_ELS_ACC)) {
+ /* No record of what this accept is for. Can't decode */
+ acc_tree = proto_item_add_subtree (ti,
+ ett_fcels_acc);
+ proto_tree_add_text (acc_tree, tvb, offset,
+ tvb_length (tvb),
+ "No record of Exchg. Unable to decode ACC");
+ return;
+ }
+ }
+ if (opcode == FC_ELS_ACC)
+ opcode = cdata->opcode;
+ else
+ failed_opcode = cdata->opcode;
+ }
+
+ if (tree) {
+ if ((cdata == NULL) && (opcode != FC_ELS_LSRJT)) {
+ /* No record of what this accept is for. Can't decode */
+ acc_tree = proto_item_add_subtree (ti, ett_fcels_acc);
+ proto_tree_add_text (acc_tree, tvb, offset, tvb_length (tvb),
+ "No record of ELS Req. Unable to decode ACC");
+ return;
+ }
+ }
+ }
+ }
+
+ if (check_col (pinfo->cinfo, COL_INFO)) {
+ if (isreq == FC_ELS_REQ) {
+ col_add_str (pinfo->cinfo, COL_INFO,
+ val_to_str (opcode, fc_els_proto_val, "0x%x"));
+ }
+ else if (opcode == FC_ELS_LSRJT) {
+ col_add_fstr (pinfo->cinfo, COL_INFO, "LS_RJT (%s)",
+ val_to_str (failed_opcode, fc_els_proto_val, "0x%x"));
+ }
+ else {
+ col_add_fstr (pinfo->cinfo, COL_INFO, "ACC (%s)",
+ val_to_str (opcode, fc_els_proto_val, "0x%x"));
+ }
+ }
+
+ switch (opcode) {
+ case FC_ELS_LSRJT:
+ dissect_fcels_lsrjt (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_PLOGI:
+ dissect_fcels_plogi (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_FLOGI:
+ dissect_fcels_flogi (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_LOGOUT:
+ dissect_fcels_logout (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_ABTX:
+ dissect_fcels_abtx (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_RSI:
+ dissect_fcels_rsi (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_RRQ:
+ dissect_fcels_rrq (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_PRLI:
+ dissect_fcels_prli (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_PRLO:
+ dissect_fcels_prlo (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_TPRLO:
+ dissect_fcels_tprlo (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_PDISC:
+ dissect_fcels_pdisc (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_FDISC:
+ dissect_fcels_fdisc (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_ADISC:
+ dissect_fcels_adisc (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_FARP_REQ:
+ dissect_fcels_farp_req (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_FARP_RPLY:
+ dissect_fcels_farp_rply (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_RPS:
+ dissect_fcels_rps (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_RPL:
+ dissect_fcels_rpl (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_FAN:
+ dissect_fcels_fan (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_RSCN:
+ dissect_fcels_rscn (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_SCR:
+ dissect_fcels_scr (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_RNFT:
+ dissect_fcels_rnft (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_LSTS:
+ dissect_fcels_lsts (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_RNID:
+ dissect_fcels_rnid (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_RLIR:
+ dissect_fcels_rlir (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_LIRR:
+ dissect_fcels_lirr (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_SRL:
+ dissect_fcels_srl (tvb, pinfo, tree, isreq, ti);
+ break;
+ case FC_ELS_RPSC:
+ dissect_fcels_rpsc (tvb, pinfo, tree, isreq, ti);
+ break;
+ default:
+ /* proto_tree_add_text ( */
+ call_dissector (data_handle, tvb, pinfo, tree);
+ break;
+ }
+}
+
+void
+proto_register_fcels (void)
+{
+
+/* Setup list of header fields See Section 1.6.1 for details*/
+ static hf_register_info hf[] = {
+ { &hf_fcels_opcode,
+ {"Cmd Code", "fcels.opcode", FT_UINT8, BASE_HEX,
+ VALS (fc_els_proto_val), 0x0, "", HFILL}},
+ { &hf_fcels_rjtcode,
+ {"Reason Code", "fcels.rjt.reason", FT_UINT8, BASE_HEX,
+ VALS (fc_els_rjt_val), 0x0, "", HFILL}},
+ { &hf_fcels_rjtdetcode,
+ {"Reason Explanation", "fcels.rjt.detail", FT_UINT8, BASE_HEX,
+ VALS (fc_els_rjt_det_val), 0x0, "", HFILL}},
+ { &hf_fcels_vnduniq,
+ {"Vendor Unique", "fcels.rjt.vnduniq", FT_UINT8, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_fcels_b2b,
+ {"B2B Credit", "fcels.logi.b2b", FT_UINT8, BASE_DEC, NULL, 0x0, "",
+ HFILL}},
+ { &hf_fcels_cmnfeatures,
+ {"Common Features", "fcels.logi.cmnfeatures", FT_UINT16, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_fcels_bbscnum,
+ {"BB_SC Number", "fcels.logi.bbscnum", FT_UINT8, BASE_DEC, NULL, 0xF0, "",
+ HFILL}},
+ { &hf_fcels_rcvsize,
+ {"Receive Size", "fcels.logi.rcvsize", FT_UINT16, BASE_DEC, NULL, 0x0FFF, "",
+ HFILL}},
+ { &hf_fcels_maxconseq,
+ {"Max Concurrent Seq", "fcels.logi.maxconseq", FT_UINT16, BASE_DEC, NULL,
+ 0x0, "", HFILL}},
+ { &hf_fcels_reloffset,
+ {"Relative Offset By Info Cat", "fcels.logi.reloff", FT_UINT16, BASE_DEC,
+ NULL, 0x0, "", HFILL}},
+ { &hf_fcels_edtov,
+ {"E_D_TOV", "fcels.edtov", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL}},
+ { &hf_fcels_npname,
+ {"N_Port Port_Name", "fcels.npname", FT_STRING, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_fcels_fnname,
+ {"Fabric/Node Name", "fcels.fnname", FT_STRING, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_fcels_cls1param,
+ {"Class 1 Svc Param", "fcels.logi.cls1param", FT_BYTES, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_fcels_cls2param,
+ {"Class 2 Svc Param", "fcels.logi.cls2param", FT_BYTES, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_fcels_cls3param,
+ {"Class 3 Svc Param", "fcels.logi.cls3param", FT_BYTES, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_fcels_cls4param,
+ {"Class 4 Svc Param", "fcels.logi.cls4param", FT_BYTES, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_fcels_vendorvers,
+ {"Vendor Version", "fcels.logi.vendvers", FT_BYTES, BASE_HEX, NULL, 0x0, "",
+ HFILL}},
+ { &hf_fcels_svcavail,
+ {"Services Availability", "fcels.logi.svcavail", FT_BYTES, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_fcels_clsflags,
+ {"Class Flags", "fcels.logi.clsflags", FT_UINT16, BASE_HEX, NULL, 0x0, "",
+ HFILL}},
+ { &hf_fcels_initctl,
+ {"Initiator Ctl", "fcels.logi.initctl", FT_UINT16, BASE_HEX, NULL, 0x0, "",
+ HFILL}},
+ { &hf_fcels_rcptctl,
+ {"Recipient Ctl", "fcels.logi.rcptctl", FT_UINT16, BASE_HEX, NULL, 0x0, "",
+ HFILL}},
+ { &hf_fcels_clsrcvsize,
+ {"Class Recv Size", "fcels.logi.clsrcvsize", FT_UINT16, BASE_DEC, NULL,
+ 0x0, "", HFILL}},
+ { &hf_fcels_conseq,
+ {"Total Concurrent Seq", "fcels.logi.totconseq", FT_UINT8, BASE_DEC, NULL,
+ 0x0, "", HFILL}},
+ { &hf_fcels_e2e,
+ {"End2End Credit", "fcels.logi.e2e", FT_UINT16, BASE_DEC, NULL, 0x0, "",
+ HFILL}},
+ { &hf_fcels_openseq,
+ {"Open Seq Per Exchg", "fcels.logi.openseq", FT_UINT8, BASE_DEC, NULL, 0x0,
+ "", HFILL}},
+ { &hf_fcels_nportid,
+ {"Originator S_ID", "fcels.portid", FT_STRING, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_fcels_oxid,
+ {"OXID", "fcels.oxid", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL}},
+ { &hf_fcels_rxid,
+ {"RXID", "fcels.rxid", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL}},
+ { &hf_fcels_recovqual,
+ {"Recovery Qualifier", "fcels.rcovqual", FT_UINT8, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_fcels_fabricaddr,
+ {"Fabric Address", "fcels.faddr", FT_STRING, BASE_HEX, NULL, 0x0, "",
+ HFILL}},
+ { &hf_fcels_fabricpname,
+ {"Fabric Port Name", "fcels.fpname", FT_STRING, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_fcels_failedrcvr,
+ {"Failed Receiver AL_PA", "fcels.faildrcvr", FT_UINT8, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_fcels_flacompliance,
+ {"FC-FLA Compliance", "fcels.flacompliance", FT_UINT8, BASE_HEX,
+ VALS (fc_els_flacompliance_val), 0x0, "", HFILL}},
+ { &hf_fcels_loopstate,
+ {"Loop State", "fcels.loopstate", FT_UINT8, BASE_HEX,
+ VALS (fc_els_loopstate_val), 0x0, "", HFILL}},
+ { &hf_fcels_publicloop_bmap,
+ {"Public Loop Device Bitmap", "fcels.pubdev_bmap", FT_BYTES, BASE_HEX,
+ NULL, 0x0, "", HFILL}},
+ { &hf_fcels_pvtloop_bmap,
+ {"Private Loop Device Bitmap", "fcels.pvtdev_bmap", FT_BYTES,
+ BASE_HEX, NULL, 0x0, "", HFILL}},
+ { &hf_fcels_alpa_map,
+ {"AL_PA Map", "fcels.alpa", FT_BYTES, BASE_HEX, NULL, 0x0, "",
+ HFILL}},
+ { &hf_fcels_scrregn,
+ {"Registration Function", "fcels.scr.regn", FT_UINT8, BASE_HEX,
+ VALS (fc_els_scr_reg_val), 0x0, "", HFILL}},
+ { &hf_fcels_farp_matchcodept,
+ {"Match Address Code Points", "fcels.matchcp", FT_UINT8, BASE_BIN,
+ NULL, 0x0, "", HFILL}},
+ { &hf_fcels_farp_respaction,
+ {"Responder Action", "fcels.respaction", FT_UINT8, BASE_HEX,
+ VALS (fc_els_farp_respaction_val), 0x0, "", HFILL}},
+ { &hf_fcels_resportid,
+ {"Responding Port ID", "fcels.resportid", FT_STRING, BASE_HEX,
+ NULL, 0x0, "", HFILL}},
+ { &hf_fcels_respname,
+ {"Responding Port Name", "fcels.respname", FT_STRING, BASE_HEX,
+ NULL, 0x0, "", HFILL}},
+ { &hf_fcels_respnname,
+ {"Responding Node Name", "fcels.respnname", FT_STRING, BASE_HEX,
+ NULL, 0x0, "", HFILL}},
+ { &hf_fcels_reqipaddr,
+ {"Requesting IP Address", "fcels.reqipaddr", FT_IPv6, BASE_DEC,
+ NULL, 0x0, "", HFILL}},
+ { &hf_fcels_respipaddr,
+ {"Responding IP Address", "fcels.respipaddr", FT_IPv6, BASE_DEC,
+ NULL, 0x0, "", HFILL}},
+ { &hf_fcels_hardaddr,
+ {"Hard Address of Originator", "fcels.hrdaddr", FT_STRING, BASE_HEX,
+ NULL, 0x0, "", HFILL}},
+ { &hf_fcels_rps_flag,
+ {"Flag", "fcels.flag", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL}},
+ { &hf_fcels_rps_portnum,
+ {"Physical Port Number", "fcels.portnum", FT_UINT32, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_fcels_rps_portstatus,
+ {"Port Status", "fcels.portstatus", FT_UINT16, BASE_HEX,
+ VALS(fc_els_portstatus_val), 0x0, "", HFILL}},
+ { &hf_fcels_rnft_fc4type,
+ {"FC-4 Type", "fcels.rnft.fc4type", FT_UINT8, BASE_HEX,
+ VALS (fc_fc4_val), 0x0, "", HFILL}},
+ { &hf_fcels_rscn_evqual,
+ {"Event Qualifier", "fcels.rscn.evqual", FT_UINT8, BASE_HEX,
+ VALS (fc_els_rscn_evqual_val), 0x3C, "", HFILL}},
+ { &hf_fcels_rscn_addrfmt,
+ {"Address Format", "fcels.rscn.addrfmt", FT_UINT8, BASE_HEX,
+ VALS (fc_els_rscn_addrfmt_val), 0x03, "", HFILL}},
+ { &hf_fcels_rscn_domain,
+ {"Affected Domain", "fcels.rscn.domain", FT_UINT8, BASE_HEX,
+ NULL, 0x0, "", HFILL}},
+ { &hf_fcels_rscn_area,
+ {"Affected Area", "fcels.rscn.area", FT_UINT8, BASE_HEX,
+ NULL, 0x0, "", HFILL}},
+ { &hf_fcels_rscn_port,
+ {"Affected Port", "fcels.rscn.port", FT_UINT8, BASE_HEX,
+ NULL, 0x0, "", HFILL}},
+ { &hf_fcels_nodeidfmt,
+ {"Node Identification Format", "fcels.rnid.nodeidfmt", FT_UINT8,
+ BASE_HEX, VALS (fc_els_nodeid_val), 0x0, "", HFILL}},
+ { &hf_fcels_spidlen,
+ {"Specific Id Length", "fcels.rnid.spidlen", FT_UINT8, BASE_DEC, NULL,
+ 0x0, "", HFILL}},
+ { &hf_fcels_vendoruniq,
+ {"Vendor Unique", "fcels.rnid.vendoruniq", FT_BYTES, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_fcels_vendorsp,
+ {"Vendor Specific", "fcels.rnid.vendorsp", FT_UINT16, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_fcels_asstype,
+ {"Associated Type", "fcels.rnid.asstype", FT_UINT32, BASE_HEX,
+ VALS (fc_els_rnid_asstype_val), 0x0, "", HFILL}},
+ { &hf_fcels_physport,
+ {"Physical Port Number", "fcels.rnid.physport", FT_UINT32, BASE_HEX,
+ NULL, 0x0, "", HFILL}},
+ { &hf_fcels_attnodes,
+ {"Number of Attached Nodes", "fcels.rnid.attnodes", FT_UINT32,
+ BASE_HEX, NULL, 0x0, "", HFILL}},
+ { &hf_fcels_nodemgmt,
+ {"Node Management", "fcels.rnid.nodemgmt", FT_UINT8, BASE_HEX,
+ VALS (fc_els_rnid_mgmt_val), 0x0, "", HFILL}},
+ { &hf_fcels_ipvers,
+ {"IP Version", "fcels.rnid.ipvers", FT_UINT8, BASE_HEX,
+ VALS (fc_els_rnid_ipvers_val), 0x0, "", HFILL}},
+ { &hf_fcels_tcpport,
+ {"TCP/UDP Port Number", "fcels.rnid.tcpport", FT_UINT16, BASE_DEC,
+ NULL, 0x0, "", HFILL}},
+ { &hf_fcels_ip,
+ {"IP Address", "fcels.rnid.ip", FT_IPv6, BASE_HEX, NULL, 0x0, "",
+ HFILL}},
+ };
+
+ static gint *ett[] = {
+ &ett_fcels,
+ &ett_fcels,
+ &ett_fcels_lsrjt,
+ &ett_fcels_acc,
+ &ett_fcels_logi,
+ &ett_fcels_logi_cmnsvc,
+ &ett_fcels_logi_clssvc,
+ &ett_fcels_logo,
+ &ett_fcels_abtx,
+ &ett_fcels_rsi,
+ &ett_fcels_rrq,
+ &ett_fcels_prli,
+ &ett_fcels_prli_svcpg,
+ &ett_fcels_adisc,
+ &ett_fcels_farp,
+ &ett_fcels_rps,
+ &ett_fcels_rpl,
+ &ett_fcels_rplpb,
+ &ett_fcels_fan,
+ &ett_fcels_rscn,
+ &ett_fcels_rscn_rec,
+ &ett_fcels_scr,
+ &ett_fcels_rnft,
+ &ett_fcels_rnft_fc4,
+ &ett_fcels_lsts,
+ &ett_fcels_rnid,
+ &ett_fcels_rlir,
+ &ett_fcels_lirr,
+ &ett_fcels_srl,
+ &ett_fcels_rpsc,
+ };
+
+ /* Register the protocol name and description */
+ proto_fcels = proto_register_protocol("FC Extended Link Svc", "FC ELS", "els");
+
+ /* Required function calls to register the header fields and subtrees used */
+ proto_register_field_array(proto_fcels, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+ register_init_routine (&fcels_init_protocol);
+}
+
+void
+proto_reg_handoff_fcels (void)
+{
+ dissector_handle_t els_handle;
+
+ els_handle = create_dissector_handle (dissect_fcels, proto_fcels);
+ dissector_add("fc.ftype", FC_FTYPE_ELS, els_handle);
+
+ data_handle = find_dissector ("data");
+}
diff --git a/packet-fcels.h b/packet-fcels.h
new file mode 100644
index 0000000000..cb6a39b2da
--- /dev/null
+++ b/packet-fcels.h
@@ -0,0 +1,321 @@
+/* packet-fcels.h
+ * Fibre Channel Extended Link Services Definitions (ddutt@cisco.com)
+ * Copyright 2001, Dinesh G Dutt <ddutt@cisco.com>
+ *
+ * $Id: packet-fcels.h,v 1.1 2002/12/08 02:32:17 gerald Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PACKET_FCELS_H_
+#define __PACKET_FCELS_H_
+
+#define FC_ELS_LSRJT 0x01
+#define FC_ELS_ACC 0x02
+#define FC_ELS_PLOGI 0x03
+#define FC_ELS_FLOGI 0x04
+#define FC_ELS_LOGOUT 0x05
+#define FC_ELS_ABTX 0x06
+#define FC_ELS_RSI 0x0A
+#define FC_ELS_TEST 0x11
+#define FC_ELS_RRQ 0x12
+#define FC_ELS_PRLI 0x20
+#define FC_ELS_PRLO 0x21
+#define FC_ELS_TPRLO 0x24
+#define FC_ELS_PDISC 0x50
+#define FC_ELS_FDISC 0x51
+#define FC_ELS_ADISC 0x52
+#define FC_ELS_FARP_REQ 0x54
+#define FC_ELS_FARP_RPLY 0x55
+#define FC_ELS_RPS 0x56
+#define FC_ELS_RPL 0x57
+#define FC_ELS_FAN 0x60
+#define FC_ELS_RSCN 0x61
+#define FC_ELS_SCR 0x62
+#define FC_ELS_RNFT 0x63
+#define FC_ELS_LINIT 0x70
+#define FC_ELS_LSTS 0x72
+#define FC_ELS_RNID 0x78
+#define FC_ELS_RLIR 0x79
+#define FC_ELS_LIRR 0x7A
+#define FC_ELS_SRL 0x7B
+#define FC_ELS_RPSC 0x7D
+
+static const value_string fc_els_proto_val[] = {
+ {FC_ELS_LSRJT , "LS_RJT"},
+ {FC_ELS_ACC , "ACC"},
+ {FC_ELS_PLOGI , "PLOGI"},
+ {FC_ELS_FLOGI , "FLOGI"},
+ {FC_ELS_LOGOUT , "LOGO"},
+ {FC_ELS_ABTX , "ABTX"},
+ {FC_ELS_RSI , "RSI"},
+ {FC_ELS_TEST , "TEST"},
+ {FC_ELS_RRQ , "RRQ"},
+ {FC_ELS_PRLI , "PRLI"},
+ {FC_ELS_PRLO , "PRLO"},
+ {FC_ELS_TPRLO , "TPRLO"},
+ {FC_ELS_PDISC , "PDISC"},
+ {FC_ELS_FDISC , "FDISC"},
+ {FC_ELS_ADISC , "ADISC"},
+ {FC_ELS_FARP_REQ , "FARP-REQ"},
+ {FC_ELS_FARP_RPLY , "FARP-REPLY"},
+ {FC_ELS_RPS , "RPS"},
+ {FC_ELS_RPL , "RPL"},
+ {FC_ELS_FAN , "FAN"},
+ {FC_ELS_RSCN , "RSCN"},
+ {FC_ELS_SCR , "SCR"},
+ {FC_ELS_RNFT , "RNFT"},
+ {FC_ELS_LINIT , "LINIT"},
+ {FC_ELS_LSTS , "LSTS"},
+ {FC_ELS_RNID , "RNID"},
+ {FC_ELS_RLIR , "RLIR"},
+ {FC_ELS_LIRR , "LIRR"},
+ {FC_ELS_SRL , "SRL"},
+ {FC_ELS_RPSC , "RPSC"},
+ {0, NULL},
+};
+
+/* Reject Reason Codes */
+#define FC_ELS_RJT_INVCMDCODE 0x01
+#define FC_ELS_RJT_LOGERR 0x03
+#define FC_ELS_RJT_LOGBSY 0x05
+#define FC_ELS_RJT_PROTERR 0x07
+#define FC_ELS_RJT_GENFAIL 0x09
+#define FC_ELS_RJT_CMDNOTSUPP 0x0B
+#define FC_ELS_RJT_GENFAIL2 0x0D
+#define FC_ELS_RJT_CMDINPROG 0x0E
+#define FC_ELS_RJT_VENDOR 0xFF
+
+static const value_string fc_els_rjt_val[] = {
+ {FC_ELS_RJT_INVCMDCODE, "Invalid Cmd Code"},
+ {FC_ELS_RJT_LOGERR , "Logical Error"},
+ {FC_ELS_RJT_LOGBSY , "Logical Busy"},
+ {FC_ELS_RJT_PROTERR , "Protocol Error"},
+ {FC_ELS_RJT_GENFAIL , "Unable to Perform Cmd"},
+ {FC_ELS_RJT_CMDNOTSUPP, "Command Not Supported"},
+ {FC_ELS_RJT_GENFAIL2 , "Unable to Perform Cmd"},
+ {FC_ELS_RJT_CMDINPROG , "Command in Progress Already"},
+ {FC_ELS_RJT_VENDOR , "Vendor Unique Error"},
+ {0, NULL},
+};
+
+#define FC_ELS_RJT_DET_NODET 0x00
+#define FC_ELS_RJT_DET_SVCPARM_OPT 0x01
+#define FC_ELS_RJT_DET_SVCPARM_INITCTL 0x03
+#define FC_ELS_RJT_DET_SVCPARM_RCPTCTL 0x05
+#define FC_ELS_RJT_DET_SVCPARM_RCVSZE 0x07
+#define FC_ELS_RJT_DET_SVCPARM_CSEQ 0x09
+#define FC_ELS_RJT_DET_SVCPARM_CREDIT 0x0B
+#define FC_ELS_RJT_DET_INV_PFNAME 0x0D
+#define FC_ELS_RJT_DET_INV_NFNAME 0x0E
+#define FC_ELS_RJT_DET_INV_CMNSVCPARM 0x0F
+#define FC_ELS_RJT_DET_INV_ASSOCHDR 0x11
+#define FC_ELS_RJT_DET_ASSOCHDR_REQD 0x13
+#define FC_ELS_RJT_DET_INV_OSID 0x15
+#define FC_ELS_RJT_DET_EXCHG_COMBO 0x17
+#define FC_ELS_RJT_DET_CMDINPROG 0x19
+#define FC_ELS_RJT_DET_PLOGI_REQ 0x1E
+#define FC_ELS_RJT_DET_INV_NPID 0x1F
+#define FC_ELS_RJT_DET_INV_SEQID 0x21
+#define FC_ELS_RJT_DET_INV_EXCHG 0x23
+#define FC_ELS_RJT_DET_INACTIVE_EXCHG 0x25
+#define FC_ELS_RJT_DET_RQUAL_REQD 0x27
+#define FC_ELS_RJT_DET_OORSRC 0x29
+#define FC_ELS_RJT_DET_SUPPLYFAIL 0x2A
+#define FC_ELS_RJT_DET_REQNOTSUPP 0x2C
+#define FC_ELS_RJT_DET_INV_PLEN 0x2D
+#define FC_ELS_RJT_DET_INV_ALIASID 0x30
+#define FC_ELS_RJT_DET_OORSRC_ALIASID 0x31
+#define FC_ELS_RJT_DET_INACTIVE_ALIASID 0x32
+#define FC_ELS_RJT_DET_DEACT_ALIAS_FAIL1 0x33
+#define FC_ELS_RJT_DET_DEACT_ALIAS_FAIL2 0x34
+#define FC_ELS_RJT_DET_SVCPARM_CONFLICT 0x35
+#define FC_ELS_RJT_DET_INV_ALIASTOK 0x36
+#define FC_ELS_RJT_DET_UNSUPP_ALIASTOK 0x37
+#define FC_ELS_RJT_DET_GRPFORM_FAIL 0x38
+#define FC_ELS_RJT_DET_QOSPARM_ERR 0x40
+#define FC_ELS_RJT_DET_INV_VCID 0x41
+#define FC_ELS_RJT_DET_OORSRC_C4 0x42
+#define FC_ELS_RJT_DET_INV_PNNAME 0x44
+
+static const value_string fc_els_rjt_det_val[] = {
+ {FC_ELS_RJT_DET_NODET , "No further details"},
+ {FC_ELS_RJT_DET_SVCPARM_OPT , "Svc Param - Options Error"},
+ {FC_ELS_RJT_DET_SVCPARM_INITCTL , "Svc Param - Initiator Ctl Error"},
+ {FC_ELS_RJT_DET_SVCPARM_RCPTCTL , "Svc Param - Recipient Ctl Error"},
+ {FC_ELS_RJT_DET_SVCPARM_RCVSZE , "Svc Param - Recv Size Error"},
+ {FC_ELS_RJT_DET_SVCPARM_CSEQ , "Svc Param - Concurrent Seq Error"},
+ {FC_ELS_RJT_DET_SVCPARM_CREDIT , "Svc Param - Credit Error"},
+ {FC_ELS_RJT_DET_INV_PFNAME , "Invalid N_/F_Port Name"},
+ {FC_ELS_RJT_DET_INV_NFNAME , "Invalid Node/Fabric Name"},
+ {FC_ELS_RJT_DET_INV_CMNSVCPARM , "Invalid Common Svc Param"},
+ {FC_ELS_RJT_DET_INV_ASSOCHDR , "Invalid Association Header"},
+ {FC_ELS_RJT_DET_ASSOCHDR_REQD , "Association Header Reqd"},
+ {FC_ELS_RJT_DET_INV_OSID , "Invalid Orig S_ID"},
+ {FC_ELS_RJT_DET_EXCHG_COMBO , "Invalid OXID-RXID Combo"},
+ {FC_ELS_RJT_DET_CMDINPROG , "Cmd Already in Progress"},
+ {FC_ELS_RJT_DET_PLOGI_REQ , "N_Port Login Required"},
+ {FC_ELS_RJT_DET_INV_NPID , "Invalid N_Port Id"},
+ {FC_ELS_RJT_DET_INV_SEQID , "Invalid SeqID"},
+ {FC_ELS_RJT_DET_INV_EXCHG , "Attempt to Abort Invalid Exchg"},
+ {FC_ELS_RJT_DET_INACTIVE_EXCHG , "Attempt to Abort Inactive Exchg"},
+ {FC_ELS_RJT_DET_RQUAL_REQD , "Resource Qualifier Required"},
+ {FC_ELS_RJT_DET_OORSRC , "Insufficient Resources for Login"},
+ {FC_ELS_RJT_DET_SUPPLYFAIL , "Unable to Supply Req Data"},
+ {FC_ELS_RJT_DET_REQNOTSUPP , "Command Not Supported"},
+ {FC_ELS_RJT_DET_INV_PLEN , "Invalid Payload Length"},
+ {FC_ELS_RJT_DET_INV_ALIASID , "No Alias IDs available"},
+ {FC_ELS_RJT_DET_OORSRC_ALIASID , "Alias_ID Cannot be Activated (Out of Rsrc)"},
+ {FC_ELS_RJT_DET_INACTIVE_ALIASID , "Alias_ID Cannot be Activated (Inv AID)"},
+ {FC_ELS_RJT_DET_DEACT_ALIAS_FAIL1, "Alias_ID Cannot be Deactivated"},
+ {FC_ELS_RJT_DET_DEACT_ALIAS_FAIL2, "Alias_ID Cannot be Deactivated"},
+ {FC_ELS_RJT_DET_SVCPARM_CONFLICT , "Svc Parameter Conflict"},
+ {FC_ELS_RJT_DET_INV_ALIASTOK , "Invalid Alias Token"},
+ {FC_ELS_RJT_DET_UNSUPP_ALIASTOK , "Unsupported Alias Token"},
+ {FC_ELS_RJT_DET_GRPFORM_FAIL , "Alias Grp Cannot be Formed"},
+ {FC_ELS_RJT_DET_QOSPARM_ERR , "QoS Param Error"},
+ {FC_ELS_RJT_DET_INV_VCID , "VC_ID Not Found"},
+ {FC_ELS_RJT_DET_OORSRC_C4 , "No Resources to Support Class 4 Conn"},
+ {FC_ELS_RJT_DET_INV_PNNAME , "Invalid Port/Node Name"},
+};
+
+static const value_string fc_els_flacompliance_val[] = {
+ {1, "FC-FLA Level 1"},
+ {2, "FC-FLA Level 2"},
+ {0, NULL},
+};
+
+static const value_string fc_els_loopstate_val[] = {
+ {1, "Online"},
+ {2, "Loop Failure"},
+ {3, "Initialization Failure"},
+ {4, "Initializing"},
+ {0, NULL},
+};
+
+static const value_string fc_els_scr_reg_val[] = {
+ {1, "Fabric Detected Regn"},
+ {2, "N_Port Detected Regn"},
+ {3, "Full Regn"},
+ {255, "Clear All Regn"},
+ {0, NULL},
+};
+
+static const value_string fc_els_farp_respaction_val[] = {
+ {0, "No Action"},
+ {1, "Login Using Requesting Port ID"},
+ {2, "Respond with FARP-REPLY"},
+ {3, "Login & send FARP-REPLY"},
+ {0, NULL},
+};
+
+static const value_string fc_els_portstatus_val[] = {
+ {0x20, "Point-to-Point Connection | No Fabric"},
+ {0x10, "AL Connection | No Fabric"},
+ {0x28, "Point-to-Point Connection | Fabric Detected"},
+ {0x2C, "Point-to-Point Connection | Fabric Detected | Loss of Signal"},
+ {0x24, "Point-to-Point Connection | Loss of Signal"},
+ {0x18, "AL Connection | Fabric Detected"},
+ {0x14, "AL Connection | Loss of Signal"},
+ {0x1C, "AL Connection | Fabric Detected | Loss of Signal"},
+ {0x04, "Loss of Signal"},
+ {0x02, "Loss of Synchronization"},
+ {0x01, "Link Reset Protocol in Progress"},
+ {0, NULL},
+};
+
+static const value_string fc_els_portspeed_val[] = {
+ {0x8000, "1 Gb"},
+ {0x4000, "2 Gb"},
+ {0x2000, "4 Gb"},
+ {0x1000, "10 Gb"},
+ {0x0002, "Unknown"},
+ {0x0001, "Speed Not Estd."},
+ {0, NULL}
+};
+
+static const value_string fc_els_lirr_regfunc_val[] = {
+ {0x1, "Set Reg: Conditionally Receive"},
+ {0x2, "Set Reg: Always Receive"},
+ {0xFF, "Clear Reg"},
+ {0, NULL},
+};
+
+static const value_string fc_els_rscn_evqual_val[] = {
+ {0x00, "Event is not specified"},
+ {0x01, "Changed Name Server Object"},
+ {0x02, "Changed Port Attribute"},
+ {0x03, "Changed Service Object"},
+ {0x04, "Changed Switch Config"},
+ {0, NULL},
+};
+
+static const value_string fc_els_rscn_addrfmt_val[] = {
+ {0, "Port Addr (single N/L Port or service)"},
+ {1, "Area Addr Group (area of E/L/N Port addresses)"},
+ {2, "Domain Addr Group"},
+ {3, "Fabric Addr Group"},
+ {0, NULL},
+};
+
+static const value_string fc_els_nodeid_val[] = {
+ {0x00, "Common Identification Data Only"},
+ {0x05, "IP Specific Data"},
+ {0x08, "FCP-Specific Data"},
+ {0x20, "FC_CT Specific Data"},
+ {0x22, "SW_ILS Specific Data"},
+ {0x23, "AL Specific Data"},
+ {0x24, "SNMP Specific Data"},
+ {0xDF, "Common ID Data + General Topology Discovery Format"},
+ {0, NULL},
+};
+
+static const value_string fc_els_rnid_asstype_val[] = {
+ {0x0, "Reserved"},
+ {0x1, "Unknown"},
+ {0x2, "Other"},
+ {0x3, "Hub"},
+ {0x4, "Switch"},
+ {0x5, "Gateway"},
+ {0x6, "Converter"},
+ {0x7, "HBA"},
+ {0x9, "Storage Device"},
+ {0xA, "Host"},
+ {0xB, "Storage Subsystem"},
+ {0xE, "Storage Access Device"},
+ {0x11, "NAS Device"},
+ {0, NULL},
+};
+
+static const value_string fc_els_rnid_mgmt_val[] = {
+ {0, "IP/UDP/SNMP"},
+ {1, "IP/TCP/Telnet"},
+ {2, "IP/TCP/HTTP"},
+ {3, "IP/TCP/HTTPS"},
+ {0, NULL},
+};
+
+static const value_string fc_els_rnid_ipvers_val[] = {
+ {0, "None"},
+ {1, "IPv4"},
+ {2, "IPv6"},
+ {0, NULL},
+};
+
+#endif
diff --git a/packet-fcip.c b/packet-fcip.c
new file mode 100644
index 0000000000..fdcc4df335
--- /dev/null
+++ b/packet-fcip.c
@@ -0,0 +1,619 @@
+/* packet-fcip.c
+ * Routines for FCIP dissection
+ * Copyright 2001, Dinesh G Dutt (ddutt@cisco.com)
+ *
+ * $Id: packet-fcip.c,v 1.1 2002/12/08 02:32:17 gerald Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <epan/packet.h>
+#include "prefs.h"
+#include <epan/conversation.h>
+
+#define FCIP_ENCAP_HEADER_LEN 28
+#define FCIP_MIN_HEADER_LEN 16 /* upto frame len field */
+#define FCIP_ENCAP_PROTO_VER 0xFEFE0101
+#define FCIP_IS_SF(pflags) ((pflags & 0x1) == 0x1)
+#define FCIP_IS_CH(pflags) ((pflags & 0x80) == 0x80)
+
+typedef enum {
+ FCIP_EOFn = 0x41,
+ FCIP_EOFt = 0x42,
+ FCIP_EOFrt = 0x44,
+ FCIP_EOFdt = 0x46,
+ FCIP_EOFni = 0x49,
+ FCIP_EOFdti = 0x4E,
+ FCIP_EOFrti = 0x4F,
+ FCIP_EOFa = 0x50,
+} fcip_eof_t;
+
+typedef enum {
+ FCIP_SOFf = 0x28,
+ FCIP_SOFi4 = 0x29,
+ FCIP_SOFi2 = 0x2D,
+ FCIP_SOFi3 = 0x2E,
+ FCIP_SOFn4 = 0x31,
+ FCIP_SOFn2 = 0x35,
+ FCIP_SOFn3 = 0x36,
+ FCIP_SOFc4 = 0x39,
+} fcip_sof_t;
+
+typedef enum {
+ FCENCAP_PROTO_FCIP = 1,
+ FCENCAP_PROTO_iFCP = 2,
+} fcencap_proto_t;
+
+static const value_string fcip_eof_vals[] = {
+ {FCIP_EOFn, "EOFn" },
+ {FCIP_EOFt, "EOFt" },
+ {FCIP_EOFrt, "EOFrt" },
+ {FCIP_EOFdt, "EOFdt" },
+ {FCIP_EOFni, "EOFni" },
+ {FCIP_EOFdti, "EOFdti" },
+ {FCIP_EOFrti, "EOFrti" },
+ {FCIP_EOFa, "EOFa" },
+ {0, NULL},
+};
+
+static const value_string fcip_sof_vals[] = {
+ {FCIP_SOFf, "SOFf" },
+ {FCIP_SOFi4, "SOFi4" },
+ {FCIP_SOFi2, "SOFi2" },
+ {FCIP_SOFi3, "SOFi3" },
+ {FCIP_SOFn4, "SOFn4" },
+ {FCIP_SOFn2, "SOFn2" },
+ {FCIP_SOFn3, "SOFn3" },
+ {FCIP_SOFc4, "SOFc4" },
+ {0, NULL},
+};
+
+static const value_string fcencap_proto_vals[] = {
+ {FCENCAP_PROTO_FCIP, "FCIP"},
+ {FCENCAP_PROTO_iFCP, "iFCP"},
+};
+
+static const value_string fsf_conn_flag_vals[] = {
+ {0, NULL},
+};
+
+static const gchar * sof_strings[] = {
+ "SOFf", "SOFi4", "", "", "", "SOFi2", "SOFi3", "", "", "SOFn4", "", "", "",
+ "SOFn2", "SOFn3", "", "", "SOFc4", "",
+};
+
+static const gchar *eof_strings[] = {
+ "EOFn", "EOFt", "", "EOFrt", "", "EOFdt", "", "", "EOFni", "", "", "", "",
+ "EOFdti", "EOFrti", "EOFa", "",
+};
+
+static guint fcip_header_2_bytes[2] = {FCIP_ENCAP_PROTO_VER,
+ FCIP_ENCAP_PROTO_VER};
+
+static int proto_fcip = -1;
+
+static int hf_fcip_protocol = -1;
+static int hf_fcip_protocol_c = -1;
+static int hf_fcip_version = -1;
+static int hf_fcip_version_c = -1;
+static int hf_fcip_encap_word1 = -1;
+static int hf_fcip_flags = -1;
+static int hf_fcip_flags_c = -1;
+static int hf_fcip_framelen = -1;
+static int hf_fcip_framelen_c = -1;
+static int hf_fcip_tsec = -1;
+static int hf_fcip_tusec = -1;
+static int hf_fcip_encap_crc = -1;
+static int hf_fcip_sof = -1;
+static int hf_fcip_sof_c = -1;
+static int hf_fcip_eof = -1;
+static int hf_fcip_eof_c = -1;
+static int hf_fcip_pflags_changed = -1;
+static int hf_fcip_pflags_special = -1;
+static int hf_fcip_pflags_c = -1;
+static int hf_fcip_src_wwn = -1;
+static int hf_fcip_dst_wwn = -1;
+static int hf_fcip_conn_code = -1;
+static int hf_fcip_katov = -1;
+static int hf_fcip_src_entity_id = -1;
+static int hf_fcip_conn_nonce = -1;
+static int hf_fcip_conn_flags = -1;
+
+static int ett_fcip = -1;
+
+static guint fcip_port = 3225;
+static gboolean fcip_desegment = TRUE;
+
+static dissector_handle_t data_handle;
+static dissector_handle_t fc_handle;
+
+/* This routine attempts to locate the position of the next header in the
+ * provided segment
+ */
+static guint
+get_next_fcip_header_offset (tvbuff_t *tvb, packet_info *pinfo, gint offset)
+{
+ gint bytes_remaining = tvb_length_remaining (tvb, offset);
+ gint frame_len;
+ guint16 flen, flen1;
+ fcip_eof_t eof, eofc;
+
+ /*
+ * As per the FCIP standard, the following tests must PASS:
+ * 1) Frame Length field validation -- 15 < Frame Length < 545;
+ * 2) Comparison of Frame Length field to its ones complement; and
+ * 3) A valid EOF is found in the word preceding the start of the next
+ * FCIP header as indicated by the Frame Length field, to be tested
+ * as follows:
+ * 1) Bits 24-31 and 16-23 contain identical legal EOF values (the
+ * list of legal EOF values is in the FC Frame Encapsulation
+ * [21]); and
+ * 2) Bits 8-15 and 0-7 contain the ones complement of the EOF
+ * value found in bits 24-31.
+ *
+ * As per the FCIP standard, in addition, at least 3 of the following set
+ * of tests must be performed to identify that we've located the start of
+ * an FCIP frame.
+ * a) Protocol# ones complement field (1 test);
+ * b) Version ones complement field (1 test);
+ * c) Replication of encapsulation word 0 in word 1 (1 test);
+ * d) Reserved field and its ones complement (2 tests);
+ * e) Flags field and its ones complement (2 tests);
+ * f) CRC field is equal to zero (1 test);
+ * g) SOF fields and ones complement fields (4 tests);
+ * h) Format and values of FC header (1 test);
+ * i) CRC of FC Frame (2 tests);
+ * j) FC Frame Encapsulation header information in the next FCIP Frame
+ * (1 test).
+ *
+ * At least 3 of the 16 tests listed above SHALL be performed. Failure
+ * of any of the above tests actually performed SHALL indicate an
+ * encapsulation error and the FC Frame SHALL NOT be forwarded on to
+ * the FC Entity.
+ */
+
+NXT_BYTE: while (bytes_remaining) {
+ if (bytes_remaining < FCIP_ENCAP_HEADER_LEN) {
+ if(fcip_desegment && pinfo->can_desegment) {
+ /*
+ * This frame doesn't have all of the data for
+ * this message, but we can do reassembly on it.
+ *
+ * Tell the TCP dissector where the data for this
+ * message starts in the data it handed us, and
+ * how many more bytes we need, and return.
+ */
+ pinfo->desegment_offset = offset;
+ pinfo->desegment_len = FCIP_ENCAP_HEADER_LEN;
+ return -2;
+ }
+ }
+
+ /* I check that we have a valid header before checking for the frame
+ * length and the other initial tests.
+ */
+
+ /*
+ * Tests a, b and c
+ */
+ if (memcmp ((void *)tvb_get_ptr (tvb, offset, 8),
+ (void *)fcip_header_2_bytes, 8) != 0) {
+ offset++;
+ bytes_remaining--;
+ goto NXT_BYTE;
+ }
+
+ flen = (tvb_get_ntohs (tvb, offset+12)) & 0x03FF;
+ frame_len = (tvb_get_ntohs (tvb, offset+12) & 0x03FF)*4;
+
+ if ((flen < 15) || (flen > 545)) {
+ /* Frame length check failed. Skip byte and try again */
+ offset++;
+ bytes_remaining--;
+ goto NXT_BYTE;
+ }
+
+ flen1 = (tvb_get_ntohs (tvb, offset+14)) & 0x03FF;
+
+ if ((flen & 0x03FF) != ((~flen1)&0x03FF)) {
+ /* frame_len and its one's complement are not the same */
+ offset++;
+ bytes_remaining--;
+ goto NXT_BYTE;
+ }
+
+ /* Valid EOF check */
+ if (tvb_bytes_exist (tvb, offset+(frame_len-1)*4, 4)) {
+ eof = (fcip_eof_t)tvb_get_guint8 (tvb, offset+(frame_len-1)*4);
+ eofc = (fcip_eof_t)tvb_get_guint8 (tvb, offset+(frame_len-1)*4+2);
+
+ if ((eof != FCIP_EOFn) && (eof != FCIP_EOFt) && (eof != FCIP_EOFrt)
+ && (eof != FCIP_EOFdt) && (eof != FCIP_EOFni) &&
+ (eof != FCIP_EOFdti) && (eof != FCIP_EOFrti) &&
+ (eof != FCIP_EOFa)) {
+ offset++;
+ bytes_remaining--;
+ goto NXT_BYTE;
+ }
+
+ if ((eof != ~eofc) ||
+ (eof != tvb_get_guint8 (tvb, offset+(frame_len-1)*4+1)) ||
+ (eofc != tvb_get_guint8 (tvb, offset+(frame_len-1)*4+3))) {
+ offset++;
+ bytes_remaining--;
+ goto NXT_BYTE;
+ }
+ }
+
+ /* Test d */
+ if ((tvb_get_guint8 (tvb, offset+9) != 0) ||
+ (tvb_get_guint8 (tvb, offset+11) != 0xFF)) {
+ /* Failed */
+ offset++;
+ bytes_remaining--;
+ goto NXT_BYTE;
+ }
+
+ /* Test e */
+
+ /* Test f */
+ if (tvb_get_ntohl (tvb, offset+24)) {
+ /* Failed */
+ offset++;
+ bytes_remaining--;
+ goto NXT_BYTE;
+ }
+
+ if (bytes_remaining >= (frame_len)) {
+ if (tvb_bytes_exist (tvb, offset+frame_len, 8)) {
+ /* The start of the next header matches what we wish to see */
+ if (memcmp ((void *)tvb_get_ptr (tvb, offset+frame_len, 8),
+ (void *)fcip_header_2_bytes, 8) == 0) {
+ return (offset);
+ }
+ else {
+ offset++;
+ bytes_remaining--;
+ goto NXT_BYTE;
+ }
+ }
+ else {
+ return (offset);
+ }
+ }
+ else {
+ if(fcip_desegment && pinfo->can_desegment) {
+ /*
+ * This frame doesn't have all of the data for
+ * this message, but we can do reassembly on it.
+ *
+ * Tell the TCP dissector where the data for this
+ * message starts in the data it handed us, and
+ * how many more bytes we need, and return.
+ */
+ pinfo->desegment_offset = offset;
+ pinfo->desegment_len = frame_len - bytes_remaining;
+ return -2;
+ }
+ else {
+ return (offset);
+ }
+ }
+ }
+
+ return (-1); /* Unable to find FCIP header */
+}
+
+static void
+dissect_fcencap_header (tvbuff_t *tvb, proto_tree *tree, gint offset)
+{
+ guint8 protocol = tvb_get_guint8 (tvb, offset);
+
+ if (tree) {
+ proto_tree_add_item (tree, hf_fcip_protocol, tvb, offset, 1, 0);
+ proto_tree_add_item (tree, hf_fcip_version, tvb, offset+1, 1, 0);
+ proto_tree_add_item (tree, hf_fcip_protocol_c, tvb, offset+2, 1, 0);
+ proto_tree_add_item (tree, hf_fcip_version_c, tvb, offset+3, 1, 0);
+
+ if (protocol == FCENCAP_PROTO_FCIP) {
+ proto_tree_add_item (tree, hf_fcip_encap_word1, tvb, offset+4,
+ 4, 0);
+ proto_tree_add_item (tree, hf_fcip_pflags_changed, tvb, offset+8,
+ 1, 0);
+ proto_tree_add_item (tree, hf_fcip_pflags_special, tvb, offset+8,
+ 1, 0);
+ proto_tree_add_item (tree, hf_fcip_pflags_c, tvb, offset+10, 1, 0);
+ }
+
+ proto_tree_add_item (tree, hf_fcip_flags, tvb, offset+12, 1, 0);
+ proto_tree_add_item (tree, hf_fcip_framelen, tvb, offset+12, 2, 0);
+ proto_tree_add_item (tree, hf_fcip_flags_c, tvb, offset+14, 1, 0);
+ proto_tree_add_item (tree, hf_fcip_framelen_c, tvb, offset+14, 2, 0);
+ proto_tree_add_item (tree, hf_fcip_tsec, tvb, offset+16, 4, 0);
+ proto_tree_add_item (tree, hf_fcip_tusec, tvb, offset+20, 4, 0);
+ proto_tree_add_item (tree, hf_fcip_encap_crc, tvb, offset+24, 4, 0);
+ }
+}
+
+static void
+dissect_fcip_sf (tvbuff_t *tvb, proto_tree *tree, gint offset)
+{
+ if (tree) {
+ proto_tree_add_string (tree, hf_fcip_src_wwn, tvb, offset, 8,
+ fcwwn_to_str (tvb_get_ptr (tvb, offset, 8)));
+ proto_tree_add_bytes (tree, hf_fcip_src_entity_id, tvb, offset+8, 8,
+ tvb_get_ptr (tvb, offset+8, 8));
+ proto_tree_add_bytes (tree, hf_fcip_conn_nonce, tvb, offset+16, 8,
+ tvb_get_ptr (tvb, offset+16, 8));
+ proto_tree_add_item (tree, hf_fcip_conn_flags, tvb, offset+24, 1, 0);
+ proto_tree_add_item (tree, hf_fcip_conn_code, tvb, offset+26, 2, 0);
+ proto_tree_add_string (tree, hf_fcip_dst_wwn, tvb, offset+30, 8,
+ fcwwn_to_str (tvb_get_ptr (tvb, offset+30, 8)));
+ proto_tree_add_item (tree, hf_fcip_katov, tvb, offset+38, 4, 0);
+ }
+}
+
+static gboolean
+dissect_fcip (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ gint offset = 0,
+ start = 0,
+ frame_len = 0;
+ guint bytes_remaining = tvb_length_remaining (tvb, offset);
+ guint8 pflags, sof, eof;
+ /* Set up structures needed to add the protocol subtree and manage it */
+ proto_item *ti;
+ proto_tree *fcip_tree = NULL;
+ tvbuff_t *next_tvb;
+
+ if (!proto_is_protocol_enabled(proto_fcip))
+ return FALSE; /* iSCSI has been disabled */
+
+ if (bytes_remaining < FCIP_ENCAP_HEADER_LEN) {
+ return FALSE;
+ }
+
+ if ((pinfo->srcport != fcip_port) && (pinfo->destport != fcip_port)) {
+ return FALSE;
+ }
+
+ while (bytes_remaining > FCIP_ENCAP_HEADER_LEN) {
+ if ((offset = get_next_fcip_header_offset (tvb, pinfo, offset)) == -1) {
+ return FALSE;
+ }
+ else if (offset == -2) {
+ /* We need more data to desegment */
+ return (TRUE);
+ }
+
+ start = offset;
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "FCIP");
+
+ frame_len = (tvb_get_ntohs (tvb, offset+12) & 0x03FF)*4;
+
+ pflags = tvb_get_guint8 (tvb, start+8);
+
+ if (tree) {
+ if (FCIP_IS_SF (pflags)) {
+ ti = proto_tree_add_protocol_format (tree, proto_fcip, tvb, 0,
+ FCIP_ENCAP_HEADER_LEN,
+ "FCIP");
+ }
+ else {
+ sof = tvb_get_guint8 (tvb, offset+FCIP_ENCAP_HEADER_LEN) - 0x28;
+ eof = tvb_get_guint8 (tvb, offset+frame_len - 4) - 0x41;
+
+ if (sof > 18) {
+ sof = 18; /* The last SOF */
+ }
+ if (eof > 15) {
+ eof = 16;
+ }
+
+ ti = proto_tree_add_protocol_format (tree, proto_fcip, tvb, 0,
+ FCIP_ENCAP_HEADER_LEN,
+ "FCIP (%s/%s)",
+ sof_strings[sof],
+ eof_strings[eof]);
+ }
+ fcip_tree = proto_item_add_subtree (ti, ett_fcip);
+ /* Dissect the Common FC Encap header */
+ dissect_fcencap_header (tvb, fcip_tree, offset);
+
+ offset += FCIP_ENCAP_HEADER_LEN;
+
+ if (!FCIP_IS_SF (pflags)) {
+ /* print SOF */
+ proto_tree_add_item (fcip_tree, hf_fcip_sof, tvb, offset, 1, 0);
+ proto_tree_add_item (fcip_tree, hf_fcip_sof_c, tvb, offset+2, 1, 0);
+ /* print EOF */
+
+ offset += (frame_len-FCIP_ENCAP_HEADER_LEN-4);
+ proto_tree_add_item (fcip_tree, hf_fcip_eof, tvb, offset, 1, 0);
+ proto_tree_add_item (fcip_tree, hf_fcip_eof_c, tvb, offset+2, 1, 0);
+ }
+ }
+
+ /* Call the FC Dissector if this is carrying an FC frame */
+ if (!FCIP_IS_SF(pflags)) {
+ /* Special frame bit is not set */
+ next_tvb = tvb_new_subset (tvb, FCIP_ENCAP_HEADER_LEN+4, -1, -1);
+ if (fc_handle) {
+ call_dissector (fc_handle, next_tvb, pinfo, tree);
+ }
+ else if (data_handle) {
+ call_dissector (data_handle, next_tvb, pinfo, tree);
+ }
+ }
+ else {
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "Special Frame");
+ if (FCIP_IS_CH (pflags)) {
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_str(pinfo->cinfo, COL_INFO, "(Changed)");
+ }
+
+ dissect_fcip_sf (tvb, fcip_tree, start);
+ }
+
+ bytes_remaining -= frame_len;
+ }
+
+ return (TRUE);
+}
+
+void
+proto_register_fcip (void)
+{
+
+ /* Setup list of header fields See Section 1.6.1 for details*/
+ static hf_register_info hf[] = {
+ { &hf_fcip_protocol,
+ { "Protocol", "fcencap.proto", FT_UINT8, BASE_DEC, NULL, 0,
+ "Protocol", HFILL }},
+ { &hf_fcip_protocol_c,
+ {"Protocol (1's Complement)", "fcencap.protoc", FT_UINT8, BASE_DEC, NULL,
+ 0, "Protocol (1's Complement)", HFILL}},
+ { &hf_fcip_version,
+ {"Version", "fcencap.version", FT_UINT8, BASE_DEC, NULL, 0, "",
+ HFILL}},
+ { &hf_fcip_version_c,
+ {"Version (1's Complement)", "fcencap.versionc", FT_UINT8, BASE_DEC,
+ NULL, 0, "", HFILL}},
+ { &hf_fcip_encap_word1,
+ {"FCIP Encapsulation Word1", "fcip.word1", FT_UINT32, BASE_HEX, NULL,
+ 0, "", HFILL}},
+ { &hf_fcip_flags,
+ {"Flags", "fcencap.flags", FT_UINT8, BASE_HEX, NULL, 0xFC, "", HFILL}},
+ { &hf_fcip_flags_c,
+ {"Flags (1's Complement)", "fcencap.flagsc", FT_UINT8, BASE_HEX,
+ NULL, 0xFC, "", HFILL}},
+ { &hf_fcip_framelen,
+ {"Frame Length (in Words)", "fcencap.framelen", FT_UINT16, BASE_DEC,
+ NULL, 0x03FF, "", HFILL}},
+ { &hf_fcip_framelen_c,
+ {"Frame Length (1's Complement)", "fcencap.framelenc", FT_UINT16,
+ BASE_DEC, NULL, 0x03FF, "", HFILL}},
+ { &hf_fcip_tsec,
+ {"Time (secs)", "fcencap.tsec", FT_UINT32, BASE_DEC, NULL, 0, "",
+ HFILL}},
+ { &hf_fcip_tusec,
+ {"Time (fraction)", "fcencap.tusec", FT_UINT32, BASE_DEC, NULL, 0,
+ "", HFILL}},
+ { &hf_fcip_encap_crc,
+ {"CRC", "fcencap.crc", FT_UINT32, BASE_HEX, NULL, 0, "", HFILL}},
+ { &hf_fcip_sof,
+ {"SOF", "fcip.sof", FT_UINT8, BASE_HEX, VALS (&fcip_sof_vals), 0,
+ "", HFILL}},
+ { &hf_fcip_sof_c,
+ {"SOF (1's Complement)", "fcip.sofc", FT_UINT8, BASE_HEX, NULL,
+ 0, "", HFILL}},
+ { &hf_fcip_eof,
+ {"EOF", "fcip.eof", FT_UINT8, BASE_HEX, VALS (&fcip_eof_vals), 0,
+ "", HFILL}},
+ { &hf_fcip_eof_c,
+ {"EOF (1's Complement)", "fcip.eofc", FT_UINT8, BASE_HEX, NULL,
+ 0, "", HFILL}},
+ { &hf_fcip_pflags_changed,
+ {"Changed Flag", "fcip.pflags.ch", FT_BOOLEAN, BASE_DEC, NULL, 0x80,
+ "", HFILL}},
+ { &hf_fcip_pflags_special,
+ {"Special Frame Flag", "fcip.pflags.sf", FT_BOOLEAN, BASE_DEC, NULL,
+ 0x1, "", HFILL}},
+ { &hf_fcip_pflags_c,
+ {"Pflags (1's Complement)", "fcip.pflagsc", FT_UINT8, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_fcip_src_wwn,
+ {"Source Fabric WWN", "fcip.srcwwn", FT_STRING, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_fcip_dst_wwn,
+ {"Destination Fabric WWN", "fcip.dstwwn", FT_STRING, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_fcip_src_entity_id,
+ {"FC/FCIP Entity Id", "fcip.srcid", FT_BYTES, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_fcip_conn_flags,
+ {"Connection Usage Flags", "fcip.connflags", FT_UINT8, BASE_HEX,
+ NULL, 0x0, "", HFILL}},
+ { &hf_fcip_conn_code,
+ {"Connection Usage Code", "fcip.conncode", FT_UINT16, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_fcip_katov,
+ {"K_A_TOV", "fcip.katov", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL}},
+ { &hf_fcip_conn_nonce,
+ {"Connection Nonce", "fcip.nonce", FT_BYTES, BASE_HEX, NULL, 0x0, "",
+ HFILL}},
+ };
+
+ static gint *ett[] = {
+ &ett_fcip,
+ };
+
+ module_t *fcip_module;
+
+ /* Register the protocol name and description */
+ proto_fcip = proto_register_protocol("FCIP", "FCIP", "fcip");
+
+ /* Required function calls to register the header fields and
+ * subtrees used */
+ proto_register_field_array(proto_fcip, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+
+ fcip_module = prefs_register_protocol(proto_fcip, NULL);
+ prefs_register_bool_preference(fcip_module,
+ "desegment_fcip_messages",
+ "Desegment FCIP messages",
+ "When enabled, FCIP messages that span multiple TCP segments are desegmented",
+ &fcip_desegment);
+ prefs_register_uint_preference(fcip_module,
+ "fcip_port",
+ "Target port",
+ "Port number used for FCIP",
+ 10,
+ &fcip_port);
+}
+
+
+/*
+ * If this dissector uses sub-dissector registration add a
+ * registration routine.
+ */
+
+/*
+ * This format is required because a script is used to find these
+ * routines and create the code that calls these routines.
+ */
+void
+proto_reg_handoff_fcip (void)
+{
+ heur_dissector_add("tcp", dissect_fcip, proto_fcip);
+ data_handle = find_dissector("data");
+ fc_handle = find_dissector("fc");
+}
diff --git a/packet-fclctl.c b/packet-fclctl.c
new file mode 100644
index 0000000000..ac67f2850d
--- /dev/null
+++ b/packet-fclctl.c
@@ -0,0 +1,102 @@
+/* packet-fclctl.c
+ * Routines for FC Link Control Frames
+ * Copyright 2001, Dinesh G Dutt <ddutt@cisco.com>
+ *
+ * $Id: packet-fclctl.c,v 1.1 2002/12/08 02:32:17 gerald Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * Copied from WHATEVER_FILE_YOU_USED (where "WHATEVER_FILE_YOU_USED"
+ * is a dissector file; if you just copied this from README.developer,
+ * don't bother with the "Copied from" - you don't even need to put
+ * in a "Copied from" if you copied an existing dissector, especially
+ * if the bulk of the code in the new dissector is your code)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#include <glib.h>
+
+#ifdef NEED_SNPRINTF_H
+# include "snprintf.h"
+#endif
+
+#include <epan/packet.h>
+#include "etypes.h"
+#include "packet-fc.h"
+#include "packet-fclctl.h"
+
+static gchar errstr[64];
+
+gchar *
+fclctl_get_typestr (guint8 linkctl_type, guint8 type)
+{
+ if ((linkctl_type == FC_LCTL_FBSYB) ||
+ (linkctl_type == FC_LCTL_FBSYL)) {
+ return (val_to_str ((type & 0xF0), fc_lctl_fbsy_val, "0x%x"));
+ }
+ else return ("\0");
+}
+
+gchar *
+fclctl_get_paramstr (guint32 linkctl_type, guint32 param)
+{
+ int len;
+
+ errstr[0] = '\0';
+
+ if (linkctl_type == FC_LCTL_PBSY) {
+ strcpy (errstr, val_to_str (((param & 0xFF000000) >> 24),
+ fc_lctl_pbsy_acode_val, "0x%x"));
+ len = strlen (errstr);
+ strcpy (&errstr[len], ", ");
+ len = strlen (errstr);
+ strcpy (&errstr[len],
+ val_to_str (((param & 0x00FF0000) >> 16),
+ fc_lctl_pbsy_rjt_val, "0x%x"));
+ }
+ else if ((linkctl_type == FC_LCTL_FRJT) ||
+ (linkctl_type == FC_LCTL_PRJT)) {
+ strcpy (errstr,
+ val_to_str (((param & 0xFF000000) >> 24),
+ fc_lctl_rjt_acode_val, "0x%x"));
+ len = strlen (errstr);
+ strcpy (&errstr[len], ", ");
+ len = strlen (errstr);
+ strcpy (&errstr[len],
+ val_to_str (((param & 0x00FF0000) >> 16), fc_lctl_rjt_val,
+ "%x"));
+ }
+
+ return (errstr);
+}
diff --git a/packet-fclctl.h b/packet-fclctl.h
new file mode 100644
index 0000000000..7cd60991ba
--- /dev/null
+++ b/packet-fclctl.h
@@ -0,0 +1,174 @@
+/* packet-fclctl.h
+ * Fibre Channel Link Control definitions
+ * Copyright 2001 Dinesh G Dutt (ddutt@cisco.com)
+ *
+ * $Id: packet-fclctl.h,v 1.1 2002/12/08 02:32:17 gerald Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PACKET_FCLCTL_H_
+#define __PACKET_FCLCTL_H_
+
+#define FC_LCTL_ACK1 0x00
+#define FC_LCTL_ACK0 0x01
+#define FC_LCTL_PRJT 0x02
+#define FC_LCTL_FRJT 0x03
+#define FC_LCTL_PBSY 0x04
+#define FC_LCTL_FBSYL 0x05
+#define FC_LCTL_FBSYB 0x06
+#define FC_LCTL_LCR 0x07
+#define FC_LCTL_NTY 0x08
+#define FC_LCTL_END 0x09
+
+static const value_string fc_lctl_proto_val[] = {
+ {FC_LCTL_ACK1 , "ACK1"},
+ {FC_LCTL_ACK0 , "ACK0"},
+ {FC_LCTL_PRJT , "P_RJT"},
+ {FC_LCTL_FRJT , "F_RJT"},
+ {FC_LCTL_PBSY , "P_BSY"},
+ {FC_LCTL_FBSYL , "F_BSY (Data frame)"},
+ {FC_LCTL_FBSYB , "F_BSY (Link Ctl)"},
+ {FC_LCTL_LCR , "LCR"},
+ {FC_LCTL_NTY , "NTY"},
+ {FC_LCTL_END , "END"},
+ {0, NULL},
+};
+
+#define FC_LCTL_FBSY_FBSY 0x01
+#define FC_LCTL_FBSY_NBSY 0x03
+
+static const value_string fc_lctl_fbsy_val[] = {
+ {FC_LCTL_FBSY_FBSY, "Fabric Busy"},
+ {FC_LCTL_FBSY_NBSY, "N_Port Busy"},
+ {0, NULL}
+};
+
+#define FC_LCTL_PBSY_ACODE_SEQBSY 0x01
+#define FC_LCTL_PBSY_ACODE_C2BSY 0x02
+
+static const value_string fc_lctl_pbsy_acode_val[] = {
+ {FC_LCTL_PBSY_ACODE_SEQBSY, "Sequence Marked Busy"},
+ {FC_LCTL_PBSY_ACODE_C2BSY, "Class 2 Frame Busy"},
+ {0, NULL},
+};
+
+#define FC_LCTL_PBSY_PORTBSY 0x01
+#define FC_LCTL_PBSY_RSRCBSY 0x03
+#define FC_LCTL_PBSY_MCASTBSY 0x07
+#define FC_LCTL_PBSY_VENDBSY 0xFF
+
+static const value_string fc_lctl_pbsy_rjt_val[] = {
+ {FC_LCTL_PBSY_PORTBSY , "Physical N_Port Busy"},
+ {FC_LCTL_PBSY_RSRCBSY , "N_Port Resource Busy"},
+ {FC_LCTL_PBSY_MCASTBSY, "Partial Multicast Busy"},
+ {FC_LCTL_PBSY_VENDBSY , "Vendor unique Busy"},
+ {0, NULL},
+};
+
+#define FC_LCTL_RJT_ACODE_RETRY 0x01
+#define FC_LCTL_RJT_ACODE_NORETRY 0x02
+
+static const value_string fc_lctl_rjt_acode_val[] = {
+ {FC_LCTL_RJT_ACODE_RETRY, "Retryable Error"},
+ {FC_LCTL_RJT_ACODE_NORETRY, "Non-retryable Error"},
+ {0, NULL},
+};
+
+#define FC_LCTL_RJT_INVDID 0x01
+#define FC_LCTL_RJT_INVSID 0x02
+#define FC_LCTL_RJT_NPORT_NOTAVAIL_T 0x03
+#define FC_LCTL_RJT_NPORT_NOTAVAIL_P 0x04
+#define FC_LCTL_RJT_CLASS_NOTSUPP 0x05
+#define FC_LCTL_RJT_DELIM_USERR 0x06
+#define FC_LCTL_RJT_TYPE_NOTSUPP 0x07
+#define FC_LCTL_RJT_INV_LCTL 0x08
+#define FC_LCTL_RJT_INV_RCTL 0x09
+#define FC_LCTL_RJT_INV_FCTL 0x0A
+#define FC_LCTL_RJT_INV_OXID 0x0B
+#define FC_LCTL_RJT_INV_RXID 0x0C
+#define FC_LCTL_RJT_INV_SEQID 0x0D
+#define FC_LCTL_RJT_INV_DFCTL 0x0E
+#define FC_LCTL_RJT_INV_SEQCNT 0x0F
+#define FC_LCTL_RJT_INV_PARAM 0x10
+#define FC_LCTL_RJT_EXCHG_ERR 0x11
+#define FC_LCTL_RJT_PROTO_ERR 0x12
+#define FC_LCTL_RJT_INV_LEN 0x13
+#define FC_LCTL_RJT_UNEXP_ACK 0x14
+#define FC_LCTL_RJT_CLS_NOTSUPP 0x15
+#define FC_LCTL_RJT_LOGI_REQD 0x16
+#define FC_LCTL_RJT_TOOMANY_SEQ 0x17
+#define FC_LCTL_RJT_EXCHG_NOTESTD 0x18
+#define FC_LCTL_RJT_RSVD 0x19
+#define FC_LCTL_RJT_FPATH_NOTAVAIL 0x1A
+#define FC_LCTL_RJT_INV_VCID 0x1B
+#define FC_LCTL_RJT_INV_CSCTL 0x1C
+#define FC_LCTL_RJT_OORSRC 0x1D
+#define FC_LCTL_RJT_INV_CLASS 0x1F
+#define FC_LCTL_RJT_PRMPT_RJT 0x20
+#define FC_LCTL_RJT_PRMPT_DIS 0x21
+#define FC_LCTL_RJT_MCAST_ERR 0x22
+#define FC_LCTL_RJT_MCAST_TERM 0x23
+#define FC_LCTL_RJT_PRLI_REQD 0x24
+#define FC_LCTL_RJT_VEND_ERR 0xFF
+
+static const value_string fc_lctl_rjt_val[] = {
+ {FC_LCTL_RJT_INVSID , "Invalid S_ID"},
+ {FC_LCTL_RJT_INVDID , "Invalid D_ID"},
+ {FC_LCTL_RJT_NPORT_NOTAVAIL_T , "N_Port Not Avail (Temporary)"},
+ {FC_LCTL_RJT_NPORT_NOTAVAIL_P , "N_Port Not Avail (Permanent)"},
+ {FC_LCTL_RJT_CLASS_NOTSUPP , "Class Not Supported"},
+ {FC_LCTL_RJT_DELIM_USERR , "Delimiter Usage Error"},
+ {FC_LCTL_RJT_TYPE_NOTSUPP , "Type Not Supported"},
+ {FC_LCTL_RJT_INV_LCTL , "Invalid Link Ctl Frame"},
+ {FC_LCTL_RJT_INV_RCTL , "Invalid R_CTL"},
+ {FC_LCTL_RJT_INV_FCTL , "Invalid F_CTL"},
+ {FC_LCTL_RJT_INV_OXID , "Invalid OX_ID"},
+ {FC_LCTL_RJT_INV_RXID , "Invalid RX_ID"},
+ {FC_LCTL_RJT_INV_SEQID , "Invalid SEQID"},
+ {FC_LCTL_RJT_INV_DFCTL , "Invalid DF_CTL"},
+ {FC_LCTL_RJT_INV_SEQCNT , "Invalid SEQCNT"},
+ {FC_LCTL_RJT_INV_PARAM , "Invalid Parameter"},
+ {FC_LCTL_RJT_EXCHG_ERR , "Exchange Error"},
+ {FC_LCTL_RJT_PROTO_ERR , "Protocol Error"},
+ {FC_LCTL_RJT_INV_LEN , "Incorrect Length"},
+ {FC_LCTL_RJT_UNEXP_ACK , "Unexpected ACK"},
+ {FC_LCTL_RJT_CLS_NOTSUPP , "Class Not Supported by Entity at 0xFFFFFE"},
+ {FC_LCTL_RJT_LOGI_REQD , "Login Required"},
+ {FC_LCTL_RJT_TOOMANY_SEQ , "Excessive Sequences Attempted"},
+ {FC_LCTL_RJT_EXCHG_NOTESTD , "Exchange Not Established"},
+ {FC_LCTL_RJT_RSVD , "Reserved"},
+ {FC_LCTL_RJT_FPATH_NOTAVAIL , "Fabric Path Not Available"},
+ {FC_LCTL_RJT_INV_VCID , "Invalid VC_ID"},
+ {FC_LCTL_RJT_INV_CSCTL , "Invalid CS_CTL"},
+ {FC_LCTL_RJT_OORSRC , "Insufficient Resources of VC (Class 4)"},
+ {FC_LCTL_RJT_INV_CLASS , "Invalid Class of Service"},
+ {FC_LCTL_RJT_PRMPT_RJT , "Preemption Request Rejected"},
+ {FC_LCTL_RJT_PRMPT_DIS , "Preemption Not Enabled"},
+ {FC_LCTL_RJT_MCAST_ERR , "Multicast Error"},
+ {FC_LCTL_RJT_MCAST_TERM , "Multicast Error Terminate"},
+ {FC_LCTL_RJT_PRLI_REQD , "PRLI Required"},
+ {FC_LCTL_RJT_VEND_ERR , "Vendor Unique Error"},
+ {0, NULL},
+};
+
+/* Function definitions */
+gchar *fclctl_get_typestr (guint8 linkctl_type, guint8 type);
+gchar *fclctl_get_paramstr (guint32 linkctl_type, guint32 param);
+#endif
diff --git a/packet-fcp.c b/packet-fcp.c
new file mode 100644
index 0000000000..7dac211fb9
--- /dev/null
+++ b/packet-fcp.c
@@ -0,0 +1,690 @@
+/* packet-fcp.c
+ * Routines for Fibre Channel Protocol for SCSI (FCP)
+ * Copyright 2001, Dinesh G Dutt <ddutt@cisco.com>
+ *
+ * $Id: packet-fcp.c,v 1.1 2002/12/08 02:32:17 gerald Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * Copied from WHATEVER_FILE_YOU_USED (where "WHATEVER_FILE_YOU_USED"
+ * is a dissector file; if you just copied this from README.developer,
+ * don't bother with the "Copied from" - you don't even need to put
+ * in a "Copied from" if you copied an existing dissector, especially
+ * if the bulk of the code in the new dissector is your code)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#include <glib.h>
+
+#ifdef NEED_SNPRINTF_H
+# include "snprintf.h"
+#endif
+
+#include "prefs.h"
+#include <epan/packet.h>
+#include <epan/conversation.h>
+#include "etypes.h"
+#include "packet-fc.h"
+#include "packet-fcp.h"
+#include "packet-scsi.h"
+
+/* Initialize the protocol and registered fields */
+static int proto_fcp = -1;
+static int hf_fcp_multilun = -1;
+static int hf_fcp_singlelun = -1;
+static int hf_fcp_crn = -1;
+static int hf_fcp_taskattr = -1;
+static int hf_fcp_taskmgmt = -1;
+static int hf_fcp_addlcdblen = -1;
+static int hf_fcp_rddata = -1;
+static int hf_fcp_wrdata = -1;
+static int hf_fcp_dl = -1;
+static int hf_fcp_data_ro = -1;
+static int hf_fcp_burstlen = -1;
+static int hf_fcp_rspflags = -1;
+static int hf_fcp_resid = -1;
+static int hf_fcp_snslen = -1;
+static int hf_fcp_rsplen = -1;
+static int hf_fcp_rspcode = -1;
+static int hf_fcp_scsistatus = -1;
+static int hf_fcp_type = -1;
+
+
+/* Initialize the subtree pointers */
+static gint ett_fcp = -1;
+static dissector_table_t fcp_dissector;
+static dissector_handle_t data_handle;
+
+typedef struct _fcp_conv_key {
+ guint32 conv_idx;
+} fcp_conv_key_t;
+
+typedef struct _fcp_conv_data {
+ guint32 fcp_dl;
+ gint32 fcp_lun;
+ guint32 abs_secs;
+ guint32 abs_usecs;
+} fcp_conv_data_t;
+
+GHashTable *fcp_req_hash = NULL;
+GMemChunk *fcp_req_keys = NULL;
+GMemChunk *fcp_req_vals = NULL;
+guint32 fcp_init_count = 25;
+
+/*
+ * Hash Functions
+ */
+static gint
+fcp_equal(gconstpointer v, gconstpointer w)
+{
+ fcp_conv_key_t *v1 = (fcp_conv_key_t *)v;
+ fcp_conv_key_t *v2 = (fcp_conv_key_t *)w;
+
+ return (v1->conv_idx == v2->conv_idx);
+}
+
+static guint
+fcp_hash (gconstpointer v)
+{
+ fcp_conv_key_t *key = (fcp_conv_key_t *)v;
+ guint val;
+
+ val = key->conv_idx;
+
+ return val;
+}
+
+/*
+ * Protocol initialization
+ */
+static void
+fcp_init_protocol(void)
+{
+ if (fcp_req_keys)
+ g_mem_chunk_destroy(fcp_req_keys);
+ if (fcp_req_vals)
+ g_mem_chunk_destroy(fcp_req_vals);
+ if (fcp_req_hash)
+ g_hash_table_destroy(fcp_req_hash);
+
+ fcp_req_hash = g_hash_table_new(fcp_hash, fcp_equal);
+ fcp_req_keys = g_mem_chunk_new("fcp_req_keys",
+ sizeof(fcp_conv_key_t),
+ fcp_init_count * sizeof(fcp_conv_key_t),
+ G_ALLOC_AND_FREE);
+ fcp_req_vals = g_mem_chunk_new("fcp_req_vals",
+ sizeof(fcp_conv_data_t),
+ fcp_init_count * sizeof(fcp_conv_data_t),
+ G_ALLOC_AND_FREE);
+}
+
+static gchar *
+task_mgmt_flags_to_str (guint8 flags, gchar *str)
+{
+ int stroff = 0;
+
+ if (str == NULL)
+ return str;
+
+ *str = '\0';
+
+ if (flags & 0x80) {
+ strcpy (str, "Obsolete, ");
+ stroff += 10;
+ }
+
+ if (flags & 0x40) {
+ strcpy (&str[stroff], "Clear ACA, ");
+ stroff += 11;
+ }
+
+ if (flags & 0x20) {
+ strcpy (&str[stroff], "Target Reset, ");
+ stroff += 14;
+ }
+
+ if (flags & 0x10) {
+ strcpy (&str[stroff], "LU Reset, ");
+ stroff += 10;
+ }
+
+ if (flags & 0x08) {
+ strcpy (&str[stroff], "Rsvd, ");
+ stroff += 6;
+ }
+
+ if (flags & 0x04) {
+ strcpy (&str[stroff], "Clear Task Set, ");
+ stroff += 16;
+ }
+
+ if (flags & 0x02) {
+ strcpy (&str[stroff], "Abort Task Set");
+ stroff += 14;
+ }
+
+ return (str);
+}
+
+static gchar *
+rspflags_to_str (guint8 flags, gchar *str)
+{
+ int stroff = 0;
+
+ if (str == NULL)
+ return (str);
+
+ *str = '\0';
+
+ if (flags & 0x10) {
+ strcpy (str, "FCP_CONF_REQ | ");
+ stroff += 15;
+ }
+ if (flags & 0x08) {
+ strcpy (&str[stroff], "FCP_RESID_UNDER | ");
+ stroff += 18;
+ }
+ if (flags & 0x04) {
+ strcpy (&str[stroff], "FCP_RESID_OVER | ");
+ stroff += 17;
+ }
+ if (flags & 0x02) {
+ strcpy (&str[stroff], "FCP_SNS_LEN_VLD | ");
+ stroff += 18;
+ }
+ if (flags & 0x01) {
+ strcpy (&str[stroff], "FCP_RSP_LEN_VLD | ");
+ }
+
+ return (str);
+}
+
+/* Code to actually dissect the packets */
+static void
+dissect_fcp_cmnd (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ int offset = 0;
+ int len,
+ add_len = 0;
+ gchar str[128];
+ guint8 flags, lun0;
+ proto_item *ti;
+ proto_tree *fcp_tree = NULL;
+ conversation_t *conversation;
+ fcp_conv_data_t *cdata;
+ fcp_conv_key_t ckey, *req_key;
+ scsi_task_id_t task_key;
+
+ /* Determine the length of the FCP part of the packet */
+ flags = tvb_get_guint8 (tvb, offset+10);
+ if (flags) {
+ add_len = tvb_get_guint8 (tvb, offset+11) & 0x7C;
+ add_len = add_len >> 2;
+
+ len = FCP_DEF_CMND_LEN + add_len;
+ }
+ else {
+ len = FCP_DEF_CMND_LEN;
+ }
+
+ /* We track the conversation to determine how many bytes is required */
+ /* by the data that is sent back or sent next by the initiator as part */
+ /* of this command. The state is destroyed in the response dissector */
+
+ conversation = find_conversation (&pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->oxid,
+ pinfo->rxid, NO_PORT2);
+ if (!conversation) {
+ conversation = conversation_new (&pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->oxid,
+ pinfo->rxid, NO_PORT2);
+ }
+
+ ckey.conv_idx = conversation->index;
+ task_key.conv_id = conversation->index;
+ task_key.task_id = conversation->index;
+ pinfo->private_data = (void *)&task_key;
+
+ cdata = (fcp_conv_data_t *)g_hash_table_lookup (fcp_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->fcp_dl = tvb_get_ntohl (tvb, offset+12+16+add_len);
+ cdata->abs_usecs = pinfo->fd->abs_usecs;
+ cdata->abs_secs = pinfo->fd->abs_secs;
+ }
+ else {
+ req_key = g_mem_chunk_alloc (fcp_req_keys);
+ req_key->conv_idx = conversation->index;
+
+ cdata = g_mem_chunk_alloc (fcp_req_vals);
+ cdata->fcp_dl = tvb_get_ntohl (tvb, offset+12+16+add_len);
+ cdata->abs_usecs = pinfo->fd->abs_usecs;
+ cdata->abs_secs = pinfo->fd->abs_secs;
+
+ g_hash_table_insert (fcp_req_hash, req_key, cdata);
+ }
+
+ dissect_scsi_cdb (tvb, pinfo, fcp_tree, offset+12, 16+add_len,
+ SCSI_DEV_UNKNOWN);
+
+ if (tree) {
+ ti = proto_tree_add_protocol_format (tree, proto_fcp, tvb, 0, len,
+ "FCP_CMND");
+ fcp_tree = proto_item_add_subtree (ti, ett_fcp);
+ proto_tree_add_uint_hidden (fcp_tree, hf_fcp_type, tvb, offset, 0, 0);
+
+ lun0 = tvb_get_guint8 (tvb, offset);
+
+ /* Display single-level LUNs in decimal for clarity */
+ /* I'm taking a shortcut here by assuming that if the first byte of the
+ * LUN field is 0, it is a single-level LUN. This is not true. For a
+ * real single-level LUN, all 8 bytes except byte 1 must be 0.
+ */
+ if (lun0) {
+ cdata->fcp_lun = -1;
+ proto_tree_add_item (fcp_tree, hf_fcp_multilun, tvb, offset, 8, 0);
+ }
+ else {
+ cdata->fcp_lun = tvb_get_guint8 (tvb, offset+1);
+ proto_tree_add_item (fcp_tree, hf_fcp_singlelun, tvb, offset+1,
+ 1, 0);
+ }
+
+ proto_tree_add_item (fcp_tree, hf_fcp_crn, tvb, offset+8, 1, 0);
+ proto_tree_add_item (fcp_tree, hf_fcp_taskattr, tvb, offset+9, 1, 0);
+ proto_tree_add_uint_format (fcp_tree, hf_fcp_taskmgmt, tvb, offset+10,
+ 1, flags,
+ "Task Management Flags: 0x%x (%s)",
+ flags,
+ task_mgmt_flags_to_str (flags, str));
+ proto_tree_add_item (fcp_tree, hf_fcp_addlcdblen, tvb, offset+11, 1, 0);
+ proto_tree_add_item (fcp_tree, hf_fcp_rddata, tvb, offset+11, 1, 0);
+ proto_tree_add_item (fcp_tree, hf_fcp_wrdata, tvb, offset+11, 1, 0);
+ dissect_scsi_cdb (tvb, pinfo, tree, offset+12, 16+add_len,
+ SCSI_DEV_UNKNOWN);
+ proto_tree_add_item (fcp_tree, hf_fcp_dl, tvb, offset+12+16+add_len,
+ 4, 0);
+ }
+}
+
+static void
+dissect_fcp_data (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ conversation_t *conversation;
+ fcp_conv_data_t *cdata = NULL;
+ fcp_conv_key_t ckey;
+ proto_item *ti;
+ proto_tree *fcp_tree;
+ scsi_task_id_t task_key;
+
+ /* Retrieve conversation state to determine expected payload */
+ conversation = find_conversation (&pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->oxid,
+ pinfo->rxid, NO_PORT2);
+ if (conversation) {
+ ckey.conv_idx = conversation->index;
+
+ cdata = (fcp_conv_data_t *)g_hash_table_lookup (fcp_req_hash,
+ &ckey);
+ task_key.conv_id = conversation->index;
+ task_key.task_id = conversation->index;
+ pinfo->private_data = (void *)&task_key;
+ }
+ else {
+ pinfo->private_data = NULL;
+ }
+ if (cdata) {
+ ti = proto_tree_add_protocol_format (tree, proto_fcp, tvb, 0, 0,
+ "FCP_DATA");
+ fcp_tree = proto_item_add_subtree (ti, ett_fcp);
+
+ if (cdata->fcp_lun >= 0)
+ proto_tree_add_uint_hidden (fcp_tree, hf_fcp_singlelun, tvb,
+ 0, 0, cdata->fcp_lun);
+
+ dissect_scsi_payload (tvb, pinfo, tree, 0, FALSE, cdata->fcp_dl);
+ }
+ else {
+ dissect_scsi_payload (tvb, pinfo, tree, 0, FALSE, 0);
+ }
+}
+
+static void
+dissect_fcp_rsp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ guint32 offset = 0,
+ del_usecs = 0;
+ guint len = 0,
+ add_len = 0,
+ rsplen = 0;
+ gchar str[128];
+ guint8 flags;
+ proto_item *ti;
+ proto_tree *fcp_tree;
+ guint8 status;
+ conversation_t *conversation;
+ fcp_conv_data_t *cdata = NULL;
+ fcp_conv_key_t ckey;
+ scsi_task_id_t task_key;
+
+ status = tvb_get_guint8 (tvb, offset+11);
+
+ if (check_col (pinfo->cinfo, COL_INFO)) {
+ col_append_fstr (pinfo->cinfo, COL_INFO, " , %s",
+ val_to_str (status, scsi_status_val, "0x%x"));
+ }
+
+ /* Response marks the end of the conversation. So destroy state */
+ conversation = find_conversation (&pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->oxid,
+ pinfo->rxid, NO_PORT2);
+ if (conversation) {
+ ckey.conv_idx = conversation->index;
+
+ cdata = (fcp_conv_data_t *)g_hash_table_lookup (fcp_req_hash,
+ &ckey);
+ task_key.conv_id = task_key.task_id = conversation->index;
+ pinfo->private_data = (void *)&task_key;
+ }
+
+ if (tree) {
+ /* Determine the length of the FCP part of the packet */
+ len = FCP_DEF_RSP_LEN;
+
+ flags = tvb_get_guint8 (tvb, offset+10);
+ if (flags & 0x2) {
+ add_len = tvb_get_ntohl (tvb, offset+20);
+ len += add_len;
+ }
+ if (flags & 0x1) {
+ add_len = tvb_get_ntohl (tvb, offset+16);
+ len += add_len;
+ }
+
+ ti = proto_tree_add_protocol_format (tree, proto_fcp, tvb, 0, len,
+ "FCP_RSP");
+ fcp_tree = proto_item_add_subtree (ti, ett_fcp);
+ proto_tree_add_uint_hidden (fcp_tree, hf_fcp_type, tvb, offset, 0, 0);
+
+ if (cdata) {
+ del_usecs = (pinfo->fd->abs_secs - cdata->abs_secs)* 1000000 +
+ (pinfo->fd->abs_usecs - cdata->abs_usecs);
+ if (del_usecs > 1000)
+ proto_tree_add_text (fcp_tree, tvb, offset, 0,
+ "Cmd Response Time: %d msecs",
+ del_usecs/1000);
+ else
+ proto_tree_add_text (fcp_tree, tvb, offset, 0,
+ "Cmd Response Time: %d usecs",
+ del_usecs);
+ if (cdata->fcp_lun >= 0)
+ proto_tree_add_uint_hidden (fcp_tree, hf_fcp_singlelun, tvb,
+ offset, 0, cdata->fcp_lun);
+ }
+ proto_tree_add_uint_format (fcp_tree, hf_fcp_rspflags, tvb, offset+10,
+ 1, flags, "Flags: 0x%x (%s)", flags,
+ rspflags_to_str (flags, str));
+ proto_tree_add_item (fcp_tree, hf_fcp_scsistatus, tvb, offset+11, 1, 0);
+ if (flags & 0xC)
+ proto_tree_add_item (fcp_tree, hf_fcp_resid, tvb, offset+12, 4, 0);
+ if (flags & 0x2)
+ proto_tree_add_item (fcp_tree, hf_fcp_snslen, tvb, offset+16, 4, 0);
+ if (flags & 0x1) {
+ rsplen = tvb_get_ntohl (tvb, offset+20);
+ proto_tree_add_item (fcp_tree, hf_fcp_rsplen, tvb, offset+20, 4, 0);
+ proto_tree_add_item (fcp_tree, hf_fcp_rspcode, tvb, offset+27, 1,
+ 0);
+ }
+ if (flags & 0x2) {
+ dissect_scsi_snsinfo (tvb, pinfo, tree, offset+24+rsplen,
+ tvb_get_ntohl (tvb, offset+16));
+ }
+ if (cdata) {
+ g_mem_chunk_free (fcp_req_vals, cdata);
+ g_hash_table_remove (fcp_req_hash, &ckey);
+ }
+ }
+}
+
+static void
+dissect_fcp_xfer_rdy (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ int offset = 0;
+ proto_item *ti;
+ proto_tree *fcp_tree;
+ guint del_usecs;
+
+ conversation_t *conversation;
+ fcp_conv_data_t *cdata = NULL;
+ fcp_conv_key_t ckey, *req_key;
+
+ /* Retrieve conversation state to determine expected payload */
+ conversation = find_conversation (&pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->oxid,
+ pinfo->rxid, NO_PORT2);
+ if (!conversation) {
+ conversation = conversation_new (&pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->oxid,
+ pinfo->rxid, NO_PORT2);
+ }
+
+ if (conversation) {
+ ckey.conv_idx = conversation->index;
+
+ cdata = (fcp_conv_data_t *)g_hash_table_lookup (fcp_req_hash,
+ &ckey);
+ if (cdata != NULL) {
+ cdata->fcp_dl = tvb_get_ntohl (tvb, offset+4);
+ }
+ else {
+ req_key = g_mem_chunk_alloc (fcp_req_keys);
+ req_key->conv_idx = conversation->index;
+
+ cdata = g_mem_chunk_alloc (fcp_req_vals);
+ cdata->fcp_dl = tvb_get_ntohl (tvb, offset+4);
+ cdata->fcp_lun = -1;
+
+ g_hash_table_insert (fcp_req_hash, req_key, cdata);
+ }
+ }
+
+ if (tree) {
+ ti = proto_tree_add_protocol_format (tree, proto_fcp, tvb, 0, 12,
+ "FCP_XFER_RDY");
+ fcp_tree = proto_item_add_subtree (ti, ett_fcp);
+ proto_tree_add_uint_hidden (fcp_tree, hf_fcp_type, tvb, offset, 0, 0);
+
+ if (cdata) {
+ del_usecs = (pinfo->fd->abs_secs - cdata->abs_secs)* 1000000 +
+ (pinfo->fd->abs_usecs - cdata->abs_usecs);
+ if (del_usecs > 1000)
+ proto_tree_add_text (fcp_tree, tvb, offset, 0,
+ "Cmd Response Time: %d msecs",
+ del_usecs/1000);
+ else
+ proto_tree_add_text (fcp_tree, tvb, offset, 0,
+ "Cmd Response Time: %d usecs",
+ del_usecs);
+ if (cdata->fcp_lun >= 0)
+ proto_tree_add_uint_hidden (fcp_tree, hf_fcp_singlelun, tvb,
+ offset, 0, cdata->fcp_lun);
+ }
+ proto_tree_add_item (fcp_tree, hf_fcp_data_ro, tvb, offset, 4, 0);
+ proto_tree_add_item (fcp_tree, hf_fcp_burstlen, tvb, offset+4, 4, 0);
+ }
+}
+
+static void
+dissect_fcp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+
+/* Set up structures needed to add the protocol subtree and manage it */
+ guint8 r_ctl;
+
+ /* Make entries in Protocol column and Info column on summary display */
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "FCP");
+
+ r_ctl = pinfo->r_ctl;
+
+ r_ctl &= 0xF;
+
+ if (check_col (pinfo->cinfo, COL_INFO)) {
+ col_set_str (pinfo->cinfo, COL_INFO, val_to_str (r_ctl, fcp_iu_val,
+ "0x%x"));
+ }
+
+ switch (r_ctl) {
+ case FCP_IU_DATA:
+ dissect_fcp_data (tvb, pinfo, tree);
+ break;
+ case FCP_IU_CONFIRM:
+ /* Nothing to be done here */
+ break;
+ case FCP_IU_XFER_RDY:
+ dissect_fcp_xfer_rdy (tvb, pinfo, tree);
+ break;
+ case FCP_IU_CMD:
+ dissect_fcp_cmnd (tvb, pinfo, tree);
+ break;
+ case FCP_IU_RSP:
+ dissect_fcp_rsp (tvb, pinfo, tree);
+ break;
+ default:
+ call_dissector (data_handle, tvb, pinfo, tree);
+ break;
+ }
+}
+
+/* Register the protocol with Ethereal */
+
+/* this format is require because a script is used to build the C function
+ that calls all the protocol registration.
+*/
+
+void
+proto_register_fcp (void)
+{
+
+ /* Setup list of header fields See Section 1.6.1 for details*/
+ static hf_register_info hf[] = {
+ { &hf_fcp_type,
+ {"Field to branch off to SCSI", "fcp.type", FT_UINT8, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ {&hf_fcp_multilun,
+ {"Multi-Level LUN", "fcp.multilun", FT_BYTES, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_fcp_singlelun,
+ {"LUN", "fcp.lun", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL}},
+ { &hf_fcp_crn,
+ {"Command Ref Num", "fcp.crn", FT_UINT8, BASE_DEC, NULL, 0x0, "",
+ HFILL}},
+ { &hf_fcp_taskattr,
+ {"Task Attribute", "fcp.taskattr", FT_UINT8, BASE_HEX,
+ VALS (fcp_task_attr_val), 0x7, "", HFILL}},
+ { &hf_fcp_taskmgmt,
+ {"Task Management Flags", "fcp.taskmgmt", FT_UINT8, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_fcp_addlcdblen,
+ {"Additional CDB Length", "fcp.addlcdblen", FT_UINT8, BASE_DEC, NULL,
+ 0xFC, "", HFILL}},
+ { &hf_fcp_rddata,
+ {"RDDATA", "fcp.rddata", FT_UINT8, BASE_BIN, NULL, 0x2, "", HFILL}},
+ { &hf_fcp_wrdata,
+ {"WRDATA", "fcp.wrdata", FT_UINT8, BASE_BIN, NULL, 0x1, "", HFILL}},
+ { &hf_fcp_dl,
+ {"FCP_DL", "fcp.dl", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL}},
+ { &hf_fcp_data_ro,
+ {"FCP_DATA_RO", "fcp.data_ro", FT_UINT32, BASE_DEC, NULL, 0x0, "",
+ HFILL}},
+ { &hf_fcp_burstlen,
+ {"Burst Length", "fcp.burstlen", FT_UINT32, BASE_DEC, NULL, 0x0, "",
+ HFILL}},
+ { &hf_fcp_rspflags,
+ {"FCP_RSP Flags", "fcp.rspflags", FT_UINT8, BASE_BIN, NULL, 0x0, "",
+ HFILL}},
+ { &hf_fcp_resid,
+ {"FCP_RESID", "fcp.resid", FT_UINT32, BASE_DEC, NULL, 0x0, "",
+ HFILL}},
+ { &hf_fcp_snslen,
+ {"FCP_SNS_LEN", "fcp.snslen", FT_UINT32, BASE_DEC, NULL, 0x0, "",
+ HFILL}},
+ { &hf_fcp_rsplen,
+ {"FCP_RSP_LEN", "fcp.rsplen", FT_UINT32, BASE_DEC, NULL, 0x0, "",
+ HFILL}},
+ { &hf_fcp_rspcode,
+ {"RSP_CODE", "fcp.rspcode", FT_UINT8, BASE_HEX,
+ VALS (fcp_rsp_code_val), 0x0, "", HFILL}},
+ { &hf_fcp_scsistatus,
+ {"SCSI Status", "fcp.status", FT_UINT8, BASE_HEX,
+ VALS (scsi_status_val), 0x0, "", HFILL}},
+ };
+
+ /* Setup protocol subtree array */
+ static gint *ett[] = {
+ &ett_fcp,
+ };
+
+ /* Register the protocol name and description */
+ proto_fcp = proto_register_protocol("Fibre Channel Protocol for SCSI",
+ "FCP", "fcp");
+
+ /* Required function calls to register the header fields and subtrees used */
+ proto_register_field_array(proto_fcp, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+ fcp_dissector = register_dissector_table ("fcp.type", "FCP Type", FT_UINT8,
+ BASE_HEX);
+ register_init_routine (&fcp_init_protocol);
+}
+
+/* If this dissector uses sub-dissector registration add a registration routine.
+ This format is required because a script is used to find these routines and
+ create the code that calls these routines.
+*/
+void
+proto_reg_handoff_fcp (void)
+{
+ dissector_handle_t fcp_handle;
+
+ fcp_handle = create_dissector_handle (dissect_fcp, proto_fcp);
+ dissector_add("fc.ftype", FC_FTYPE_SCSI, fcp_handle);
+
+ data_handle = find_dissector ("data");
+}
+
+
diff --git a/packet-fcp.h b/packet-fcp.h
new file mode 100644
index 0000000000..3960654288
--- /dev/null
+++ b/packet-fcp.h
@@ -0,0 +1,69 @@
+/* packet-fcp.h
+ * Fibre Channel SCSI (FCP) Protocol definitions
+ * Copyright 2001 Dinesh G Dutt (ddutt@cisco.com)
+ *
+ * $Id: packet-fcp.h,v 1.1 2002/12/08 02:32:17 gerald Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PACKET_FCP_H_
+#define __PACKET_FCP_H_
+
+/* Information Categories based on lower 4 bits of R_CTL */
+#define FCP_IU_DATA 0x1
+#define FCP_IU_CONFIRM 0x3
+#define FCP_IU_XFER_RDY 0x5
+#define FCP_IU_CMD 0x6
+#define FCP_IU_RSP 0x7
+
+static const value_string fcp_iu_val[] = {
+ {FCP_IU_DATA , "FCP_DATA"},
+ {FCP_IU_CONFIRM , "Confirm"},
+ {FCP_IU_XFER_RDY , "XFER_RDY"},
+ {FCP_IU_CMD , "FCP_CMND"},
+ {FCP_IU_RSP , "FCP_RSP"},
+ {0, NULL},
+};
+
+/* Task Attribute Values */
+static const value_string fcp_task_attr_val[] = {
+ {0, "Simple"},
+ {1, "Head of Queue"},
+ {2, "Ordered"},
+ {4, "ACA"},
+ {5, "Untagged"},
+ {0, NULL},
+};
+
+/* RSP Code Definitions (from FCP_RSP_INFO) */
+static const value_string fcp_rsp_code_val[] = {
+ {0, "Task Management Function Complete"},
+ {1, "FCP_DATA length Different from FCP_BURST_LEN"},
+ {2, "FCP_CMND Fields Invalid"},
+ {3, "FCP_DATA Parameter Mismatch With FCP_DATA_RO"},
+ {4, "Task Management Function Rejected"},
+ {5, "Task Management Function Failed"},
+ {0, NULL},
+};
+
+#define FCP_DEF_CMND_LEN 32 /* by default cmnd is 32 bytes */
+#define FCP_DEF_RSP_LEN 24 /* default FCP_RSP len */
+
+#endif
diff --git a/packet-fcswils.c b/packet-fcswils.c
new file mode 100644
index 0000000000..cbf45aafbf
--- /dev/null
+++ b/packet-fcswils.c
@@ -0,0 +1,1727 @@
+/* packet-fcswils
+ * Routines for FC Inter-switch link services
+ * Copyright 2001, Dinesh G Dutt <ddutt@cisco.com>
+ *
+ * $Id: packet-fcswils.c,v 1.1 2002/12/08 02:32:17 gerald Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * Copied from WHATEVER_FILE_YOU_USED (where "WHATEVER_FILE_YOU_USED"
+ * is a dissector file; if you just copied this from README.developer,
+ * don't bother with the "Copied from" - you don't even need to put
+ * in a "Copied from" if you copied an existing dissector, especially
+ * if the bulk of the code in the new dissector is your code)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#include <glib.h>
+
+#ifdef NEED_SNPRINTF_H
+# include "snprintf.h"
+#endif
+
+#include <epan/packet.h>
+#include <epan/conversation.h>
+#include "etypes.h"
+#include "packet-fc.h"
+#include "packet-fcswils.h"
+
+#define FC_SWILS_RPLY 0x0
+#define FC_SWILS_REQ 0x1
+
+/* Zone name has the structure:
+ * name_len (1 byte), rsvd (3 bytes), name (m bytes), fill (n bytes)
+ * name_len excludes the 4 initial bytes before the name
+ */
+#define ZONENAME_LEN(x, y) (tvb_get_guint8(x, y)+4)
+
+/* Initialize the protocol and registered fields */
+static int proto_fcswils = -1;
+static int hf_swils_opcode = -1;
+static int hf_swils_elp_rev = -1;
+static int hf_swils_elp_flags = -1;
+static int hf_swils_elp_r_a_tov = -1;
+static int hf_swils_elp_e_d_tov = -1;
+static int hf_swils_elp_req_epn = -1;
+static int hf_swils_elp_req_esn = -1;
+static int hf_swils_elp_clsf_svcp = -1;
+static int hf_swils_elp_clsf_rcvsz = -1;
+static int hf_swils_elp_clsf_conseq = -1;
+static int hf_swils_elp_clsf_e2e = -1;
+static int hf_swils_elp_clsf_openseq = -1;
+static int hf_swils_elp_cls1_svcp = -1;
+static int hf_swils_elp_cls1_rcvsz = -1;
+static int hf_swils_elp_cls2_svcp = -1;
+static int hf_swils_elp_cls2_rcvsz = -1;
+static int hf_swils_elp_cls3_svcp = -1;
+static int hf_swils_elp_cls3_rcvsz = -1;
+static int hf_swils_elp_isl_fc_mode = -1;
+static int hf_swils_elp_fcplen = -1;
+static int hf_swils_elp_b2bcredit = -1;
+static int hf_swils_elp_compat1 = -1;
+static int hf_swils_elp_compat2 = -1;
+static int hf_swils_elp_compat3 = -1;
+static int hf_swils_elp_compat4 = -1;
+static int hf_swils_efp_rec_type = -1;
+static int hf_swils_efp_dom_id = -1;
+static int hf_swils_efp_switch_name = -1;
+static int hf_swils_efp_mcast_grpno = -1;
+static int hf_swils_efp_alias_token = -1;
+static int hf_swils_efp_payload_len = -1;
+static int hf_swils_efp_pswitch_pri = -1;
+static int hf_swils_efp_pswitch_name = -1;
+static int hf_swils_dia_switch_name = -1;
+static int hf_swils_rdi_payload_len = -1;
+static int hf_swils_rdi_req_sname = -1;
+static int hf_swils_fspfh_cmd = -1;
+static int hf_swils_fspfh_rev = -1;
+static int hf_swils_fspfh_ar_num = -1;
+static int hf_swils_fspfh_auth_type = -1;
+static int hf_swils_fspfh_dom_id = -1;
+static int hf_swils_fspfh_auth = -1;
+static int hf_swils_hlo_options = -1;
+static int hf_swils_hlo_hloint = -1;
+static int hf_swils_hlo_deadint = -1;
+static int hf_swils_hlo_rcv_domid = -1;
+static int hf_swils_hlo_orig_pidx = -1;
+static int hf_swils_ldrec_linkid = -1;
+static int hf_swils_ldrec_out_pidx = -1;
+static int hf_swils_ldrec_nbr_pidx = -1;
+static int hf_swils_ldrec_link_type = -1;
+static int hf_swils_ldrec_link_cost = -1;
+static int hf_swils_lsrh_lsr_type = -1;
+static int hf_swils_lsrh_lsid = -1;
+static int hf_swils_lsrh_adv_domid = -1;
+static int hf_swils_lsrh_ls_incid = -1;
+static int hf_swils_esc_pdesc_vendorid = -1;
+static int hf_swils_esc_swvendorid = -1;
+static int hf_swils_esc_protocolid = -1;
+static int hf_swils_rscn_evtype = -1;
+static int hf_swils_rscn_addrfmt = -1;
+static int hf_swils_rscn_detectfn = -1;
+static int hf_swils_rscn_affectedport = -1;
+static int hf_swils_rscn_portstate = -1;
+static int hf_swils_rscn_portid = -1;
+static int hf_swils_rscn_pwwn = -1;
+static int hf_swils_rscn_nwwn = -1;
+static int hf_swils_zone_activezonenm = -1;
+static int hf_swils_zone_objname = -1;
+static int hf_swils_zone_objtype = -1;
+static int hf_swils_zone_mbrtype = -1;
+static int hf_swils_zone_protocol = -1;
+static int hf_swils_zone_mbrid = -1;
+static int hf_swils_zone_status = -1;
+static int hf_swils_zone_reason = -1;
+static int hf_swils_aca_domainid = -1;
+static int hf_swils_sfc_opcode = -1;
+static int hf_swils_sfc_zonenm = -1;
+static int hf_swils_rjt = -1;
+static int hf_swils_rjtdet = -1;
+static int hf_swils_rjtvendor = -1;
+static int hf_swils_zone_mbrid_lun = -1;
+
+/* Initialize the subtree pointers */
+static gint ett_fcswils = -1;
+static gint ett_fcswils_swacc = -1;
+static gint ett_fcswils_swrjt = -1;
+static gint ett_fcswils_elp = -1;
+static gint ett_fcswils_efp = -1;
+static gint ett_fcswils_efplist = -1;
+static gint ett_fcswils_dia = -1;
+static gint ett_fcswils_rdi = -1;
+static gint ett_fcswils_fspfhdr = -1;
+static gint ett_fcswils_hlo = -1;
+static gint ett_fcswils_lsrec = -1;
+static gint ett_fcswils_lsrechdr = -1;
+static gint ett_fcswils_ldrec = -1;
+static gint ett_fcswils_lsu = -1;
+static gint ett_fcswils_lsa = -1;
+static gint ett_fcswils_bf = -1;
+static gint ett_fcswils_rcf = -1;
+static gint ett_fcswils_rscn = -1;
+static gint ett_fcswils_rscn_dev = -1;
+static gint ett_fcswils_drlir = -1;
+static gint ett_fcswils_mr = -1;
+static gint ett_fcswils_zoneobjlist = -1;
+static gint ett_fcswils_zoneobj = -1;
+static gint ett_fcswils_zonembr = -1;
+static gint ett_fcswils_aca = -1;
+static gint ett_fcswils_rca = -1;
+static gint ett_fcswils_sfc = -1;
+static gint ett_fcswils_ufc = -1;
+static gint ett_fcswils_esc = -1;
+static gint ett_fcswils_esc_pdesc = -1;
+
+typedef struct _zonename {
+ guint32 namelen:8,
+ rsvd:24;
+ gchar *name;
+ gchar *pad;
+} zonename_t;
+
+typedef struct _fcswils_conv_key {
+ guint32 conv_idx;
+} fcswils_conv_key_t;
+
+typedef struct _fcswils_conv_data {
+ guint32 opcode;
+} fcswils_conv_data_t;
+
+#ifndef WIN32
+#define PACKED __attribute__((__packed__))
+#else
+#define PACKED
+#endif
+
+GHashTable *fcswils_req_hash = NULL;
+GMemChunk *fcswils_req_keys = NULL;
+GMemChunk *fcswils_req_vals = NULL;
+guint32 fcswils_init_count = 25;
+
+static dissector_handle_t data_handle;
+
+static gint get_zoneobj_len (tvbuff_t *tvb, gint offset);
+
+/*
+ * Hash Functions
+ */
+static gint
+fcswils_equal(gconstpointer v, gconstpointer w)
+{
+ fcswils_conv_key_t *v1 = (fcswils_conv_key_t *)v;
+ fcswils_conv_key_t *v2 = (fcswils_conv_key_t *)w;
+
+ return (v1->conv_idx == v2->conv_idx);
+}
+
+static guint
+fcswils_hash (gconstpointer v)
+{
+ fcswils_conv_key_t *key = (fcswils_conv_key_t *)v;
+ guint val;
+
+ val = key->conv_idx;
+
+ return val;
+}
+
+/*
+ * Protocol initialization
+ */
+static void
+fcswils_init_protocol(void)
+{
+ if (fcswils_req_keys)
+ g_mem_chunk_destroy (fcswils_req_keys);
+ if (fcswils_req_vals)
+ g_mem_chunk_destroy (fcswils_req_vals);
+ if (fcswils_req_hash)
+ g_hash_table_destroy (fcswils_req_hash);
+
+ fcswils_req_hash = g_hash_table_new(fcswils_hash, fcswils_equal);
+ fcswils_req_keys = g_mem_chunk_new("fcswils_req_keys",
+ sizeof(fcswils_conv_key_t),
+ fcswils_init_count * sizeof(fcswils_conv_key_t),
+ G_ALLOC_AND_FREE);
+ fcswils_req_vals = g_mem_chunk_new("fcswils_req_vals",
+ sizeof(fcswils_conv_data_t),
+ fcswils_init_count * sizeof(fcswils_conv_data_t),
+ G_ALLOC_AND_FREE);
+}
+
+static gchar *
+zonenm_to_str (tvbuff_t *tvb, gint offset)
+{
+ int len = tvb_get_guint8 (tvb, offset);
+ return ((gchar *)tvb_get_ptr (tvb, offset+4, len));
+}
+
+/* Offset points to the start of the zone object */
+static gint
+get_zoneobj_len (tvbuff_t *tvb, gint offset)
+{
+ gint numrec, numrec1;
+ guint8 objtype;
+ gint i, j, len;
+
+ /* zone object structure is:
+ * type (1 byte), protocol (1 byte), rsvd (2 bytes), obj name (x bytes),
+ * num of zone mbrs (4 bytes ), list of zone members (each member if of
+ * variable length).
+ *
+ * zone member structure is:
+ * type (1 byte), rsvd (1 byte), flags (1 byte), id_len (1 byte),
+ * id (id_len bytes)
+ */
+ objtype = tvb_get_guint8 (tvb, offset);
+ len = 4 + ZONENAME_LEN (tvb, offset+4); /* length upto num_of_mbrs field */
+ numrec = tvb_get_ntohl (tvb, offset+len); /* gets us num of zone mbrs */
+
+ len += 4; /* + num_mbrs */
+ for (i = 0; i < numrec; i++) {
+ if (objtype == FC_SWILS_ZONEOBJ_ZONESET) {
+ len += 4 + ZONENAME_LEN (tvb, offset+4+len); /* length upto num_of_mbrs field */
+ numrec1 = tvb_get_ntohl (tvb, offset+len);
+
+ len += 4;
+ for (j = 0; j < numrec1; j++) {
+ len += 4 + tvb_get_guint8 (tvb, offset+3+len);
+ }
+ }
+ else if (objtype == FC_SWILS_ZONEOBJ_ZONE) {
+ len += 4 + tvb_get_guint8 (tvb, offset+3+len);
+ }
+ }
+
+ return len;
+}
+
+static void
+dissect_swils_elp (tvbuff_t *tvb, proto_tree *elp_tree, guint8 isreq _U_)
+{
+
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 0,
+ stroff = 0;
+ gchar flags[40];
+ fcswils_elp elp;
+
+ /* Response i.e. SW_ACC for an ELP has the same format as the request */
+ /* We skip the initial 4 bytes as we don't care about the opcode */
+ tvb_memcpy (tvb, (guint8 *)&elp, 4, FC_SWILS_ELP_SIZE);
+
+ elp.r_a_tov = ntohl (elp.r_a_tov);
+ elp.e_d_tov = ntohl (elp.e_d_tov);
+ elp.isl_flwctrl_mode = ntohs (elp.isl_flwctrl_mode);
+ elp.flw_ctrl_parmlen = ntohs (elp.flw_ctrl_parmlen);
+
+ if (elp_tree) {
+ offset += 4;
+ proto_tree_add_item (elp_tree, hf_swils_elp_rev, tvb, offset++, 1, 0);
+ proto_tree_add_item (elp_tree, hf_swils_elp_flags, tvb, offset, 2, 0);
+ offset += 3;
+ proto_tree_add_uint_format (elp_tree, hf_swils_elp_r_a_tov, tvb, offset, 4,
+ elp.r_a_tov, "R_A_TOV: %d msecs", elp.r_a_tov);
+ offset += 4;
+ proto_tree_add_uint_format (elp_tree, hf_swils_elp_e_d_tov, tvb, offset, 4,
+ elp.e_d_tov, "E_D_TOV: %d msecs", elp.e_d_tov);
+ offset += 4;
+ proto_tree_add_string (elp_tree, hf_swils_elp_req_epn, tvb, offset, 8,
+ fcwwn_to_str (elp.req_epname));
+ offset += 8;
+ proto_tree_add_string (elp_tree, hf_swils_elp_req_esn, tvb, offset, 8,
+ fcwwn_to_str (elp.req_sname));
+ offset += 8;
+
+ flags[0] = '\0';
+ if (elp.clsf_svcparm[0] & 0x80) {
+ strcpy (flags, "Class F Valid");
+
+ if (elp.clsf_svcparm[4] & 0x20) {
+ strcpy (&flags[13], " | X_ID Interlock");
+ }
+ else {
+ strcpy (&flags[13], " | No X_ID Interlk");
+ }
+ }
+ else {
+ strcpy (flags, "Class F Invld");
+ }
+ proto_tree_add_bytes_format (elp_tree, hf_swils_elp_clsf_svcp, tvb, offset, 6,
+ &elp.clsf_svcparm[0], "Class F Svc Parameters: (%s)", flags);
+ offset += 6;
+
+ proto_tree_add_item (elp_tree, hf_swils_elp_clsf_rcvsz, tvb, offset, 2, 0);
+ offset += 2;
+ proto_tree_add_item (elp_tree, hf_swils_elp_clsf_conseq, tvb, offset, 2, 0);
+ offset += 2;
+ proto_tree_add_item (elp_tree, hf_swils_elp_clsf_e2e, tvb, offset, 2, 0);
+ offset += 2;
+ proto_tree_add_item (elp_tree, hf_swils_elp_clsf_openseq, tvb, offset, 2, 0);
+ offset += 4;
+
+ flags[0] = '\0';
+ stroff = 0;
+ if (elp.cls1_svcparm[0] & 0x80) {
+ strcpy (&flags[stroff], "Class 1 Valid");
+ stroff += 13;
+ if (elp.cls1_svcparm[0] & 0x40) {
+ strcpy (&flags[stroff], " | IMX");
+ stroff += 6;
+ }
+ if (elp.cls1_svcparm[0] & 0x20) {
+ strcpy (&flags[stroff], " | XPS");
+ stroff += 6;
+ }
+ if (elp.cls1_svcparm[0] & 0x10) {
+ strcpy (&flags[stroff], " | LKS");
+ }
+ }
+ else {
+ strcpy (&flags[0], "Class 1 Invalid");
+ }
+
+ proto_tree_add_bytes_format (elp_tree, hf_swils_elp_cls1_svcp, tvb, offset, 2,
+ tvb_get_ptr (tvb, offset, 2),
+ "Class 1 Svc Parameters: (%s)", flags);
+ offset += 2;
+ if (elp.cls1_svcparm[0] & 0x80) {
+ proto_tree_add_item (elp_tree, hf_swils_elp_cls1_rcvsz, tvb, offset, 2, 0);
+ }
+ offset += 2;
+
+ flags[0] = '\0';
+ if (elp.cls2_svcparm[0] & 0x80) {
+ strcpy (flags, "Class 2 Valid");
+
+ if (elp.cls2_svcparm[0] & 0x08) {
+ strcpy (&flags[13], " | Seq Delivery");
+ }
+ else {
+ strcpy (&flags[13], " | No Seq Delivery");
+ }
+ }
+ else {
+ strcpy (flags, "Class 2 Invld");
+ }
+
+ proto_tree_add_bytes_format (elp_tree, hf_swils_elp_cls2_svcp, tvb, offset, 2,
+ &elp.cls2_svcparm[0],
+ "Class 2 Svc Parameters: (%s)", flags);
+ offset += 2;
+
+ if (elp.cls2_svcparm[0] & 0x80) {
+ proto_tree_add_item (elp_tree, hf_swils_elp_cls2_rcvsz, tvb, offset, 2, 0);
+ }
+ offset += 2;
+
+ flags[0] = '\0';
+ if (elp.cls3_svcparm[0] & 0x80) {
+ strcpy (flags, "Class 3 Valid");
+
+ if (elp.cls3_svcparm[0] & 0x08) {
+ strcpy (&flags[13], " | Seq Delivery");
+ }
+ else {
+ strcpy (&flags[13], " | No Seq Delivery");
+ }
+ }
+ else {
+ strcpy (flags, "Class 3 Invld");
+ }
+ proto_tree_add_bytes_format (elp_tree, hf_swils_elp_cls3_svcp, tvb, offset, 2,
+ &elp.cls3_svcparm[0],
+ "Class 3 Svc Parameters: (%s)", flags);
+ offset += 2;
+
+ if (elp.cls3_svcparm[0] & 0x80) {
+ proto_tree_add_item (elp_tree, hf_swils_elp_cls3_rcvsz, tvb, offset, 2, 0);
+ }
+ offset += 22;
+
+ proto_tree_add_string (elp_tree, hf_swils_elp_isl_fc_mode, tvb, offset, 2,
+ val_to_str (elp.isl_flwctrl_mode, fcswils_elp_fc_val, "Vendor Unique"));
+ offset += 2;
+ proto_tree_add_item (elp_tree, hf_swils_elp_fcplen, tvb, offset, 2, 0);
+ offset += 2;
+ proto_tree_add_item (elp_tree, hf_swils_elp_b2bcredit, tvb, offset, 4, 0);
+ offset += 4;
+ proto_tree_add_item (elp_tree, hf_swils_elp_compat1, tvb, offset, 4, 0);
+ offset += 4;
+ proto_tree_add_item (elp_tree, hf_swils_elp_compat2, tvb, offset, 4, 0);
+ offset += 4;
+ proto_tree_add_item (elp_tree, hf_swils_elp_compat3, tvb, offset, 4, 0);
+ offset += 4;
+ proto_tree_add_item (elp_tree, hf_swils_elp_compat4, tvb, offset, 4, 0);
+ }
+
+}
+
+static void
+dissect_swils_efp (tvbuff_t *tvb, proto_tree *efp_tree, guint8 isreq _U_)
+{
+
+/* Set up structures needed to add the protocol subtree and manage it */
+ proto_item *subti;
+ proto_tree *lrec_tree;
+ int num_listrec = 0,
+ offset = 0;
+ fcswils_efp efp;
+ fcswils_efp_listrec *lrec;
+
+ tvb_memcpy (tvb, (guint8 *)&efp, offset, FC_SWILS_EFP_SIZE);
+ efp.payload_len = ntohs (efp.payload_len);
+ efp.listrec = (fcswils_efp_listrec *)tvb_get_ptr (tvb, FC_SWILS_EFP_SIZE,
+ efp.payload_len - FC_SWILS_EFP_SIZE);
+
+ if (efp_tree) {
+ offset += 2;
+ proto_tree_add_item (efp_tree, hf_swils_efp_payload_len, tvb, offset, 2, 0);
+ offset += 5;
+ proto_tree_add_item (efp_tree, hf_swils_efp_pswitch_pri, tvb,
+ offset++, 1, 0);
+ proto_tree_add_string (efp_tree, hf_swils_efp_pswitch_name, tvb, offset,
+ 8, fcwwn_to_str (efp.pswitch_name));
+ offset += 8;
+
+ /* Add List Records now */
+ if (efp.reclen) {
+ num_listrec = (efp.payload_len - FC_SWILS_EFP_SIZE)/efp.reclen;
+ }
+ else {
+ num_listrec = 0;
+ }
+
+ while (num_listrec--) {
+ lrec = (fcswils_efp_listrec *)tvb_get_ptr (tvb, offset, efp.reclen);
+ if (lrec != NULL) {
+ if (lrec->didrec.rec_type == FC_SWILS_LRECTYPE_DOMAIN) {
+ subti = proto_tree_add_text (efp_tree, tvb, offset,
+ (efp.payload_len - FC_SWILS_EFP_SIZE),
+ "Domain ID Record");
+ lrec_tree = proto_item_add_subtree (subti, ett_fcswils_efplist);
+ proto_tree_add_item (lrec_tree, hf_swils_efp_dom_id, tvb, offset+1, 1, 0);
+ proto_tree_add_string (lrec_tree, hf_swils_efp_switch_name, tvb, offset+8, 8,
+ fcwwn_to_str (lrec->didrec.sname));
+ }
+ else if (lrec->didrec.rec_type == FC_SWILS_LRECTYPE_MCAST) {
+ subti = proto_tree_add_text (efp_tree, tvb, offset,
+ (efp.payload_len - FC_SWILS_EFP_SIZE),
+ "Multicast ID Record");
+ lrec_tree = proto_item_add_subtree (subti, ett_fcswils_efplist);
+ proto_tree_add_item (lrec_tree, hf_swils_efp_mcast_grpno, tvb, offset+1, 1, 0);
+ }
+ offset += efp.reclen;
+ }
+ }
+ }
+}
+
+static void
+dissect_swils_dia (tvbuff_t *tvb, proto_tree *dia_tree, guint8 isreq _U_)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 0;
+
+ if (dia_tree) {
+ proto_tree_add_string (dia_tree, hf_swils_dia_switch_name, tvb, offset+4,
+ 8, fcwwn_to_str (tvb_get_ptr (tvb, offset+4, 8)));
+ }
+}
+
+static void
+dissect_swils_rdi (tvbuff_t *tvb, proto_tree *rdi_tree, guint8 isreq)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 0;
+ int i, plen, numrec;
+
+ if (rdi_tree) {
+ plen = tvb_get_ntohs (tvb, offset+2);
+
+ proto_tree_add_item (rdi_tree, hf_swils_rdi_payload_len, tvb, offset+2, 2, 0);
+ proto_tree_add_string (rdi_tree, hf_swils_rdi_req_sname, tvb, offset+4,
+ 8, fcwwn_to_str (tvb_get_ptr (tvb, offset+4, 8)));
+
+ /* 12 is the length of the initial header and 4 is the size of each
+ * domain request record.
+ */
+ numrec = (plen - 12)/4;
+ offset = 12;
+ for (i = 0; i < numrec; i++) {
+ if (isreq) {
+ proto_tree_add_text (rdi_tree, tvb, offset+3, 1,
+ "Requested Domain ID: %d",
+ tvb_get_guint8 (tvb, offset+3));
+ }
+ else {
+ proto_tree_add_text (rdi_tree, tvb, offset+3, 1,
+ "Granted Domain ID: %d",
+ tvb_get_guint8 (tvb, offset+3));
+ }
+ offset += 4;
+ }
+ }
+}
+
+static void
+dissect_swils_fspf_hdr (tvbuff_t *tvb, proto_tree *tree, int offset)
+{
+ proto_item *subti;
+ proto_tree *fspfh_tree;
+
+ if (tree) {
+ /* 20 is the size of FSPF header */
+ subti = proto_tree_add_text (tree, tvb, offset, 20, "FSPF Header");
+ fspfh_tree = proto_item_add_subtree (subti, ett_fcswils_fspfhdr);
+
+ proto_tree_add_item (fspfh_tree, hf_swils_fspfh_rev, tvb, offset+4,
+ 1, 0);
+ proto_tree_add_item (fspfh_tree, hf_swils_fspfh_ar_num, tvb,
+ offset+5, 1, 0);
+ proto_tree_add_item (fspfh_tree, hf_swils_fspfh_auth_type, tvb,
+ offset+6, 1, 0);
+ proto_tree_add_item (fspfh_tree, hf_swils_fspfh_dom_id, tvb, offset+11,
+ 1, 0);
+ proto_tree_add_item (fspfh_tree, hf_swils_fspfh_auth, tvb, offset+12,
+ 8, 0);
+ }
+}
+
+static void
+dissect_swils_fspf_lsrechdr (tvbuff_t *tvb, proto_tree *lsrec_tree, int offset)
+{
+ proto_tree *tree;
+ proto_item *subti;
+
+ subti = proto_tree_add_text (lsrec_tree, tvb, offset, 24,
+ "Link State Record Header");
+ tree = proto_item_add_subtree (subti, ett_fcswils_lsrechdr);
+
+ proto_tree_add_item (tree, hf_swils_lsrh_lsr_type, tvb, offset, 1, 0);
+ proto_tree_add_text (tree, tvb, offset+2, 2, "LSR Age: %d secs",
+ tvb_get_ntohs (tvb, offset+2));
+ proto_tree_add_text (tree, tvb, offset+4, 4, "Options : 0x%x",
+ tvb_get_ntohl (tvb, offset+4));
+ proto_tree_add_item (tree, hf_swils_lsrh_lsid, tvb, offset+11, 1, 0);
+ proto_tree_add_item (tree, hf_swils_lsrh_adv_domid, tvb, offset+15, 1, 0);
+ proto_tree_add_item (tree, hf_swils_lsrh_ls_incid, tvb, offset+16, 4, 0);
+ proto_tree_add_text (tree, tvb, offset+20, 2, "Checksum: 0x%x",
+ tvb_get_ntohs (tvb, offset+20));
+ proto_tree_add_text (tree, tvb, offset+22, 2, "LSR Length: %d",
+ tvb_get_ntohs (tvb, offset+22));
+}
+
+static void
+dissect_swils_fspf_ldrec (tvbuff_t *tvb, proto_tree *tree, int offset)
+{
+ proto_tree_add_string (tree, hf_swils_ldrec_linkid, tvb, offset, 4,
+ fc_to_str (tvb_get_ptr (tvb, offset+1, 3)));
+ proto_tree_add_item (tree, hf_swils_ldrec_out_pidx, tvb, offset+5, 3, 0);
+ proto_tree_add_item (tree, hf_swils_ldrec_nbr_pidx, tvb, offset+9, 3, 0);
+ proto_tree_add_item (tree, hf_swils_ldrec_link_type, tvb, offset+12, 1, 0);
+ proto_tree_add_item (tree, hf_swils_ldrec_link_cost, tvb, offset+14, 2, 0);
+}
+
+static void
+dissect_swils_fspf_lsrec (tvbuff_t *tvb, proto_tree *tree, int offset,
+ int num_lsrec)
+{
+ int i, j, num_ldrec;
+ proto_item *subti1, *subti;
+ proto_tree *lsrec_tree, *ldrec_tree;
+
+ if (tree) {
+ for (j = 0; j < num_lsrec; j++) {
+ num_ldrec = tvb_get_ntohs (tvb, offset+26);
+ subti = proto_tree_add_text (tree, tvb, offset, (28+num_ldrec*16),
+ "Link State Record %d", j);
+ lsrec_tree = proto_item_add_subtree (subti, ett_fcswils_lsrec);
+
+ dissect_swils_fspf_lsrechdr (tvb, lsrec_tree, offset);
+ proto_tree_add_text (tree, tvb, offset+26, 2, "Number of Links: %d",
+ num_ldrec);
+ offset += 28;
+
+ for (i = 0; i < num_ldrec; i++) {
+ subti1 = proto_tree_add_text (tree, tvb, offset, 16,
+ "Link Descriptor %d", i);
+ ldrec_tree = proto_item_add_subtree (subti1, ett_fcswils_ldrec);
+ dissect_swils_fspf_ldrec (tvb, ldrec_tree, offset);
+ offset += 16;
+ }
+ }
+ }
+}
+
+static void
+dissect_swils_hello (tvbuff_t *tvb, proto_tree *hlo_tree, guint8 isreq _U_)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 0;
+
+ if (hlo_tree) {
+ dissect_swils_fspf_hdr (tvb, hlo_tree, offset);
+
+ proto_tree_add_item (hlo_tree, hf_swils_hlo_options, tvb, offset+20, 4, 0);
+ proto_tree_add_item (hlo_tree, hf_swils_hlo_hloint, tvb, offset+24, 4, 0);
+ proto_tree_add_item (hlo_tree, hf_swils_hlo_deadint, tvb, offset+28, 4, 0);
+ proto_tree_add_item (hlo_tree, hf_swils_hlo_rcv_domid, tvb, offset+35, 1, 0);
+ proto_tree_add_item (hlo_tree, hf_swils_hlo_orig_pidx, tvb, offset+37, 3, 0);
+ }
+}
+
+static void
+dissect_swils_lsupdate (tvbuff_t *tvb, proto_tree *lsu_tree, guint8 isreq _U_)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 0;
+ int num_lsrec;
+
+ if (lsu_tree) {
+ dissect_swils_fspf_hdr (tvb, lsu_tree, offset);
+
+ proto_tree_add_text (lsu_tree, tvb, offset+23, 1, "Flags : %s",
+ val_to_str (tvb_get_guint8 (tvb, offset+23),
+ fc_swils_fspf_lsrflags_val, "0x%x"));
+ num_lsrec = tvb_get_ntohl (tvb, offset+24);
+
+ proto_tree_add_text (lsu_tree, tvb, offset+24, 4, "Num of LSRs: %d",
+ num_lsrec);
+
+ offset = 28;
+ dissect_swils_fspf_lsrec (tvb, lsu_tree, offset, num_lsrec);
+ }
+}
+
+static void
+dissect_swils_lsack (tvbuff_t *tvb, proto_tree *lsa_tree, guint8 isreq _U_)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 0;
+ int num_lsrechdr, i;
+
+ if (lsa_tree) {
+ dissect_swils_fspf_hdr (tvb, lsa_tree, offset);
+
+ proto_tree_add_text (lsa_tree, tvb, offset+23, 1, "Flags : %s",
+ val_to_str (tvb_get_guint8 (tvb, offset+23),
+ fc_swils_fspf_lsrflags_val, "0x%x"));
+ num_lsrechdr = tvb_get_ntohl (tvb, offset+24);
+
+ proto_tree_add_text (lsa_tree, tvb, offset+24, 4, "Num of LSR Headers: %d",
+ num_lsrechdr);
+
+ offset = 28;
+
+ for (i = 0; i < num_lsrechdr; i++) {
+ dissect_swils_fspf_lsrechdr (tvb, lsa_tree, offset);
+ offset += 24;
+ }
+ }
+}
+
+static void
+dissect_swils_rscn (tvbuff_t *tvb, proto_tree *rscn_tree, guint8 isreq)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 0;
+ proto_tree *dev_tree;
+ int addrfmt, evtype;
+ int numrec, i;
+ proto_item *subti;
+
+ if (rscn_tree) {
+ if (!isreq)
+ return;
+
+ evtype = tvb_get_guint8 (tvb, offset+4);
+ addrfmt = evtype & 0x0F;
+ evtype = evtype >> 4;
+
+ proto_tree_add_item (rscn_tree, hf_swils_rscn_evtype, tvb, offset+4,
+ 1, 0);
+ proto_tree_add_item (rscn_tree, hf_swils_rscn_addrfmt, tvb, offset+4,
+ 1, 0);
+ proto_tree_add_string (rscn_tree, hf_swils_rscn_affectedport, tvb,
+ offset+5, 3, fc_to_str (tvb_get_ptr (tvb,
+ offset+5, 3)));
+ proto_tree_add_item (rscn_tree, hf_swils_rscn_detectfn, tvb,
+ offset+8, 4, 0);
+ numrec = tvb_get_ntohl (tvb, offset+12);
+ proto_tree_add_text (rscn_tree, tvb, offset+12, 4, "Num Entries: %d",
+ numrec);
+
+ offset = 16;
+ for (i = 0; i < numrec; i++) {
+ subti = proto_tree_add_text (rscn_tree, tvb, offset, 20,
+ "Device Entry %d", i);
+ dev_tree = proto_item_add_subtree (rscn_tree, ett_fcswils_rscn_dev);
+
+ proto_tree_add_item (dev_tree, hf_swils_rscn_portstate, tvb, offset, 1, 0);
+ proto_tree_add_string (dev_tree, hf_swils_rscn_portid, tvb, offset+1, 3,
+ fc_to_str (tvb_get_ptr (tvb, offset+1, 3)));
+ proto_tree_add_string (dev_tree, hf_swils_rscn_pwwn, tvb, offset+4, 8,
+ fcwwn_to_str (tvb_get_ptr (tvb, offset+4, 8)));
+ proto_tree_add_string (dev_tree, hf_swils_rscn_nwwn, tvb, offset+4, 8,
+ fcwwn_to_str (tvb_get_ptr (tvb, offset+4, 8)));
+ offset += 20;
+ }
+ }
+}
+
+/*
+ * Merge Request contains zoning objects organized in the following format:
+ *
+ * Zone Set Object
+ * |
+ * +---------------- Zone Object
+ * | |
+ * +-- +---------------- Zone Member
+ * | | |
+ * +-- +---- +-----
+ *
+ * So the decoding of the zone merge request is based on this structure
+ */
+
+static void
+dissect_swils_zone_mbr (tvbuff_t *tvb, proto_tree *zmbr_tree, int offset)
+{
+ int mbrlen = 4 + tvb_get_guint8 (tvb, offset+3);
+
+ proto_tree_add_item (zmbr_tree, hf_swils_zone_mbrtype, tvb,
+ offset, 1, 0);
+ proto_tree_add_text (zmbr_tree, tvb, offset+2, 1, "Flags: 0x%x",
+ tvb_get_guint8 (tvb, offset+2));
+ proto_tree_add_text (zmbr_tree, tvb, offset+3, 1,
+ "Identifier Length: %d",
+ tvb_get_guint8 (tvb, offset+3));
+ switch (tvb_get_guint8 (tvb, offset)) {
+ case FC_SWILS_ZONEMBR_WWN:
+ proto_tree_add_string (zmbr_tree, hf_swils_zone_mbrid, tvb,
+ offset+4, 8,
+ fcwwn_to_str (tvb_get_ptr (tvb,
+ offset+4,
+ 8)));
+ break;
+ case FC_SWILS_ZONEMBR_DP:
+ proto_tree_add_string_format (zmbr_tree,
+ hf_swils_zone_mbrid,
+ tvb, offset+4, 4, " ",
+ "0x%x",
+ tvb_get_ntohl (tvb,
+ offset+4));
+ break;
+ case FC_SWILS_ZONEMBR_FCID:
+ proto_tree_add_string (zmbr_tree, hf_swils_zone_mbrid, tvb,
+ offset+4, 4,
+ fc_to_str (tvb_get_ptr (tvb,
+ offset+5,
+ 3)));
+ break;
+ case FC_SWILS_ZONEMBR_ALIAS:
+ proto_tree_add_string (zmbr_tree, hf_swils_zone_mbrid, tvb,
+ offset+4,
+ tvb_get_guint8 (tvb, offset+3),
+ zonenm_to_str (tvb, offset+4));
+ break;
+ case FC_SWILS_ZONEMBR_WWN_LUN:
+ proto_tree_add_string (zmbr_tree, hf_swils_zone_mbrid, tvb,
+ offset+4, 8,
+ fcwwn_to_str (tvb_get_ptr (tvb,
+ offset+4,
+ 8)));
+ proto_tree_add_item (zmbr_tree, hf_swils_zone_mbrid_lun, tvb,
+ offset+12, 8, 0);
+ break;
+ case FC_SWILS_ZONEMBR_DP_LUN:
+ proto_tree_add_string_format (zmbr_tree,
+ hf_swils_zone_mbrid,
+ tvb, offset+4, 4, " ",
+ "0x%x",
+ tvb_get_ntohl (tvb,
+ offset+4));
+ proto_tree_add_item (zmbr_tree, hf_swils_zone_mbrid_lun, tvb,
+ offset+8, 8, 0);
+ break;
+ case FC_SWILS_ZONEMBR_FCID_LUN:
+ proto_tree_add_string (zmbr_tree, hf_swils_zone_mbrid, tvb,
+ offset+4, 4,
+ fc_to_str (tvb_get_ptr (tvb,
+ offset+5,
+ 3)));
+ proto_tree_add_item (zmbr_tree, hf_swils_zone_mbrid_lun, tvb,
+ offset+8, 8, 0);
+ break;
+ default:
+ proto_tree_add_string (zmbr_tree, hf_swils_zone_mbrid, tvb,
+ offset+4, mbrlen,
+ "Unknown member type format");
+
+ }
+}
+
+static void
+dissect_swils_zone_obj (tvbuff_t *tvb, proto_tree *zobj_tree, int offset)
+{
+ proto_tree *zmbr_tree;
+ int mbrlen, numrec, i, objtype;
+ proto_item *subti;
+
+ objtype = tvb_get_guint8 (tvb, offset);
+
+ proto_tree_add_item (zobj_tree, hf_swils_zone_objtype, tvb, offset,
+ 1, 0);
+ proto_tree_add_item (zobj_tree, hf_swils_zone_protocol, tvb,
+ offset+1, 1, 0);
+ proto_tree_add_string (zobj_tree, hf_swils_zone_objname, tvb,
+ offset+4, ZONENAME_LEN (tvb, offset+4),
+ zonenm_to_str (tvb, offset+4));
+
+ numrec = tvb_get_ntohl (tvb, offset+4+ZONENAME_LEN (tvb, offset+4));
+ proto_tree_add_text (zobj_tree, tvb,
+ offset+4+ZONENAME_LEN (tvb, offset+4), 4,
+ "Number of Zone Members: %d", numrec);
+
+ offset += 8 + ZONENAME_LEN (tvb, offset+4);
+ for (i = 0; i < numrec; i++) {
+ if (objtype == FC_SWILS_ZONEOBJ_ZONESET) {
+ dissect_swils_zone_obj (tvb, zobj_tree, offset);
+ offset += get_zoneobj_len (tvb, offset);
+ }
+ else {
+ mbrlen = 4 + tvb_get_guint8 (tvb, offset+3);
+ subti = proto_tree_add_text (zobj_tree, tvb, offset, mbrlen,
+ "Zone Member %d", i);
+ zmbr_tree = proto_item_add_subtree (zobj_tree,
+ ett_fcswils_zonembr);
+ dissect_swils_zone_mbr (tvb, zmbr_tree, offset);
+ offset += mbrlen;
+ }
+ }
+}
+
+static void
+dissect_swils_mergereq (tvbuff_t *tvb, proto_tree *mr_tree, guint8 isreq)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 0;
+ proto_tree *zobjlist_tree, *zobj_tree;
+ int numrec, i, zonesetlen, objlistlen, objlen;
+ proto_item *subti;
+
+ if (mr_tree) {
+ if (isreq) {
+ /* zonesetlen is the size of the zoneset including the zone name */
+ zonesetlen = tvb_get_ntohs (tvb, offset+2);
+ proto_tree_add_text (mr_tree, tvb, offset+2, 2,
+ "Active ZoneSet Length: %d", zonesetlen);
+
+ if (zonesetlen) {
+ proto_tree_add_string (mr_tree, hf_swils_zone_activezonenm, tvb,
+ offset+4, ZONENAME_LEN (tvb, offset+4),
+ zonenm_to_str (tvb, offset+4));
+
+ /* objlistlen gives the size of the active zoneset object list */
+ objlistlen = zonesetlen - ZONENAME_LEN (tvb, offset+4);
+ /* Offset = start of the active zoneset zoning object list */
+ offset = offset + (4 + ZONENAME_LEN (tvb, offset+4));
+ numrec = tvb_get_ntohl (tvb, offset);
+
+ subti = proto_tree_add_text (mr_tree, tvb, offset, objlistlen,
+ "Active Zone Set");
+ zobjlist_tree = proto_item_add_subtree (subti,
+ ett_fcswils_zoneobjlist);
+
+ proto_tree_add_text (zobjlist_tree, tvb, offset, 4,
+ "Number of zoning objects: %d", numrec);
+
+ offset += 4;
+ for (i = 0; i < numrec; i++) {
+ objlen = get_zoneobj_len (tvb, offset);
+ subti = proto_tree_add_text (zobjlist_tree, tvb, offset+4,
+ objlen, "Zone Object %d", i);
+ zobj_tree = proto_item_add_subtree (subti, ett_fcswils_zoneobj);
+ dissect_swils_zone_obj (tvb, zobj_tree, offset);
+ offset += objlen;
+ }
+ }
+ else {
+ offset += 4;
+ }
+
+ zonesetlen = tvb_get_ntohl (tvb, offset);
+ proto_tree_add_text (mr_tree, tvb, offset, 4,
+ "Full Zone Set Length: %d", zonesetlen);
+
+ if (zonesetlen) {
+ objlistlen = zonesetlen;
+ /* Offset = start of the active zoneset zoning object list */
+ offset += 4;
+ numrec = tvb_get_ntohl (tvb, offset);
+
+ subti = proto_tree_add_text (mr_tree, tvb, offset, objlistlen,
+ "Full Zone Set");
+
+ zobjlist_tree = proto_item_add_subtree (subti,
+ ett_fcswils_zoneobjlist);
+ proto_tree_add_text (zobjlist_tree, tvb, offset, 4,
+ "Number of zoning objects: %d", numrec);
+ offset += 4;
+ for (i = 0; i < numrec; i++) {
+ objlen = get_zoneobj_len (tvb, offset);
+ subti = proto_tree_add_text (zobjlist_tree, tvb, offset,
+ objlen, "Zone Object %d", i);
+ zobj_tree = proto_item_add_subtree (subti, ett_fcswils_zoneobj);
+ dissect_swils_zone_obj (tvb, zobj_tree, offset);
+ offset += objlen;
+ }
+ }
+ }
+ else {
+ proto_tree_add_item (mr_tree, hf_swils_zone_status, tvb,
+ offset+5, 1, 0);
+ proto_tree_add_item (mr_tree, hf_swils_zone_reason, tvb,
+ offset+6, 1, 0);
+ proto_tree_add_text (mr_tree, tvb, offset+7, 1,
+ "Vendor Unique: 0x%x",
+ tvb_get_guint8 (tvb, offset+7));
+ }
+ }
+}
+
+static void
+dissect_swils_aca (tvbuff_t *tvb, proto_tree *aca_tree, guint8 isreq)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 0;
+ int numrec, plen, i;
+
+ if (aca_tree) {
+ if (isreq) {
+ plen = tvb_get_ntohs (tvb, offset+2);
+ proto_tree_add_text (aca_tree, tvb, offset+2, 2,
+ "Domain ID List Length: %d", plen);
+ numrec = plen/4;
+ offset = 4;
+
+ for (i = 0; i < numrec; i++) {
+ proto_tree_add_uint_format (aca_tree, hf_swils_aca_domainid,
+ tvb, offset+3, 1,
+ tvb_get_guint8 (tvb, offset+3),
+ "Domain ID %d: %d", i,
+ tvb_get_guint8 (tvb, offset+3));
+ offset += 4;
+ }
+ }
+ else {
+ proto_tree_add_item (aca_tree, hf_swils_zone_status, tvb,
+ offset+5, 1, 0);
+ proto_tree_add_item (aca_tree, hf_swils_zone_reason, tvb,
+ offset+6, 1, 0);
+ proto_tree_add_text (aca_tree, tvb, offset+7, 1,
+ "Vendor Unique: 0x%x",
+ tvb_get_guint8 (tvb, offset+7));
+ }
+ }
+}
+
+static void
+dissect_swils_rca (tvbuff_t *tvb, proto_tree *rca_tree, guint8 isreq)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 0;
+
+ if (rca_tree) {
+ if (!isreq) {
+ proto_tree_add_item (rca_tree, hf_swils_zone_status, tvb,
+ offset+5, 1, 0);
+ proto_tree_add_item (rca_tree, hf_swils_zone_reason, tvb,
+ offset+6, 1, 0);
+ proto_tree_add_text (rca_tree, tvb, offset+7, 1,
+ "Vendor Unique: 0x%x",
+ tvb_get_guint8 (tvb, offset+7));
+ }
+ }
+}
+
+static void
+dissect_swils_sfc (tvbuff_t *tvb, proto_tree *sfc_tree, guint8 isreq)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 0;
+ proto_tree *zobjlist_tree, *zobj_tree;
+ int numrec, i, zonesetlen, objlistlen, objlen;
+ proto_item *subti;
+
+ if (sfc_tree) {
+ if (isreq) {
+ proto_tree_add_item (sfc_tree, hf_swils_sfc_opcode, tvb, offset+1, 1, 0);
+
+ zonesetlen = tvb_get_ntohs (tvb, offset+2);
+ proto_tree_add_text (sfc_tree, tvb, offset+2, 2,
+ "ZoneSet Length: %d", zonesetlen);
+
+ if (zonesetlen) {
+ proto_tree_add_string (sfc_tree, hf_swils_sfc_zonenm, tvb,
+ offset+4, ZONENAME_LEN (tvb, offset+4),
+ zonenm_to_str (tvb, offset+4));
+
+ /* objlistlen gives the size of the active zoneset object list */
+ objlistlen = zonesetlen - ZONENAME_LEN (tvb, offset+4);
+ /* Offset = start of the active zoneset zoning object list */
+ offset = offset + (4 + ZONENAME_LEN (tvb, offset+4));
+ numrec = tvb_get_ntohl (tvb, offset);
+
+ subti = proto_tree_add_text (sfc_tree, tvb, offset, objlistlen,
+ "Zone Set");
+ zobjlist_tree = proto_item_add_subtree (subti,
+ ett_fcswils_zoneobjlist);
+
+ proto_tree_add_text (zobjlist_tree, tvb, offset, 4,
+ "Number of zoning objects: %d", numrec);
+
+ offset += 4;
+ for (i = 0; i < numrec; i++) {
+ objlen = get_zoneobj_len (tvb, offset);
+ subti = proto_tree_add_text (zobjlist_tree, tvb, offset,
+ objlen, "Zone Object %d", i);
+ zobj_tree = proto_item_add_subtree (subti, ett_fcswils_zoneobj);
+ dissect_swils_zone_obj (tvb, zobj_tree, offset);
+ offset += objlen;
+ }
+ }
+ else {
+ offset += 4;
+ }
+
+ zonesetlen = tvb_get_ntohl (tvb, offset);
+ proto_tree_add_text (sfc_tree, tvb, offset, 4,
+ "Full Zone Set Length: %d", zonesetlen);
+
+ if (zonesetlen) {
+ objlistlen = zonesetlen;
+ /* Offset = start of the active zoneset zoning object list */
+ offset += 4;
+ numrec = tvb_get_ntohl (tvb, offset);
+
+ subti = proto_tree_add_text (sfc_tree, tvb, offset, objlistlen,
+ "Full Zone Set");
+
+ zobjlist_tree = proto_item_add_subtree (subti,
+ ett_fcswils_zoneobjlist);
+ proto_tree_add_text (zobjlist_tree, tvb, offset, 4,
+ "Number of zoning objects: %d", numrec);
+ offset += 4;
+ for (i = 0; i < numrec; i++) {
+ objlen = get_zoneobj_len (tvb, offset);
+ subti = proto_tree_add_text (zobjlist_tree, tvb, offset,
+ objlen, "Zone Object %d", i);
+ zobj_tree = proto_item_add_subtree (subti, ett_fcswils_zoneobj);
+ dissect_swils_zone_obj (tvb, zobj_tree, offset);
+ offset += objlen;
+ }
+ }
+ }
+ else {
+ proto_tree_add_item (sfc_tree, hf_swils_zone_status, tvb,
+ offset+5, 1, 0);
+ proto_tree_add_item (sfc_tree, hf_swils_zone_reason, tvb,
+ offset+6, 1, 0);
+ proto_tree_add_text (sfc_tree, tvb, offset+7, 1,
+ "Vendor Unique: 0x%x",
+ tvb_get_guint8 (tvb, offset+7));
+ }
+ }
+}
+
+static void
+dissect_swils_ufc (tvbuff_t *tvb, proto_tree *ufc_tree, guint8 isreq)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 0;
+
+ if (ufc_tree) {
+ if (!isreq) {
+ proto_tree_add_item (ufc_tree, hf_swils_zone_status, tvb,
+ offset+5, 1, 0);
+ proto_tree_add_item (ufc_tree, hf_swils_zone_reason, tvb,
+ offset+6, 1, 0);
+ proto_tree_add_text (ufc_tree, tvb, offset+7, 1,
+ "Vendor Unique: 0x%x",
+ tvb_get_guint8 (tvb, offset+7));
+ }
+ }
+}
+
+static void
+dissect_swils_esc (tvbuff_t *tvb, proto_tree *esc_tree, guint8 isreq)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 0;
+ int i, numrec, plen;
+ proto_tree *pdesc_tree;
+ proto_item *subti;
+
+ if (esc_tree) {
+ if (isreq) {
+ plen = tvb_get_ntohs (tvb, offset+2);
+ proto_tree_add_text (esc_tree, tvb, offset+2, 2,
+ "Payload Length: %d", plen);
+ proto_tree_add_item (esc_tree, hf_swils_esc_swvendorid, tvb,
+ offset+4, 8, 0);
+ numrec = (plen - 12)/12;
+ offset = 12;
+
+ for (i = 0; i < numrec; i++) {
+ subti = proto_tree_add_text (esc_tree, tvb, offset, 12,
+ "Protocol Descriptor %d", i);
+ pdesc_tree = proto_item_add_subtree (subti,
+ ett_fcswils_esc_pdesc);
+ proto_tree_add_item (pdesc_tree, hf_swils_esc_pdesc_vendorid, tvb,
+ offset, 8, 0);
+ proto_tree_add_item (pdesc_tree, hf_swils_esc_protocolid,
+ tvb, offset+10, 2, 0);
+ offset += 12;
+ }
+ }
+ else {
+ proto_tree_add_item (esc_tree, hf_swils_esc_swvendorid, tvb,
+ offset+4, 8, 0);
+ subti = proto_tree_add_text (esc_tree, tvb, offset+12, 12,
+ "Accepted Protocol Descriptor");
+ pdesc_tree = proto_item_add_subtree (subti, ett_fcswils_esc_pdesc);
+
+ proto_tree_add_item (pdesc_tree, hf_swils_esc_pdesc_vendorid, tvb,
+ offset+12, 8, 0);
+ proto_tree_add_item (pdesc_tree, hf_swils_esc_protocolid,
+ tvb, offset+22, 2, 0);
+ }
+ }
+}
+
+static void
+dissect_swils_drlir (tvbuff_t *tvb _U_, proto_tree *drlir_tree _U_,
+ guint8 isreq _U_)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ return;
+}
+
+static void
+dissect_swils_swrjt (tvbuff_t *tvb, proto_tree *swrjt_tree)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ int offset = 0;
+
+ if (swrjt_tree) {
+ proto_tree_add_item (swrjt_tree, hf_swils_rjt, tvb, offset+5, 1, 0);
+ proto_tree_add_item (swrjt_tree, hf_swils_rjtdet, tvb, offset+6, 1, 0);
+ proto_tree_add_item (swrjt_tree, hf_swils_rjtvendor, tvb, offset+7,
+ 1, 0);
+ }
+}
+
+/* Code to actually dissect the packets */
+static void
+dissect_fcswils (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_item *ti = NULL;
+ guint8 opcode,
+ failed_opcode = 0;
+ int offset = 0;
+ conversation_t *conversation;
+ fcswils_conv_data_t *cdata;
+ fcswils_conv_key_t ckey, *req_key;
+ proto_tree *swils_tree = NULL;
+ guint8 isreq = FC_SWILS_REQ;
+
+ /* Make entries in Protocol column and Info column on summary display */
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "SW_ILS");
+
+ /* decoding of this is done by each individual opcode handler */
+ opcode = tvb_get_guint8 (tvb, 0);
+
+ if (tree) {
+ ti = proto_tree_add_protocol_format (tree, proto_fcswils, tvb, 0,
+ tvb_length (tvb), "SW_ILS");
+ swils_tree = proto_item_add_subtree (ti, ett_fcswils);
+ }
+
+ /* Register conversation if this is not a response */
+ if ((opcode != FC_SWILS_SWACC) && (opcode != FC_SWILS_SWRJT)) {
+ conversation = find_conversation (&pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->oxid,
+ pinfo->rxid, NO_PORT2);
+ if (!conversation) {
+ conversation = conversation_new (&pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->oxid,
+ pinfo->rxid, NO_PORT2);
+ }
+
+ ckey.conv_idx = conversation->index;
+
+ cdata = (fcswils_conv_data_t *)g_hash_table_lookup (fcswils_req_hash,
+ &ckey);
+ if (cdata) {
+ /* Since we never free the memory used by an exchange, this maybe a
+ * case of another request using the same exchange as a previous
+ * req.
+ */
+ cdata->opcode = opcode;
+ }
+ else {
+ req_key = g_mem_chunk_alloc (fcswils_req_keys);
+ req_key->conv_idx = conversation->index;
+
+ cdata = g_mem_chunk_alloc (fcswils_req_vals);
+ cdata->opcode = opcode;
+
+ g_hash_table_insert (fcswils_req_hash, req_key, cdata);
+ }
+ }
+ else {
+ /* Opcode is ACC or RJT */
+ conversation = find_conversation (&pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->oxid,
+ pinfo->rxid, NO_PORT2);
+ isreq = FC_SWILS_RPLY;
+ if (!conversation) {
+ if (tree && (opcode == FC_SWILS_SWACC)) {
+ /* No record of what this accept is for. Can't decode */
+ proto_tree_add_text (swils_tree, tvb, 0, tvb_length (tvb),
+ "No record of Exchg. Unable to decode SW_ACC");
+ return;
+ }
+ }
+ else {
+ ckey.conv_idx = conversation->index;
+
+ cdata = (fcswils_conv_data_t *)g_hash_table_lookup (fcswils_req_hash, &ckey);
+
+ if (cdata != NULL) {
+ if (opcode == FC_SWILS_SWACC)
+ opcode = cdata->opcode;
+ else
+ failed_opcode = cdata->opcode;
+ }
+
+ if (tree) {
+ if ((cdata == NULL) && (opcode != FC_SWILS_SWRJT)) {
+ /* No record of what this accept is for. Can't decode */
+ proto_tree_add_text (swils_tree, tvb, 0, tvb_length (tvb),
+ "No record of SW_ILS Req. Unable to decode SW_ACC");
+ return;
+ }
+ }
+ }
+ }
+
+ if (check_col (pinfo->cinfo, COL_INFO)) {
+ if (isreq == FC_SWILS_REQ) {
+ col_add_str (pinfo->cinfo, COL_INFO,
+ val_to_str (opcode, fc_swils_opcode_key_val, "0x%x"));
+ }
+ else if (opcode == FC_SWILS_SWRJT) {
+ col_add_fstr (pinfo->cinfo, COL_INFO, "SW_RJT (%s)",
+ val_to_str (failed_opcode, fc_swils_opcode_key_val, "0x%x"));
+ }
+ else {
+ col_add_fstr (pinfo->cinfo, COL_INFO, "SW_ACC (%s)",
+ val_to_str (opcode, fc_swils_opcode_key_val, "0x%x"));
+ }
+ }
+
+ if (tree) {
+ proto_tree_add_item (swils_tree, hf_swils_opcode, tvb, offset, 1, 0);
+ }
+
+ switch (opcode) {
+ case FC_SWILS_SWRJT:
+ dissect_swils_swrjt (tvb, swils_tree);
+ break;
+ case FC_SWILS_ELP:
+ dissect_swils_elp (tvb, swils_tree, isreq);
+ break;
+ case FC_SWILS_EFP:
+ dissect_swils_efp (tvb, swils_tree, isreq);
+ break;
+ case FC_SWILS_DIA:
+ dissect_swils_dia (tvb, swils_tree, isreq);
+ break;
+ case FC_SWILS_RDI:
+ dissect_swils_rdi (tvb, swils_tree, isreq);
+ break;
+ case FC_SWILS_HLO:
+ dissect_swils_hello (tvb, swils_tree, isreq);
+ break;
+ case FC_SWILS_LSU:
+ dissect_swils_lsupdate (tvb, swils_tree, isreq);
+ break;
+ case FC_SWILS_LSA:
+ dissect_swils_lsack (tvb, swils_tree, isreq);
+ break;
+ case FC_SWILS_BF:
+ case FC_SWILS_RCF:
+ /* Nothing to be displayed for these two commands */
+ break;
+ case FC_SWILS_RSCN:
+ dissect_swils_rscn (tvb, swils_tree, isreq);
+ break;
+ case FC_SWILS_DRLIR:
+ dissect_swils_drlir (tvb, swils_tree, isreq);
+ break;
+ case FC_SWILS_MR:
+ dissect_swils_mergereq (tvb, swils_tree, isreq);
+ break;
+ case FC_SWILS_ACA:
+ dissect_swils_aca (tvb, swils_tree, isreq);
+ break;
+ case FC_SWILS_RCA:
+ dissect_swils_rca (tvb, swils_tree, isreq);
+ break;
+ case FC_SWILS_SFC:
+ dissect_swils_sfc (tvb, swils_tree, isreq);
+ break;
+ case FC_SWILS_UFC:
+ dissect_swils_ufc (tvb, swils_tree, isreq);
+ break;
+ case FC_SWILS_ESC:
+ dissect_swils_esc (tvb, swils_tree, isreq);
+ break;
+ default:
+ call_dissector (data_handle, tvb, pinfo, tree);
+ }
+
+}
+
+/* Register the protocol with Ethereal */
+
+/* this format is require because a script is used to build the C function
+ that calls all the protocol registration.
+*/
+
+void
+proto_register_fcswils (void)
+{
+/* Setup list of header fields See Section 1.6.1 for details*/
+ static hf_register_info hf[] = {
+ { &hf_swils_opcode,
+ {"Cmd Code", "swils.opcode", FT_UINT8, BASE_HEX,
+ VALS (fc_swils_opcode_key_val), 0x0, "", HFILL}},
+ { &hf_swils_elp_rev,
+ {"Revision", "swils.elp.rev", FT_UINT8, BASE_DEC, NULL,
+ 0x0, "", HFILL}},
+ { &hf_swils_elp_flags,
+ {"Flag", "swils.elp.flag", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL}},
+ { &hf_swils_elp_r_a_tov,
+ {"R_A_TOV", "swils.elp.ratov", FT_UINT32, BASE_DEC, NULL,
+ 0x0, "", HFILL}},
+ { &hf_swils_elp_e_d_tov,
+ {"E_D_TOV", "swils.elp.edtov", FT_UINT32, BASE_DEC, NULL, 0x0, "",
+ HFILL}},
+ { &hf_swils_elp_req_epn,
+ {"Req Eport Name", "swils.elp.reqepn", FT_STRING, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_swils_elp_req_esn,
+ {"Req Switch Name", "swils.elp.reqesn", FT_STRING, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_swils_elp_clsf_svcp,
+ {"Class F Svc Param", "swils.elp.clsfp", FT_BYTES, BASE_NONE, NULL, 0x0,
+ "", HFILL}},
+ { &hf_swils_elp_clsf_rcvsz,
+ {"Max Class F Frame Size", "swils.elp.clsfrsz", FT_UINT16, BASE_DEC,
+ NULL, 0x0, "", HFILL}},
+ { &hf_swils_elp_clsf_conseq,
+ {"Class F Max Concurrent Seq", "swils.elp.clsfcs", FT_UINT16, BASE_DEC,
+ NULL, 0x0, "", HFILL}},
+ { &hf_swils_elp_clsf_e2e,
+ {"Class F E2E Credit", "swils.elp.cfe2e", FT_UINT16, BASE_DEC, NULL,
+ 0x0, "", HFILL}},
+ { &hf_swils_elp_clsf_openseq,
+ {"Class F Max Open Seq", "swils.elp.oseq", FT_UINT16, BASE_DEC, NULL,
+ 0x0, "", HFILL}},
+ { &hf_swils_elp_cls1_svcp,
+ {"Class 1 Svc Param", "swils.elp.cls1p", FT_BYTES, BASE_NONE, NULL, 0x0,
+ "", HFILL}},
+ { &hf_swils_elp_cls1_rcvsz,
+ {"Class 1 Frame Size", "swils.elp.cls1rsz", FT_UINT16, BASE_DEC, NULL,
+ 0x0, "", HFILL}},
+ { &hf_swils_elp_cls2_svcp,
+ {"Class 2 Svc Param", "swils.elp.cls2p", FT_BYTES, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_swils_elp_cls2_rcvsz,
+ {"Class 2 Frame Size", "swils.elp.cls1rsz", FT_UINT16, BASE_DEC, NULL,
+ 0x0, "", HFILL}},
+ { &hf_swils_elp_cls3_svcp,
+ {"Class 3 Svc Param", "swils.elp.cls3p", FT_BYTES, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_swils_elp_cls3_rcvsz,
+ {"Class 3 Frame Size", "swils.elp.cls1rsz", FT_UINT16, BASE_DEC, NULL,
+ 0x0, "", HFILL}},
+ { &hf_swils_elp_isl_fc_mode,
+ {"ISL Flow Ctrl Mode", "swils.elp.fcmode", FT_STRING, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_swils_elp_fcplen,
+ {"Flow Ctrl Param Len", "swils.elp.fcplen", FT_UINT16, BASE_DEC, NULL,
+ 0x0, "", HFILL}},
+ { &hf_swils_elp_b2bcredit,
+ {"B2B Credit", "swils.elp.b2b", FT_UINT32, BASE_DEC, NULL, 0x0, "",
+ HFILL}},
+ { &hf_swils_elp_compat1,
+ {"Compatability Param 1", "swils.elp.compat1", FT_UINT32, BASE_DEC, NULL,
+ 0x0, "", HFILL}},
+ { &hf_swils_elp_compat2,
+ {"Compatability Param 2", "swils.elp.compat2", FT_UINT32, BASE_DEC, NULL,
+ 0x0, "", HFILL}},
+ { &hf_swils_elp_compat3,
+ {"Compatability Param 3", "swils.elp.compat3", FT_UINT32, BASE_DEC, NULL,
+ 0x0, "", HFILL}},
+ { &hf_swils_elp_compat4,
+ {"Compatability Param 4", "swils.elp.compat4", FT_UINT32, BASE_DEC, NULL,
+ 0x0, "", HFILL}},
+ { &hf_swils_efp_rec_type,
+ {"Record Type", "swils.efp.rectype", FT_UINT8, BASE_HEX,
+ VALS (fcswils_rectype_val), 0x0, "", HFILL}},
+ { &hf_swils_efp_dom_id,
+ {"Domain ID", "swils.efp.domid", FT_UINT8, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_swils_efp_switch_name,
+ {"Switch Name", "swils.efp.sname", FT_STRING, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_swils_efp_mcast_grpno,
+ {"Mcast Grp#", "swils.efp.mcastno", FT_UINT8, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_swils_efp_alias_token,
+ {"Alias Token", "swils.efp.aliastok", FT_BYTES, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_swils_efp_payload_len,
+ {"Payload Len", "swils.efp.payloadlen", FT_UINT16, BASE_DEC, NULL, 0x0,
+ "", HFILL}},
+ { &hf_swils_efp_pswitch_pri,
+ {"Principal Switch Priority", "swils.efp.psprio", FT_UINT8, BASE_DEC,
+ NULL, 0x0, "", HFILL}},
+ { &hf_swils_efp_pswitch_name,
+ {"Principal Switch Name", "swils.efp.psname", FT_STRING, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_swils_dia_switch_name,
+ {"Switch Name", "swils.dia.sname", FT_STRING, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_swils_rdi_payload_len,
+ {"Payload Len", "swils.rdi.len", FT_UINT16, BASE_DEC, NULL, 0x0, "",
+ HFILL}},
+ { &hf_swils_rdi_req_sname,
+ {"Req Switch Name", "swils.rdi.reqsn", FT_STRING, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_swils_fspfh_cmd,
+ {"Command: ", "swils.fspf.cmd", FT_UINT8, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_swils_fspfh_rev,
+ {"Version", "swils.fspf.ver", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL}},
+ { &hf_swils_fspfh_ar_num,
+ {"AR Number", "swils.fspf.arnum", FT_UINT8, BASE_HEX, NULL, 0x0, "",
+ HFILL}},
+ { &hf_swils_fspfh_auth_type,
+ {"Authentication Type", "swils.fspf.authtype", FT_UINT8, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_swils_fspfh_dom_id,
+ {"Originating Domain ID", "swils.fspf.origdomid", FT_UINT8, BASE_DEC,
+ NULL, 0x0, "", HFILL}},
+ { &hf_swils_fspfh_auth,
+ {"Authentication", "swils.fspf.auth", FT_BYTES, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_swils_hlo_options,
+ {"Options", "swils.hlo.options", FT_BYTES, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_swils_hlo_hloint,
+ {"Hello Interval (secs)", "swils.hlo.hloint", FT_UINT32, BASE_DEC,
+ NULL, 0x0, "", HFILL}},
+ { &hf_swils_hlo_deadint,
+ {"Dead Interval (secs)", "swils.hlo.deadint", FT_UINT32, BASE_DEC,
+ NULL, 0x0, "", HFILL}},
+ { &hf_swils_hlo_rcv_domid,
+ {"Recipient Domain ID", "swils.hlo.rcvdomid", FT_UINT8, BASE_DEC,
+ NULL, 0x0, "", HFILL}},
+ { &hf_swils_hlo_orig_pidx,
+ {"Originating Port Idx", "swils.hlo.origpidx", FT_UINT24, BASE_HEX,
+ NULL, 0x0, "", HFILL}},
+ { &hf_swils_lsrh_lsr_type,
+ {"LSR Type", "swils.lsr.type", FT_UINT8, BASE_HEX,
+ VALS (fc_swils_fspf_linkrec_val), 0x0, "", HFILL}},
+ { &hf_swils_lsrh_lsid,
+ {"Link State Id", "swils.ls.id", FT_UINT8, BASE_DEC, NULL, 0x0,
+ "", HFILL}},
+ { &hf_swils_lsrh_adv_domid,
+ {"Advertising Domain Id", "swils.lsr.advdomid", FT_UINT8, BASE_DEC,
+ NULL, 0x0, "", HFILL}},
+ { &hf_swils_lsrh_ls_incid,
+ {"LS Incarnation Number", "swils.lsr.incid", FT_UINT32, BASE_DEC,
+ NULL, 0x0, "", HFILL}},
+ { &hf_swils_ldrec_linkid,
+ {"Link ID", "swils.ldr.linkid", FT_STRING, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_swils_ldrec_out_pidx,
+ {"Output Port Idx", "swils.ldr.out_portidx", FT_UINT24, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_swils_ldrec_nbr_pidx,
+ {"Neighbor Port Idx", "swils.ldr.nbr_portidx", FT_UINT24, BASE_HEX,
+ NULL, 0x0, "", HFILL}},
+ { &hf_swils_ldrec_link_type,
+ {"Link Type", "swils.ldr.linktype", FT_UINT8, BASE_HEX,
+ VALS (fc_swils_link_type_val), 0x0, "", HFILL}},
+ { &hf_swils_ldrec_link_cost,
+ {"Link Cost", "swils.ldr.linkcost", FT_UINT16, BASE_DEC, NULL, 0x0,
+ "", HFILL}},
+ { &hf_swils_rscn_evtype,
+ {"Event Type", "swils.rscn.evtype", FT_UINT8, BASE_DEC,
+ VALS (fc_swils_rscn_portstate_val), 0xF0, "", HFILL}},
+ { &hf_swils_rscn_addrfmt,
+ {"Address Format", "swils.rscn.addrfmt", FT_UINT8, BASE_DEC,
+ VALS (fc_swils_rscn_addrfmt_val), 0x0F, "", HFILL}},
+ { &hf_swils_rscn_affectedport,
+ {"Affected Port ID", "swils.rscn.affectedport", FT_STRING, BASE_HEX,
+ NULL, 0x0, "", HFILL}},
+ { &hf_swils_rscn_detectfn,
+ {"Detection Function", "swils.rscn.detectfn", FT_UINT32, BASE_HEX,
+ VALS (fc_swils_rscn_detectfn_val), 0x0, "", HFILL}},
+ { &hf_swils_rscn_portstate,
+ {"Port State", "swils.rscn.portstate", FT_UINT8, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_swils_rscn_portid,
+ {"Port Id", "swils.rscn.portid", FT_STRING, BASE_HEX, NULL, 0x0, "",
+ HFILL}},
+ { &hf_swils_rscn_pwwn,
+ {"Port WWN", "swils.rscn.pwwn", FT_STRING, BASE_HEX, NULL, 0x0, "",
+ HFILL}},
+ { &hf_swils_rscn_nwwn,
+ {"Node WWN", "swils.rscn.nwwn", FT_STRING, BASE_HEX, NULL, 0x0, "",
+ HFILL}},
+ { &hf_swils_esc_swvendorid,
+ {"Switch Vendor ID", "swils.esc.swvendor", FT_STRING, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_swils_esc_pdesc_vendorid,
+ {"Vendor ID", "swils.esc.vendorid", FT_STRING, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_swils_esc_protocolid,
+ {"Protocol ID", "swils.esc.protocol", FT_UINT16, BASE_HEX,
+ VALS (fc_swils_esc_protocol_val), 0x0, "", HFILL}},
+ { &hf_swils_zone_activezonenm,
+ {"Active Zoneset Name", "swils.mr.activezonesetname", FT_STRING,
+ BASE_HEX, NULL, 0x0, "", HFILL}},
+ { &hf_swils_zone_objname,
+ {"Zone Object Name", "swils.zone.zoneobjname", FT_STRING, BASE_HEX,
+ NULL, 0x0, "", HFILL}},
+ { &hf_swils_zone_objtype,
+ {"Zone Object Type", "swils.zone.zoneobjtype", FT_UINT8, BASE_HEX,
+ VALS (fc_swils_zoneobj_type_val), 0x0, "", HFILL}},
+ { &hf_swils_zone_mbrtype,
+ {"Zone Member Type", "swils.zone.mbrtype", FT_UINT8, BASE_HEX,
+ VALS (fc_swils_zonembr_type_val), 0x0, "", HFILL}},
+ { &hf_swils_zone_protocol,
+ {"Zone Protocol", "swils.zone.protocol", FT_UINT8, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_swils_zone_mbrid,
+ {"Member Identifier", "swils.zone.mbrid", FT_STRING, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_swils_zone_status,
+ {"Zone Command Status", "swils.zone.status", FT_UINT8, BASE_HEX,
+ VALS (fc_swils_mr_rsp_val), 0x0, "Applies to MR, ACA, RCA, SFC, UFC",
+ HFILL}},
+ { &hf_swils_zone_reason,
+ {"Zone Command Reason Code", "swils.zone.reason", FT_UINT8, BASE_HEX,
+ VALS (fc_swils_mr_reason_val), 0x0, "Applies to MR, ACA, RCA, SFC, UFC",
+ HFILL}},
+ { &hf_swils_aca_domainid,
+ {"Known Domain ID", "swils.aca.domainid", FT_UINT8, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_swils_sfc_opcode,
+ {"Operation Request", "swils.sfc.opcode", FT_UINT8, BASE_HEX,
+ VALS (fc_swils_sfc_op_val), 0x0, "", HFILL}},
+ { &hf_swils_sfc_zonenm,
+ {"Zone Set Name", "swils.sfc.zonename", FT_STRING, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_swils_rjt,
+ {"Reason Code", "swils.rjt.reason", FT_UINT8, BASE_HEX,
+ VALS (fc_swils_rjt_val), 0x0, "", HFILL}},
+ { &hf_swils_rjtdet,
+ {"Reason Code Explanantion", "swils.rjt.reasonexpl", FT_UINT8,
+ BASE_HEX, VALS (fc_swils_deterr_val), 0x0, "", HFILL}},
+ { &hf_swils_rjtvendor,
+ {"Vendor Unique Error Code", "swils.rjt.vendor", FT_UINT8, BASE_HEX,
+ NULL, 0x0, "", HFILL}},
+ { &hf_swils_zone_mbrid_lun,
+ {"LUN", "swils.zone.lun", FT_BYTES, BASE_HEX, NULL, 0x0, "",
+ HFILL}},
+ };
+
+ /* Setup protocol subtree array */
+ static gint *ett[] = {
+ &ett_fcswils,
+ &ett_fcswils_swacc,
+ &ett_fcswils_swrjt,
+ &ett_fcswils_elp,
+ &ett_fcswils_efp,
+ &ett_fcswils_efplist,
+ &ett_fcswils_dia,
+ &ett_fcswils_rdi,
+ &ett_fcswils_fspfhdr,
+ &ett_fcswils_hlo,
+ &ett_fcswils_lsrec,
+ &ett_fcswils_lsrechdr,
+ &ett_fcswils_ldrec,
+ &ett_fcswils_lsu,
+ &ett_fcswils_lsa,
+ &ett_fcswils_bf,
+ &ett_fcswils_rcf,
+ &ett_fcswils_rscn,
+ &ett_fcswils_rscn_dev,
+ &ett_fcswils_drlir,
+ &ett_fcswils_mr,
+ &ett_fcswils_zoneobjlist,
+ &ett_fcswils_zoneobj,
+ &ett_fcswils_zonembr,
+ &ett_fcswils_aca,
+ &ett_fcswils_rca,
+ &ett_fcswils_sfc,
+ &ett_fcswils_ufc,
+ &ett_fcswils_esc,
+ &ett_fcswils_esc_pdesc,
+ };
+
+ /* Register the protocol name and description */
+ proto_fcswils = proto_register_protocol("Fibre Channel SW_ILS", "FC-SWILS", "swils");
+
+ /* Required function calls to register the header fields and subtrees used */
+ proto_register_field_array(proto_fcswils, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+ register_init_routine(&fcswils_init_protocol);
+}
+
+/* If this dissector uses sub-dissector registration add a registration routine.
+ This format is required because a script is used to find these routines and
+ create the code that calls these routines.
+*/
+void
+proto_reg_handoff_fcswils (void)
+{
+ dissector_handle_t swils_handle;
+
+ swils_handle = create_dissector_handle (dissect_fcswils, proto_fcswils);
+ dissector_add("fc.ftype", FC_FTYPE_SWILS, swils_handle);
+
+ data_handle = find_dissector ("data");
+}
+
+
diff --git a/packet-fcswils.h b/packet-fcswils.h
new file mode 100644
index 0000000000..365304d8b4
--- /dev/null
+++ b/packet-fcswils.h
@@ -0,0 +1,389 @@
+/* packet-fcswils.h
+ * Fibre Channel Switch InterLink Services Definitions
+ * Copyright 2001 Dinesh G Dutt (ddutt@cisco.com)
+ *
+ * $Id: packet-fcswils.h,v 1.1 2002/12/08 02:32:17 gerald Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PACKET_FCSWILS_H_
+#define __PACKET_FCSWILS_H_
+
+/* Command codes */
+#define FC_SWILS_SWRJT 0x01
+#define FC_SWILS_SWACC 0x02
+#define FC_SWILS_ELP 0x10
+#define FC_SWILS_EFP 0x11
+#define FC_SWILS_DIA 0x12
+#define FC_SWILS_RDI 0x13
+#define FC_SWILS_HLO 0x14
+#define FC_SWILS_LSU 0x15
+#define FC_SWILS_LSA 0x16
+#define FC_SWILS_BF 0x17
+#define FC_SWILS_RCF 0x18
+#define FC_SWILS_RSCN 0x1B
+#define FC_SWILS_DRLIR 0x1E
+#define FC_SWILS_DSCN 0x20
+#define FC_SWILS_LOOPD 0x21
+#define FC_SWILS_MR 0x22
+#define FC_SWILS_ACA 0x23
+#define FC_SWILS_RCA 0x24
+#define FC_SWILS_SFC 0x25
+#define FC_SWILS_UFC 0x26
+#define FC_SWILS_ESC 0x30
+
+/* Used in filters */
+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"},
+ {0, NULL},
+};
+
+/* Used in Info field */
+static const value_string fc_swils_opcode_val[] = {
+ {FC_SWILS_SWRJT , "SW_RJT"},
+ {FC_SWILS_SWACC , "SW_ACC"},
+ {FC_SWILS_ELP , "ELP"},
+ {FC_SWILS_EFP , "EFP"},
+ {FC_SWILS_DIA , "Domain ID Assigned"},
+ {FC_SWILS_RDI , "Request Domain ID"},
+ {FC_SWILS_HLO , "Hello"},
+ {FC_SWILS_LSU , "Link State Update"},
+ {FC_SWILS_LSA , "Link State Ack"},
+ {FC_SWILS_BF , "Build Fabric"},
+ {FC_SWILS_RCF , "Reconfigure Fabric"},
+ {FC_SWILS_RSCN , "Interswitch RSCN"},
+ {FC_SWILS_DRLIR , "DRLIR"},
+ {FC_SWILS_DSCN , "SW_RSCN"},
+ {FC_SWILS_LOOPD , "LOOPD"},
+ {FC_SWILS_MR , "Merge Req"},
+ {FC_SWILS_ACA , "Acquire Change Auth"},
+ {FC_SWILS_RCA , "Release Change Auth"},
+ {FC_SWILS_SFC , "Stage Fabric Conf"},
+ {FC_SWILS_UFC , "Update Fabric Conf"},
+ {FC_SWILS_ESC , "ESC"},
+ {0, NULL},
+};
+
+/* Reject reason codes */
+
+#define FC_SWILS_RJT_INVCODE 0x01
+#define FC_SWILS_RJT_INVVER 0x02
+#define FC_SWILS_RJT_LOGERR 0x03
+#define FC_SWILS_RJT_INVSIZE 0x04
+#define FC_SWILS_RJT_LOGBSY 0x05
+#define FC_SWILS_RJT_PROTERR 0x07
+#define FC_SWILS_RJT_GENFAIL 0x09
+#define FC_SWILS_RJT_CMDNOTSUPP 0x0B
+#define FC_SWILS_RJT_VENDUNIQ 0xFF
+
+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},
+};
+
+/* Detailed reason code defines */
+#define FC_SWILS_RJT_NODET 0x0
+#define FC_SWILS_RJT_CLSF_ERR 0x1
+#define FC_SWILS_RJT_CLSN_ERR 0x3
+#define FC_SWILS_RJT_INVFC_CODE 0x4
+#define FC_SWILS_RJT_INVFC_PARM 0x5
+#define FC_SWILS_RJT_INV_PNAME 0xD
+#define FC_SWILS_RJT_INV_SNAME 0xE
+#define FC_SWILS_RJT_TOV_MSMTCH 0xF
+#define FC_SWILS_RJT_INV_DIDLST 0x10
+#define FC_SWILS_RJT_CMD_INPROG 0x19
+#define FC_SWILS_RJT_OORSRC 0x29
+#define FC_SWILS_RJT_NO_DID 0x2A
+#define FC_SWILS_RJT_INV_DID 0x2B
+#define FC_SWILS_RJT_NO_REQ 0x2C
+#define FC_SWILS_RJT_NOLNK_PARM 0x2D
+#define FC_SWILS_RJT_NO_REQDID 0x2E
+#define FC_SWILS_RJT_EP_ISOL 0x2F
+
+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}
+};
+
+typedef struct _fcswils_elp {
+ guint8 revision;
+ guint8 flags[2];
+ guint8 rsvd1;
+ guint32 r_a_tov;
+ guint32 e_d_tov;
+ guint8 req_epname[8];
+ guint8 req_sname[8];
+ guint8 clsf_svcparm[6];
+ guint16 clsf_rcvsize;
+ guint16 clsf_conseq;
+ guint16 clsf_e2e;
+ guint16 clsf_openseq;
+ guint16 rsvd;
+ guint8 cls1_svcparm[2];
+ guint16 cls1_rcvsize;
+ guint8 cls2_svcparm[2];
+ guint16 cls2_rcvsize;
+ guint8 cls3_svcparm[2];
+ guint16 cls3_rcvsize;
+ guint8 rsvd2[20];
+ guint16 isl_flwctrl_mode;
+ guint16 flw_ctrl_parmlen;
+ guint32 b2b_credit;
+ guint32 compat_p1;
+ guint32 compat_p2;
+ guint32 compat_p3;
+ guint32 compat_p4;
+} fcswils_elp;
+#define FC_SWILS_ELP_SIZE 100
+
+#define FC_SWILS_ELP_FC_VENDOR 0x1
+#define FC_SWILS_ELP_FC_RRDY 0x2
+
+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},
+};
+
+struct _fcswils_efp_didrec {
+ guint8 rec_type;
+ guint8 dom_id;
+ guint16 rsvd1;
+ guint32 rsvd2;
+ guint8 sname[8];
+};
+struct _fcswils_efp_mcastrec {
+ guint8 rec_type;
+ guint8 mcast_grpnum;
+ guint8 rsvd[14];
+};
+
+typedef union _fcswils_efp_listrec {
+ struct _fcswils_efp_didrec didrec;
+ struct _fcswils_efp_mcastrec mcastrec;
+} fcswils_efp_listrec;
+
+#define FC_SWILS_LRECTYPE_DOMAIN 0x1
+#define FC_SWILS_LRECTYPE_MCAST 0x2
+
+static const value_string fcswils_rectype_val[] = {
+ {FC_SWILS_LRECTYPE_DOMAIN, "Domain ID List Rec"},
+ {FC_SWILS_LRECTYPE_MCAST, "Multicast ID List Rec"},
+ {0, NULL},
+};
+
+typedef struct _fcswils_efp {
+ guint8 opcode;
+ guint8 reclen;
+ guint16 payload_len;
+ guint8 rsvd1[3];
+ guint8 pswitch_prio;
+ guint8 pswitch_name[8];
+ fcswils_efp_listrec *listrec;
+} fcswils_efp;
+#define FC_SWILS_EFP_SIZE 16 /* not including listrec */
+
+typedef struct _fcswils_dia {
+ guint8 switch_name[8];
+ guint8 rsvd[4];
+} fcswils_dia;
+
+typedef struct _fcswils_rdi_req {
+ guint8 rsvd[3];
+ guint8 domain_id;
+} fcswils_rdi_req;
+#define FC_SWILS_RDIREQ_SIZE 4
+
+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},
+};
+
+#define FC_SWILS_LSR_SLR 0x1 /* switch link record */
+#define FC_SWILS_LSR_ARS 0x2 /* AR Summary record */
+
+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},
+};
+
+#define FC_SWILS_PDESC_FSPF_BB 0x01
+#define FC_SWILS_PDESC_FSPF 0x02
+
+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"},
+};
+
+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},
+};
+
+#define FC_SWILS_ZONEOBJ_ZONESET 1
+#define FC_SWILS_ZONEOBJ_ZONE 2
+#define FC_SWILS_ZONEOBJ_ZONEALIAS 3
+
+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},
+};
+
+#define FC_SWILS_ZONEMBR_WWN 1
+#define FC_SWILS_ZONEMBR_DP 2
+#define FC_SWILS_ZONEMBR_FCID 3
+#define FC_SWILS_ZONEMBR_ALIAS 4
+#define FC_SWILS_ZONEMBR_WWN_LUN 0xE1
+#define FC_SWILS_ZONEMBR_DP_LUN 0xE2
+#define FC_SWILS_ZONEMBR_FCID_LUN 0xE3
+
+static 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},
+};
+
+#endif
diff --git a/packet-ipfc.c b/packet-ipfc.c
new file mode 100644
index 0000000000..2c2b91135f
--- /dev/null
+++ b/packet-ipfc.c
@@ -0,0 +1,155 @@
+/* packet-ipfc.c
+ * Routines for Decoding FC header for IP/FC
+ * Copyright 2001, Dinesh G Dutt <ddutt@cisco.com>
+ *
+ * $Id: packet-ipfc.c,v 1.1 2002/12/08 02:32:17 gerald Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * Copied from WHATEVER_FILE_YOU_USED (where "WHATEVER_FILE_YOU_USED"
+ * is a dissector file; if you just copied this from README.developer,
+ * don't bother with the "Copied from" - you don't even need to put
+ * in a "Copied from" if you copied an existing dissector, especially
+ * if the bulk of the code in the new dissector is your code)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#include <glib.h>
+
+#ifdef NEED_SNPRINTF_H
+# include "snprintf.h"
+#endif
+
+#include <epan/packet.h>
+#include "etypes.h"
+#include "packet-fc.h"
+
+/* Initialize the protocol and registered fields */
+static int proto_ipfc = -1;
+static int hf_ipfc_network_da = -1;
+static int hf_ipfc_network_sa = -1;
+static int hf_ipfc_llc = -1;
+
+/* Initialize the subtree pointers */
+static gint ett_ipfc = -1;
+static dissector_table_t ipfc_dissector_table;
+static dissector_handle_t data_handle;
+
+static void
+dissect_ipfc (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+
+/* Set up structures needed to add the protocol subtree and manage it */
+ proto_item *ti;
+ proto_tree *ipfc_tree;
+ int offset = 0;
+ tvbuff_t *next_tvb;
+
+ /* Make entries in Protocol column and Info column on summary display */
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "IP/FC");
+
+ if (tree) {
+ ti = proto_tree_add_text (tree, tvb, offset, 16,
+ "Network Header");
+ ipfc_tree = proto_item_add_subtree (ti, ett_ipfc);
+
+ proto_tree_add_string (ipfc_tree, hf_ipfc_network_da, tvb, offset, 8,
+ fcwwn_to_str (tvb_get_ptr (tvb, offset, 8)));
+ proto_tree_add_string (ipfc_tree, hf_ipfc_network_sa, tvb, offset+8, 8,
+ fcwwn_to_str (tvb_get_ptr (tvb, offset+8, 8)));
+ /* This is a dummy add to just switch to llc */
+ proto_tree_add_uint_hidden (ipfc_tree, hf_ipfc_llc, tvb, offset, 16, 0);
+ }
+
+ next_tvb = tvb_new_subset (tvb, 16, -1, -1);
+ if (!dissector_try_port (ipfc_dissector_table, 0, next_tvb, pinfo, tree)) {
+ call_dissector (data_handle, next_tvb, pinfo, tree);
+ }
+}
+
+/* Register the protocol with Ethereal */
+
+/* this format is require because a script is used to build the C function
+ that calls all the protocol registration.
+*/
+
+void
+proto_register_ipfc (void)
+{
+
+/* Setup list of header fields See Section 1.6.1 for details*/
+ static hf_register_info hf[] = {
+ { &hf_ipfc_network_da,
+ {"Network DA", "ipfc.nethdr.da", FT_STRING, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_ipfc_network_sa,
+ {"Network SA", "ipfc.nethdr.sa", FT_STRING, BASE_HEX, NULL,
+ 0x0, "", HFILL}},
+ { &hf_ipfc_llc,
+ {"LLC/SNAP", "ipfc.llc", FT_UINT8, BASE_HEX, NULL, 0x0, "",
+ HFILL}},
+ };
+
+ /* Setup protocol subtree array */
+ static gint *ett[] = {
+ &ett_ipfc,
+ };
+
+ /* Register the protocol name and description */
+ proto_ipfc = proto_register_protocol("IP Over FC", "IPFC", "ipfc");
+
+ /* Required function calls to register the header fields and subtrees used */
+ proto_register_field_array(proto_ipfc, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+
+ ipfc_dissector_table = register_dissector_table ("ipfc.llc", "IPFC",
+ FT_UINT8, BASE_HEX);
+}
+
+/* If this dissector uses sub-dissector registration add a registration routine.
+ This format is required because a script is used to find these routines and
+ create the code that calls these routines.
+*/
+void
+proto_reg_handoff_ipfc (void)
+{
+ dissector_handle_t ipfc_handle;
+
+ ipfc_handle = create_dissector_handle (dissect_ipfc, proto_ipfc);
+ dissector_add("fc.ftype", FC_FTYPE_IP, ipfc_handle);
+
+ data_handle = find_dissector ("data");
+}
+
diff --git a/packet-llc.c b/packet-llc.c
index 0371f768a1..bb1054a6a3 100644
--- a/packet-llc.c
+++ b/packet-llc.c
@@ -2,7 +2,7 @@
* Routines for IEEE 802.2 LLC layer
* Gilbert Ramirez <gram@alumni.rice.edu>
*
- * $Id: packet-llc.c,v 1.102 2002/11/16 08:55:11 guy Exp $
+ * $Id: packet-llc.c,v 1.103 2002/12/08 02:32:17 gerald Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -560,4 +560,5 @@ proto_reg_handoff_llc(void)
dissector_add("udp.port", UDP_PORT_LLC3, llc_handle);
dissector_add("udp.port", UDP_PORT_LLC4, llc_handle);
dissector_add("udp.port", UDP_PORT_LLC5, llc_handle);
+ dissector_add("ipfc.llc", 0, llc_handle);
}