diff options
author | Sage Weil <sage@inktank.com> | 2013-08-15 10:50:19 -0700 |
---|---|---|
committer | Sage Weil <sage@inktank.com> | 2013-08-15 10:50:19 -0700 |
commit | 4a437b84156d3b911d0ab6e444b9021afcab10a6 (patch) | |
tree | 248ebe2ce266346bb848f1f9ea42a11bb0ae348b | |
parent | ab60b5dac276bed091582764128584c80b00dfbb (diff) | |
parent | 972d22e2453c133eecc34390fbfe229058754537 (diff) | |
download | ceph-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.am | 126 | ||||
-rw-r--r-- | wireshark/ceph-alt/Makefile.common | 31 | ||||
-rw-r--r-- | wireshark/ceph-alt/Makefile.nmake | 100 | ||||
-rw-r--r-- | wireshark/ceph-alt/README.txt | 49 | ||||
-rw-r--r-- | wireshark/ceph-alt/moduleinfo.h | 16 | ||||
-rw-r--r-- | wireshark/ceph-alt/moduleinfo.nmake | 28 | ||||
-rw-r--r-- | wireshark/ceph-alt/packet-ceph.c | 2661 | ||||
-rw-r--r-- | wireshark/ceph-alt/plugin.c | 33 | ||||
-rw-r--r-- | wireshark/ceph-alt/plugin.rc.in | 34 | ||||
-rw-r--r-- | wireshark/ceph-alt/ws-1.10.0.patch | 95 |
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: |