summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSage Weil <sage@inktank.com>2013-08-15 10:50:19 -0700
committerSage Weil <sage@inktank.com>2013-08-15 10:50:19 -0700
commit4a437b84156d3b911d0ab6e444b9021afcab10a6 (patch)
tree248ebe2ce266346bb848f1f9ea42a11bb0ae348b
parentab60b5dac276bed091582764128584c80b00dfbb (diff)
parent972d22e2453c133eecc34390fbfe229058754537 (diff)
downloadceph-4a437b84156d3b911d0ab6e444b9021afcab10a6.tar.gz
Merge pull request #396 from hutkev/wip-wireshark-alt
Adding alternative Wireshark dissector. Signed-off-by: Kevin Jones <k.j.jonez@gmail.com>
-rw-r--r--wireshark/ceph-alt/Makefile.am126
-rw-r--r--wireshark/ceph-alt/Makefile.common31
-rw-r--r--wireshark/ceph-alt/Makefile.nmake100
-rw-r--r--wireshark/ceph-alt/README.txt49
-rw-r--r--wireshark/ceph-alt/moduleinfo.h16
-rw-r--r--wireshark/ceph-alt/moduleinfo.nmake28
-rw-r--r--wireshark/ceph-alt/packet-ceph.c2661
-rw-r--r--wireshark/ceph-alt/plugin.c33
-rw-r--r--wireshark/ceph-alt/plugin.rc.in34
-rw-r--r--wireshark/ceph-alt/ws-1.10.0.patch95
10 files changed, 3173 insertions, 0 deletions
diff --git a/wireshark/ceph-alt/Makefile.am b/wireshark/ceph-alt/Makefile.am
new file mode 100644
index 00000000000..76b3e7a11b2
--- /dev/null
+++ b/wireshark/ceph-alt/Makefile.am
@@ -0,0 +1,126 @@
+# Makefile.am
+# Automake file for Cisco SS7 Session Management plugin
+# Copyright 2004, Duncan Sargeant <dunc-ethereal@rcpt.to>
+#
+# $Id: Makefile.am 24488 2008-02-27 16:18:30Z stig $
+#
+# Wireshark - Network traffic analyzer
+# By Gerald Combs <gerald@wireshark.org>
+# 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.
+#
+
+INCLUDES = -I$(top_srcdir) -I$(includedir)
+
+include Makefile.common
+
+
+if HAVE_WARNINGS_AS_ERRORS
+AM_CFLAGS = -Werror
+endif
+
+plugindir = @plugindir@
+
+plugin_LTLIBRARIES = ceph.la
+ceph_la_SOURCES = \
+ plugin.c \
+ moduleinfo.h \
+ $(DISSECTOR_SRC) \
+ $(DISSECTOR_INCLUDES)
+ceph_la_LDFLAGS = -module -avoid-version
+ceph_la_LIBADD = @PLUGIN_LIBS@
+
+# Libs must be cleared, or else libtool won't create a shared module.
+# If your module needs to be linked against any particular libraries,
+# add them here.
+LIBS =
+
+#
+# Build plugin.c, which contains the plugin version[] string, a
+# function plugin_register() that calls the register routines for all
+# protocols, and a function plugin_reg_handoff() that calls the handoff
+# registration routines for all protocols.
+#
+# We do this by scanning sources. If that turns out to be too slow,
+# maybe we could just require every .o file to have an register routine
+# of a given name (packet-aarp.o -> proto_register_aarp, etc.).
+#
+# Formatting conventions: The name of the proto_register_* routines an
+# proto_reg_handoff_* routines must start in column zero, or must be
+# preceded only by "void " starting in column zero, and must not be
+# inside #if.
+#
+# DISSECTOR_SRC is assumed to have all the files that need to be scanned.
+#
+# For some unknown reason, having a big "for" loop in the Makefile
+# to scan all the files doesn't work with some "make"s; they seem to
+# pass only the first few names in the list to the shell, for some
+# reason.
+#
+# Therefore, we have a script to generate the plugin.c file.
+# The shell script runs slowly, as multiple greps and seds are run
+# for each input file; this is especially slow on Windows. Therefore,
+# if Python is present (as indicated by PYTHON being defined), we run
+# a faster Python script to do that work instead.
+#
+# The first argument is the directory in which the source files live.
+# The second argument is "plugin", to indicate that we should build
+# a plugin.c file for a plugin.
+# All subsequent arguments are the files to scan.
+#
+plugin.c: $(DISSECTOR_SRC) $(top_srcdir)/tools/make-dissector-reg \
+ $(top_srcdir)/tools/make-dissector-reg.py
+ @if test -n "$(PYTHON)"; then \
+ echo Making plugin.c with python ; \
+ $(PYTHON) $(top_srcdir)/tools/make-dissector-reg.py $(srcdir) \
+ plugin $(DISSECTOR_SRC) ; \
+ else \
+ echo Making plugin.c with shell script ; \
+ $(top_srcdir)/tools/make-dissector-reg $(srcdir) \
+ $(plugin_src) plugin $(DISSECTOR_SRC) ; \
+ fi
+
+#
+# Currently plugin.c can be included in the distribution because
+# we always build all protocol dissectors. We used to have to check
+# whether or not to build the snmp dissector. If we again need to
+# variably build something, making plugin.c non-portable, uncomment
+# the dist-hook line below.
+#
+# Oh, yuk. We don't want to include "plugin.c" in the distribution, as
+# its contents depend on the configuration, and therefore we want it
+# to be built when the first "make" is done; however, Automake insists
+# on putting *all* source into the distribution.
+#
+# We work around this by having a "dist-hook" rule that deletes
+# "plugin.c", so that "dist" won't pick it up.
+#
+#dist-hook:
+# @rm -f $(distdir)/plugin.c
+
+CLEANFILES = \
+ ceph \
+ *~
+
+MAINTAINERCLEANFILES = \
+ Makefile.in \
+ plugin.c
+
+EXTRA_DIST = \
+ Makefile.common \
+ Makefile.nmake \
+ moduleinfo.nmake \
+ plugin.rc.in
diff --git a/wireshark/ceph-alt/Makefile.common b/wireshark/ceph-alt/Makefile.common
new file mode 100644
index 00000000000..271b61f2e22
--- /dev/null
+++ b/wireshark/ceph-alt/Makefile.common
@@ -0,0 +1,31 @@
+# Makefile.common for Cisco SS7 Session Management plugin
+# Contains the stuff from Makefile.am and Makefile.nmake that is
+# a) common to both files and
+# b) portable between both files
+#
+# $Id: Makefile.common 18197 2006-05-21 05:12:17Z sahlberg $
+#
+# Wireshark - Network traffic analyzer
+# By Gerald Combs <gerald@wireshark.org>
+# 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.
+
+# the name of the plugin
+PLUGIN_NAME = ceph
+
+# the dissector sources (without any helpers)
+DISSECTOR_SRC = \
+ packet-ceph.c
diff --git a/wireshark/ceph-alt/Makefile.nmake b/wireshark/ceph-alt/Makefile.nmake
new file mode 100644
index 00000000000..857e4354bc3
--- /dev/null
+++ b/wireshark/ceph-alt/Makefile.nmake
@@ -0,0 +1,100 @@
+# Makefile.nmake
+# nmake file for Wireshark plugin
+#
+# $Id: Makefile.nmake 24520 2008-03-01 12:31:01Z jake $
+#
+
+include ..\..\config.nmake
+include moduleinfo.nmake
+
+include Makefile.common
+
+CFLAGS=/WX /DHAVE_CONFIG_H /I../.. /I../../wiretap $(GLIB_CFLAGS) \
+ /I$(PCAP_DIR)\include -D_U_="" $(LOCAL_CFLAGS)
+
+.c.obj::
+ $(CC) $(CFLAGS) -Fd.\ -c $<
+
+LDFLAGS = $(PLUGIN_LDFLAGS)
+
+!IFDEF ENABLE_LIBWIRESHARK
+LINK_PLUGIN_WITH=..\..\epan\libwireshark.lib
+CFLAGS=/DHAVE_WIN32_LIBWIRESHARK_LIB /D_NEED_VAR_IMPORT_ $(CFLAGS)
+
+DISSECTOR_OBJECTS = $(DISSECTOR_SRC:.c=.obj)
+
+DISSECTOR_SUPPORT_OBJECTS = $(DISSECTOR_SUPPORT_SRC:.c=.obj)
+
+OBJECTS = $(DISSECTOR_OBJECTS) $(DISSECTOR_SUPPORT_OBJECTS) plugin.obj
+
+RESOURCE=$(PLUGIN_NAME).res
+
+all: $(PLUGIN_NAME).dll
+
+$(PLUGIN_NAME).rc : moduleinfo.nmake
+ sed -e s/@PLUGIN_NAME@/$(PLUGIN_NAME)/ \
+ -e s/@RC_MODULE_VERSION@/$(RC_MODULE_VERSION)/ \
+ -e s/@RC_VERSION@/$(RC_VERSION)/ \
+ -e s/@MODULE_VERSION@/$(MODULE_VERSION)/ \
+ -e s/@PACKAGE@/$(PACKAGE)/ \
+ -e s/@VERSION@/$(VERSION)/ \
+ -e s/@MSVC_VARIANT@/$(MSVC_VARIANT)/ \
+ < plugin.rc.in > $@
+
+$(PLUGIN_NAME).dll $(PLUGIN_NAME).exp $(PLUGIN_NAME).lib : $(OBJECTS) $(LINK_PLUGIN_WITH) $(RESOURCE)
+ link -dll /out:$(PLUGIN_NAME).dll $(LDFLAGS) $(OBJECTS) $(LINK_PLUGIN_WITH) \
+ $(GLIB_LIBS) $(RESOURCE)
+
+#
+# Build plugin.c, which contains the plugin version[] string, a
+# function plugin_register() that calls the register routines for all
+# protocols, and a function plugin_reg_handoff() that calls the handoff
+# registration routines for all protocols.
+#
+# We do this by scanning sources. If that turns out to be too slow,
+# maybe we could just require every .o file to have an register routine
+# of a given name (packet-aarp.o -> proto_register_aarp, etc.).
+#
+# Formatting conventions: The name of the proto_register_* routines an
+# proto_reg_handoff_* routines must start in column zero, or must be
+# preceded only by "void " starting in column zero, and must not be
+# inside #if.
+#
+# DISSECTOR_SRC is assumed to have all the files that need to be scanned.
+#
+# For some unknown reason, having a big "for" loop in the Makefile
+# to scan all the files doesn't work with some "make"s; they seem to
+# pass only the first few names in the list to the shell, for some
+# reason.
+#
+# Therefore, we have a script to generate the plugin.c file.
+# The shell script runs slowly, as multiple greps and seds are run
+# for each input file; this is especially slow on Windows. Therefore,
+# if Python is present (as indicated by PYTHON being defined), we run
+# a faster Python script to do that work instead.
+#
+# The first argument is the directory in which the source files live.
+# The second argument is "plugin", to indicate that we should build
+# a plugin.c file for a plugin.
+# All subsequent arguments are the files to scan.
+#
+!IFDEF PYTHON
+plugin.c: $(DISSECTOR_SRC) moduleinfo.h ../../tools/make-dissector-reg.py
+ @echo Making plugin.c (using python)
+ @$(PYTHON) "../../tools/make-dissector-reg.py" . plugin $(DISSECTOR_SRC)
+!ELSE
+plugin.c: $(DISSECTOR_SRC) moduleinfo.h ../../tools/make-dissector-reg
+ @echo Making plugin.c (using sh)
+ @$(SH) ../../tools/make-dissector-reg . plugin $(DISSECTOR_SRC)
+!ENDIF
+
+!ENDIF
+
+clean:
+ rm -f $(OBJECTS) $(RESOURCE) plugin.c *.pdb \
+ $(PLUGIN_NAME).dll $(PLUGIN_NAME).dll.manifest $(PLUGIN_NAME).lib \
+ $(PLUGIN_NAME).exp $(PLUGIN_NAME).rc
+
+distclean: clean
+
+maintainer-clean: distclean
diff --git a/wireshark/ceph-alt/README.txt b/wireshark/ceph-alt/README.txt
new file mode 100644
index 00000000000..7e7337618fc
--- /dev/null
+++ b/wireshark/ceph-alt/README.txt
@@ -0,0 +1,49 @@
+
+This is an alternative Ceph plugin for Wireshark. It's not yet as functional as
+the standard plugin. However it is written to conform to the Wireshark coding
+guidelines so that at some point in the future it may be possible to make
+this a built-in dissector in Wireshark.
+
+At present the plugin can dissect handshaking and a handful of the many message
+types that Ceph servers use. It is port agnostic and attempts to identify who
+the sender and receivers are by looking at the messages being passed. I have
+tried to make the dissecting code less dependant on the underlying transport
+just in case it needs to be ported.
+
+There is no support for IPv6 addresses yet or CRC checking which I have
+removed temporarily to simplifying things. If you look at the code you might
+wonder why it does not use the Ceph headers to describe message structure, this
+is to avoid the many differences you can find with struct packing that might
+break dissection on other platforms supported by Wireshark.
+
+The plugin has been tested against Wireshark 1.10.0 on Ubuntu precise and
+Windows 7 64-bit builds.
+
+Linux Build
+
+1. Copy the contents of this directory into the plugins/ceph directory in the
+ Wireshark source, you will need to create this.
+2. From the Wireshark source directory run:
+ patch -p1 < plugins/ceph/ws-1.10.0.patch
+3. Compile Wireshark as normal
+ ./autogen.sh
+ ./configure
+ make
+ sudo make install
+
+Windows 7 Build
+
+Building Wireshark under Windows is rather involved so ideally avoid this!
+
+If you can't, either patch the source on a Linux machine and copy to your
+target machine then follow the standard build instructions or install cygwin
+and apply the patch before following normal build instructions.
+
+Kevin Jones
+k.j.jonez@gmail.com
+Last Updated: 1st July 2013
+
+
+
+
+
diff --git a/wireshark/ceph-alt/moduleinfo.h b/wireshark/ceph-alt/moduleinfo.h
new file mode 100644
index 00000000000..1218fcf6fec
--- /dev/null
+++ b/wireshark/ceph-alt/moduleinfo.h
@@ -0,0 +1,16 @@
+/* Included *after* config.h, in order to re-define these macros */
+
+#ifdef PACKAGE
+#undef PACKAGE
+#endif
+
+/* Name of package */
+#define PACKAGE "ceph"
+
+
+#ifdef VERSION
+#undef VERSION
+#endif
+
+/* Version number of package */
+#define VERSION "0.0.1"
diff --git a/wireshark/ceph-alt/moduleinfo.nmake b/wireshark/ceph-alt/moduleinfo.nmake
new file mode 100644
index 00000000000..ff67c25b40b
--- /dev/null
+++ b/wireshark/ceph-alt/moduleinfo.nmake
@@ -0,0 +1,28 @@
+#
+# $Id: moduleinfo.nmake 20158 2006-12-19 22:23:37Z jake $
+#
+
+# The name
+PACKAGE=ceph
+
+# The version
+MODULE_VERSION_MAJOR=0
+MODULE_VERSION_MINOR=0
+MODULE_VERSION_MICRO=1
+MODULE_VERSION_EXTRA=0
+
+#
+# The RC_VERSION should be comma-separated, not dot-separated,
+# as per Graham Bloice's message in
+#
+# http://www.ethereal.com/lists/ethereal-dev/200303/msg00283.html
+#
+# "The RC_VERSION variable in config.nmake should be comma separated.
+# This allows the resources to be built correctly and the version
+# number to be correctly displayed in the explorer properties dialog
+# for the executables, and XP's tooltip, rather than 0.0.0.0."
+#
+
+MODULE_VERSION=$(MODULE_VERSION_MAJOR).$(MODULE_VERSION_MINOR).$(MODULE_VERSION_MICRO).$(MODULE_VERSION_EXTRA)
+RC_MODULE_VERSION=$(MODULE_VERSION_MAJOR),$(MODULE_VERSION_MINOR),$(MODULE_VERSION_MICRO),$(MODULE_VERSION_EXTRA)
+
diff --git a/wireshark/ceph-alt/packet-ceph.c b/wireshark/ceph-alt/packet-ceph.c
new file mode 100644
index 00000000000..41a01fdff96
--- /dev/null
+++ b/wireshark/ceph-alt/packet-ceph.c
@@ -0,0 +1,2661 @@
+/* packet-ceph.c
+ * Routines for Ceph Protocols
+ * http://www.ceph.com
+ *
+ * Copyright 2013, Kevin Jones <k.j.jonez@gmail.com>
+ *
+ * This file contains parts of the original dissector code found in
+ * the CEPH source tree. The author of that code was not marked.
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "../../epan/packet.h"
+#include "../../epan/tvbuff.h"
+#include "../../epan/tvbuff-int.h"
+#include "../../epan/prefs.h"
+#include "../../epan/range.h"
+#include "../../epan/report_err.h"
+#include "../../epan/conversation.h"
+#include "../../epan/expert.h"
+#include "../../epan/dissectors/packet-tcp.h"
+
+/* Protocol name */
+#define PROTO_TAG_CEPH "CEPHalt"
+
+/****************************************************************************
+ * Global handles
+ ****************************************************************************/
+
+/* Wireshark ID of the CEPH protocol */
+static int g_proto_ceph = -1;
+
+/* The registered dissector handle */
+static dissector_handle_t g_ceph_handle;
+
+/*
+ * The following hf_* variables are used to hold the Wireshark IDs of
+ * our header fields; they are filled out when we call
+ * proto_register_field_array() in proto_register_ceph()
+ */
+static gint hf_header = -1;
+static gint hf_banner = -1;
+static gint hf_entity_addr = -1;
+static gint hf_entity_type = -1;
+static gint hf_entity_num = -1;
+static gint hf_banner_magic = -1;
+static gint hf_banner_version = -1;
+static gint hf_entity_erank = -1;
+static gint hf_entity_nonce = -1;
+static gint hf_sockaddr_in = -1;
+static gint hf_sin_family = -1;
+static gint hf_sin_port = -1;
+static gint hf_sin_addr = -1;
+static gint hf_hdr_tag = -1;
+static gint hf_hdr_seq_ack = -1;
+static gint hf_hdr_seq = -1;
+static gint hf_hdr_tid = -1;
+static gint hf_hdr_type = -1;
+static gint hf_hdr_priority = -1;
+static gint hf_hdr_version = -1;
+static gint hf_hdr_mon_protocol = -1;
+static gint hf_hdr_osd_protocol = -1;
+static gint hf_hdr_mds_protocol = -1;
+static gint hf_hdr_client_protocol = -1;
+static gint hf_hdr_front_len = -1;
+static gint hf_hdr_middle_len = -1;
+static gint hf_hdr_data_off = -1;
+static gint hf_hdr_data_len = -1;
+static gint hf_hdr_src = -1;
+static gint hf_hdr_crc = -1;
+static gint hf_footer = -1;
+static gint hf_footer_front_crc = -1;
+static gint hf_footer_middle_crc = -1;
+static gint hf_footer_data_crc = -1;
+static gint hf_footer_sig = -1;
+static gint hf_footer_flags = -1;
+static gint hf_paxos_version = -1;
+static gint hf_featureset_mask = -1;
+static gint hf_featureset_id = -1;
+static gint hf_featureset_name = -1;
+static gint hf_compatset_compat = -1;
+static gint hf_compatset_rocompat = -1;
+static gint hf_compatset_incompat = -1;
+
+static gint hf_connect_features = -1;
+static gint hf_connect_host_type = -1;
+static gint hf_connect_tag = -1;
+static gint hf_connect_global_seq = -1;
+static gint hf_connect_connect_seq = -1;
+static gint hf_connect_protocol_version = -1;
+static gint hf_connect_authorizer_protocol = -1;
+static gint hf_connect_authorizer_len = -1;
+static gint hf_connect_flags = -1;
+static gint hf_connect_authentication_key = -1;
+static gint hf_monmap = -1;
+static gint hf_monmap_version = -1;
+static gint hf_monmap_compat = -1;
+static gint hf_monmap_epoch = -1;
+static gint hf_monmap_name = -1;
+static gint hf_monmap_lastchanged = -1;
+static gint hf_monmap_created = -1;
+static gint hf_monsubscribe = -1;
+static gint hf_monsubscribe_name = -1;
+static gint hf_monsubscribe_start = -1;
+static gint hf_monsubscribe_flags = -1;
+static gint hf_monsubscribeack = -1;
+static gint hf_monsubscribeack_interval = -1;
+static gint hf_mdsbeacon = -1;
+static gint hf_mdsbeacon_globalid = -1;
+static gint hf_mdsbeacon_state = -1;
+static gint hf_mdsbeacon_seq = -1;
+static gint hf_mdsbeacon_name = -1;
+static gint hf_mdsbeacon_standbyforrank = -1;
+static gint hf_mdsbeacon_standbyforname = -1;
+static gint hf_auth = -1;
+static gint hf_auth_protocol = -1;
+static gint hf_auth_authlen = -1;
+static gint hf_auth_authbytes = -1;
+static gint hf_auth_monmapepoch = -1;
+static gint hf_authreply = -1;
+static gint hf_authreply_protocol = -1;
+static gint hf_authreply_result = -1;
+static gint hf_authreply_globalid = -1;
+static gint hf_authreply_authlen = -1;
+static gint hf_authreply_authbytes = -1;
+static gint hf_authreply_msglen = -1;
+static gint hf_authreply_msgstring = -1;
+
+/* These are the ids of the subtrees that we may be creating */
+static gint ett_ceph = -1;
+static gint ett_header = -1;
+static gint ett_banner = -1;
+static gint ett_entity_addr = -1;
+static gint ett_front = -1;
+static gint ett_footer = -1;
+static gint ett_sockaddr_in = -1;
+static gint ett_entity_name = -1;
+static gint ett_compat = -1;
+static gint ett_rocompat = -1;
+static gint ett_incompat = -1;
+
+/****************************************************************************
+ * Conversation helper - to find exact matches only
+ ****************************************************************************/
+static conversation_t*
+conv_find_exact(guint32 frame, const address* addr1, guint32 port1,
+ const address* addr2, guint32 port2) {
+ conversation_t* conv;
+ conv = find_conversation(frame, addr1, addr2,PT_TCP, port1, port2, 0);
+ if (conv != NULL) {
+ if (ADDRESSES_EQUAL(&conv->key_ptr->addr1, addr1) &&
+ ADDRESSES_EQUAL(&conv->key_ptr->addr2, addr2) &&
+ conv->key_ptr->port1 == port1 &&
+ conv->key_ptr->port2 == port2)
+ {
+ return conv;
+ }
+ if (ADDRESSES_EQUAL(&conv->key_ptr->addr1, addr2) &&
+ ADDRESSES_EQUAL(&conv->key_ptr->addr2, addr1) &&
+ conv->key_ptr->port1 == port2 &&
+ conv->key_ptr->port2 == port1)
+ {
+ return conv;
+ }
+ }
+ return NULL;
+}
+
+/****************************************************************************
+ * Entities (aka ceph service endpoints)
+ * These should match the CEPH_ENTITY_ macros to make conversion easy from
+ * on the wire formats.
+ ****************************************************************************/
+typedef enum _entity_type {
+ ENTITY_TYPE_UNKNOWN = 0x00,
+ ENTITY_TYPE_MON = 0x01,
+ ENTITY_TYPE_MDS = 0x02,
+ ENTITY_TYPE_OSD = 0x04,
+ ENTITY_TYPE_CLIENT = 0x08,
+ ENTITY_TYPE_AUTH = 0x20
+} entity_type;
+
+/*
+ * This is what we record (within conv state) about each known endpoint.
+ * Beware that conv_data maintains a pointer to these records so that should
+ * not be reallocated, see get_entity() for obtaining them. They are shared
+ * this way so conversations may pass info to each other about endpoints.
+ */
+typedef struct _entity_data {
+ entity_type type;
+ char* name;
+ address addr;
+ guint16 port;
+} entity_data;
+
+/*
+ * Map a entity type to a display string
+ */
+static const char*
+entityTypeDescription(entity_type type) {
+ switch (type) {
+ case ENTITY_TYPE_UNKNOWN:
+ return "?";
+ case ENTITY_TYPE_MON:
+ return "mon";
+ case ENTITY_TYPE_MDS:
+ return "mds";
+ case ENTITY_TYPE_OSD:
+ return "osd";
+ case ENTITY_TYPE_CLIENT:
+ return "client";
+ case ENTITY_TYPE_AUTH:
+ return "auth";
+ }
+ assert(FALSE);
+ return NULL;
+}
+
+/*
+ * Test for a valid entity type
+ */
+static gboolean
+isEntityType(guint32 type) {
+ switch (type) {
+ case ENTITY_TYPE_MON:
+ case ENTITY_TYPE_MDS:
+ case ENTITY_TYPE_OSD:
+ case ENTITY_TYPE_CLIENT:
+ case ENTITY_TYPE_AUTH:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Find or create a new entity data entry from an address/port pair.
+ */
+static entity_data*
+conv_get_entity(const address* addr, guint32 port) {
+ conversation_t *conv=NULL;
+ entity_data *edata;
+
+ /*
+ * Have we seen this conversation before? We record this as a conversation
+ * to the same address/port. This is just to help keep the data together.
+ */
+ conv = conv_find_exact(-1, addr, port, addr, port);
+ if (conv == NULL) {
+ edata = (entity_data*)se_alloc(sizeof(entity_data));
+ edata->type = ENTITY_TYPE_UNKNOWN;
+ edata->name = NULL;
+ SE_COPY_ADDRESS(&edata->addr,addr);
+ edata->port = port;
+ conv = conversation_new(0, addr, addr, PT_TCP, port, port, 0);
+ conversation_add_proto_data(conv, g_proto_ceph, edata);
+ } else {
+ edata=(entity_data*)conversation_get_proto_data(conv, g_proto_ceph);
+ }
+ return edata;
+}
+
+/****************************************************************************
+ * Data for tracking messages
+ * This is mainly to track the startup handling which was confusing in the
+ * old dissector because the connect_reply would appear before its matching
+ * request. Here we track in finer granularity and allow for some
+ * interweaving of messages. Of course the code also needs to handle traces
+ * which have conversations already running.
+ ****************************************************************************/
+enum msg_type {
+ SERVER_BANNER =0x1, /* Server send banner to client */
+ CLIENT_BANNER =0x2, /* Client responds to SERVER_BANNER */
+ SERVER_ADDRESS =0x4, /* Server sends its & client addresses to client */
+ CLIENT_ADDRESS =0x8, /* Client sends it own address to server */
+ CONNECT_REQUEST=0x10, /* Client send connection request to server */
+ CONNECT_REPLY =0x20, /* Server responds to connect request */
+ CONVERSING =0x40 /* All other messages */
+};
+#define MSG_ANY 0xFF /* Accept any type of message */
+
+/*
+ * Per message data, we record these during conversation startup
+ */
+typedef struct _pdu_data {
+ guint32 position; /* The stream position msg seen at */
+ guint32 toserver; /* To/from the server */
+ enum msg_type type; /* The type of this message */
+ guint32 seen; /* Cumulative flags of previous messages */
+} pdu_data;
+
+/*
+ * Per conversation data, there should be one of these for every detected
+ * conversation between ceph entities. The to/from direction is arbitrary,
+ * we probably don't know who the entities are when we establish the
+ * conversation.
+ */
+typedef struct _conv_data {
+ emem_tree_t *pdu_table; /* Message tree, stores accumulated pdu_data */
+ entity_data* to; /* Who is this to */
+ entity_data* from; /* Who is this from */
+ guint direction_set; /* Do we know to/from set correctly */
+ char* displayT2F; /* Cached 'to' to 'from' display string */
+ char* displayF2T; /* Cached 'from' to 'to' display string */
+} conv_data;
+
+/*
+ * Find/create a conversation for the given source & destination
+ */
+static conv_data*
+conv_get(packet_info *pinfo) {
+ conversation_t* conv;
+ conv_data* cdata;
+
+ /* Have we seen this conversation before? */
+ conv = conv_find_exact(pinfo->fd->num, &pinfo->src, pinfo->srcport,
+ &pinfo->dst, pinfo->destport);
+ if (conv == NULL) {
+ conv = conversation_new(pinfo->fd->num, &pinfo->src,
+ &pinfo->dst, pinfo->ptype,
+ pinfo->srcport, pinfo->destport, 0);
+ conv = conv_find_exact(pinfo->fd->num, &pinfo->src, pinfo->srcport,
+ &pinfo->dst, pinfo->destport);
+ }
+
+ cdata=(conv_data*)conversation_get_proto_data(conv, g_proto_ceph);
+ if (cdata==NULL) {
+ cdata = (conv_data*)se_alloc(sizeof(conv_data));
+ cdata->pdu_table = se_tree_create(EMEM_TREE_TYPE_RED_BLACK, "ceph_pdu");
+ cdata->to = conv_get_entity(&pinfo->dst, pinfo->destport);
+ cdata->from = conv_get_entity(&pinfo->src, pinfo->srcport);
+ cdata->direction_set = FALSE;
+ cdata->displayT2F=NULL;
+ cdata->displayF2T=NULL;
+ conversation_add_proto_data(conv, g_proto_ceph, cdata);
+ }
+ return cdata;
+}
+
+/*
+ * Reverse to/from in a stream to correct a wrong guess
+ */
+static void
+conv_fixup(guint clientSrc, packet_info *pinfo) {
+ conversation_t* conv;
+ conv_data* cdata;
+ entity_data* edata;
+ guint fromClient;
+ pdu_data* pdata;
+ guint position;
+
+ conv = conv_find_exact(pinfo->fd->num, &pinfo->src, pinfo->srcport,
+ &pinfo->dst, pinfo->destport);
+ if (conv != NULL) {
+ /* Do we need to reverse because from & to mixup */
+ cdata=(conv_data*)conversation_get_proto_data(conv, g_proto_ceph);
+ if (cdata->direction_set==FALSE) {
+ cdata->direction_set=TRUE;
+ fromClient = ADDRESSES_EQUAL(&pinfo->src, &cdata->from->addr) &&
+ pinfo->srcport == cdata->from->port;
+ if (clientSrc != fromClient) {
+ edata = cdata->from;
+ cdata->from = cdata->to;
+ cdata->to = edata;
+ cdata->displayF2T = NULL;
+ cdata->displayT2F = NULL;
+ }
+
+ /* & Reverse pdata as well correcting SERVER_BANNER if needed */
+ position = 0xFFFFFFFF;
+ while ((pdata = (pdu_data*)se_tree_lookup32_le(
+ cdata->pdu_table, position))!=NULL) {
+ if (clientSrc != fromClient)
+ pdata->toserver = !pdata->toserver;
+ if (pdata->toserver && pdata->type == SERVER_BANNER) {
+ pdata->type = CLIENT_BANNER;
+ pdata->seen &= (~SERVER_BANNER);
+ pdata->seen |= CLIENT_BANNER;
+ }
+ position = pdata->position -1;
+ }
+ }
+ }
+}
+
+/*
+ * Calculate the stream index for a given offset
+ */
+static guint32
+conv_position(packet_info *pinfo, tvbuff_t *tvb, guint32 offset) {
+ return pinfo->fd->cum_bytes - tvb_reported_length_remaining (tvb, offset);
+}
+
+static guint32
+conv_expecting(packet_info *pinfo, tvbuff_t *tvb, guint32 offset) {
+ conv_data* cdata;
+ pdu_data* pdata;
+ guint32 allowed;
+ guint32 position;
+
+ cdata = conv_get(pinfo);
+
+ /*
+ * Return what should be happening next
+ */
+ position = conv_position(pinfo, tvb, offset);
+ pdata = (pdu_data*)se_tree_lookup32_le(cdata->pdu_table, position);
+
+ /*
+ * If new may see any message type
+ */
+ if (pdata == 0)
+ return MSG_ANY;
+
+ /*
+ * If exact match, return what we actually saw in previous dissect
+ */
+ if (pdata->position == position)
+ return pdata->type;
+
+ /*
+ * Otherwise, work out what could be next, the difficulty here is that
+ * the client banner may appear before or after the server sends its
+ * addresses and also that we me mistake a client banner for a server
+ * banner
+ */
+ allowed = 0;
+ switch (pdata->type) {
+ case SERVER_BANNER:
+ return (CLIENT_BANNER | SERVER_ADDRESS | CLIENT_ADDRESS);
+ case CLIENT_BANNER:
+ if ((pdata->seen & SERVER_ADDRESS) == 0)
+ allowed = SERVER_ADDRESS;
+ allowed |= CLIENT_ADDRESS;
+ break;
+ case SERVER_ADDRESS:
+ if ((pdata->seen & CLIENT_BANNER) == 0)
+ allowed = CLIENT_BANNER;
+ allowed |= CLIENT_ADDRESS;
+ break;
+ case CLIENT_ADDRESS:
+ allowed = CONNECT_REQUEST;
+ break;
+ case CONNECT_REQUEST:
+ allowed = CONNECT_REPLY;
+ break;
+ case CONNECT_REPLY:
+ default:
+ allowed = CONVERSING;
+ }
+ return allowed;
+}
+
+/*
+ * Tag a position in a conversation as a specific type
+ */
+static void
+conv_tag(packet_info *pinfo, tvbuff_t *tvb,
+ guint32 offset, enum msg_type type) {
+ conv_data* cdata;
+ pdu_data* pdata;
+ pdu_data* previous_pdata;
+ guint32 position;
+
+ /*
+ * Get/Create a pdu_data to describe the message
+ */
+ cdata = conv_get(pinfo);
+ position = conv_position(pinfo, tvb, offset);
+ pdata = (pdu_data*)se_tree_lookup32(cdata->pdu_table, position);
+
+ if (pdata == 0) {
+ pdata = (pdu_data*)se_alloc(sizeof(pdu_data));
+ pdata->position = position;
+ pdata->toserver = (ADDRESSES_EQUAL(&cdata->to->addr, &pinfo->dst) &&
+ cdata->to->port == pinfo->destport);
+ pdata->type = type;
+ pdata->seen = type;
+
+ /*
+ * If new we have to carry forward previously seen to allow for
+ * checking on interleaving of messages, a pain I know..
+ */
+ previous_pdata = (pdu_data*)se_tree_lookup32_le(cdata->pdu_table,
+ position-1);
+ if (previous_pdata != 0) {
+ pdata->seen |= previous_pdata->seen;
+ }
+
+ /*
+ * Insert new record
+ */
+ se_tree_insert32(cdata->pdu_table, position, pdata);
+
+ } else {
+ /*
+ * Just update the existing record
+ */
+ pdata->type = type;
+ pdata->seen |= type;
+ }
+}
+
+static void
+conv_setfrom(packet_info *pinfo, entity_type type) {
+ conv_data* cdata;
+
+ cdata = conv_get(pinfo);
+ cdata->from->type = type;
+ cdata->displayT2F = NULL;
+ cdata->displayF2T = NULL;
+}
+
+static char*
+conv_format(const entity_data* from, const entity_data* to) {
+ const char* from_name;
+ const char* to_name;
+
+ from_name = entityTypeDescription(from->type);
+ if (from->name) {
+ from_name = se_strdup_printf("%s.%s",
+ entityTypeDescription(from->type), from->name);
+ }
+
+ to_name = entityTypeDescription(to->type);
+ if (to->name) {
+ to_name = se_strdup_printf("%s.%s",
+ entityTypeDescription(to->type), to->name);
+ }
+
+ return se_strdup_printf("%s -> %s", from_name, to_name);
+}
+
+/*
+ * Get conversation display string
+ */
+static char*
+conv_display(packet_info *pinfo) {
+ conv_data* cdata;
+ guint to;
+
+ cdata = conv_get(pinfo);
+ to = ADDRESSES_EQUAL(&cdata->to->addr, &pinfo->dst) &&
+ cdata->to->port == pinfo->destport;
+
+ if (to) {
+ if (cdata->displayF2T == NULL) {
+ cdata->displayF2T = conv_format(cdata->from, cdata->to);
+ }
+ return cdata->displayF2T;
+ } else {
+ if (cdata->displayT2F == NULL) {
+ cdata->displayT2F = conv_format(cdata->to, cdata->from);
+ }
+ return cdata->displayT2F;
+ }
+}
+
+/*
+ * Sockaddr details extracted from protocol
+ * Note: Don't map from tvb, only assign to avoid portability concerns
+ */
+typedef struct _sockaddr_info {
+ guint16 port;
+ guint32 addr;
+} sockaddr_info;
+
+/*
+ * Entity info as extracted from protocol
+ * Note: Don't map from tvb, only assign to avoid portability concerns
+ */
+typedef struct _entity_info {
+ guint32 erank;
+ guint32 nonce;
+ sockaddr_info addr;
+} entity_info;
+
+/*
+ * Recover conversation entity data from entity_info
+ */
+static entity_data*
+conv_get_entity_frominfo(entity_info* info) {
+ address addr;
+
+ SET_ADDRESS(&addr, AT_IPv4, sizeof(info->addr.addr), &info->addr.addr);
+ return conv_get_entity(&addr, info->addr.port);
+}
+
+/*
+ * Set type & name for an entity
+ * nameOffset is offset into tvb of where to find FT_UINT_STRING
+ */
+static void
+conv_set_entity_name(entity_data* edata, tvbuff_t *tvb,
+ guint32 nameOffset, entity_type type) {
+ guint32 len;
+
+ if (type != ENTITY_TYPE_UNKNOWN)
+ edata->type = type;
+
+ /* Same name? */
+ len = tvb_get_letohl(tvb, nameOffset);
+ if (edata->name) {
+ if (strlen(edata->name) == len &&
+ tvb_memeql(tvb, nameOffset+4, edata->name, len)) {
+ return;
+ }
+ }
+ edata->name = (char*)se_alloc(len+1);
+ tvb_memcpy(tvb, edata->name, nameOffset+4,len);
+ edata->name[len]=0;
+}
+
+/****************************************************************************
+ * INFO Column helpers
+ ****************************************************************************/
+
+/*
+ * Flag for controlling formatting of INFO column handling, this needs
+ * a manual reset before decoding possible multiple PDUs
+ */
+static guint g_firstPdu;
+
+/*
+ * Helper to prepare for a PDU display by setting info column.
+ */
+static void
+setPDUInfo(packet_info *pinfo, const char* info) {
+
+ /*
+ * Reset info column, with a fence to stop being changed by other PDUs that
+ * might be contained in the same packet.
+ */
+ if(check_col(pinfo->cinfo,COL_INFO)){
+ if (g_firstPdu == TRUE)
+ col_add_fstr(pinfo->cinfo, COL_INFO, " %s", info);
+ else
+ col_add_fstr(pinfo->cinfo, COL_INFO, ", %s", info);
+ col_set_fence(pinfo->cinfo,COL_INFO);
+ }
+}
+
+
+/****************************************************************************
+ * Start of dissector handlers
+ * NOTES:
+ * The coding style is odd, we avoid the normal use of structures to describe
+ * on the wire formats because of the difficulty of getting *all* compilers
+ * to handle the packing correctly. Wireshark coding style prefers direct
+ * decoding so that is what we do. I have included structures in comments
+ * just to make it easier to understand what the code is pulling apart.
+ *
+ * The dissector functions *may* check the data contents for sanity to allow
+ * them to be used where the content type is ambiguous. If the data provided
+ * can not be for that dissector the return will be 0. If there is not enough
+ * data then they return -1. Otherwise they return the number of bytes they
+ * consumed so they can be used to dissect multiple PDUs per packet.
+ *
+ ****************************************************************************/
+
+/*
+ * Message tag types, numbers must match protocol
+ * There are two types of tags here, most are used with connect_reply to
+ * indicate status, but CLOSE, MSG, ACK & KEEPALIVE tags are used for
+ * standalone messages. TAG_SEQ is another oddball, it indicates the server
+ * is requesting an exhachange of sequence numbers following the connect_reply.
+ */
+enum msg_tag {
+ MSGR_TAG_MIN=1,
+ MSGR_TAG_READY=1, /* S->C: ready for messages */
+ MSGR_TAG_RESETSESSION=2, /* S->C: reset, try again */
+ MSGR_TAG_WAIT=3, /* S->C: wait for racing incoming connection */
+ MSGR_TAG_RETRY_SESSION=4, /* S->C + cseq: try again with higher cseq */
+ MSGR_TAG_RETRY_GLOBAL=5, /* S->C + gseq: try again with higher gseq */
+ MSGR_TAG_CLOSE=6, /* closing pipe */
+ MSGR_TAG_MSG=7, /* message */
+ MSGR_TAG_ACK=8, /* message ack */
+ MSGR_TAG_KEEPALIVE=9, /* just a keepalive byte! */
+ MSGR_TAG_BADPROTOVER=10, /* bad protocol version */
+ MSGR_TAG_BADAUTHORIZER=11, /* bad authorizer */
+ MSGR_TAG_FEATURES=12, /* insufficient features */
+ MSGR_TAG_SEQ=13, /* 64-bit int follows with seen seq number */
+ MSGR_TAG_MAX=13
+};
+
+static guint
+isMsgrTag(guint tag) {
+ return (tag>=MSGR_TAG_MIN && tag<=MSGR_TAG_MAX);
+}
+
+static guint
+isMsgrConnectTag(guint tag) {
+ return isMsgrTag(tag) &&
+ (tag != MSGR_TAG_CLOSE) &&
+ (tag != MSGR_TAG_MSG) &&
+ (tag != MSGR_TAG_ACK) &&
+ (tag != MSGR_TAG_KEEPALIVE);
+}
+
+static const char*
+replyTagDescription(guint tag) {
+ switch (tag) {
+ case MSGR_TAG_READY: return "Ready";
+ case MSGR_TAG_RESETSESSION: return "Reset Session";
+ case MSGR_TAG_WAIT: return "Wait";
+ case MSGR_TAG_RETRY_SESSION: return "Retry Session";
+ case MSGR_TAG_RETRY_GLOBAL: return "Retry Global";
+ case MSGR_TAG_BADPROTOVER: return "Bad Protocol";
+ case MSGR_TAG_BADAUTHORIZER: return "Bad Authorizer";
+ case MSGR_TAG_FEATURES: return "Missing Features";
+ case MSGR_TAG_SEQ: return "Sequence";
+ }
+ return NULL;
+}
+
+/****************************************************************************
+ * Handshake handling (Banners & Addresses)
+ ****************************************************************************/
+
+#define CEPH_BANNER "ceph v027"
+#define CEPH_BANNER_LEN (sizeof(CEPH_BANNER)-1)
+#define CEPH_BANNER_MAGIC_LEN 4
+
+/*
+ * Dissect a banner, this can be used in either direction, client to server
+ * or server to client.
+ */
+static gint
+dissect_banner(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ guint offset, guint client)
+{
+ proto_tree *ceph_banner_tree = NULL;
+ proto_item *ceph_sub_item = NULL;
+
+ if (tvb_strneql(tvb, offset, CEPH_BANNER, CEPH_BANNER_LEN) == 0) {
+
+ /* All OK, just show the banner */
+ setPDUInfo(pinfo, client?"Client Banner":"Server Banner");
+ ceph_sub_item = proto_tree_add_item( tree, hf_banner, tvb, offset,
+ CEPH_BANNER_LEN, TRUE );
+ ceph_banner_tree = proto_item_add_subtree(ceph_sub_item, ett_banner);
+ proto_tree_add_item(ceph_banner_tree, hf_banner_magic, tvb, offset,
+ CEPH_BANNER_MAGIC_LEN, TRUE);
+ proto_tree_add_item(ceph_banner_tree, hf_banner_version, tvb, offset+
+ CEPH_BANNER_MAGIC_LEN, CEPH_BANNER_LEN-CEPH_BANNER_MAGIC_LEN, TRUE);
+
+ return CEPH_BANNER_LEN;
+ } else if (tvb_reported_length_remaining (tvb, offset) >=
+ (gint)CEPH_BANNER_LEN) {
+ /* Enough data, but not a banner */
+ return 0;
+ } else {
+ /* Not enough data */
+ return -1;
+ }
+}
+
+/*
+ * Supported family types, these are defined here for portability.
+ */
+typedef enum _families {
+ CEPH_AF_INET=2,
+ CEPH_AF_INET6=10
+} families;
+
+static guint
+isFamily(guint32 family) {
+ return ((family==CEPH_AF_INET) || (family==CEPH_AF_INET6));
+}
+
+static const char*
+familyDescription(guint family) {
+ switch (family) {
+ case CEPH_AF_INET: return "inet V4";
+ case CEPH_AF_INET6: return "inet V6";
+ }
+ return NULL;
+}
+
+/*
+ * Storage structure for addresses, can really only be AF_INET or AF_INET6
+ * but this is the structure used by the protocol.
+ *
+struct ceph_sockaddr_storage {
+ guint16 ss_family;
+ guint8 __ss_pad1[6];
+ guint64 __ss_align;
+ guint8 __ss_pad2[112];
+}
+*/
+#define SIZE_OF_SOCKADDR_STORAGE (2+6+8+112)
+
+/*
+ * Dissect a sockaddr_storage. This may be a IPv4 or IPv6 format but currently
+ * only IPv4 is handled.
+ */
+static gint
+dissect_sockaddr_in(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ guint offset, sockaddr_info* info)
+{
+ proto_tree *ceph_sockaddr_tree;
+ proto_item *ceph_sub_item = NULL;
+ guint16 family;
+
+ ceph_sub_item = proto_tree_add_item( tree, hf_sockaddr_in, tvb, offset,
+ 16, TRUE );
+ ceph_sockaddr_tree = proto_item_add_subtree(ceph_sub_item, ett_sockaddr_in);
+
+ family = tvb_get_ntohs(tvb, offset);
+ if (family == CEPH_AF_INET6) {
+ expert_add_info_format(pinfo, ceph_sub_item, PI_UNDECODED, PI_WARN,
+ "Address using IPv6 addressing, dissecting is not yet supported");
+ } else if (family == CEPH_AF_INET) {
+ proto_tree_add_uint_format_value(ceph_sockaddr_tree, hf_sin_family, tvb,
+ offset, 2, family, "%d (%s)", family, familyDescription(family));
+ proto_tree_add_item(ceph_sockaddr_tree, hf_sin_port, tvb, offset+2,
+ 2, ENC_BIG_ENDIAN);
+ proto_tree_add_item(ceph_sockaddr_tree, hf_sin_addr, tvb, offset+4,
+ 4, FALSE);
+ if (info) {
+ info->port = tvb_get_ntohs(tvb, offset+2);
+ info->addr = tvb_get_letohl(tvb, offset+4);
+ }
+ } else {
+ expert_add_info_format(pinfo, ceph_sub_item, PI_UNDECODED, PI_WARN,
+ "Unknown family (%d) being used in address", family);
+ }
+ offset += 16;
+ return offset;
+}
+
+/*
+ * entity_addr - endpoint details including IP address
+ *
+struct ceph_entity_addr {
+ guint32 type;
+ guint32 nonce; // unique id for process (e.g. pid)
+ struct ceph_sockaddr_storage in_addr;
+};
+*/
+#define SIZE_OF_ENTITY_ADDR (4+4+SIZE_OF_SOCKADDR_STORAGE)
+
+/*
+ * Dissect an entity address, just a type
+ */
+static gint
+dissect_entity_addr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ guint offset, entity_info* info)
+{
+ proto_tree *ceph_entity_tree = NULL;
+ proto_item *ceph_sub_item = NULL;
+ guint16 family;
+
+ /* Check the sockaddr_in looks sane before full decoding */
+ if (tvb_reported_length_remaining (tvb, offset) < SIZE_OF_ENTITY_ADDR)
+ return -1;
+
+ /* TODO: Could really do with better sanity checking here */
+ family = tvb_get_ntohs(tvb, offset+8);
+ if (family != CEPH_AF_INET && family!= CEPH_AF_INET6) {
+ return 0;
+ }
+
+ /* Decode it */
+ if (tree) {
+ ceph_sub_item = proto_tree_add_item( tree, hf_entity_addr, tvb, offset,
+ SIZE_OF_ENTITY_ADDR, TRUE );
+ ceph_entity_tree = proto_item_add_subtree(ceph_sub_item,
+ ett_entity_addr);
+ proto_tree_add_item(ceph_entity_tree, hf_entity_erank, tvb, offset,
+ 4, TRUE);
+ proto_tree_add_item(ceph_entity_tree, hf_entity_nonce, tvb, offset+4,
+ 4, TRUE);
+ }
+
+ dissect_sockaddr_in(tvb, pinfo, ceph_entity_tree, offset+8,
+ info? &info->addr:NULL);
+
+ if (info) {
+ info->erank = tvb_get_letohl(tvb, offset);
+ info->nonce = tvb_get_letohl(tvb, offset+4);
+ }
+
+ return SIZE_OF_ENTITY_ADDR;
+}
+
+/*
+ * server-address - passed from server to client during handshake
+ *
+struct ceph_server_address {
+ struct ceph_entity_addr server_addr;
+ struct ceph_entity_addr client_addr;
+};
+*/
+static gint
+dissect_server_address(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ guint offset) {
+ gint len1;
+ gint len2;
+
+ len1 = dissect_entity_addr(tvb, pinfo, tree, offset, NULL);
+ if (len1 > 0) {
+ offset += len1;
+ len2 = dissect_entity_addr(tvb, pinfo, tree, offset, NULL);
+ if (len2>0) {
+ setPDUInfo(pinfo, "Server Addresses");
+ conv_fixup(FALSE, pinfo);
+ return len1+len2;
+ }
+ return len2;
+ }
+ return len1;
+}
+
+/*
+ * client-address - passed from client to server during handshake
+ *
+struct ceph_client_address {
+ struct ceph_entity_addr client_addr;
+};
+*/
+static gint
+dissect_client_address(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ guint offset) {
+ gint len;
+
+ /* To avoid identifying a server address as a client address we rely on the
+ * server sending its data un-fragmented after a banner, so either we have
+ * data for two valid addresses or this must be a client address.
+ */
+ if (tvb_reported_length_remaining (tvb, offset) >= 2*SIZE_OF_ENTITY_ADDR) {
+ /* Might be a server address, peek to see */
+ if (isFamily(tvb_get_ntohs(tvb, offset+8)) &&
+ isFamily(tvb_get_ntohs(tvb, offset+SIZE_OF_ENTITY_ADDR+8)))
+ return 0;
+ }
+
+ /* Is it just a client addr */
+ len=dissect_entity_addr(tvb, pinfo, tree, offset, NULL);
+ if (len>0) {
+ setPDUInfo(pinfo,"Client Address");
+ conv_fixup(TRUE, pinfo);
+ }
+ return len;
+}
+
+
+/****************************************************************************
+ * Connection Request & Reply
+ ****************************************************************************/
+
+/*
+ * msg_connect - Client->Server connection request
+ *
+struct ceph_msg_connect {
+ guint64 features; // supported feature bits
+ guint32 host_type; // CEPH_ENTITY_TYPE_*
+ guint32 global_seq; // count connections initiated by this host
+ guint32 connect_seq; // count connections initiated in this session
+ guint32 protocol_version;
+ guint32 authorizer_protocol;
+ guint32 authorizer_len;
+ guint8 flags; // CEPH_MSG_CONNECT_*
+}
+*/
+#define SIZE_OF_MSG_CONNECT (8+4+4+4+4+4+4+1)
+
+#define FEATURE_UID G_GINT64_CONSTANT(1<<0)
+#define FEATURE_NOSRCADDR G_GINT64_CONSTANT(1<<1)
+#define FEATURE_MONCLOCKCHECK G_GINT64_CONSTANT(1<<2)
+#define FEATURE_FLOCK G_GINT64_CONSTANT(1<<3)
+#define FEATURE_SUBSCRIBE2 G_GINT64_CONSTANT(1<<4)
+#define FEATURE_MONNAMES G_GINT64_CONSTANT(1<<5)
+#define FEATURE_RECONNECT_SEQ G_GINT64_CONSTANT(1<<6)
+#define FEATURE_DIRLAYOUTHASH G_GINT64_CONSTANT(1<<7)
+#define FEATURE_OBJECTLOCATOR G_GINT64_CONSTANT(1<<8)
+#define FEATURE_PGID64 G_GINT64_CONSTANT(1<<9)
+#define FEATURE_INCSUBOSDMAP G_GINT64_CONSTANT(1<<10)
+#define FEATURE_PGPOOL3 G_GINT64_CONSTANT(1<<11)
+#define FEATURE_OSDREPLYMUX G_GINT64_CONSTANT(1<<12)
+#define FEATURE_OSDENC G_GINT64_CONSTANT(1<<13)
+#define FEATURE_OMAP G_GINT64_CONSTANT(1<<14)
+#define FEATURE_MONENC G_GINT64_CONSTANT(1<<15)
+#define FEATURE_QUERY_T G_GINT64_CONSTANT(1<<16)
+#define FEATURE_INDEP_PG_MAP G_GINT64_CONSTANT(1<<17)
+#define FEATURE_CRUSH_TUNABLES G_GINT64_CONSTANT(1<<18)
+#define FEATURE_CHUNKY_SCRUB G_GINT64_CONSTANT(1<<19)
+#define FEATURE_MON_NULLROUTE G_GINT64_CONSTANT(1<<20)
+#define FEATURE_MON_GV G_GINT64_CONSTANT(1<<21)
+#define FEATURE_BACKFILL_RESERVATION G_GINT64_CONSTANT(1<<22)
+#define FEATURE_MSG_AUTH G_GINT64_CONSTANT(1<<23)
+#define FEATURE_RECOVERY_RESERVATION G_GINT64_CONSTANT(1<<24)
+#define FEATURE_CRUSH_TUNABLES2 G_GINT64_CONSTANT(1<<25)
+#define FEATURE_CREATEPOOLID G_GINT64_CONSTANT(1<<26)
+#define FEATURE_REPLY_CREATE_INODE G_GINT64_CONSTANT(1<<27)
+#define FEATURE_OSD_HBMSGS G_GINT64_CONSTANT(1<<28)
+#define FEATURE_MDSENC G_GINT64_CONSTANT(1<<29)
+#define FEATURE_OSDHASHPSPOOL G_GINT64_CONSTANT(1<<30)
+#define FEATURE_MON_SINGLE_PAXOS G_GINT64_CONSTANT(1<<31)
+#define FEATURE_OSD_SNAPMAPPER G_GINT64_CONSTANT(0x100000000)
+
+#define FEATURES_ALL \
+ (FEATURE_UID | \
+ FEATURE_NOSRCADDR | \
+ FEATURE_MONCLOCKCHECK | \
+ FEATURE_FLOCK | \
+ FEATURE_SUBSCRIBE2 | \
+ FEATURE_MONNAMES | \
+ FEATURE_RECONNECT_SEQ | \
+ FEATURE_DIRLAYOUTHASH | \
+ FEATURE_OBJECTLOCATOR | \
+ FEATURE_PGID64 | \
+ FEATURE_INCSUBOSDMAP | \
+ FEATURE_PGPOOL3 | \
+ FEATURE_OSDREPLYMUX | \
+ FEATURE_OSDENC | \
+ FEATURE_OMAP | \
+ FEATURE_QUERY_T | \
+ FEATURE_MONENC | \
+ FEATURE_INDEP_PG_MAP | \
+ FEATURE_CRUSH_TUNABLES | \
+ FEATURE_CHUNKY_SCRUB | \
+ FEATURE_MON_NULLROUTE | \
+ FEATURE_MON_GV | \
+ FEATURE_BACKFILL_RESERVATION | \
+ FEATURE_MSG_AUTH | \
+ FEATURE_RECOVERY_RESERVATION | \
+ FEATURE_CRUSH_TUNABLES2 | \
+ FEATURE_CREATEPOOLID | \
+ FEATURE_REPLY_CREATE_INODE | \
+ FEATURE_OSD_HBMSGS | \
+ FEATURE_MDSENC | \
+ FEATURE_OSDHASHPSPOOL | \
+ FEATURE_MON_SINGLE_PAXOS | \
+ FEATURE_OSD_SNAPMAPPER)
+
+struct feature_description {
+ guint64 feature;
+ const char* description;
+};
+
+struct feature_description fdesc[] = {
+ {FEATURE_UID, "uid"},
+ {FEATURE_NOSRCADDR, "nosrcaddr"},
+ {FEATURE_MONCLOCKCHECK, "monclockcheck"},
+ {FEATURE_FLOCK, "flock"},
+ {FEATURE_SUBSCRIBE2, "subscribe2"},
+ {FEATURE_MONNAMES, "monnames"},
+ {FEATURE_RECONNECT_SEQ, "reconnect_seq"},
+ {FEATURE_DIRLAYOUTHASH, "dirlayouthash"},
+ {FEATURE_OBJECTLOCATOR, "objectlocator"},
+ {FEATURE_PGID64, "pgid64"},
+ {FEATURE_INCSUBOSDMAP, "incsubosdmap"},
+ {FEATURE_PGPOOL3, "pgpool3"},
+ {FEATURE_OSDREPLYMUX, "osdreplymux"},
+ {FEATURE_OSDENC, "osdenc"},
+ {FEATURE_OMAP, "omap"},
+ {FEATURE_QUERY_T, "query_t"},
+ {FEATURE_MONENC, "monenc"},
+ {FEATURE_INDEP_PG_MAP, "indep_pg_map"},
+ {FEATURE_CRUSH_TUNABLES, "crush_tunables"},
+ {FEATURE_CHUNKY_SCRUB, "chunk_scrub"},
+ {FEATURE_MON_NULLROUTE, "mon_nullroute"},
+ {FEATURE_MON_GV, " mon_gv"},
+ {FEATURE_BACKFILL_RESERVATION, "backfill_reservation"},
+ {FEATURE_MSG_AUTH, "msg_auth"},
+ {FEATURE_RECOVERY_RESERVATION, "recovery_reservation"},
+ {FEATURE_CRUSH_TUNABLES2, "crush_tunables2"},
+ {FEATURE_CREATEPOOLID, "createpoolid"},
+ {FEATURE_REPLY_CREATE_INODE, "reply_create_inode"},
+ {FEATURE_OSD_HBMSGS, "osd_hbmsgs"},
+ {FEATURE_MDSENC, "mdsenc"},
+ {FEATURE_OSDHASHPSPOOL, "osdhashpspool"},
+ {FEATURE_MON_SINGLE_PAXOS, "mon_single_paxos"},
+ {FEATURE_OSD_SNAPMAPPER, "osd_snapmapper"}
+};
+#define FEATURE_COUNT (sizeof(fdesc)/sizeof(struct feature_description))
+
+static char* featureDescription(guint64 features) {
+ guint i;
+ char *desc;
+ char *next;
+
+ if (features == (guint64)FEATURES_ALL) {
+ return g_strdup("All features");
+ } else {
+ desc=g_strdup("");
+ for (i=0; i< FEATURE_COUNT; i++) {
+ if (features & fdesc[i].feature) {
+ next = g_strconcat(desc, fdesc[i].description, " ", NULL);
+ g_free(desc);
+ desc = next;
+ }
+ }
+ return desc;
+ }
+}
+
+/*
+ * Connect message flags, numbers must match protocol
+ * There is only a lossy flag, maybe more will be added later
+ */
+typedef enum _connect_flags {
+ MSG_CONNECT_MIN=1,
+ MSG_CONNECT_LOSSY=1,
+ MSG_CONNECT_MAX=1
+} connect_flags;
+
+static const char*
+connectFlagDescription(guint flag) {
+ switch (flag) {
+ case MSG_CONNECT_LOSSY: return "Lossy";
+ }
+ return "No Flags";
+}
+
+static void
+format_connect_features(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ guint offset) {
+ proto_item* item;
+ guint64 features;
+ char* desc;
+ char linebuf[201];
+ guint len, start, end;
+
+ features = tvb_get_letoh64(tvb, offset);
+ desc = featureDescription(features);
+ len = strlen(desc);
+ if (len < 150) {
+ /* Short description on one line */
+ item = proto_tree_add_uint64_format_value(tree, hf_connect_features,
+ tvb, offset, 8, features, "0x%" G_GINT64_MODIFIER "x (%s)",
+ features, desc);
+ } else {
+
+ /* Format as multi-line entry */
+ item = proto_tree_add_uint64_format_value(tree, hf_connect_features,
+ tvb, offset, 8, features, "0x%" G_GINT64_MODIFIER "x", features);
+
+ start = 0;
+ while (start < len) {
+ end = start + (strlen(&desc[start])>200 ? 200 :
+ strlen(&desc[start]));
+ while (end>len || desc[end-1] != ' ')
+ end--;
+ strncpy(linebuf, &desc[start], end-start);
+ linebuf[end-start]=0;
+ proto_tree_add_uint64_format_value(tree, hf_connect_features, tvb,
+ offset, 8, features, "%s", linebuf);
+ start = end;
+ }
+ }
+ g_free(desc);
+
+ if ((features & (~FEATURES_ALL)) != 0) {
+ expert_add_info_format(pinfo, item, PI_UNDECODED, PI_WARN,
+ "Unexpected feature flags seen, dissector may need updating");
+ }
+}
+
+static gint
+dissect_connect_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ guint offset) {
+
+ gint auth_len;
+ entity_type host_type;
+ guint flags;
+
+ if (tvb_reported_length_remaining (tvb, offset) < SIZE_OF_MSG_CONNECT)
+ return -1;
+
+ host_type = (entity_type)tvb_get_letohl(tvb, offset+8);
+ if (!isEntityType(host_type))
+ return 0;
+
+ auth_len = tvb_get_letohl(tvb, offset+28);
+ if (tvb_reported_length_remaining (tvb, offset) <
+ SIZE_OF_MSG_CONNECT+auth_len)
+ return -1;
+
+ /* All here, just decode */
+ setPDUInfo(pinfo, "Connect Request");
+ format_connect_features(tvb, pinfo, tree, offset);
+ proto_tree_add_uint_format_value(tree, hf_connect_host_type, tvb, offset+8,
+ 4, host_type, "%d (%s)", host_type, entityTypeDescription(host_type));
+ proto_tree_add_item(tree, hf_connect_global_seq, tvb, offset+12, 4, TRUE);
+ proto_tree_add_item(tree, hf_connect_connect_seq, tvb, offset+16, 4, TRUE);
+ proto_tree_add_item(tree, hf_connect_protocol_version, tvb, offset+20,
+ 4, TRUE);
+ proto_tree_add_item(tree, hf_connect_authorizer_protocol, tvb, offset+24,
+ 4, TRUE);
+ proto_tree_add_item(tree, hf_connect_authorizer_len, tvb, offset+28,
+ 4, TRUE);
+ flags = tvb_get_guint8(tvb, offset+32);
+ proto_tree_add_uint_format_value(tree, hf_connect_flags, tvb, offset+32, 1,
+ flags, "%d (%s)", flags, connectFlagDescription(flags));
+
+ if (auth_len >0)
+ proto_tree_add_item(tree, hf_connect_authentication_key, tvb, offset+33,
+ auth_len, TRUE);
+
+ /* Tag it in conv */
+ conv_fixup(TRUE, pinfo);
+ conv_tag(pinfo, tvb, offset, CONNECT_REQUEST);
+ conv_setfrom(pinfo, (entity_type)tvb_get_letohl(tvb, offset+8));
+
+ return SIZE_OF_MSG_CONNECT+auth_len;
+}
+
+/*
+ * msg_connect_reply - Server->Client connection reply following a request
+ *
+ struct ceph_msg_connect_reply {
+ guint8 tag;
+ guint64 features;
+ guint32 global_seq;
+ guint32 connect_seq;
+ guint32 protocol_version;
+ guint32 authorizer_len;
+ guint8 flags;
+}
+*/
+#define SIZE_OF_MSG_CONNECT_REPLY (1+8+4+4+4+4+1)
+
+static gint
+dissect_connect_reply(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ guint offset) {
+
+ gint auth_len;
+ guint tag;
+ guint flags;
+
+ /* Test we have enough data including auth */
+ if (tvb_reported_length_remaining (tvb, offset) < SIZE_OF_MSG_CONNECT_REPLY)
+ return -1;
+
+ /* TODO: This isn't an ideal test but we need something :-( */
+ tag = tvb_get_guint8(tvb, offset);
+ if (!isMsgrConnectTag(tag))
+ return 0;
+
+ auth_len = tvb_get_letohl(tvb, offset+21);
+ if (tvb_reported_length_remaining (tvb, offset) <
+ SIZE_OF_MSG_CONNECT_REPLY+auth_len)
+ return -1;
+
+ setPDUInfo(pinfo, "Connect Reply");
+ proto_tree_add_uint_format_value(tree, hf_connect_tag, tvb, offset, 1,
+ tag, "%d (%s)", tag, replyTagDescription(tag));
+ format_connect_features(tvb, pinfo, tree, offset+1);
+ proto_tree_add_item(tree, hf_connect_global_seq, tvb, offset+9, 4, TRUE);
+ proto_tree_add_item(tree, hf_connect_connect_seq, tvb, offset+13, 4, TRUE);
+ proto_tree_add_item(tree, hf_connect_protocol_version, tvb, offset+17,
+ 4, TRUE);
+ proto_tree_add_item(tree, hf_connect_authorizer_len, tvb, offset+21,
+ 4, TRUE);
+ flags = tvb_get_guint8(tvb, offset+25);
+ proto_tree_add_uint_format_value(tree, hf_connect_flags, tvb, offset+25, 1,
+ flags, "%d (%s)", flags, connectFlagDescription(flags));
+
+ /* Tag it in conversation */
+ conv_fixup(FALSE, pinfo);
+ conv_tag(pinfo, tvb, offset, CONNECT_REPLY);
+ return SIZE_OF_MSG_CONNECT_REPLY+auth_len;
+}
+
+/*
+ * msg_ack - Simple ack of previous messages
+ *
+ struct ceph_msg_ack {
+ guint8 tag;
+ guint64 seq;
+}
+*/
+#define SIZE_OF_MSG_ACK (1+8)
+
+static guint
+dissect_ack(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset)
+{
+ if (tvb_reported_length_remaining (tvb, offset) < SIZE_OF_MSG_ACK)
+ return -1;
+
+ if (tree) {
+ setPDUInfo(pinfo, "Ack");
+ proto_tree_add_item(tree, hf_hdr_tag, tvb, offset, 1, TRUE);
+ proto_tree_add_item(tree, hf_hdr_seq_ack, tvb, offset+1, 8, TRUE);
+ }
+ return SIZE_OF_MSG_ACK;
+}
+
+/*
+ * entity_name
+ *
+struct ceph_entity_name {
+ guint8 type; //
+ guint64 num;
+}
+*/
+#define SIZE_OF_ENTITY_NAME (1+8)
+
+static guint
+dissect_entity_name(tvbuff_t *tvb, proto_tree *tree, gint hf, int offset) {
+ proto_item *entity_name_item;
+ proto_tree *entity_name_tree;
+
+ if (tvb_reported_length_remaining (tvb, offset) < SIZE_OF_ENTITY_NAME)
+ return -1;
+
+ if (tree) {
+ entity_name_item = proto_tree_add_item( tree, hf, tvb, offset,
+ SIZE_OF_ENTITY_NAME, TRUE );
+ entity_name_tree = proto_item_add_subtree(entity_name_item,
+ ett_entity_name);
+
+ proto_tree_add_item(entity_name_tree, hf_entity_type, tvb, offset,
+ 1, TRUE);
+ proto_tree_add_item(entity_name_tree, hf_entity_num, tvb, offset+1,
+ 8, TRUE);
+ }
+ return SIZE_OF_ENTITY_NAME;
+}
+
+/*
+ * msg_header
+ *
+ struct ceph_msg_header {
+ guint64 seq; // message seq# for this session
+ guint64 tid; // transaction id
+ guint16 type; // message type
+ guint16 priority; // priority. higher value == higher priority
+ guint16 version; // version of message encoding
+
+ guint32 front_len; // bytes in main payload
+ guint32 middle_len; // bytes in middle payload
+ guint32 data_len; // bytes of data payload
+ guint16 data_off; // sender: include full offset;
+ // receiver: mask against ~PAGE_MASK
+
+ struct ceph_entity_name src;
+ guint32 reserved;
+ guint32 crc; // header crc32c
+}
+*/
+#define SIZE_OF_MSG_HEADER (8+8+2+2+2 +4+4+4+2 +SIZE_OF_ENTITY_NAME+4+4)
+#define HEADER_TYPE_OFFSET (8+8)
+#define HEADER_ETYPE_OFFSET (8+8+2+2+2 +4+4+4+2)
+#define HEADER_CRC_OFFSET (SIZE_OF_MSG_HEADER-4)
+
+typedef struct _header_info {
+ guint32 type;
+ guint32 front_len;
+ guint32 middle_len;
+ guint32 data_len;
+} header_info;
+
+static gint
+dissect_msg_header(tvbuff_t *tvb, proto_tree *tree, int offset,
+ header_info* info) {
+ proto_item *header_item;
+ proto_tree *header_tree;
+
+ if (tvb_reported_length_remaining (tvb, offset) < SIZE_OF_MSG_HEADER)
+ return -1;
+
+ if (info) {
+ info->type = tvb_get_letohs(tvb, offset+16);
+ info->front_len = tvb_get_letohl(tvb, offset+22);
+ info->middle_len = tvb_get_letohl(tvb, offset+26);
+ info->data_len = tvb_get_letohl(tvb, offset+30);
+ }
+
+ if (tree) {
+ header_item = proto_tree_add_item( tree, hf_header, tvb, offset,
+ SIZE_OF_MSG_HEADER, TRUE );
+ header_tree = proto_item_add_subtree(header_item, ett_header);
+
+ proto_tree_add_item(header_tree, hf_hdr_seq, tvb, offset+0, 8, TRUE);
+ proto_tree_add_item(header_tree, hf_hdr_tid, tvb, offset+8, 8, TRUE);
+ proto_tree_add_item(header_tree, hf_hdr_type, tvb, offset+16, 2, TRUE);
+ proto_tree_add_item(header_tree, hf_hdr_priority, tvb, offset+18,
+ 2, TRUE);
+ proto_tree_add_item(header_tree, hf_hdr_version, tvb, offset+20,
+ 2, TRUE);
+
+ proto_tree_add_item(header_tree, hf_hdr_front_len, tvb, offset+22,
+ 4, TRUE);
+ proto_tree_add_item(header_tree, hf_hdr_middle_len, tvb, offset+26,
+ 4, TRUE);
+ proto_tree_add_item(header_tree, hf_hdr_data_len, tvb, offset+30,
+ 4, TRUE);
+ proto_tree_add_item(header_tree, hf_hdr_data_off, tvb, offset+34,
+ 2, TRUE);
+
+ dissect_entity_name(tvb, header_tree, hf_hdr_src, offset+36);
+
+ proto_tree_add_item(header_tree, hf_hdr_crc, tvb,
+ offset+36+4+SIZE_OF_ENTITY_NAME, 4, TRUE);
+ }
+ return SIZE_OF_MSG_HEADER;
+}
+
+/*
+ * msg_footer
+ *
+ struct ceph_msg_footer {
+ guint32 front_crc;
+ guint32 middle_crc;
+ guint32 data_crc;
+ guint64 sig;
+ guint8 flags;
+}
+*/
+#define SIZE_OF_MSG_FOOTER (4+4+4+8+1)
+
+static guint32
+dissect_footer(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
+{
+ proto_item *footer_item;
+ proto_tree *footer_tree;
+
+ if (tvb_reported_length_remaining (tvb, offset) < SIZE_OF_MSG_FOOTER)
+ return -1;
+
+ if (tree) {
+ footer_item = proto_tree_add_item( tree, hf_footer, tvb, offset,
+ SIZE_OF_MSG_FOOTER, TRUE );
+ footer_tree = proto_item_add_subtree(footer_item, ett_footer);
+
+ proto_tree_add_item(footer_tree, hf_footer_front_crc, tvb, offset,
+ 4, TRUE);
+ proto_tree_add_item(footer_tree, hf_footer_middle_crc, tvb, offset+4,
+ 4, TRUE);
+ proto_tree_add_item(footer_tree, hf_footer_data_crc, tvb, offset+8,
+ 4, TRUE);
+ proto_tree_add_item(footer_tree, hf_footer_sig, tvb, offset+12,
+ 8, TRUE);
+ proto_tree_add_item(footer_tree, hf_footer_flags, tvb, offset+20,
+ 1, TRUE);
+ }
+
+ return SIZE_OF_MSG_FOOTER;
+}
+
+static guint32
+dissect_fsid(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
+{
+ guint32 fsid[4];
+
+ tvb_memcpy(tvb, &fsid, offset, sizeof(fsid));
+ proto_tree_add_text(tree, tvb, offset, sizeof(fsid), "fsid: %x-%x-%x-%x",
+ g_ntohl(fsid[0]), g_ntohl(fsid[1]), g_ntohl(fsid[2]), g_ntohl(fsid[3]));
+ return sizeof(fsid);
+}
+
+/*
+ * Message types
+ * There is no order to these as yet, maybe better split by source->target type?
+ */
+typedef enum _msg_ctype {
+ MSG_SHUTDOWN=1,
+ MSG_PING=2,
+ MSG_MON_MAP=4,
+ MSG_MON_GET_MAP=5,
+ MSG_STATFS=13,
+ MSG_STATFS_REPLY=14,
+ MSG_MON_SUBSCRIBE=15,
+ MSG_MON_SUBSCRIBE_ACK=16,
+ MSG_AUTH=17,
+ MSG_AUTH_REPLY=18,
+ MSG_MON_GET_VERSION=19,
+ MSG_MON_GET_VERSION_REPLY=20,
+ MSG_MDS_MAP=21,
+ MSG_CLIENT_SESSION=22,
+ MSG_CLIENT_RECONNECT=23,
+ MSG_CLIENT_REQUEST=24,
+ MSG_CLIENT_REQUEST_FORWARD=25,
+ MSG_CLIENT_REPLY=26,
+ MSG_CLIENT_CAPS=0x310,
+ MSG_CLIENT_LEASE=0x311,
+ MSG_CLIENT_SNAP=0x312,
+ MSG_CLIENT_CAPRELEASE=0x313,
+ MSG_POOLOP_REPLY=48,
+ MSG_POOLOP=49,
+ MSG_OSD_MAP=41,
+ MSG_OSD_OP=42,
+ MSG_OSD_OPREPLY=43,
+ MSG_WATCH_NOTIFY=44,
+ MSG_MON_ELECTION=65,
+ MSG_MON_PAXOS=66,
+ MSG_MON_PROBE=67,
+ MSG_MON_JOIN=68,
+ MSG_MON_SYNC=69,
+ MSG_MON_COMMAND=50,
+ MSG_MON_COMMAND_ACK=51,
+ MSG_LOG=52,
+ MSG_LOGACK=53,
+ MSG_CLASS=56,
+ MSG_CLASS_ACK=57,
+ MSG_GETPOOLSTATS=58,
+ MSG_GETPOOLSTATSREPLY=59,
+ MSG_MON_GLOBAL_ID=60,
+ MSG_ROUTE=47,
+ MSG_FORWARD=46,
+ MSG_PAXOS=40,
+ MSG_OSD_PING=70,
+ MSG_OSD_BOOT=71,
+ MSG_OSD_FAILURE=72,
+ MSG_OSD_ALIVE=73,
+ MSG_OSD_MARK_ME_DOWN=74,
+ MSG_OSD_SUBOP=76,
+ MSG_OSD_SUBOPREPLY=77,
+ MSG_OSD_PGTEMP=78,
+ MSG_OSD_PG_NOTIFY=80,
+ MSG_OSD_PG_QUERY=81,
+ MSG_OSD_PG_SUMMARY=82,
+ MSG_OSD_PG_LOG=83,
+ MSG_OSD_PG_REMOVE=84,
+ MSG_OSD_PG_INFO=85,
+ MSG_OSD_PG_TRIM=86,
+ MSG_PGSTATS=87,
+ MSG_PGSTATSACK=88,
+ MSG_OSD_PG_CREATE=89,
+ MSG_REMOVE_SNAPS=90,
+ MSG_OSD_SCRUB=91,
+ MSG_OSD_PG_MISSING=92,
+ MSG_OSD_REP_SCRUB=93,
+ MSG_OSD_PG_SCAN=94,
+ MSG_OSD_PG_BACKFILL=95,
+ MSG_COMMAND=97,
+ MSG_COMMAND_REPLY=98,
+ MSG_OSD_BACKFILL_RESERVE=99,
+ MSG_OSD_RECOVERY_RESERVE=150,
+ MSG_MDS_BEACON=100,
+ MSG_MDS_SLAVE_REQUEST=101,
+ MSG_MDS_TABLE_REQUEST=102,
+ MSG_MDS_RESOLVE=0x200,
+ MSG_MDS_RESOLVEACK=0x201,
+ MSG_MDS_CACHEREJOIN=0x202,
+ MSG_MDS_DISCOVER=0x203,
+ MSG_MDS_DISCOVERREPLY=0x204,
+ MSG_MDS_INODEUPDATE=0x205,
+ MSG_MDS_DIRUPDATE=0x206,
+ MSG_MDS_CACHEEXPIRE=0x207,
+ MSG_MDS_DENTRYUNLINK=0x208,
+ MSG_MDS_FRAGMENTNOTIFY=0x209,
+ MSG_MDS_OFFLOAD_TARGETS=0x20a,
+ MSG_MDS_DENTRYLINK=0x20c,
+ MSG_MDS_FINDINO=0x20d,
+ MSG_MDS_FINDINOREPLY=0x20e,
+ MSG_MDS_OPENINO=0x20f,
+ MSG_MDS_OPENINOREPLY=0x210,
+ MSG_MDS_LOCK=0x300,
+ MSG_MDS_INODEFILECAPS=0x301,
+ MSG_MDS_EXPORTDIRDISCOVER=0x449,
+ MSG_MDS_EXPORTDIRDISCOVERACK=0x450,
+ MSG_MDS_EXPORTDIRCANCEL=0x451,
+ MSG_MDS_EXPORTDIRPREP=0x452,
+ MSG_MDS_EXPORTDIRPREPACK=0x453,
+ MSG_MDS_EXPORTDIRWARNING=0x454,
+ MSG_MDS_EXPORTDIRWARNINGACK=0x455,
+ MSG_MDS_EXPORTDIR=0x456,
+ MSG_MDS_EXPORTDIRACK=0x457,
+ MSG_MDS_EXPORTDIRNOTIFY=0x458,
+ MSG_MDS_EXPORTDIRNOTIFYACK=0x459,
+ MSG_MDS_EXPORTDIRFINISH=0x460,
+ MSG_MDS_EXPORTCAPS=0x470,
+ MSG_MDS_EXPORTCAPSACK=0x471,
+ MSG_MDS_HEARTBEAT=0x500,
+ MSG_TIMECHECK=0x600,
+ MSG_MON_HEALTH=0x601
+} msg_ctype;
+
+static value_string msg_ctype_values[]={
+ {MSG_SHUTDOWN, "Shutdown"},
+ {MSG_PING, "Ping"},
+ {MSG_MON_MAP, "MON Map"},
+ {MSG_MON_GET_MAP, "MON Get Map"},
+ {MSG_STATFS, "Stat FS"},
+ {MSG_STATFS_REPLY, "Stat FS Reply"},
+ {MSG_MON_SUBSCRIBE, "MON Subscribe"},
+ {MSG_MON_SUBSCRIBE_ACK, "MON Subscribe Ack"},
+ {MSG_AUTH, "Auth"},
+ {MSG_AUTH_REPLY, "Auth Reply"},
+ {MSG_MON_GET_VERSION, "MON Get Version"},
+ {MSG_MON_GET_VERSION_REPLY, "MON Get Version Reply"},
+ {MSG_MDS_MAP, "MDS Map"},
+ {MSG_CLIENT_SESSION, "Client Session"},
+ {MSG_CLIENT_RECONNECT, "Client Reconnect"},
+ {MSG_CLIENT_REQUEST, "Client Request"},
+ {MSG_CLIENT_REQUEST_FORWARD, "Client Request Forward"},
+ {MSG_CLIENT_REPLY, "Client Reply"},
+ {MSG_PAXOS, "Paxos"},
+ {MSG_OSD_MAP, "OSD Map"},
+ {MSG_OSD_OP, "OSD Op"},
+ {MSG_OSD_OPREPLY, "OSD Op Reply"},
+ {MSG_WATCH_NOTIFY, "Watch Notify"},
+ {MSG_FORWARD, "Forward"},
+ {MSG_ROUTE, "Route"},
+ {MSG_POOLOP_REPLY, "Pool Op Reply"},
+ {MSG_POOLOP, "Pool Op"},
+ {MSG_MON_COMMAND, "MON Command"},
+ {MSG_MON_COMMAND_ACK, "MON Command Ack"},
+ {MSG_LOG, "Log"},
+ {MSG_LOGACK, "Log Ack"},
+ {MSG_CLASS, "Class"},
+ {MSG_CLASS_ACK, "Class Ack"},
+ {MSG_GETPOOLSTATS, "Get Pool Stats"},
+ {MSG_GETPOOLSTATSREPLY, "Get Pools Stats Reply"},
+ {MSG_MON_GLOBAL_ID, "MON Global Id"},
+ {MSG_MON_ELECTION, "MON Election"},
+ {MSG_MON_PAXOS, "MON Paxos"},
+ {MSG_MON_PROBE, "MON Probe"},
+ {MSG_MON_JOIN, "MON Join"},
+ {MSG_MON_SYNC, "MON Sync"},
+ {MSG_OSD_PING, "OSD Ping"},
+ {MSG_OSD_BOOT, "OSD Boot"},
+ {MSG_OSD_FAILURE, "OSD Failure"},
+ {MSG_OSD_ALIVE, "OSD Alive"},
+ {MSG_OSD_MARK_ME_DOWN, "OSD Mark Me Down"},
+ {MSG_OSD_SUBOP, "OSD Subop"},
+ {MSG_OSD_SUBOPREPLY, "OSD Subop Reply"},
+ {MSG_OSD_PGTEMP, "OSD PG Temp"},
+ {MSG_OSD_PG_NOTIFY, "OSD PG Notify"},
+ {MSG_OSD_PG_QUERY, "OSD PG Query"},
+ {MSG_OSD_PG_SUMMARY, "OSD PG Summary"},
+ {MSG_OSD_PG_LOG, "OSD PG Log"},
+ {MSG_OSD_PG_REMOVE, "OSD PG Remove"},
+ {MSG_OSD_PG_INFO, "OSD PG Info"},
+ {MSG_OSD_PG_TRIM, "OSD PG Trim"},
+ {MSG_PGSTATS, "MPN PG Stats"},
+ {MSG_PGSTATSACK, "MON PG Stats Ack"},
+ {MSG_OSD_PG_CREATE, "OSD PG Create"},
+ {MSG_REMOVE_SNAPS, "Remove Snaps"},
+ {MSG_OSD_SCRUB, "OSD Scrub"},
+ {MSG_OSD_PG_MISSING, "OSD PG Missing"},
+ {MSG_OSD_REP_SCRUB, "OSD REP Scrub"},
+ {MSG_OSD_PG_SCAN, "OSD PG Scan"},
+ {MSG_OSD_PG_BACKFILL, "OSD PG Backfill"},
+ {MSG_COMMAND, "Command"},
+ {MSG_COMMAND_REPLY, "Command Reply"},
+ {MSG_OSD_BACKFILL_RESERVE, "OSD Backfill Reserve"},
+ {MSG_MDS_BEACON, "MDS Beacon"},
+ {MSG_MDS_SLAVE_REQUEST, "MDS Slave Request"},
+ {MSG_MDS_TABLE_REQUEST, "MDS Table Request"},
+ {MSG_OSD_RECOVERY_RESERVE, "OSD Recovery Reserve"},
+ {MSG_MDS_RESOLVE, "MDS Resolve"},
+ {MSG_MDS_RESOLVEACK, "MDS Resolve Ack"},
+ {MSG_MDS_CACHEREJOIN, "MDS Cache Rejoin"},
+ {MSG_MDS_DISCOVER, "MDS Discover"},
+ {MSG_MDS_DISCOVERREPLY, "MDS Discover Reply"},
+ {MSG_MDS_INODEUPDATE, "MDS INode Update"},
+ {MSG_MDS_DIRUPDATE, "MDS Dir Update"},
+ {MSG_MDS_CACHEEXPIRE, "MDS Cache Expire"},
+ {MSG_MDS_DENTRYUNLINK, "MDS DEntry Unlink"},
+ {MSG_MDS_FRAGMENTNOTIFY, "MDS Fragment Notify"},
+ {MSG_MDS_OFFLOAD_TARGETS, "MDS Offload Targets"},
+ {MSG_MDS_DENTRYLINK, "MDS DEntry Link"},
+ {MSG_MDS_FINDINO, "MDS Find INO"},
+ {MSG_MDS_FINDINOREPLY, "MDS Find INO Reply"},
+ {MSG_MDS_OPENINO, "MDS Open INO"},
+ {MSG_MDS_OPENINOREPLY, "MDS Open INO Reply"},
+ {MSG_MDS_LOCK, "MDS Lock"},
+ {MSG_MDS_INODEFILECAPS, "MDS INODE File Caps"},
+ {MSG_CLIENT_CAPS, "Client Caps"},
+ {MSG_CLIENT_LEASE, "Client Lease"},
+ {MSG_CLIENT_SNAP, "Client Snap"},
+ {MSG_CLIENT_CAPRELEASE, "Client Cap Release"},
+ {MSG_MDS_EXPORTDIRDISCOVER, "MDS Export DIR Discover"},
+ {MSG_MDS_EXPORTDIRDISCOVERACK, "MDS Export DIR Discover Ack"},
+ {MSG_MDS_EXPORTDIRCANCEL, "MDS Export DIR Cancel"},
+ {MSG_MDS_EXPORTDIRPREP, "MDS Export DIR Prep"},
+ {MSG_MDS_EXPORTDIRPREPACK, "MDS Export DIR Prepack"},
+ {MSG_MDS_EXPORTDIRWARNING, "MDS Export DIR Warning"},
+ {MSG_MDS_EXPORTDIRWARNINGACK, "MDS Export DIR Warning Ack"},
+ {MSG_MDS_EXPORTDIR, "MDS Export DIR"},
+ {MSG_MDS_EXPORTDIRACK, "MDS Export DIR Ack"},
+ {MSG_MDS_EXPORTDIRNOTIFY, "MDS Export DIR Notify"},
+ {MSG_MDS_EXPORTDIRNOTIFYACK, "MDS Export DIR Notify Ack"},
+ {MSG_MDS_EXPORTDIRFINISH, "MDS Export DIR Finish"},
+ {MSG_MDS_EXPORTCAPS, "MDS Export Caps"},
+ {MSG_MDS_EXPORTCAPSACK, "MDS Export Caps Ack"},
+ {MSG_MDS_HEARTBEAT, "MDS Heartbeat"},
+ {MSG_TIMECHECK, "Timecheck"},
+ {MSG_MON_HEALTH, "MON Health"}
+};
+
+static gboolean
+isMsgCType(guint32 type) {
+ return (try_val_to_str(type, msg_ctype_values)!=NULL);
+}
+
+static const char*
+msgCTypeDescription(msg_ctype type) {
+ return val_to_str(type, msg_ctype_values, "Unknown Message Type: %d");
+}
+
+/*
+ * PaxosServiceMessage
+ *
+struct {
+ guint64 version;
+ gint16 deprecated_session_mon;
+ guint64 deprecated_session_mon_tid;
+}
+*/
+#define SIZE_OF_PAXOS (8+2+8)
+
+static guint32
+dissect_paxos(tvbuff_t *tvb, proto_tree *tree, guint32 offset){
+
+ proto_tree_add_item(tree, hf_paxos_version, tvb, offset, 8, TRUE);
+ return SIZE_OF_PAXOS;
+}
+
+/*
+ * feature_set
+ *
+struct {
+ uint64_t mask;
+ map <uint64_t,string> names;
+}
+*/
+static guint32
+dissect_featureset(tvbuff_t *tvb, proto_tree *tree, guint32 offset, int hinfo,
+ gint ett) {
+ proto_item *litem;
+ proto_tree *ltree;
+ guint32 i, items;
+ guint32 at;
+
+ litem = proto_tree_add_item( tree, hinfo, tvb, offset, 1, TRUE );
+ ltree = proto_item_add_subtree(litem, ett);
+
+ at = offset;
+ proto_tree_add_item(ltree, hf_featureset_mask, tvb, at, 8, TRUE); at += 8;
+ items = tvb_get_letohl(tvb, at); at+=4;
+ for (i=0; i<items; i++) {
+ proto_tree_add_item(ltree, hf_featureset_id, tvb, at, 8, TRUE); at += 8;
+ proto_tree_add_item(ltree, hf_featureset_name, tvb, at, 4, TRUE);
+ at += tvb_get_letohl(tvb, at)+ 4;
+ }
+
+ proto_item_set_len(litem, (at-offset));
+ return (at-offset);
+}
+
+static guint32
+dissect_compatset(tvbuff_t *tvb, proto_tree *tree, guint32 offset) {
+
+ guint32 at;
+
+ at = offset;
+ at +=dissect_featureset(tvb, tree, at, hf_compatset_compat, ett_compat);
+ at +=dissect_featureset(tvb, tree, at, hf_compatset_rocompat, ett_rocompat);
+ at +=dissect_featureset(tvb, tree, at, hf_compatset_incompat, ett_incompat);
+
+ return (at-offset);
+}
+
+/*
+ * MAuth
+ *
+ struct {
+ paxos paxos;
+ guint32 protocol;
+ guint32 auth_len;
+ guint8 auth[];
+ guint32 monmap_epoch;
+}
+*/
+#define SIZE_OF_MSG_AUTH (SIZE_OF_PAXOS+4+4+0+4)
+
+static guint32
+dissect_auth(tvbuff_t *tvb, proto_tree *tree, guint32 offset){
+ proto_item *auth_item;
+ proto_tree *auth_tree;
+ gint auth_len;
+ guint8* auth_bytes;
+
+ auth_len = tvb_get_letohl(tvb, offset+SIZE_OF_PAXOS+4);
+
+ if (tree) {
+ auth_item = proto_tree_add_item( tree, hf_auth, tvb, offset,
+ SIZE_OF_MSG_AUTH+auth_len, TRUE );
+ auth_tree = proto_item_add_subtree(auth_item, ett_front);
+
+ offset += dissect_paxos(tvb, auth_tree, offset);
+ proto_tree_add_item(auth_tree, hf_auth_protocol, tvb, offset, 4, TRUE);
+ proto_tree_add_item(auth_tree, hf_auth_authlen, tvb, offset+4, 4, TRUE);
+ auth_bytes = (guint8*)tvb_memdup(tvb, offset+8, auth_len);
+ proto_tree_add_bytes(auth_tree, hf_auth_authbytes, tvb, offset+8,
+ auth_len, auth_bytes);
+ g_free(auth_bytes);
+ proto_tree_add_item(auth_tree, hf_auth_monmapepoch, tvb,
+ offset+8+auth_len, 4, TRUE);
+ }
+ return SIZE_OF_MSG_AUTH+auth_len;
+}
+
+/*
+ * msg_auth_reply
+ *
+ struct ceph_msg_auth_reply {
+ guint32 protocol;
+ gint32 result;
+ guint64 global_id;
+ guint32 auth_len;
+ guint8 auth[];
+ guint32 msg_len;
+ char msg[];
+}
+*/
+#define SIZE_OF_MSG_AUTH_REPLY (4+4+8+4+0+4+0)
+
+static guint32
+dissect_auth_reply(tvbuff_t *tvb, proto_tree *tree, guint32 offset){
+ proto_item *auth_item;
+ proto_tree *auth_tree;
+ gint auth_len;
+ guint8* auth_bytes;
+ gint msg_len;
+ char* msg_string;
+
+ auth_len = tvb_get_letohl(tvb, offset+16);
+ msg_len = tvb_get_letohl(tvb, offset+20+auth_len);
+
+ if (tree) {
+ auth_item = proto_tree_add_item( tree, hf_authreply, tvb, offset,
+ SIZE_OF_MSG_AUTH_REPLY+auth_len+msg_len, TRUE );
+ auth_tree = proto_item_add_subtree(auth_item, ett_front);
+
+ proto_tree_add_item(auth_tree, hf_authreply_protocol, tvb, offset+0,
+ 4, TRUE);
+ proto_tree_add_item(auth_tree, hf_authreply_result, tvb, offset+4,
+ 4, TRUE);
+ proto_tree_add_item(auth_tree, hf_authreply_globalid, tvb, offset+8,
+ 8, TRUE);
+ proto_tree_add_item(auth_tree, hf_authreply_authlen, tvb, offset+16,
+ 4, TRUE);
+
+ auth_bytes = (guint8*)tvb_memdup(tvb, offset+20, auth_len);
+ proto_tree_add_bytes(auth_tree, hf_authreply_authbytes, tvb, offset+20,
+ auth_len, auth_bytes);
+ g_free(auth_bytes);
+
+ proto_tree_add_item(auth_tree, hf_authreply_msglen, tvb,
+ offset+20+auth_len, 4, TRUE);
+ msg_string = (char*)tvb_memdup(tvb, offset+20+auth_len+4, msg_len);
+ proto_tree_add_string(auth_tree, hf_authreply_msgstring, tvb,
+ offset+20+auth_len+4, msg_len, msg_string);
+ g_free(msg_string);
+ }
+ return SIZE_OF_MSG_AUTH_REPLY+auth_len+msg_len;
+}
+
+/*
+ * msg_mon_map
+ *
+ struct ceph_msg_monmap {
+ guint32 length;
+ guint8 version;
+ guint8 compat;
+ guint32 entry_size;
+ ceph_msg_monmap_entry entries[];
+ };
+
+ struct ceph_msg_monmap_entry {
+ guint8[16] fsid
+ guint32 epoch
+ map<string,entity_addr_t> mon_addr
+ guint64 last_changed
+ guint64 created
+}
+*/
+
+static guint32
+dissect_mon_map(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ guint32 offset) {
+ proto_item *litem = NULL;
+ proto_tree *ltree = NULL;
+ guint32 i, at, name_at;
+ guint32 map_len, addr_len, entries_len;
+ entity_info einfo;
+
+ map_len = tvb_get_letohl(tvb, offset)+sizeof(map_len);
+
+ litem = proto_tree_add_item( tree, hf_monmap, tvb, offset, map_len, TRUE );
+ ltree = proto_item_add_subtree(litem, ett_front);
+
+ proto_tree_add_item(ltree, hf_monmap_version, tvb, offset+4, 1, TRUE);
+ proto_tree_add_item(ltree, hf_monmap_compat, tvb, offset+5, 1, TRUE);
+
+ entries_len = tvb_get_letohl(tvb, offset+6);
+ offset += 10;
+ while (entries_len>0) {
+ at = offset;
+ at += dissect_fsid(tvb, ltree, at);
+ proto_tree_add_item(ltree, hf_monmap_epoch, tvb, at, 4, TRUE); at+=4;
+
+ addr_len = tvb_get_letohl(tvb, at); at+=4;
+ for (i=0; i< addr_len; i++) {
+ name_at = at;
+ proto_tree_add_item(ltree, hf_monmap_name, tvb, at, 4, TRUE);
+ at += tvb_get_letohl(tvb, at)+ 4;
+ at += dissect_entity_addr(tvb, pinfo, ltree, at, &einfo);
+ conv_set_entity_name(conv_get_entity_frominfo(&einfo),
+ tvb, name_at, ENTITY_TYPE_MON);
+ }
+
+ proto_tree_add_item(ltree, hf_monmap_lastchanged, tvb, at, 8, TRUE);
+ at+=8;
+ proto_tree_add_item(ltree, hf_monmap_created, tvb, at, 8, TRUE);
+ at+=8;
+
+ entries_len -= (at-offset);
+ offset = at;
+ }
+ if (entries_len !=0 )
+ expert_add_info_format(pinfo, tree, PI_UNDECODED, PI_WARN,
+ "Length mismatch in decoding mon map entries");
+
+ return map_len;
+}
+
+/*
+ * msg_mon_subscribe
+ *
+struct ceph_mon_subscribe_item {
+ guint64 start;
+ guint8 flags;
+};
+
+struct ceph_msg_monsubscribe {
+ map<string, ceph_mon_subscribe_item> what
+};
+*/
+static guint32
+dissect_mon_subscribe(tvbuff_t *tvb, proto_tree *tree, guint32 offset,
+ guint32 length) {
+ proto_item *litem = NULL;
+ proto_tree *ltree = NULL;
+ guint32 i, items;
+ guint32 at;
+
+ litem = proto_tree_add_item( tree, hf_monsubscribe, tvb, offset,
+ length, TRUE );
+ ltree = proto_item_add_subtree(litem, ett_front);
+
+ items = tvb_get_letohl(tvb, offset);
+ at = offset +4;
+ for (i=0; i< items; i++) {
+ proto_tree_add_item(ltree, hf_monsubscribe_name, tvb, at, 4, TRUE);
+ at += tvb_get_letohl(tvb, at)+ 4;
+
+ proto_tree_add_item(ltree, hf_monsubscribe_start, tvb, at, 8, TRUE);
+ at += 8;
+ proto_tree_add_item(ltree, hf_monsubscribe_flags, tvb, at, 1, TRUE);
+ at += 1;
+ }
+
+ return (at-offset);
+}
+
+/*
+ * msg_mon_subscribeack
+ *
+struct ceph_msg_mon_subscribeack {
+ guint32 interval;
+ guint8 fsid[16];
+};
+*/
+static guint32
+dissect_mon_subscribeack(tvbuff_t *tvb, proto_tree *tree, guint32 offset,
+ guint32 length) {
+ proto_item *litem = NULL;
+ proto_tree *ltree = NULL;
+
+ litem = proto_tree_add_item( tree, hf_monsubscribeack, tvb, offset,
+ length, TRUE );
+ ltree = proto_item_add_subtree(litem, ett_front);
+
+ proto_tree_add_item(ltree, hf_monsubscribeack_interval, tvb, offset,
+ 4, TRUE);
+ dissect_fsid(tvb, ltree, offset+4);
+ return 20;
+}
+
+/*
+ * mds_beacon
+ *
+struct mds_beacon {
+ paxos
+ guint8[16] fsid;
+ guint64 global_id;
+ guint32 state;
+ guint64 seq;
+ string name;
+ gint32 standby_for_rank;
+ string standby_for_name;
+ CompatSet compat;
+};
+*/
+static guint32
+dissect_mdsbeacon(tvbuff_t *tvb, proto_tree *tree,
+ guint32 offset, guint32 length) {
+ proto_item *litem = NULL;
+ proto_tree *ltree = NULL;
+ guint32 at;
+
+ litem = proto_tree_add_item( tree, hf_mdsbeacon, tvb, offset, length, TRUE);
+ ltree = proto_item_add_subtree(litem, ett_front);
+
+ at = offset;
+ at += dissect_paxos(tvb, ltree, at);
+ at += dissect_fsid(tvb, ltree, at);
+ proto_tree_add_item(ltree, hf_mdsbeacon_globalid, tvb, at, 8, TRUE); at+=8;
+ proto_tree_add_item(ltree, hf_mdsbeacon_state, tvb, at, 4, TRUE); at+=4;
+ proto_tree_add_item(ltree, hf_mdsbeacon_seq, tvb, at, 8, TRUE); at+=8;
+ proto_tree_add_item(ltree, hf_mdsbeacon_name, tvb, at, 4, TRUE);
+ at += tvb_get_letohl(tvb, at)+ 4;
+ proto_tree_add_item(ltree, hf_mdsbeacon_standbyforrank, tvb, at, 4, TRUE);
+ at+=4;
+ proto_tree_add_item(ltree, hf_mdsbeacon_standbyforname, tvb, at, 4, TRUE);
+ at += tvb_get_letohl(tvb, at)+ 4;
+ at += dissect_compatset(tvb, ltree, at);
+
+ return (at-offset);
+}
+
+/*
+ * Pull apart a contained message.
+ * Dissectors called from here don't need to length check just return how
+ * many bytes they actually consumed.
+ */
+static guint
+dissect_msg_ctype(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ int offset, msg_ctype type, guint32 length)
+{
+ tvbuff_t* ltvb;
+ guint32 len=0;
+
+ /* Create a subset to isolate the dissectors
+ so they don't really need to length check */
+
+ ltvb = tvb_new_subset_length(tvb, offset, length);
+
+ switch (type) {
+ case MSG_MON_MAP:
+ len = dissect_mon_map(ltvb, pinfo, tree, 0);
+ break;
+ case MSG_AUTH:
+ len = dissect_auth(ltvb, tree, 0);
+ break;
+ case MSG_AUTH_REPLY:
+ len = dissect_auth_reply(ltvb, tree, 0);
+ break;
+ case MSG_MON_SUBSCRIBE:
+ len = dissect_mon_subscribe(ltvb, tree, 0, length);
+ break;
+ case MSG_MON_SUBSCRIBE_ACK:
+ len = dissect_mon_subscribeack(ltvb, tree, 0, length);
+ break;
+ case MSG_MDS_BEACON:
+ len = dissect_mdsbeacon(ltvb, tree, 0, length);
+ break;
+ default:
+ break;
+ }
+ return len;
+}
+
+static guint
+dissect_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset) {
+ guint start;
+ gint len=0;
+ header_info info;
+
+ start = offset;
+ len = dissect_msg_header(tvb, tree, offset, &info);
+ if (len <0 ) return len;
+ offset += len;
+
+ if (info.front_len) {
+ if ((guint)tvb_reported_length_remaining (tvb, offset) < info.front_len)
+ return -1;
+
+ len = dissect_msg_ctype(tvb, pinfo, tree, offset,
+ (msg_ctype)info.type, info.front_len);
+ if (len <0 ) return len;
+ else if (len == 0)
+ expert_add_info_format(pinfo, tree, PI_UNDECODED, PI_WARN,
+ "Undecoded: %s", msgCTypeDescription((msg_ctype)info.type));
+ else if ((guint32)len != info.front_len)
+ expert_add_info_format(pinfo, tree, PI_UNDECODED, PI_WARN,
+ "Header front length (%u) does not match message length (%u)",
+ info.front_len, len);
+ offset += info.front_len;
+ }
+
+ offset += info.middle_len;
+ offset += info.data_len;
+ len = dissect_footer(tvb, tree, offset);
+ if (len <0 ) return len;
+
+ offset += len;
+ setPDUInfo(pinfo, msgCTypeDescription((msg_ctype)info.type));
+ return (offset-start);
+}
+
+/*
+ * Create an expert warning that part of the packet could not be decoded.
+ */
+static void
+undecodedWarning(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ guint32 offset, guint32 expecting) {
+
+ /*
+ * Post warning message
+ */
+ setPDUInfo(pinfo, "Undecoded data");
+ if ((expecting & SERVER_BANNER) != 0)
+ expert_add_info_format(pinfo, tree, PI_UNDECODED, PI_WARN,
+ "Expected server to send banner, ignoring packet");
+ if ((expecting & CLIENT_BANNER) != 0)
+ expert_add_info_format(pinfo, tree, PI_UNDECODED, PI_WARN,
+ "Expected client to send banner, ignoring packet");
+ if ((expecting & SERVER_ADDRESS) != 0)
+ expert_add_info_format(pinfo, tree, PI_UNDECODED, PI_WARN,
+ "Expected server to send addresses, ignoring packet");
+ if ((expecting & CLIENT_ADDRESS) != 0)
+ expert_add_info_format(pinfo, tree, PI_UNDECODED, PI_WARN,
+ "Expected client to send addresses, ignoring packet");
+ if ((expecting & CONNECT_REQUEST) != 0)
+ expert_add_info_format(pinfo, tree, PI_UNDECODED, PI_WARN,
+ "Expected client to send connection request, ignoring packet");
+ if ((expecting & CONNECT_REPLY) != 0)
+ expert_add_info_format(pinfo, tree, PI_UNDECODED, PI_WARN,
+ "Expected server to send connection reply, ignoring packet");
+
+ /*
+ * Assume we jumped into middle of conversation
+ */
+ conv_tag(pinfo, tvb, offset, CONVERSING);
+}
+
+static void dissect_ceph(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree){
+
+ proto_item *ceph_item = NULL;
+ proto_tree *ceph_tree = NULL;
+ guint pduNum;
+ guint offset;
+ gint32 len;
+ guint32 expecting;
+ guint32 needMore;
+ guint8 type;
+
+ /* Tag as CEPH & prep info */
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_CEPH);
+ if(check_col(pinfo->cinfo,COL_INFO)){
+ col_clear(pinfo->cinfo,COL_INFO);
+ col_add_fstr(pinfo->cinfo, COL_INFO, "[%s]",conv_display(pinfo));
+ col_set_fence(pinfo->cinfo,COL_INFO);
+ }
+
+ /*
+ * Loop reading PDUs
+ */
+ needMore = FALSE;
+ offset=0;
+ pduNum=0;
+ while (tvb_reported_length_remaining (tvb, offset) != 0) {
+
+ /* Flag if this is first PDU in packet, helps formating info */
+ g_firstPdu = (pduNum++ == 0);
+
+ /* Create a new tree for it */
+ if (tree) {
+ ceph_item = proto_tree_add_item(tree, g_proto_ceph, tvb, 0,
+ -1, TRUE);
+ ceph_tree = proto_item_add_subtree(ceph_item, ett_ceph);
+ } else {
+ ceph_tree = NULL;
+ }
+
+ /*
+ * Recover what type of message we are expecting to see both for
+ * error checking and guiding the dissector to do the right thing
+ */
+ expecting = conv_expecting(pinfo, tvb, offset);
+
+ /*
+ * Try decode something
+ */
+ if ((expecting & SERVER_BANNER) != 0) {
+ len = dissect_banner(tvb, pinfo, ceph_tree, offset, FALSE);
+ if (len == -1) needMore = TRUE;
+ else if (len>0) {
+ conv_tag(pinfo, tvb, offset, SERVER_BANNER);
+ offset += len;
+ continue;
+ }
+ }
+
+ if ((expecting & CLIENT_BANNER) != 0) {
+ len = dissect_banner(tvb, pinfo, ceph_tree, offset, TRUE);
+ if (len == -1) needMore = TRUE;
+ else if (len>0) {
+ conv_tag(pinfo, tvb, offset, CLIENT_BANNER);
+ offset += len;
+ continue;
+ }
+ }
+
+ if ((expecting & CLIENT_ADDRESS) != 0) {
+ len = dissect_client_address(tvb, pinfo, ceph_tree, offset);
+ if (len == -1) needMore = TRUE;
+ else if (len>0) {
+ conv_tag(pinfo, tvb, offset, CLIENT_ADDRESS);
+ offset += len;
+ continue;
+ }
+ }
+
+ if ((expecting & SERVER_ADDRESS) != 0) {
+ len = dissect_server_address(tvb, pinfo, ceph_tree, offset);
+ if (len == -1) needMore = TRUE;
+ else if (len>0) {
+ conv_tag(pinfo, tvb, offset, SERVER_ADDRESS);
+ offset += len;
+ continue;
+ }
+ }
+
+ if ((expecting & CONNECT_REQUEST) != 0) {
+ len = dissect_connect_request(tvb, pinfo, ceph_tree, offset);
+ if (len == -1) needMore = TRUE;
+ else if (len>0) {
+ conv_tag(pinfo, tvb, offset, CONNECT_REQUEST);
+ offset += len;
+ continue;
+ }
+ }
+
+ if ((expecting & CONNECT_REPLY) != 0) {
+ len = dissect_connect_reply(tvb, pinfo, ceph_tree, offset);
+ if (len == -1) needMore = TRUE;
+ else if (len>0) {
+ conv_tag(pinfo, tvb, offset, CONNECT_REPLY);
+ offset += len;
+ continue;
+ }
+ }
+
+ if ((expecting & CONVERSING) != 0) {
+ type = tvb_get_guint8(tvb, offset);
+
+ if(type == MSGR_TAG_CLOSE){
+ setPDUInfo(pinfo, "Close");
+ conv_tag(pinfo, tvb, offset, CONVERSING);
+ offset++;
+ }
+ else if (type == MSGR_TAG_KEEPALIVE){
+ setPDUInfo(pinfo, "Keep Alive");
+ conv_tag(pinfo, tvb, offset, CONVERSING);
+ offset++;
+ }
+ else if (type == MSGR_TAG_ACK) {
+ len = dissect_ack(tvb, pinfo, ceph_tree, offset);
+ if (len == -1) needMore = TRUE;
+ if (len>0) {
+ conv_tag(pinfo, tvb, offset, CONVERSING);
+ offset += len;
+ continue;
+ }
+ }
+ else if (type == MSGR_TAG_MSG) {
+ len = dissect_msg(tvb, pinfo, ceph_tree, offset+1);
+ if (len == -1) needMore = TRUE;
+ if (len>0) {
+ conv_tag(pinfo, tvb, offset+1, CONVERSING);
+ offset += (1+len);
+ continue;
+ }
+ }
+ }
+
+ /* We have fallen through without decoding something */
+ if (needMore) {
+ /* One of decoders wants to see more data, so request it */
+ pinfo->desegment_offset = offset;
+ pinfo->desegment_len=DESEGMENT_ONE_MORE_SEGMENT;
+ } else {
+ /* Throw data away, we don't know what it is */
+ undecodedWarning(tvb, pinfo, ceph_tree, offset, expecting);
+ }
+ return;
+ }
+}
+
+/****************************************************************************
+ * Initialisation code
+ ****************************************************************************/
+
+static gboolean
+dissect_ceph_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ void *data) {
+
+ conversation_t* conversation;
+ (void)data; /* unused but required */
+
+ if (tvb_memeql(tvb,0, "ceph",4)!=0) {
+ if (tvb_reported_length_remaining (tvb, 0) >= 1+SIZE_OF_MSG_HEADER) {
+ if (!isMsgrTag(tvb_get_guint8(tvb, 0)))
+ return FALSE;
+
+ if (!isEntityType(tvb_get_guint8(tvb, 1+HEADER_ETYPE_OFFSET)))
+ return FALSE;
+
+ if (!isMsgCType(tvb_get_letohs(tvb, 1+HEADER_TYPE_OFFSET)))
+ return FALSE;
+
+
+ } else {
+ return FALSE;
+ }
+ }
+
+ /* This is for us */
+ conversation = find_or_create_conversation(pinfo);
+ conversation_set_dissector(conversation, g_ceph_handle);
+ dissect_ceph(tvb, pinfo, tree);
+ return TRUE;
+}
+
+/*
+ * Create the dissector, this is called once after proto_register_ceph
+ * has been invoked.
+ * Note. the dissector is only valid on a range of ports, you can
+ * get around this by writing a 'heuristic' detector but that is
+ * rather more complex to do.
+ */
+void proto_reg_handoff_ceph(void)
+{
+ g_ceph_handle = create_dissector_handle(dissect_ceph, g_proto_ceph);
+ heur_dissector_add("tcp", dissect_ceph_heur, g_proto_ceph);
+}
+
+/*
+ * This is the first part of the two-part registration for the plugin,
+ * see proto_reg_handoff_ceph() for part 2.
+ */
+void proto_register_ceph (void)
+{
+ /* A header field is something you can search/filter on.
+ *
+ * We create a structure to register our fields. It consists of an
+ * array of hf_register_info structures, each of which are of the format
+ * {&(field id), {name, abbrev, type, display, strings, bitmask, blurb, HFILL}}.
+ */
+ static hf_register_info hf[] = {
+ { &hf_paxos_version,
+ { "version", "ceph.paxosservicemessage.version", FT_UINT64 ,
+ BASE_HEX, NULL, 0, NULL, HFILL }},
+ { &hf_featureset_mask,
+ { "mask", "ceph.featureset.mask", FT_UINT64 ,
+ BASE_HEX, NULL, 0, NULL, HFILL }},
+ { &hf_featureset_id,
+ { "id", "ceph.featureset.id", FT_UINT64 ,
+ BASE_HEX, NULL, 0, NULL, HFILL }},
+ { &hf_featureset_name,
+ { "name", "ceph.featureset.name", FT_UINT_STRING ,
+ BASE_NONE, NULL, 0, NULL, HFILL }},
+ { &hf_compatset_compat,
+ { "Compat", "ceph.compat", FT_NONE ,
+ BASE_NONE, NULL, 0, NULL, HFILL }},
+ { &hf_compatset_rocompat,
+ { "RO Compat", "ceph.rocompat", FT_NONE ,
+ BASE_NONE, NULL, 0, NULL, HFILL }},
+ { &hf_compatset_incompat,
+ { "Incompat", "ceph.incompat", FT_NONE ,
+ BASE_NONE, NULL, 0, NULL, HFILL }},
+ { &hf_monmap,
+ { "MON map", "ceph.monmap", FT_NONE ,
+ BASE_NONE, NULL, 0, NULL, HFILL }},
+ { &hf_monmap_version,
+ { "version", "ceph.monmap.version", FT_UINT8 ,
+ BASE_DEC, NULL, 0, NULL, HFILL }},
+ { &hf_monmap_compat,
+ { "compat", "ceph.monmap.compat", FT_UINT8 ,
+ BASE_DEC, NULL, 0, NULL, HFILL }},
+ { &hf_monmap_epoch,
+ { "epoch", "ceph.monmap.epoch", FT_UINT32 ,
+ BASE_DEC, NULL, 0, NULL, HFILL }},
+ { &hf_monmap_name,
+ { "name", "ceph.monmap.name", FT_UINT_STRING ,
+ BASE_NONE, NULL, 0, NULL, HFILL }},
+ { &hf_monmap_lastchanged,
+ { "last changed", "ceph.monmap.lastchanged", FT_UINT64 ,
+ BASE_HEX, NULL, 0, NULL, HFILL }},
+ { &hf_monmap_created,
+ { "created", "ceph.monmap.created", FT_UINT64 ,
+ BASE_HEX, NULL, 0, NULL, HFILL }},
+ { &hf_monsubscribe,
+ { "MON subscribe", "ceph.monsubscribe", FT_NONE ,
+ BASE_NONE, NULL, 0, NULL, HFILL }},
+ { &hf_monsubscribe_name,
+ { "name", "ceph.monsubscribe.name", FT_UINT_STRING ,
+ BASE_NONE, NULL, 0, NULL, HFILL }},
+ { &hf_monsubscribe_start,
+ { "start", "ceph.monsubscribe.start", FT_UINT64 ,
+ BASE_HEX, NULL, 0, NULL, HFILL }},
+ { &hf_monsubscribe_flags,
+ { "flags", "ceph.monsubscribe.flags", FT_UINT8 ,
+ BASE_HEX, NULL, 0, NULL, HFILL }},
+ { &hf_monsubscribeack,
+ { "MON subscribe ack", "ceph.monsubscribeack", FT_NONE ,
+ BASE_NONE, NULL, 0, NULL, HFILL }},
+ { &hf_monsubscribeack_interval,
+ { "interval", "ceph.monsubscribeack.interval", FT_UINT32 ,
+ BASE_DEC, NULL, 0, NULL, HFILL }},
+ { &hf_mdsbeacon,
+ { "MDS Beacon", "ceph.mdsbeacon", FT_NONE ,
+ BASE_NONE, NULL, 0, NULL, HFILL }},
+ { &hf_mdsbeacon_globalid,
+ { "global_id", "ceph.mdsbeason.globalid", FT_UINT64 ,
+ BASE_HEX, NULL, 0, NULL, HFILL }},
+ { &hf_mdsbeacon_state,
+ { "state", "ceph.mdsbeason.state", FT_UINT32 ,
+ BASE_HEX, NULL, 0, NULL, HFILL }},
+ { &hf_mdsbeacon_seq,
+ { "seq", "ceph.mdsbeason.seq", FT_UINT64 ,
+ BASE_DEC, NULL, 0, NULL, HFILL }},
+ { &hf_mdsbeacon_name,
+ { "name", "ceph.mdsbeason.name", FT_UINT_STRING ,
+ BASE_NONE, NULL, 0, NULL, HFILL }},
+ { &hf_mdsbeacon_standbyforrank,
+ { "standby for rank", "ceph.mdsbeason.standbyforrank", FT_INT32 ,
+ BASE_DEC, NULL, 0, NULL, HFILL }},
+ { &hf_mdsbeacon_standbyforname,
+ { "standby for name", "ceph.mdsbeason.standbyforname", FT_UINT_STRING ,
+ BASE_NONE, NULL, 0, NULL, HFILL }},
+ { &hf_auth,
+ { "Authentication Request", "ceph.auth.request", FT_NONE ,
+ BASE_NONE, NULL, 0, NULL, HFILL }},
+ { &hf_auth_protocol,
+ { "protocol", "ceph.auth.protocol", FT_UINT32,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_auth_authlen,
+ { "auth len", "ceph.auth.authlen", FT_UINT32,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_auth_authbytes,
+ { "auth bytes", "ceph.auth.authbytes", FT_BYTES,
+ BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_auth_monmapepoch,
+ { "monmap epoch", "ceph.auth.monmapepoch", FT_UINT32,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_authreply,
+ { "Authentication reply", "ceph.auth.reply", FT_NONE ,
+ BASE_NONE, NULL, 0, NULL, HFILL }},
+ { &hf_authreply_protocol,
+ { "protocol", "ceph.authreply.protocol", FT_UINT32 ,
+ BASE_DEC, NULL, 0, NULL, HFILL }},
+ { &hf_authreply_result,
+ { "result", "ceph.authreply.result", FT_INT32 ,
+ BASE_DEC, NULL, 0, NULL, HFILL }},
+ { &hf_authreply_globalid,
+ { "global_id", "ceph.authreply.global_id", FT_UINT64 ,
+ BASE_HEX, NULL, 0, NULL, HFILL }},
+ { &hf_authreply_authlen,
+ { "auth len", "ceph.authreply.authlen", FT_UINT32,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_authreply_authbytes,
+ { "auth bytes", "ceph.authreply.authbytes", FT_BYTES,
+ BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_authreply_msglen,
+ { "msg len", "ceph.authreply.msglen", FT_UINT32,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_authreply_msgstring,
+ { "msg bytes", "ceph.authreply.msgbytes", FT_STRINGZ,
+ BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_header,
+ { "Header", "ceph.header", FT_NONE,
+ BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_banner,
+ { "Banner", "ceph.connect.banner", FT_STRING,
+ BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_entity_type,
+ { "entity type", "ceph.entity.type", FT_UINT32,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_entity_num,
+ { "entity num", "ceph.entity.num", FT_UINT64,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_entity_addr,
+ { "Entity Addr", "ceph.entity.addr", FT_NONE,
+ BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_banner_magic,
+ { "Banner Magic", "ceph.connect.banner.magic", FT_STRING,
+ BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_banner_version,
+ { "Banner Version", "ceph.connect.banner.ver", FT_STRING,
+ BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_entity_erank,
+ { "erank", "ceph.entity.erank", FT_UINT32,
+ BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_entity_nonce,
+ { "nonce", "ceph.entity.nonce", FT_UINT32,
+ BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_sockaddr_in,
+ { "sockaddr_in", "ceph.sockaddr_in", FT_NONE,
+ BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_sin_family,
+ { "sin_family", "ceph.sin_family", FT_UINT16,
+ BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_sin_port,
+ { "sin_port", "ceph.sin_port", FT_UINT16,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_sin_addr,
+ { "ip addr", "ceph.addr", FT_IPv4,
+ BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_connect_features,
+ { "features", "ceph.connect.features", FT_UINT64,
+ BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_connect_host_type,
+ { "host_type", "ceph.connect.host_type", FT_UINT32,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_connect_tag,
+ { "tag", "ceph.connect.tag", FT_UINT8,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_connect_global_seq,
+ { "global_seq", "ceph.connect.global_seq", FT_UINT32,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_connect_connect_seq,
+ { "connect_seq", "ceph.connect.connect_seq", FT_UINT32,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_connect_protocol_version,
+ { "protocol_version", "ceph.connect.protocol_version", FT_UINT32,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_connect_authorizer_protocol,
+ { "authorizer_protocol", "ceph.connect.authorizer_protocol", FT_UINT32,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_connect_authorizer_len,
+ { "authorizer_len", "ceph.connect.authorizer_len", FT_UINT32,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_connect_flags,
+ { "flags", "ceph.connect.flags", FT_UINT8,
+ BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_connect_authentication_key,
+ { "authentication_key", "ceph.connect.authentication_key", FT_BYTES,
+ BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_hdr_tag,
+ { "tag", "ceph.tag", FT_UINT8,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_hdr_seq_ack,
+ { "ack seq", "ceph.ack.seq", FT_UINT64,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_hdr_seq,
+ { "seq", "ceph.seq", FT_UINT64,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_hdr_tid,
+ { "tid", "ceph.tid", FT_UINT64,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_hdr_type,
+ { "type", "ceph.type", FT_UINT16,
+ BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_hdr_priority,
+ { "priority", "ceph.priority", FT_UINT16,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_hdr_version,
+ { "version", "ceph.version", FT_UINT16,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_hdr_mon_protocol,
+ { "mon_protocol", "ceph.mon_protocol", FT_UINT16,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_hdr_osd_protocol,
+ { "osd_protocol", "ceph.osd_protocol", FT_UINT16,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_hdr_mds_protocol,
+ { "mds_protocol", "ceph.mds_protocol", FT_UINT16,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_hdr_client_protocol,
+ { "client_protocol", "ceph.client_protocol", FT_UINT16,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_hdr_front_len,
+ { "front_len", "ceph.front_len", FT_UINT32,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_hdr_middle_len,
+ { "middle_len", "ceph.middle_len", FT_UINT32,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_hdr_data_off,
+ { "data_off", "ceph.data_off", FT_UINT32,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_hdr_data_len,
+ { "data_len", "ceph.data_len", FT_UINT32,
+ BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_hdr_src,
+ { "src entity name", "ceph.src", FT_NONE,
+ BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_hdr_crc,
+ { "crc", "ceph.crc", FT_UINT32,
+ BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_footer,
+ { "Footer", "ceph.footer", FT_NONE,
+ BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_footer_front_crc,
+ { "front_crc", "ceph.footer.front_crc", FT_UINT32,
+ BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_footer_middle_crc,
+ { "middle_crc", "ceph.footer.middle_crc", FT_UINT32,
+ BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_footer_data_crc,
+ { "data_crc", "ceph.footer.data_crc", FT_UINT32,
+ BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_footer_sig,
+ { "sig", "ceph.footer.sig", FT_UINT64,
+ BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_footer_flags,
+ { "flags", "ceph.footer.flags", FT_UINT8,
+ BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ };
+ static gint *ett[] = {
+ &ett_ceph,
+ &ett_header,
+ &ett_banner,
+ &ett_entity_addr,
+ &ett_front,
+ &ett_footer,
+ &ett_sockaddr_in,
+ &ett_entity_name,
+ &ett_compat,
+ &ett_rocompat,
+ &ett_incompat,
+ };
+
+ /*
+ * Register the CEPH protocol
+ */
+ g_proto_ceph = proto_register_protocol ("CEPH Protocol", "CEPH", "ceph");
+ proto_register_field_array (g_proto_ceph, hf, array_length (hf));
+ proto_register_subtree_array (ett, array_length (ett));
+ register_dissector("ceph", dissect_ceph, g_proto_ceph);
+}
+
+
diff --git a/wireshark/ceph-alt/plugin.c b/wireshark/ceph-alt/plugin.c
new file mode 100644
index 00000000000..3c5ff04c0df
--- /dev/null
+++ b/wireshark/ceph-alt/plugin.c
@@ -0,0 +1,33 @@
+/*
+ * Do not modify this file. Changes will be overwritten.
+ *
+ * Generated automatically from ../../tools/make-dissector-reg.py.
+ */
+
+#include "config.h"
+
+#include <gmodule.h>
+
+#include "moduleinfo.h"
+
+/* plugins are DLLs */
+#define WS_BUILD_DLL
+#include "ws_symbol_export.h"
+
+#ifndef ENABLE_STATIC
+WS_DLL_PUBLIC_NOEXTERN const gchar version[] = VERSION;
+
+/* Start the functions we need for the plugin stuff */
+
+WS_DLL_PUBLIC_NOEXTERN void
+plugin_register (void)
+{
+ {extern void proto_register_ceph (void); proto_register_ceph ();}
+}
+
+WS_DLL_PUBLIC_NOEXTERN void
+plugin_reg_handoff(void)
+{
+ {extern void proto_reg_handoff_ceph (void); proto_reg_handoff_ceph ();}
+}
+#endif
diff --git a/wireshark/ceph-alt/plugin.rc.in b/wireshark/ceph-alt/plugin.rc.in
new file mode 100644
index 00000000000..b1e22ef3732
--- /dev/null
+++ b/wireshark/ceph-alt/plugin.rc.in
@@ -0,0 +1,34 @@
+#include "winver.h"
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION @RC_MODULE_VERSION@
+ PRODUCTVERSION @RC_VERSION@
+ FILEFLAGSMASK 0x0L
+#ifdef _DEBUG
+ FILEFLAGS VS_FF_PRERELEASE+VS_FF_DEBUG
+#else
+ FILEFLAGS VS_FF_PRERELEASE
+#endif
+ FILEOS VOS_NT_WINDOWS32
+ FILETYPE VFT_DLL
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "The Wireshark developer community, http://www.wireshark.org/\0"
+ VALUE "FileDescription", "@PACKAGE@ dissector\0"
+ VALUE "FileVersion", "@MODULE_VERSION@\0"
+ VALUE "InternalName", "@PACKAGE@ @MODULE_VERSION@\0"
+ VALUE "LegalCopyright", "Copyright © 1998 Gerald Combs <gerald@wireshark.org>, Gilbert Ramirez <gram@alumni.rice.edu> and others\0"
+ VALUE "OriginalFilename", "@PLUGIN_NAME@.dll\0"
+ VALUE "ProductName", "Wireshark\0"
+ VALUE "ProductVersion", "@VERSION@\0"
+ VALUE "Comments", "Build with @MSVC_VARIANT@\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/wireshark/ceph-alt/ws-1.10.0.patch b/wireshark/ceph-alt/ws-1.10.0.patch
new file mode 100644
index 00000000000..5b1be8fdd7e
--- /dev/null
+++ b/wireshark/ceph-alt/ws-1.10.0.patch
@@ -0,0 +1,95 @@
+diff -rupN wireshark-1.10.0.orig/configure wireshark-1.10.0.new/configure
+--- wireshark-1.10.0.orig/configure 2013-06-05 18:27:58.000000000 +0100
++++ wireshark-1.10.0.new/configure 2013-07-01 18:24:23.711203830 +0100
+@@ -33865,7 +33865,7 @@ rm -f confcache
+
+ ac_config_headers="$ac_config_headers config.h"
+
+-ac_config_files="$ac_config_files Makefile doxygen.cfg asn1/Makefile asn1/acp133/Makefile asn1/acse/Makefile asn1/ansi_map/Makefile asn1/ansi_tcap/Makefile asn1/c1222/Makefile asn1/camel/Makefile asn1/cdt/Makefile asn1/charging_ase/Makefile asn1/cmip/Makefile asn1/cmp/Makefile asn1/crmf/Makefile asn1/cms/Makefile asn1/credssp/Makefile asn1/dap/Makefile asn1/disp/Makefile asn1/dop/Makefile asn1/dsp/Makefile asn1/ess/Makefile asn1/ftam/Makefile asn1/gnm/Makefile asn1/goose/Makefile asn1/gprscdr/Makefile asn1/gsm_map/Makefile asn1/h225/Makefile asn1/h235/Makefile asn1/h245/Makefile asn1/h248/Makefile asn1/h282/Makefile asn1/h283/Makefile asn1/h323/Makefile asn1/h450/Makefile asn1/h450-ros/Makefile asn1/h460/Makefile asn1/h501/Makefile asn1/HI2Operations/Makefile asn1/hnbap/Makefile asn1/idmp/Makefile asn1/inap/Makefile asn1/isdn-sup/Makefile asn1/kerberos/Makefile asn1/lcsap/Makefile asn1/ldap/Makefile asn1/logotypecertextn/Makefile asn1/lpp/Makefile asn1/lppa/Makefile asn1/lppe/Makefile asn1/lte-rrc/Makefile asn1/m3ap/Makefile asn1/mms/Makefile asn1/mpeg-audio/Makefile asn1/mpeg-pes/Makefile asn1/nbap/Makefile asn1/ns_cert_exts/Makefile asn1/ocsp/Makefile asn1/p1/Makefile asn1/p22/Makefile asn1/p7/Makefile asn1/p772/Makefile asn1/pcap/Makefile asn1/pkcs1/Makefile asn1/pkcs12/Makefile asn1/pkinit/Makefile asn1/pkixac/Makefile asn1/pkix1explicit/Makefile asn1/pkix1implicit/Makefile asn1/pkixproxy/Makefile asn1/pkixqualified/Makefile asn1/pkixtsp/Makefile asn1/pres/Makefile asn1/q932/Makefile asn1/q932-ros/Makefile asn1/qsig/Makefile asn1/ranap/Makefile asn1/rnsap/Makefile asn1/ros/Makefile asn1/rrc/Makefile asn1/rrlp/Makefile asn1/rtse/Makefile asn1/rua/Makefile asn1/s1ap/Makefile asn1/sabp/Makefile asn1/sbc-ap/Makefile asn1/smrse/Makefile asn1/snmp/Makefile asn1/spnego/Makefile asn1/sv/Makefile asn1/t124/Makefile asn1/t125/Makefile asn1/t38/Makefile asn1/tcap/Makefile asn1/tetra/Makefile asn1/ulp/Makefile asn1/wlancertextn/Makefile asn1/x2ap/Makefile asn1/x509af/Makefile asn1/x509ce/Makefile asn1/x509if/Makefile asn1/x509sat/Makefile asn1/x721/Makefile doc/Makefile docbook/Makefile epan/Makefile epan/crypt/Makefile epan/doxygen.cfg epan/dfilter/Makefile epan/dissectors/Makefile epan/dissectors/dcerpc/Makefile epan/dissectors/pidl/Makefile epan/ftypes/Makefile epan/wmem/Makefile epan/wslua/Makefile epan/wspython/Makefile codecs/Makefile ui/Makefile ui/doxygen.cfg ui/gtk/Makefile ui/gtk/doxygen.cfg ui/cli/Makefile ui/qt/Makefile ui/qt/doxygen.cfg help/Makefile packaging/Makefile packaging/macosx/Info.plist packaging/macosx/Makefile packaging/macosx/osx-dmg.sh packaging/nsis/Makefile packaging/rpm/Makefile packaging/rpm/SPECS/Makefile packaging/rpm/SPECS/wireshark.spec packaging/svr4/Makefile packaging/svr4/checkinstall packaging/svr4/pkginfo plugins/Makefile plugins/asn1/Makefile plugins/docsis/Makefile plugins/ethercat/Makefile plugins/gryphon/Makefile plugins/irda/Makefile plugins/m2m/Makefile plugins/mate/Makefile plugins/opcua/Makefile plugins/profinet/Makefile plugins/stats_tree/Makefile plugins/unistim/Makefile plugins/wimax/Makefile plugins/wimaxasncp/Makefile plugins/wimaxmacphy/Makefile tools/Makefile tools/lemon/Makefile wiretap/Makefile wsutil/Makefile"
++ac_config_files="$ac_config_files Makefile doxygen.cfg asn1/Makefile asn1/acp133/Makefile asn1/acse/Makefile asn1/ansi_map/Makefile asn1/ansi_tcap/Makefile asn1/c1222/Makefile asn1/camel/Makefile asn1/cdt/Makefile asn1/charging_ase/Makefile asn1/cmip/Makefile asn1/cmp/Makefile asn1/crmf/Makefile asn1/cms/Makefile asn1/credssp/Makefile asn1/dap/Makefile asn1/disp/Makefile asn1/dop/Makefile asn1/dsp/Makefile asn1/ess/Makefile asn1/ftam/Makefile asn1/gnm/Makefile asn1/goose/Makefile asn1/gprscdr/Makefile asn1/gsm_map/Makefile asn1/h225/Makefile asn1/h235/Makefile asn1/h245/Makefile asn1/h248/Makefile asn1/h282/Makefile asn1/h283/Makefile asn1/h323/Makefile asn1/h450/Makefile asn1/h450-ros/Makefile asn1/h460/Makefile asn1/h501/Makefile asn1/HI2Operations/Makefile asn1/hnbap/Makefile asn1/idmp/Makefile asn1/inap/Makefile asn1/isdn-sup/Makefile asn1/kerberos/Makefile asn1/lcsap/Makefile asn1/ldap/Makefile asn1/logotypecertextn/Makefile asn1/lpp/Makefile asn1/lppa/Makefile asn1/lppe/Makefile asn1/lte-rrc/Makefile asn1/m3ap/Makefile asn1/mms/Makefile asn1/mpeg-audio/Makefile asn1/mpeg-pes/Makefile asn1/nbap/Makefile asn1/ns_cert_exts/Makefile asn1/ocsp/Makefile asn1/p1/Makefile asn1/p22/Makefile asn1/p7/Makefile asn1/p772/Makefile asn1/pcap/Makefile asn1/pkcs1/Makefile asn1/pkcs12/Makefile asn1/pkinit/Makefile asn1/pkixac/Makefile asn1/pkix1explicit/Makefile asn1/pkix1implicit/Makefile asn1/pkixproxy/Makefile asn1/pkixqualified/Makefile asn1/pkixtsp/Makefile asn1/pres/Makefile asn1/q932/Makefile asn1/q932-ros/Makefile asn1/qsig/Makefile asn1/ranap/Makefile asn1/rnsap/Makefile asn1/ros/Makefile asn1/rrc/Makefile asn1/rrlp/Makefile asn1/rtse/Makefile asn1/rua/Makefile asn1/s1ap/Makefile asn1/sabp/Makefile asn1/sbc-ap/Makefile asn1/smrse/Makefile asn1/snmp/Makefile asn1/spnego/Makefile asn1/sv/Makefile asn1/t124/Makefile asn1/t125/Makefile asn1/t38/Makefile asn1/tcap/Makefile asn1/tetra/Makefile asn1/ulp/Makefile asn1/wlancertextn/Makefile asn1/x2ap/Makefile asn1/x509af/Makefile asn1/x509ce/Makefile asn1/x509if/Makefile asn1/x509sat/Makefile asn1/x721/Makefile doc/Makefile docbook/Makefile epan/Makefile epan/crypt/Makefile epan/doxygen.cfg epan/dfilter/Makefile epan/dissectors/Makefile epan/dissectors/dcerpc/Makefile epan/dissectors/pidl/Makefile epan/ftypes/Makefile epan/wmem/Makefile epan/wslua/Makefile epan/wspython/Makefile codecs/Makefile ui/Makefile ui/doxygen.cfg ui/gtk/Makefile ui/gtk/doxygen.cfg ui/cli/Makefile ui/qt/Makefile ui/qt/doxygen.cfg help/Makefile packaging/Makefile packaging/macosx/Info.plist packaging/macosx/Makefile packaging/macosx/osx-dmg.sh packaging/nsis/Makefile packaging/rpm/Makefile packaging/rpm/SPECS/Makefile packaging/rpm/SPECS/wireshark.spec packaging/svr4/Makefile packaging/svr4/checkinstall packaging/svr4/pkginfo plugins/Makefile plugins/asn1/Makefile plugins/ceph plugins/docsis/Makefile plugins/ethercat/Makefile plugins/gryphon/Makefile plugins/irda/Makefile plugins/m2m/Makefile plugins/mate/Makefile plugins/opcua/Makefile plugins/profinet/Makefile plugins/stats_tree/Makefile plugins/unistim/Makefile plugins/wimax/Makefile plugins/wimaxasncp/Makefile plugins/wimaxmacphy/Makefile tools/Makefile tools/lemon/Makefile wiretap/Makefile wsutil/Makefile"
+
+ cat >confcache <<\_ACEOF
+ # This file is a shell script that caches the results of configure
+@@ -35221,6 +35221,7 @@ do
+ "packaging/svr4/pkginfo") CONFIG_FILES="$CONFIG_FILES packaging/svr4/pkginfo" ;;
+ "plugins/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/Makefile" ;;
+ "plugins/asn1/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/asn1/Makefile" ;;
++ "plugins/ceph/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/ceph/Makefile" ;;
+ "plugins/docsis/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/docsis/Makefile" ;;
+ "plugins/ethercat/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/ethercat/Makefile" ;;
+ "plugins/gryphon/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/gryphon/Makefile" ;;
+diff -rupN wireshark-1.10.0.orig/configure.ac wireshark-1.10.0.new/configure.ac
+--- wireshark-1.10.0.orig/configure.ac 2013-06-05 18:27:26.000000000 +0100
++++ wireshark-1.10.0.new/configure.ac 2013-07-01 18:24:42.191203182 +0100
+@@ -2449,6 +2449,7 @@ AC_OUTPUT(
+ packaging/svr4/pkginfo
+ plugins/Makefile
+ plugins/asn1/Makefile
++ plugins/ceph/Makefile
+ plugins/docsis/Makefile
+ plugins/ethercat/Makefile
+ plugins/gryphon/Makefile
+diff -rupN wireshark-1.10.0.orig/epan/Makefile.am wireshark-1.10.0.new/epan/Makefile.am
+--- wireshark-1.10.0.orig/epan/Makefile.am 2013-06-04 00:37:27.000000000 +0100
++++ wireshark-1.10.0.new/epan/Makefile.am 2013-07-01 18:27:34.099197136 +0100
+@@ -197,6 +197,7 @@ if ENABLE_STATIC
+ -include ../plugins/Custom.make
+ plugin_src = \
+ ../plugins/asn1/packet-asn1.c \
++ ../plugins/ceph/packet-ceph.c \
+ ../plugins/docsis/packet-bintrngreq.c \
+ ../plugins/docsis/packet-bpkmattr.c \
+ ../plugins/docsis/packet-bpkmreq.c \
+diff -rupN wireshark-1.10.0.orig/packaging/nsis/Makefile.nmake wireshark-1.10.0.new/packaging/nsis/Makefile.nmake
+--- wireshark-1.10.0.orig/packaging/nsis/Makefile.nmake 2013-04-23 18:42:17.000000000 +0100
++++ wireshark-1.10.0.new/packaging/nsis/Makefile.nmake 2013-07-01 18:25:49.039200833 +0100
+@@ -46,6 +46,7 @@ HELP=$(STAGING_DIR)/help/capture_filters
+
+ PLUGINS= \
+ ../../plugins/asn1/asn1.dll \
++ ../../plugins/asn1/ceph.dll \
+ ../../plugins/docsis/docsis.dll \
+ ../../plugins/ethercat/ethercat.dll \
+ ../../plugins/gryphon/gryphon.dll \
+diff -rupN wireshark-1.10.0.orig/packaging/nsis/wireshark.nsi wireshark-1.10.0.new/packaging/nsis/wireshark.nsi
+--- wireshark-1.10.0.orig/packaging/nsis/wireshark.nsi 2013-05-07 00:45:35.000000000 +0100
++++ wireshark-1.10.0.new/packaging/nsis/wireshark.nsi 2013-07-01 18:26:27.067199497 +0100
+@@ -844,6 +844,7 @@ Section "Dissector Plugins" SecPlugins
+ ;-------------------------------------------
+ SetOutPath '$INSTDIR\plugins\${VERSION}'
+ File "${STAGING_DIR}\plugins\${VERSION}\asn1.dll"
++File "${STAGING_DIR}\plugins\${VERSION}\ceph.dll"
+ File "${STAGING_DIR}\plugins\${VERSION}\docsis.dll"
+ File "${STAGING_DIR}\plugins\${VERSION}\ethercat.dll"
+ File "${STAGING_DIR}\plugins\${VERSION}\gryphon.dll"
+diff -rupN wireshark-1.10.0.orig/plugins/Makefile.am wireshark-1.10.0.new/plugins/Makefile.am
+--- wireshark-1.10.0.orig/plugins/Makefile.am 2013-04-22 19:04:14.000000000 +0100
++++ wireshark-1.10.0.new/plugins/Makefile.am 2013-07-01 18:21:48.731209276 +0100
+@@ -25,6 +25,7 @@
+
+ SUBDIRS = $(_CUSTOM_SUBDIRS_) \
+ asn1 \
++ ceph \
+ docsis \
+ ethercat \
+ gryphon \
+diff -rupN wireshark-1.10.0.orig/plugins/Makefile.nmake wireshark-1.10.0.new/plugins/Makefile.nmake
+--- wireshark-1.10.0.orig/plugins/Makefile.nmake 2013-04-22 19:04:14.000000000 +0100
++++ wireshark-1.10.0.new/plugins/Makefile.nmake 2013-07-01 18:22:08.647208577 +0100
+@@ -8,6 +8,7 @@ include ..\config.nmake
+
+ PLUGIN_LIST = \
+ asn1 \
++ ceph \
+ docsis \
+ ethercat \
+ gryphon \
+@@ -20,7 +21,7 @@ PLUGIN_LIST = \
+ unistim \
+ wimax \
+ wimaxasncp \
+- wimaxmacphy
++ wimaxmacphy
+
+
+ all: