aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--debian/libwireshark0.symbols2
-rw-r--r--doc/README.dissector39
-rw-r--r--epan/packet.c4
-rw-r--r--epan/proto.c126
-rw-r--r--epan/proto.h24
5 files changed, 183 insertions, 12 deletions
diff --git a/debian/libwireshark0.symbols b/debian/libwireshark0.symbols
index 92ac448880..bf0edfc64a 100644
--- a/debian/libwireshark0.symbols
+++ b/debian/libwireshark0.symbols
@@ -1017,6 +1017,7 @@ libwireshark.so.0 libwireshark0 #MINVER#
proto_is_protocol_enabled@Base 1.9.1
proto_is_protocol_enabled_by_default@Base 2.3.0
proto_is_frame_protocol@Base 1.99.1
+ proto_is_pino@Base 2.3.0
proto_item_add_subtree@Base 1.9.1
proto_item_append_text@Base 1.9.1
proto_item_fill_label@Base 1.9.1
@@ -1034,6 +1035,7 @@ libwireshark.so.0 libwireshark0 #MINVER#
proto_register_fields_section@Base 1.12.0~rc1
proto_register_prefix@Base 1.9.1
proto_register_protocol@Base 1.9.1
+ proto_register_protocol_in_name_only@Base 2.3.0
proto_register_subtree_array@Base 1.9.1
proto_registrar_dump_fieldcount@Base 2.0.0
proto_registrar_dump_fields@Base 1.9.1
diff --git a/doc/README.dissector b/doc/README.dissector
index 911fd78889..39600c515e 100644
--- a/doc/README.dissector
+++ b/doc/README.dissector
@@ -3345,7 +3345,32 @@ The arguments to udp_dissect_pdus are:
a void pointer to user data that is passed to the length-determining
routine, and the dissector routine referenced in the previous parameter.
-2.9 Creating Decode As functionality.
+2.9 PINOs (Protocols in name only)
+
+For the typical dissector there is a 1-1 relationship between it and it's
+protocol. However, there are times when a protocol needs multiple "names"
+because it has multiple dissection functions going into the same dissector
+table. The muliple names removes confusion when picking dissection through
+Decode As functionality.
+
+Once the "main" protocol name has been created through proto_register_protocol,
+additional "pinos" can be created with proto_register_protocol_in_name_only.
+These pinos have all of the naming conventions of a protocol, but are stored
+separately as to remove confusion from real protocols. "pinos" the main
+protocol's properties for things like enable/disable. i.e. If the "main"
+protocol has been disabled, all of its pinos will be disabled as well.
+Pinos should not have any fields registered with them or heuristic tables
+associated with them.
+
+Another use case for pinos is when a protocol contains a TLV design and it
+wants to create a dissector table to handle dissection of the "V". Dissector
+tables require a "protocol", but the dissection functions for that table
+typically aren't a protocol. In this case proto_register_protocol_in_name_only
+creates the necessary placeholder for the dissector table. In addition, because
+a dissector table exists, "V"s of the TLVs can be dissected outside of the
+original dissector file.
+
+2.10 Creating Decode As functionality.
While the Decode As functionality is available through the GUI, the underlying
functionality is controlled by dissectors themselves. To create Decode As
@@ -3381,7 +3406,11 @@ to the dissector table through Decode As GUI functionality. For dissector
tables that are an integer or string type, the provided "default" handling
functions shown in the example should suffice.
-2.10 ptvcursors.
+All entries into a dissector table that use Decode As must have a unique
+protocol ID. If a protocol wants multiple entries into a dissector table,
+a pino should be used (see section 2.9)
+
+2.11 ptvcursors.
The ptvcursor API allows a simpler approach to writing dissectors for
simple protocols. The ptvcursor API works best for protocols whose fields
@@ -3414,7 +3443,7 @@ To use the ptvcursor API, include the "ptvcursor.h" file. The PGM dissector
is an example of how to use it. You don't need to look at it as a guide;
instead, the API description here should be good enough.
-2.10.1 ptvcursor API.
+2.11.1 ptvcursor API.
ptvcursor_t*
ptvcursor_new(proto_tree* tree, tvbuff_t* tvb, gint offset)
@@ -3470,7 +3499,7 @@ If the length is unknown, length may be defined as SUBTREE_UNDEFINED_LENGTH.
In this case, at the next pop, the item length will be equal to the advancement
of the cursor since the creation of the subtree.
-2.9.2 Miscellaneous functions.
+2.11.2 Miscellaneous functions.
tvbuff_t*
ptvcursor_tvbuff(ptvcursor_t* ptvc)
@@ -3493,7 +3522,7 @@ ptvcursor_set_subtree(ptvcursor_t* ptvc, proto_item* it, gint ett_subtree);
Creates a subtree and adds it to the cursor as the working tree but does
not save the old working tree.
-2.11 Optimizations
+2.12 Optimizations
A protocol dissector may be called in 2 different ways - with, or
without a non-null "tree" argument.
diff --git a/epan/packet.c b/epan/packet.c
index 5a0b2e115a..67ebb65f4b 100644
--- a/epan/packet.c
+++ b/epan/packet.c
@@ -642,7 +642,7 @@ call_dissector_through_handle(dissector_handle_t handle, tvbuff_t *tvb,
saved_proto = pinfo->current_proto;
- if (handle->protocol != NULL) {
+ if ((handle->protocol != NULL) && (!proto_is_pino(handle->protocol))) {
pinfo->current_proto =
proto_get_protocol_short_name(handle->protocol);
}
@@ -702,7 +702,7 @@ call_dissector_work(dissector_handle_t handle, tvbuff_t *tvb, packet_info *pinfo
*/
pinfo->saved_can_desegment = saved_can_desegment;
pinfo->can_desegment = saved_can_desegment-(saved_can_desegment>0);
- if (handle->protocol != NULL) {
+ if ((handle->protocol != NULL) && (!proto_is_pino(handle->protocol))) {
pinfo->current_proto =
proto_get_protocol_short_name(handle->protocol);
diff --git a/epan/proto.c b/epan/proto.c
index ceb74c6f1e..d42ac90a7a 100644
--- a/epan/proto.c
+++ b/epan/proto.c
@@ -315,11 +315,16 @@ struct _protocol {
gboolean is_enabled; /* TRUE if protocol is enabled */
gboolean enabled_by_default; /* TRUE if protocol is enabled by default */
gboolean can_toggle; /* TRUE if is_enabled can be changed */
+ int parent_proto_id; /* Used to identify "pino"s (Protocol In Name Only).
+ For dissectors that need a protocol name so they
+ can be added to a dissector table, but use the
+ parent_proto_id for things like enable/disable */
GList *heur_list; /* Heuristic dissectors associated with this protocol */
};
/* List of all protocols */
static GList *protocols = NULL;
+static GList *pino_protocols = NULL;
/* Deregistered fields */
static GPtrArray *deregistered_fields = NULL;
@@ -568,6 +573,9 @@ proto_init(void (register_all_protocols_func)(register_cb cb, gpointer client_da
void
proto_cleanup(void)
{
+ protocol_t *protocol;
+ header_field_info *hfinfo;
+
/* Free the abbrev/ID hash table */
if (gpa_name_map) {
g_hash_table_destroy(gpa_name_map);
@@ -577,8 +585,7 @@ proto_cleanup(void)
last_field_name = NULL;
while (protocols) {
- protocol_t *protocol = (protocol_t *)protocols->data;
- header_field_info *hfinfo;
+ protocol = (protocol_t *)protocols->data;
PROTO_REGISTRAR_GET_NTH(protocol->proto_id, hfinfo);
DISSECTOR_ASSERT(protocol->proto_id == hfinfo->id);
@@ -591,6 +598,17 @@ proto_cleanup(void)
g_free(protocol);
}
+ while (pino_protocols) {
+ protocol = (protocol_t *)pino_protocols->data;
+ PROTO_REGISTRAR_GET_NTH(protocol->proto_id, hfinfo);
+ DISSECTOR_ASSERT(protocol->proto_id == hfinfo->id);
+ DISSECTOR_ASSERT(protocol->fields == NULL); //helpers should not have any registered fields
+ g_slice_free(header_field_info, hfinfo);
+ DISSECTOR_ASSERT(protocol->heur_list == NULL); //helpers should not have a heuristic list
+ pino_protocols = g_list_remove(pino_protocols, protocol);
+ g_free(protocol);
+ }
+
if (proto_names) {
g_hash_table_destroy(proto_names);
proto_names = NULL;
@@ -5821,6 +5839,7 @@ proto_register_protocol(const char *name, const char *short_name,
protocol->is_enabled = TRUE; /* protocol is enabled by default */
protocol->enabled_by_default = TRUE; /* see previous comment */
protocol->can_toggle = TRUE;
+ protocol->parent_proto_id = -1;
protocol->heur_list = NULL;
/* list will be sorted later by name, when all protocols completed registering */
protocols = g_list_prepend(protocols, protocol);
@@ -5844,6 +5863,77 @@ proto_register_protocol(const char *name, const char *short_name,
return proto_id;
}
+int
+proto_register_protocol_in_name_only(const char *name, const char *short_name, const char *filter_name, int parent_proto, enum ftenum field_type)
+{
+ protocol_t *protocol;
+ header_field_info *hfinfo;
+ guint i;
+ gchar c;
+ gboolean found_invalid = FALSE;
+
+ /*
+ * Helper protocols don't need the strict rules as a "regular" protocol
+ * Just register it in a list and make a hf_ field from it
+ */
+ if ((field_type != FT_PROTOCOL) && (field_type != FT_BYTES)) {
+ g_error("Pino \"%s\" must be of type FT_PROTOCOL or FT_BYTES.", name);
+ }
+
+ if (parent_proto < 0) {
+ g_error("Must have a valid parent protocol for helper protocol \"%s\"!"
+ " This might be caused by an inappropriate plugin or a development error.", name);
+ }
+
+ for (i = 0; filter_name[i]; i++) {
+ c = filter_name[i];
+ if (!(g_ascii_islower(c) || g_ascii_isdigit(c) || c == '-' || c == '_' || c == '.')) {
+ found_invalid = TRUE;
+ }
+ }
+ if (found_invalid) {
+ g_error("Protocol filter name \"%s\" has one or more invalid characters."
+ " Allowed are lower characters, digits, '-', '_' and '.'."
+ " This might be caused by an inappropriate plugin or a development error.", filter_name);
+ }
+
+ /* Add this protocol to the list of helper protocols (just so it can be properly freed) */
+ protocol = g_new(protocol_t, 1);
+ protocol->name = name;
+ protocol->short_name = short_name;
+ protocol->filter_name = filter_name;
+ protocol->fields = NULL;
+
+ /* Enabling and toggling is really determined by parent protocol,
+ but provide default values here */
+ protocol->is_enabled = TRUE;
+ protocol->enabled_by_default = TRUE;
+ protocol->can_toggle = TRUE;
+
+ protocol->parent_proto_id = parent_proto;
+ protocol->heur_list = NULL;
+ /* list will be sorted later by name, when all protocols completed registering */
+ pino_protocols = g_list_prepend(pino_protocols, protocol);
+
+ /* Here we allocate a new header_field_info struct */
+ hfinfo = g_slice_new(header_field_info);
+ hfinfo->name = name;
+ hfinfo->abbrev = filter_name;
+ hfinfo->type = field_type;
+ hfinfo->display = BASE_NONE;
+ if (field_type == FT_BYTES) {
+ hfinfo->display |= (BASE_NO_DISPLAY_VALUE|BASE_PROTOCOL_INFO);
+ }
+ hfinfo->strings = protocol;
+ hfinfo->bitmask = 0;
+ hfinfo->ref_type = HF_REF_TYPE_NONE;
+ hfinfo->blurb = NULL;
+ hfinfo->parent = -1; /* this field differentiates protos and fields */
+
+ protocol->proto_id = proto_register_field_init(hfinfo, hfinfo->parent);
+ return protocol->proto_id;
+}
+
gboolean
proto_deregister_protocol(const char *short_name)
{
@@ -5972,7 +6062,9 @@ find_protocol_by_id(const int proto_id)
return NULL;
PROTO_REGISTRAR_GET_NTH(proto_id, hfinfo);
- DISSECTOR_ASSERT_FIELD_TYPE(hfinfo, FT_PROTOCOL);
+ if (hfinfo->type != FT_PROTOCOL) {
+ DISSECTOR_ASSERT(hfinfo->display & BASE_PROTOCOL_INFO);
+ }
return (protocol_t *)hfinfo->strings;
}
@@ -6150,16 +6242,29 @@ proto_is_frame_protocol(const wmem_list_t *layers, const char* proto_name)
return FALSE;
}
+gboolean
+proto_is_pino(const protocol_t *protocol)
+{
+ return (protocol->parent_proto_id != -1);
+}
gboolean
proto_is_protocol_enabled(const protocol_t *protocol)
{
+ //parent protocol determines enable/disable for helper dissectors
+ if (proto_is_pino(protocol))
+ return proto_is_protocol_enabled(find_protocol_by_id(protocol->parent_proto_id));
+
return protocol->is_enabled;
}
gboolean
proto_is_protocol_enabled_by_default(const protocol_t *protocol)
{
+ //parent protocol determines enable/disable for helper dissectors
+ if (proto_is_pino(protocol))
+ return proto_is_protocol_enabled_by_default(find_protocol_by_id(protocol->parent_proto_id));
+
return protocol->enabled_by_default;
}
@@ -6169,6 +6274,10 @@ proto_can_toggle_protocol(const int proto_id)
protocol_t *protocol;
protocol = find_protocol_by_id(proto_id);
+ //parent protocol determines toggling for helper dissectors
+ if (proto_is_pino(protocol))
+ return proto_can_toggle_protocol(protocol->parent_proto_id);
+
return protocol->can_toggle;
}
@@ -6179,6 +6288,7 @@ proto_disable_by_default(const int proto_id)
protocol = find_protocol_by_id(proto_id);
DISSECTOR_ASSERT(protocol->can_toggle);
+ DISSECTOR_ASSERT(proto_is_pino(protocol) == FALSE);
protocol->is_enabled = FALSE;
protocol->enabled_by_default = FALSE;
}
@@ -6190,6 +6300,7 @@ proto_set_decoding(const int proto_id, const gboolean enabled)
protocol = find_protocol_by_id(proto_id);
DISSECTOR_ASSERT(protocol->can_toggle);
+ DISSECTOR_ASSERT(proto_is_pino(protocol) == FALSE);
protocol->is_enabled = enabled;
}
@@ -6577,6 +6688,12 @@ tmp_fld_check_assert(header_field_info *hfinfo)
break;
//fallthrough
+ case FT_BYTES:
+ //allowed to support string if its a protocol (for pinos)
+ if (hfinfo->display & BASE_PROTOCOL_INFO)
+ break;
+
+ //fallthrough
default:
g_error("Field '%s' (%s) has a 'strings' value but is of type %s"
" (which is not allowed to have strings)\n",
@@ -6790,7 +6907,8 @@ tmp_fld_check_assert(header_field_info *hfinfo)
g_error("Field '%s' (%s) is an %s but has a bitmask\n",
hfinfo->name, hfinfo->abbrev,
ftype_name(hfinfo->type));
- if (hfinfo->strings != NULL)
+ //allowed to support string if its a protocol (for pinos)
+ if ((hfinfo->strings != NULL) && (!(hfinfo->display & BASE_PROTOCOL_INFO)))
g_error("Field '%s' (%s) is an %s but has a strings value\n",
hfinfo->name, hfinfo->abbrev,
ftype_name(hfinfo->type));
diff --git a/epan/proto.h b/epan/proto.h
index ed4b6971e6..80756281c5 100644
--- a/epan/proto.h
+++ b/epan/proto.h
@@ -554,6 +554,7 @@ typedef enum {
#define BASE_UNIT_STRING 0x1000 /**< Add unit text to the field value */
#define BASE_NO_DISPLAY_VALUE 0x2000 /**< Just display the field name with no value. Intended for
byte arrays or header fields above a subtree */
+#define BASE_PROTOCOL_INFO 0x4000 /**< protocol_t in [FIELDCONVERT]. Internal use only. */
/** BASE_ values that cause the field value to be displayed twice */
#define IS_BASE_DUAL(b) ((b)==BASE_DEC_HEX||(b)==BASE_HEX_DEC)
@@ -582,7 +583,7 @@ struct _header_field_info {
int display; /**< [FIELDDISPLAY] one of BASE_, or field bit-width if FT_BOOLEAN and non-zero bitmask */
const void *strings; /**< [FIELDCONVERT] value_string, val64_string, range_string or true_false_string,
typically converted by VALS(), RVALS() or TFS().
- If this is an FT_PROTOCOL then it points to the
+ If this is an FT_PROTOCOL or BASE_PROTOCOL_INFO then it points to the
associated protocol_t structure */
guint64 bitmask; /**< [BITMASK] bitmask of interesting bits */
const char *blurb; /**< [FIELDDESCR] Brief description of field */
@@ -2096,6 +2097,23 @@ proto_item_fill_label(field_info *fi, gchar *label_str);
WS_DLL_PUBLIC int
proto_register_protocol(const char *name, const char *short_name, const char *filter_name);
+/** Register a "helper" protocol (pino - protocol in name only).
+ This is for dissectors that need distinguishing names and don't need the other
+ features (like enable/disable). One use case is a protocol with multiple dissection
+ functions in a single dissector table needing unique "dissector names" to remove
+ confusion with Decode As dialog. Another use case is for a dissector table set
+ up to handle TLVs within a single protocol (and allow "external" TLVs being
+ registered through the dissector table).
+ @param name the full name of the new protocol
+ @param short_name abbreviated name of the new protocol
+ @param filter_name protocol name used for a display filter string
+ @param parent_proto the "real" protocol for the helper. The parent decides enable/disable
+ @param field_type FT_PROTOCOL or FT_BYTES. Allows removal of "protocol highlighting" (FT_BYTES)
+ if pino is part of TLV.
+ @return the new protocol handle */
+WS_DLL_PUBLIC int
+proto_register_protocol_in_name_only(const char *name, const char *short_name, const char *filter_name, int parent_proto, enum ftenum field_type);
+
/** Deregister a protocol.
@param short_name abbreviated name of the protocol
@return TRUE if protocol is removed */
@@ -2256,6 +2274,10 @@ WS_DLL_PUBLIC gboolean proto_is_protocol_enabled(const protocol_t *protocol);
@return TRUE if decoding is enabled by default, FALSE if not */
WS_DLL_PUBLIC gboolean proto_is_protocol_enabled_by_default(const protocol_t *protocol);
+/** Is this a protocol in name only (i.e. not a real one)?
+ @return TRUE if helper, FALSE if not */
+WS_DLL_PUBLIC gboolean proto_is_pino(const protocol_t *protocol);
+
/** Get a protocol's filter name by its item number.
@param proto_id protocol id (0-indexed)
@return its filter name. */