forked from osmocom/wireshark
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:
parent
6a5fcc5a38
commit
a0be5ad6f1
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
126
epan/proto.c
126
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;
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
|
24
epan/proto.h
24
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. */
|
||||
|
|
Loading…
Reference in New Issue