Add interface for "pinos" (Protocols in name only)

This is for dissectors that need distinguishing names either for registering
multiple dissection functions in a single dissector table or for "internal"
dissectors whose just need a name associated with the dissection function.
Features like enable/disable are handled by the "parent" protocol.
This avoids clutter in the "official" protocol list.

Change-Id: I69e7d27d332ae85286f254e95e8d79920da7a9e2
Reviewed-on: https://code.wireshark.org/review/19464
Petri-Dish: Michael Mann <mmann78@netscape.net>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Michael Mann <mmann78@netscape.net>
This commit is contained in:
Michael Mann 2016-12-29 19:41:33 -05:00
parent 6a5fcc5a38
commit a0be5ad6f1
5 changed files with 183 additions and 12 deletions

View File

@ -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

View File

@ -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.

View File

@ -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);

View File

@ -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;
}
@ -6576,6 +6687,12 @@ tmp_fld_check_assert(header_field_info *hfinfo)
if (hfinfo->display & BASE_UNIT_STRING)
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"
@ -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));

View File

@ -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. */