Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

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;
}

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 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;
}