forked from osmocom/wireshark
From Alexey Neyman :
This patch implements a function for dissecting bitfields with better control over the resulting representation than the existing proto_tree_add_bitmask() routine. This function will be used by reworked IPMI/ATCA dissector (bug 2048). The function is described in README.developer. In short, the differences are as follows: - The new function does not require a hf_XXX field for the whole bitmask. When the bitmask includes several unrelated fields, such hf_XXX field does not make sense. - The new function allows better control over the way the sub-item descriptions are added to the top-level item. For example, proto_tree_add_bitmask() function does not add non-enumerated integers, does not use true_false_string to display boolean. - The new function allows to specify "fallback" text for the top-level item which is used if no items were added to the top-level item. svn path=/trunk/; revision=25920
This commit is contained in:
parent
774f288597
commit
da85c3dfab
|
@ -2018,6 +2018,11 @@ protocol or field labels to the proto_tree:
|
||||||
proto_tree_add_bitmask(tree, tvb, start, header, ett, **fields,
|
proto_tree_add_bitmask(tree, tvb, start, header, ett, **fields,
|
||||||
little_endian);
|
little_endian);
|
||||||
|
|
||||||
|
proto_item *
|
||||||
|
proto_tree_add_bitmask_text(proto_tree *tree, tvbuff_t *tvb,
|
||||||
|
guint offset, guint len, const char *name, const char *fallback,
|
||||||
|
gint ett, const int **fields, gboolean little_endian, int flags);
|
||||||
|
|
||||||
The 'tree' argument is the tree to which the item is to be added. The
|
The 'tree' argument is the tree to which the item is to be added. The
|
||||||
'tvb' argument is the tvbuff from which the item's value is being
|
'tvb' argument is the tvbuff from which the item's value is being
|
||||||
extracted; the 'start' argument is the offset from the beginning of that
|
extracted; the 'start' argument is the offset from the beginning of that
|
||||||
|
@ -2318,8 +2323,8 @@ This is like proto_tree_add_text(), but takes, as the last argument, a
|
||||||
variable-length list of arguments to add a text item to the protocol
|
variable-length list of arguments to add a text item to the protocol
|
||||||
tree.
|
tree.
|
||||||
|
|
||||||
proto_tree_add_bitmask()
|
proto_tree_add_bitmask() and proto_tree_add_bitmask_text()
|
||||||
------------------------
|
----------------------------------------------------------
|
||||||
This function provides an easy to use and convenient helper function
|
This function provides an easy to use and convenient helper function
|
||||||
to manage many types of common bitmasks that occur in protocols.
|
to manage many types of common bitmasks that occur in protocols.
|
||||||
|
|
||||||
|
@ -2430,6 +2435,24 @@ filter is then possible:
|
||||||
|
|
||||||
tr.rif_ring eq 0x013
|
tr.rif_ring eq 0x013
|
||||||
|
|
||||||
|
The proto_tree_add_bitmask_text() function is an extended version of
|
||||||
|
the proto_tree_add_bitmask() function. In addition, it allows to:
|
||||||
|
- Provide a leading text (e.g. "Flags: ") that will appear before
|
||||||
|
the comma-separated list of field values
|
||||||
|
- Provide a fallback text (e.g. "None") that will be appended if
|
||||||
|
no fields warranted a change to the top-level title.
|
||||||
|
- Using flags, specify which fields will affect the top-level title.
|
||||||
|
|
||||||
|
There are the following flags defined:
|
||||||
|
|
||||||
|
BMT_NO_APPEND - the title is taken "as-is" from the 'name' argument.
|
||||||
|
BMT_NO_INT - only boolean flags are added to the title.
|
||||||
|
BMT_NO_FALSE - boolean flags are only added to the title if they are set.
|
||||||
|
BMT_NO_TFS - only add flag name to the title, do not use true_false_string
|
||||||
|
|
||||||
|
The proto_tree_add_bitmask() behavior can be obtained by providing
|
||||||
|
both 'name' and 'fallback' arguments as NULL, and a flags of
|
||||||
|
(BMT_NO_FALSE|BMT_NO_TFS).
|
||||||
|
|
||||||
1.7 Utility routines.
|
1.7 Utility routines.
|
||||||
|
|
||||||
|
|
229
epan/proto.c
229
epan/proto.c
|
@ -202,6 +202,9 @@ static void
|
||||||
proto_tree_set_uint64(field_info *fi, guint64 value);
|
proto_tree_set_uint64(field_info *fi, guint64 value);
|
||||||
static void
|
static void
|
||||||
proto_tree_set_uint64_tvb(field_info *fi, tvbuff_t *tvb, gint start, guint length, gboolean little_endian);
|
proto_tree_set_uint64_tvb(field_info *fi, tvbuff_t *tvb, gint start, guint length, gboolean little_endian);
|
||||||
|
static gboolean
|
||||||
|
proto_item_add_bitmask_tree(proto_item *item, tvbuff_t *tvb, int offset, int len, gint ett,
|
||||||
|
const gint **fields, gboolean little_endian, int flags, gboolean first);
|
||||||
|
|
||||||
static int proto_register_field_init(header_field_info *hfinfo, int parent);
|
static int proto_register_field_init(header_field_info *hfinfo, int parent);
|
||||||
|
|
||||||
|
@ -5695,6 +5698,124 @@ proto_construct_match_selected_string(field_info *finfo, epan_dissect_t *edt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This function is common code for both proto_tree_add_bitmask() and
|
||||||
|
* proto_tree_add_bitmask_text() functions.
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
proto_item_add_bitmask_tree(proto_item *item, tvbuff_t *tvb, int offset, int len, gint ett,
|
||||||
|
const int **fields, gboolean little_endian, int flags, gboolean first)
|
||||||
|
{
|
||||||
|
guint32 value = 0, tmpval;
|
||||||
|
proto_tree *tree = NULL;
|
||||||
|
header_field_info *hf;
|
||||||
|
const char *fmt;
|
||||||
|
|
||||||
|
switch (len) {
|
||||||
|
case 1:
|
||||||
|
value = tvb_get_guint8(tvb, offset);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
value = little_endian ? tvb_get_letohs(tvb, offset) :
|
||||||
|
tvb_get_ntohs(tvb, offset);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
value = little_endian ? tvb_get_letoh24(tvb, offset) :
|
||||||
|
tvb_get_ntoh24(tvb, offset);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
value = little_endian ? tvb_get_letohl(tvb, offset) :
|
||||||
|
tvb_get_ntohl(tvb, offset);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
tree = proto_item_add_subtree(item, ett);
|
||||||
|
while (*fields) {
|
||||||
|
proto_tree_add_item(tree, **fields, tvb, offset, len, little_endian);
|
||||||
|
if (flags & BMT_NO_APPEND) {
|
||||||
|
fields++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
hf = proto_registrar_get_nth(**fields);
|
||||||
|
DISSECTOR_ASSERT(hf->bitmask != 0);
|
||||||
|
tmpval = (value & hf->bitmask) >> hf->bitshift;
|
||||||
|
|
||||||
|
switch (hf->type) {
|
||||||
|
case FT_INT8:
|
||||||
|
case FT_UINT8:
|
||||||
|
case FT_INT16:
|
||||||
|
case FT_UINT16:
|
||||||
|
case FT_INT24:
|
||||||
|
case FT_UINT24:
|
||||||
|
case FT_INT32:
|
||||||
|
case FT_UINT32:
|
||||||
|
DISSECTOR_ASSERT(len == ftype_length(hf->type));
|
||||||
|
|
||||||
|
if (hf->display == BASE_CUSTOM) {
|
||||||
|
gchar lbl[ITEM_LABEL_LENGTH];
|
||||||
|
custom_fmt_func_t fmtfunc = (custom_fmt_func_t)hf->strings;
|
||||||
|
|
||||||
|
DISSECTOR_ASSERT(fmtfunc);
|
||||||
|
fmtfunc(lbl, tmpval);
|
||||||
|
proto_item_append_text(item, "%s%s: %s", first ? "" : ", ",
|
||||||
|
hf->name, lbl);
|
||||||
|
first = FALSE;
|
||||||
|
}
|
||||||
|
else if (hf->strings) {
|
||||||
|
proto_item_append_text(item, "%s%s: %s", first ? "" : ", ",
|
||||||
|
hf->name, val_to_str(tmpval, hf->strings, "Unknown"));
|
||||||
|
first = FALSE;
|
||||||
|
}
|
||||||
|
else if (!(flags & BMT_NO_INT)) {
|
||||||
|
if (!first) {
|
||||||
|
proto_item_append_text(item, ", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt = IS_FT_INT(hf->type) ? hfinfo_int_format(hf) : hfinfo_uint_format(hf);
|
||||||
|
if (IS_BASE_DUAL(hf->display)) {
|
||||||
|
proto_item_append_text(item, fmt, hf->name, tmpval, tmpval);
|
||||||
|
} else {
|
||||||
|
proto_item_append_text(item, fmt, hf->name, tmpval);
|
||||||
|
}
|
||||||
|
first = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case FT_BOOLEAN:
|
||||||
|
DISSECTOR_ASSERT(len * 8 == hf->display);
|
||||||
|
|
||||||
|
if (hf->strings && !(flags & BMT_NO_TFS)) {
|
||||||
|
/* If we have true/false strings, emit full - otherwise messages
|
||||||
|
might look weird */
|
||||||
|
const struct true_false_string *tfs =
|
||||||
|
(const struct true_false_string *)hf->strings;
|
||||||
|
|
||||||
|
if (tmpval) {
|
||||||
|
proto_item_append_text(item, "%s%s: %s", first ? "" : ", ",
|
||||||
|
hf->name, tfs->true_string);
|
||||||
|
first = FALSE;
|
||||||
|
} else if (!(flags & BMT_NO_FALSE)) {
|
||||||
|
proto_item_append_text(item, "%s%s: %s", first ? "" : ", ",
|
||||||
|
hf->name, tfs->false_string);
|
||||||
|
first = FALSE;
|
||||||
|
}
|
||||||
|
} else if (hf->bitmask & value) {
|
||||||
|
/* If the flag is set, show the name */
|
||||||
|
proto_item_append_text(item, "%s%s", first ? "" : ", ", hf->name);
|
||||||
|
first = FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
fields++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
/* This function will dissect a sequence of bytes that describe a
|
/* This function will dissect a sequence of bytes that describe a
|
||||||
* bitmask.
|
* bitmask.
|
||||||
* hf_hdr is a 8/16/24/32 bit integer that describes the bitmask to be dissected.
|
* hf_hdr is a 8/16/24/32 bit integer that describes the bitmask to be dissected.
|
||||||
|
@ -5712,101 +5833,41 @@ proto_construct_match_selected_string(field_info *finfo, epan_dissect_t *edt)
|
||||||
* matched string displayed on the expansion line.
|
* matched string displayed on the expansion line.
|
||||||
*/
|
*/
|
||||||
proto_item *
|
proto_item *
|
||||||
proto_tree_add_bitmask(proto_tree *parent_tree, tvbuff_t *tvb, int offset, int hf_hdr, gint ett, const int **fields, gboolean little_endian)
|
proto_tree_add_bitmask(proto_tree *parent_tree, tvbuff_t *tvb, guint offset, int hf_hdr,
|
||||||
|
gint ett, const int **fields, gboolean little_endian)
|
||||||
{
|
{
|
||||||
proto_tree *tree=NULL;
|
|
||||||
proto_item *item = NULL;
|
proto_item *item = NULL;
|
||||||
header_field_info *hf_info;
|
header_field_info *hf;
|
||||||
int len=0;
|
int len;
|
||||||
guint32 value=0;
|
|
||||||
|
|
||||||
hf_info=proto_registrar_get_nth(hf_hdr);
|
hf = proto_registrar_get_nth(hf_hdr);
|
||||||
switch(hf_info->type){
|
DISSECTOR_ASSERT(IS_FT_INT(hf->type) || IS_FT_UINT(hf->type));
|
||||||
case FT_INT8:
|
len = ftype_length(hf->type);
|
||||||
case FT_UINT8:
|
|
||||||
len=1;
|
|
||||||
value=tvb_get_guint8(tvb, offset);
|
|
||||||
break;
|
|
||||||
case FT_INT16:
|
|
||||||
case FT_UINT16:
|
|
||||||
len=2;
|
|
||||||
if(little_endian){
|
|
||||||
value=tvb_get_letohs(tvb, offset);
|
|
||||||
} else {
|
|
||||||
value=tvb_get_ntohs(tvb, offset);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FT_INT24:
|
|
||||||
case FT_UINT24:
|
|
||||||
len=3;
|
|
||||||
if(little_endian){
|
|
||||||
value=tvb_get_letoh24(tvb, offset);
|
|
||||||
} else {
|
|
||||||
value=tvb_get_ntoh24(tvb, offset);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FT_INT32:
|
|
||||||
case FT_UINT32:
|
|
||||||
len=4;
|
|
||||||
if(little_endian){
|
|
||||||
value=tvb_get_letohl(tvb, offset);
|
|
||||||
} else {
|
|
||||||
value=tvb_get_ntohl(tvb, offset);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
g_assert_not_reached();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parent_tree) {
|
if (parent_tree) {
|
||||||
item = proto_tree_add_item(parent_tree, hf_hdr, tvb, offset, len, little_endian);
|
item = proto_tree_add_item(parent_tree, hf_hdr, tvb, offset, len, little_endian);
|
||||||
tree=proto_item_add_subtree(item, ett);
|
proto_item_add_bitmask_tree(item, tvb, offset, len, ett, fields, little_endian,
|
||||||
|
BMT_NO_INT|BMT_NO_TFS, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
while(*fields){
|
return item;
|
||||||
header_field_info *hf_field;
|
|
||||||
guint32 tmpval, tmpmask;
|
|
||||||
|
|
||||||
hf_field=proto_registrar_get_nth(**fields);
|
|
||||||
switch(hf_field->type){
|
|
||||||
case FT_INT8:
|
|
||||||
case FT_UINT8:
|
|
||||||
case FT_INT16:
|
|
||||||
case FT_UINT16:
|
|
||||||
case FT_INT24:
|
|
||||||
case FT_UINT24:
|
|
||||||
case FT_INT32:
|
|
||||||
case FT_UINT32:
|
|
||||||
proto_tree_add_item(tree, **fields, tvb, offset, len, little_endian);
|
|
||||||
|
|
||||||
/* Mask and shift out the value */
|
|
||||||
tmpmask=hf_field->bitmask;
|
|
||||||
tmpval=value;
|
|
||||||
if(tmpmask){
|
|
||||||
tmpval&=tmpmask;
|
|
||||||
while(!(tmpmask&0x00000001)){
|
|
||||||
tmpval>>=1;
|
|
||||||
tmpmask>>=1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Show the value_string content (if there is one) */
|
|
||||||
if(hf_field->strings && hf_field->display != BASE_CUSTOM){
|
|
||||||
proto_item_append_text(item, ", %s", val_to_str(tmpval, hf_field->strings, "Unknown"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
/* The same as proto_tree_add_bitmask(), but using an arbitrary text as a top-level item */
|
||||||
case FT_BOOLEAN:
|
proto_item *
|
||||||
proto_tree_add_item(tree, **fields, tvb, offset, len, little_endian);
|
proto_tree_add_bitmask_text(proto_tree *parent_tree, tvbuff_t *tvb, guint offset, guint len,
|
||||||
/* if the flag is set, show the name */
|
const char *name, const char *fallback,
|
||||||
if(hf_field->bitmask&value){
|
gint ett, const int **fields, gboolean little_endian, int flags)
|
||||||
proto_item_append_text(item, ", %s", hf_field->name);
|
{
|
||||||
}
|
proto_item *item = NULL;
|
||||||
break;
|
|
||||||
default:
|
|
||||||
g_assert_not_reached();
|
|
||||||
}
|
|
||||||
|
|
||||||
fields++;
|
if (parent_tree) {
|
||||||
|
item = proto_tree_add_text(parent_tree, tvb, offset, len, "%s", name ? name : "");
|
||||||
|
if (proto_item_add_bitmask_tree(item, tvb, offset, len, ett, fields, little_endian,
|
||||||
|
flags, TRUE) && fallback) {
|
||||||
|
/* Still at first item - append 'fallback' text if any */
|
||||||
|
proto_item_append_text(item, "%s", fallback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
|
|
24
epan/proto.h
24
epan/proto.h
|
@ -1539,6 +1539,7 @@ proto_find_field_from_offset(proto_tree *tree, guint offset, tvbuff_t *tvb);
|
||||||
This field will form an expansion under which the individual fields of the
|
This field will form an expansion under which the individual fields of the
|
||||||
bitmask is dissected and displayed.
|
bitmask is dissected and displayed.
|
||||||
This field must be of the type FT_[U]INT{8|16|24|32}.
|
This field must be of the type FT_[U]INT{8|16|24|32}.
|
||||||
|
@param ett subtree index
|
||||||
@param fields an array of pointers to int that lists all the fields of the
|
@param fields an array of pointers to int that lists all the fields of the
|
||||||
bitmask. These fields can be either of the type FT_BOOLEAN for flags
|
bitmask. These fields can be either of the type FT_BOOLEAN for flags
|
||||||
or another integer of the same type/size as hf_hdr with a mask specified.
|
or another integer of the same type/size as hf_hdr with a mask specified.
|
||||||
|
@ -1549,7 +1550,28 @@ proto_find_field_from_offset(proto_tree *tree, guint offset, tvbuff_t *tvb);
|
||||||
@param little_endian big or little endian byte representation
|
@param little_endian big or little endian byte representation
|
||||||
@return the newly created item */
|
@return the newly created item */
|
||||||
extern proto_item *
|
extern proto_item *
|
||||||
proto_tree_add_bitmask(proto_tree *tree, tvbuff_t *tvb, int offset, int hf_hdr, gint ett, const int **fields, gboolean little_endian);
|
proto_tree_add_bitmask(proto_tree *tree, tvbuff_t *tvb, guint offset,
|
||||||
|
int hf_hdr, gint ett, const int **fields, gboolean little_endian);
|
||||||
|
|
||||||
|
/** Add a text with a subtree of bitfields.
|
||||||
|
@param tree the tree to append this item to
|
||||||
|
@param tvb the tv buffer of the current data
|
||||||
|
@param offset start of data in tvb
|
||||||
|
@param name field name (NULL if bitfield contents should be used)
|
||||||
|
@param fallback field name if none of bitfields were usable
|
||||||
|
@param ett subtree index
|
||||||
|
@param fields NULL-terminated array of bitfield indexes
|
||||||
|
@param little_endian big or little endian byte representation
|
||||||
|
@return the newly created item */
|
||||||
|
extern proto_item *
|
||||||
|
proto_tree_add_bitmask_text(proto_tree *tree, tvbuff_t *tvb, guint offset, guint len,
|
||||||
|
const char *name, const char *fallback,
|
||||||
|
gint ett, const int **fields, gboolean little_endian, int flags);
|
||||||
|
|
||||||
|
#define BMT_NO_APPEND 0x01 /**< Don't change the title at all */
|
||||||
|
#define BMT_NO_INT 0x02 /**< Don't add integral (non-boolean) fields to title */
|
||||||
|
#define BMT_NO_FALSE 0x04 /**< Don't add booleans unless they're TRUE */
|
||||||
|
#define BMT_NO_TFS 0x08 /**< Don't use true_false_string while formatting booleans */
|
||||||
|
|
||||||
/** Add bits to a proto_tree, using the text label registered to that item.
|
/** Add bits to a proto_tree, using the text label registered to that item.
|
||||||
The item is extracted from the tvbuff handed to it.
|
The item is extracted from the tvbuff handed to it.
|
||||||
|
|
Loading…
Reference in New Issue