Ask Your Question
0

Dissector plugin: binary-coded-decimal encoding

asked 2018-01-04 02:42:11 +0000

anton gravatar image

updated 2018-01-04 02:42:47 +0000

Writing a Wireshark dissector plugin in C++. The protocol I'm trying to parse uses the uncommon packed binary-coded-decimal format for all of its integers.

Normally, when I want to add an item of length length at offset offset, I write:

proto_tree_add_item(body, fields.foo, tvb, offset, length, ENC_LITTLE_ENDIAN);
proto_tree_add_item(body, fields.foo, tvb, offset, length, ENC_NA); // big-endian int
proto_tree_add_item(body, fields.foo, tvb, offset, length, ENC_ASCII); // string

... etc. I also need to register the field array with:

proto_register_field_array(handle, field_array, array_length(field_array));

... where the field_array is an array of hf_register_info, like this:

static hf_register_info field_array[] = {
    { &fields.foo, { "Foo Field", "protocol.foo", FT_UINT48, BASE_DEC } },
    // etc. other fields
};

... supposing my example is a 6-byte packed BCD (capable of holding 12 decimal digits).

This all works nicely when I'm parsing sensible protocols that send uint32, ASCII, int64, etc., over the wire. But there appears to be no built-in Wireshark encoding for packed BCDs.

I can see a hacky work-around to parse it as raw data, and then write a function to translate the raw data into the correct value (or use something like tvb_bcd_dig_to_wmem_packet_str), and then use proto_item_set_text to set the item to my desired representation.

Is there a better way?

edit retag flag offensive close merge delete

2 Answers

Sort by ยป oldest newest most voted
0

answered 2018-01-04 05:13:26 +0000

Anders gravatar image

updated 2018-01-05 10:29:12 +0000

grahamb gravatar image

If you search for tvb_bcd_dig... in the code base you can find many examples on how people have dealt with it. If you are planning to commit your dissector to Wireshark, write it in C not C++. Regards Anders

edit flag offensive delete link more

Comments

Thank you: I did come across that function as well, but as it turns out, it wasn't necessary for my particular dissector. (I'm not planning to commit the dissector to Wireshark: it's too specific).

anton gravatar imageanton ( 2018-01-04 05:34:04 +0000 )edit
0

answered 2018-01-04 04:58:46 +0000

anton gravatar image

updated 2018-01-05 10:29:37 +0000

grahamb gravatar image

No particular encoding is necessary to make Wireshark display the value nicely. A binary-coded-decimal is like a plain integer, except that the value needs to be translated as if it were decimal.

So 56 (decimal value) for example will be transmitted (assuming big-endian / network-byte-order on the wire) as 0000 0000 0101 0110 or 0056 (hex). All that is needed is to register the field as a FT_UINTX (e.g. UINT32 for 4 byte Packed BCD, UINT40 for 5 byte, etc.) with BASE_HEX representation.

static hf_register_info field_array[] = {
    { &fields.foo, { "Foo Field", "protocol.foo", FT_UINT48, BASE_HEX } },
    // etc. other fields
}; // works for 6-byte packed BCD

And in the dissecting function itself, add the item:

proto_tree_add_item(body, fields.foo, tvb, offset, length, ENC_NA);

As for actually turning the BCD bytes into an integer, we can just write a function to transform BCDs to unsigned, e.g.:

#include <cstdint>

uint64_t bcd_to_uint(const char* start, const size_t bytes)
{
    uint64_t value = 0;
    for (size_t i = 0; i < bytes; ++i)
    {
        uint8_t data = start[i] - '0';
        value += ((data >> 4) * 10 + (data & 0x0f)) * ipow(100, bytes - i - 1);
        // right-shift unsigned will fill with 0s
        // integer promotion will prevent overflow up to UINT_MAX
        // ipow(base, exp) returns base to the power of exp, returns uint64
    }
    return value;
}
edit flag offensive delete link more

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

Stats

Asked: 2018-01-04 02:42:11 +0000

Seen: 956 times

Last updated: Jan 05 '18