aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--epan/proto.c156
-rw-r--r--epan/proto.h52
2 files changed, 193 insertions, 15 deletions
diff --git a/epan/proto.c b/epan/proto.c
index 777e08c224..45978dd286 100644
--- a/epan/proto.c
+++ b/epan/proto.c
@@ -7301,13 +7301,7 @@ _proto_tree_add_bits_ret_val(proto_tree *tree, const int hf_index, tvbuff_t *tvb
if (tot_no_bits & 0x07)
length++;
- if (no_of_bits < 9){
- value = tvb_get_bits8(tvb, bit_offset, no_of_bits);
- }else if(no_of_bits < 17){
- value = tvb_get_bits16(tvb, bit_offset, no_of_bits, encoding);
- }else if(no_of_bits < 33){
- value = tvb_get_bits32(tvb, bit_offset, no_of_bits, encoding);
- }else if(no_of_bits < 65){
+ if(no_of_bits < 65){
value = tvb_get_bits64(tvb, bit_offset, no_of_bits, encoding);
}else{
DISSECTOR_ASSERT_NOT_REACHED();
@@ -7387,6 +7381,144 @@ _proto_tree_add_bits_ret_val(proto_tree *tree, const int hf_index, tvbuff_t *tvb
}
proto_item *
+proto_tree_add_split_bits_ret_val(proto_tree *tree, const int hf_index, tvbuff_t *tvb,
+ const gint bit_offset, const crumb_spec_t *crumb_spec,
+ guint64 *return_value)
+{
+ proto_item *pi;
+ gint octet_offset, mask_initial_bit_offset, mask_greatest_bit_offset = 0;
+ guint octet_length;
+ guint8 i = 0;
+ char *bf_str = NULL, lbl_str[ITEM_LABEL_LENGTH];
+ header_field_info *hf_field;
+ guint64 value = 0, composite_bitmask = 0, composite_bitmap = 0;
+ const true_false_string *tfstring;
+
+ /* We can't fake it just yet. We have to fill in the 'return_value' parameter */
+ PROTO_REGISTRAR_GET_NTH(hf_index, hf_field);
+
+ if(hf_field -> bitmask != 0) {
+ REPORT_DISSECTOR_BUG(ep_strdup_printf("Incompatible use of proto_tree_add_bits_ret_val with field '%s' (%s) with bitmask != 0",
+ hf_field->abbrev, hf_field->name));
+ }
+
+ mask_initial_bit_offset = bit_offset % 8;
+
+ while(crumb_spec[i].crumb_bit_length != 0)
+ {
+ guint64 crumb_mask, crumb_value;
+ guint8 crumb_end_bit_offset;
+
+ DISSECTOR_ASSERT(i < 64);
+ crumb_value = tvb_get_bits64(tvb, bit_offset + crumb_spec[i].crumb_bit_offset, crumb_spec[i].crumb_bit_length, ENC_BIG_ENDIAN);
+ value += crumb_value;
+
+ /* the bitmask is 64 bit, left-aligned, starting at the first bit of the octet containing the initial offset */
+ /* if the mask is beyond 32 bits, then give up on bit map display
+ this could be improved in future, probably showing a table of 32 or 64 bits per row */
+ if (mask_greatest_bit_offset < 32)
+ {
+ crumb_end_bit_offset = mask_initial_bit_offset + crumb_spec[i].crumb_bit_offset + crumb_spec[i].crumb_bit_length;
+ crumb_mask = (1 << crumb_spec[i].crumb_bit_length) - 1;
+
+ if(crumb_end_bit_offset > mask_greatest_bit_offset)
+ {
+ mask_greatest_bit_offset = crumb_end_bit_offset;
+ }
+ composite_bitmask |= (crumb_mask << (64 - crumb_end_bit_offset));
+ composite_bitmap |= (crumb_value << (64 - crumb_end_bit_offset));
+ }
+ /* shift left for the next segment */
+ value <<= crumb_spec[++i].crumb_bit_length;
+ }
+ if(return_value){
+ *return_value=value;
+ }
+
+ /* Coast clear. Try and fake it */
+ TRY_TO_FAKE_THIS_ITEM(tree, hf_index, hf_field);
+
+ /* initialise the fromat string */
+ bf_str=ep_alloc(256);
+ bf_str[0] = '\0';
+
+ octet_offset = bit_offset >> 3;
+
+ /* round up mask length to nearest octet */
+ octet_length = ((mask_greatest_bit_offset + 7) >> 3);
+ mask_greatest_bit_offset = octet_length << 3;
+
+ /* as noted above, we currently only produce a bitmap if the crumbs span less than 4 octets of the tvb,
+ it would be a useful enhancement to eliminate this restriction. */
+ if (mask_greatest_bit_offset <= 32)
+ {
+ other_decode_bitfield_value(bf_str, (guint32)(composite_bitmap >> (64 - mask_greatest_bit_offset)),
+ (guint32)(composite_bitmask >> (64 - mask_greatest_bit_offset)),
+ mask_greatest_bit_offset);
+ }
+
+ switch(hf_field->type){
+ case FT_BOOLEAN: /* it is a bit odd to have a boolean encoded as split-bits, but possible, I suppose? */
+ /* Boolean field */
+ tfstring = (const true_false_string *) &tfs_true_false;
+ if (hf_field->strings)
+ tfstring = (const true_false_string *) hf_field->strings;
+ return proto_tree_add_boolean_format(tree, hf_index, tvb, octet_offset, octet_length, (guint32)value,
+ "%s = %s: %s",
+ bf_str, hf_field->name,
+ (guint32)value ? tfstring->true_string : tfstring->false_string);
+ break;
+
+ case FT_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
+ pi = proto_tree_add_uint(tree, hf_index, tvb, octet_offset, octet_length, (guint32)value);
+ fill_label_uint(PITEM_FINFO(pi), lbl_str);
+ break;
+
+ case FT_INT8:
+ case FT_INT16:
+ case FT_INT24:
+ case FT_INT32:
+ pi = proto_tree_add_int(tree, hf_index, tvb, octet_offset, octet_length, (gint32)value);
+ fill_label_int(PITEM_FINFO(pi), lbl_str);
+ break;
+
+ case FT_UINT64:
+ pi = proto_tree_add_uint64(tree, hf_index, tvb, octet_offset, octet_length, value);
+ fill_label_uint64(PITEM_FINFO(pi), lbl_str);
+ break;
+
+ case FT_INT64:
+ pi = proto_tree_add_int64(tree, hf_index, tvb, octet_offset, octet_length, (gint64)value);
+ fill_label_int64(PITEM_FINFO(pi), lbl_str);
+ break;
+
+ default:
+ DISSECTOR_ASSERT_NOT_REACHED();
+ return NULL;
+ break;
+ }
+ proto_item_set_text(pi, "%s = %s", bf_str, lbl_str);
+ return pi;
+}
+
+void
+proto_tree_add_split_bits_crumb(proto_tree *tree, const int hf_index, tvbuff_t *tvb, const gint bit_offset,
+ const crumb_spec_t *crumb_spec, guint16 crumb_index)
+{
+ header_field_info *hf_info;
+
+ PROTO_REGISTRAR_GET_NTH(hf_index, hf_info);
+ proto_tree_add_text(tree, tvb, bit_offset >> 3, ((bit_offset + crumb_spec[crumb_index].crumb_bit_length - 1) >> 3) - (bit_offset >> 3) + 1,
+ "%s crumb %d of %s (decoded above)",
+ decode_bits_in_field(bit_offset, crumb_spec[crumb_index].crumb_bit_length,
+ tvb_get_bits(tvb, bit_offset, crumb_spec[crumb_index].crumb_bit_length, ENC_BIG_ENDIAN)),
+ crumb_index, hf_info->name);
+}
+
+proto_item *
proto_tree_add_bits_ret_val(proto_tree *tree, const int hf_index, tvbuff_t *tvb,
const gint bit_offset, const gint no_of_bits,
guint64 *return_value, const guint encoding)
@@ -7436,14 +7568,8 @@ _proto_tree_add_bits_format_value(proto_tree *tree, const int hf_index,
if (tot_no_bits & 0x07)
length++;
- if (no_of_bits < 9){
- value = tvb_get_bits8(tvb, bit_offset, no_of_bits);
- }else if(no_of_bits < 17){
- value = tvb_get_bits16(tvb, bit_offset, no_of_bits, FALSE);
- }else if(no_of_bits < 33){
- value = tvb_get_bits32(tvb, bit_offset, no_of_bits, FALSE);
- }else if(no_of_bits < 65){
- value = tvb_get_bits64(tvb, bit_offset, no_of_bits, FALSE);
+ if(no_of_bits < 65){
+ value = tvb_get_bits64(tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN);
}else{
DISSECTOR_ASSERT_NOT_REACHED();
return NULL;
diff --git a/epan/proto.h b/epan/proto.h
index 6859d4829b..ff05d796d0 100644
--- a/epan/proto.h
+++ b/epan/proto.h
@@ -384,6 +384,20 @@ typedef struct field_info {
/*
+ * This structure describes one segment of a split-bits item
+ * crumb_bit_offset is the bit offset in the input tvb of the first (most significant) bit of this crumb
+ * crumb_bit_length is the number of contiguous bits of this crumb.
+ * The first element of an array of bits_specs describes the most significant crumb of the output value.
+ * The second element of an array of bits_specs describes the next-most significant crumb of the output value, etc.
+ * The array is terminated by a sentinal entry with crumb_bit_length of 0.
+*/
+typedef struct
+{
+ guint crumb_bit_offset;
+ guint8 crumb_bit_length;
+}crumb_spec_t;
+
+/*
* Flag fields. Do not assign values greater than 0x00000080 unless you
* shuffle the expert information upward; see below.
*/
@@ -1884,6 +1898,44 @@ extern proto_item *
proto_tree_add_bits_item(proto_tree *tree, const int hf_index, tvbuff_t *tvb, const gint bit_offset, const gint no_of_bits, const guint encoding);
/** Add bits to a proto_tree, using the text label registered to that item.
+* The item is extracted from the tvbuff handed to it as a set
+* of crumbs (segments) of contiguous bits, specified by an
+* array of crumb_spec elements. The crumbs are assembled to
+* create the value. There may be any number of crumbs
+* specifying up to a total of 64 bits which may occur anywhere
+* within the tvb. If the span of the crumbs within the tvb is 4
+* octets or less, a bitmap of the crumbs is produced.
+ @param tree the tree to append this item to
+ @param hf_index field index. Fields for use with this function should have bitmask==0.
+ @param tvb the tv buffer of the current data
+ @param bit_offset of the first crumb in tvb expressed in bits
+ @param pointer to crumb_spec array
+ @param return_value if a pointer is passed here the value is returned.
+ @return the newly created item */
+extern proto_item *
+proto_tree_add_split_bits_ret_val(proto_tree *tree, const int hf_index, tvbuff_t *tvb,
+ const gint bit_offset, const crumb_spec_t *crumb_spec,
+ guint64 *return_value);
+
+
+/** Add bitmap text for a split-bits crumb to a proto_tree,
+* using the text label registered to an item. The bitmap is
+* extracted from the tvbuff handed to it as a crumb (segment)
+* of contiguous bits, specified by one of an array of
+* crumb_spec elements. This function is normally called once
+* per crumb, after the call to
+ proto_tree_add_split_bits_ret_val
+ @param tree the tree to append this item to
+ @param hf_index field index. Fields for use with this function should have bitmask==0.
+ @param tvb the tv buffer of the current data
+ @param bit_offset of the first crumb in tvb expressed in bits
+ @param pointer to crumb_spec array
+ @param index into the crumb_spec array for this crumb */
+void
+proto_tree_add_split_bits_crumb(proto_tree *tree, const int hf_index, tvbuff_t *tvb, const gint bit_offset,
+ const crumb_spec_t *crumb_spec, guint16 crumb_index);
+
+/** Add bits to a proto_tree, using the text label registered to that item.
The item is extracted from the tvbuff handed to it.
@param tree the tree to append this item to
@param hf_index field index. Fields for use with this function should have bitmask==0.