Wireshark-dev: Re: [Wireshark-dev] dissecting bits versus bytes

From: Brian Oleksa <oleksab@xxxxxxxxxxxxxxxxxxxxxx>
Date: Tue, 17 May 2011 10:28:23 -0400

Wiresharkers:

I am dissecting bits not bytes. I am running into some problems.

I figured out that bits 5-8 are the version. Bit 4 is the FPI. If FPI = 1...then bits 3 and 2 are present (which is the data compression type). Bit 1 is the GPI. If GPI = 1...then the next Group (G1) is present.

The problem that I am having...is if Bit 4 (The FPI) = 0...then I am skipping the next 2 bits (when I shouldn't be).

But how am I supposed to not skip these bits when I am selecting specific bits..??

Also....I am not 100% sure how/when to increment the offset and bit_offset.

Here is part of the packet that I am trying to dissect:





Here is the code:


void proto_register_vmf(void) {
    static hf_register_info hf[] = {

        { &hf_vmf_version,
            { "Version", "vmf.version", FT_UINT8, BASE_DEC, NULL, 0x0f,
                NULL, HFILL}},
        { &hf_vmf_fpi,
            { "FPI", "vmf.fpi", FT_UINT8, BASE_DEC, NULL, 0x10,
                NULL, HFILL}},
        { &hf_vmf_fpi2,
            { "FPI", "vmf.fpi", FT_UINT8, BASE_DEC, NULL, 0x01,
                NULL, HFILL}},
        { &hf_vmf_fpi3,
            { "FPI", "vmf.fpi", FT_UINT8, BASE_DEC, NULL, 0x10,
                NULL, HFILL}},
        { &hf_vmf_datacompressiontype,
            { "Data Compression Type", "vmf.dataCompressionType", FT_UINT8, BASE_DEC, NULL, 0x60,
                NULL, HFILL}},
        { &hf_vmf_gpi,
            { "GPI", "vmf.gpi", FT_UINT8, BASE_DEC, NULL, 0x80,
                NULL, HFILL}},
           { &hf_vmf_urn,
            { "URN", "vmf.urn", FT_STRING, BASE_NONE, NULL, 0x0,
                NULL, HFILL}}
    };


void dissect_vmf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {

    proto_item *vmf_item = NULL;
    proto_item *vmf_sub_item = NULL;
    proto_tree *vmf_tree = NULL;
    proto_tree *vmf_header_tree = NULL;

    guint8 fpi;
    guint8 fpi2;
    guint8 fpi3;
    guint8 gpi;

    col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_VMF);
    col_clear(pinfo->cinfo, COL_INFO);

    if (tree) {
        guint8 bit_offset;
        guint32 offset;

        vmf_item = proto_tree_add_item(tree, proto_vmf, tvb, 0, -1, FALSE);
        vmf_tree = proto_item_add_subtree(vmf_item, ett_vmf);
        vmf_header_tree = proto_item_add_subtree(vmf_item, ett_vmf);

        vmf_header_tree = proto_item_add_subtree(vmf_sub_item, ett_vmf);
        {
            #define MAXIUM_BUFFER 1024
            char *buf = (char*)ep_alloc(MAXIUM_BUFFER);
            char * packet_name = "VMF Message Rev C";
            proto_tree *vmf_sub_tree = NULL;

            offset = 0;
            bit_offset = 0;

            g_snprintf(buf, BUFFER, "%s", packet_name);

            vmf_item = proto_tree_add_text(tree, tvb, offset, 0, "%s", buf);
            vmf_sub_tree = proto_item_add_subtree(vmf_item, ett_vmf);

            //Version
            proto_tree_add_item(vmf_sub_tree,hf_vmf_version, tvb, offset, 1, FALSE);
            bit_offset += 4;

            //FPI
            fpi = tvb_get_bits8(tvb, bit_offset, 1);
            proto_tree_add_item(vmf_sub_tree,hf_vmf_fpi, tvb, offset, 1, FALSE);
            bit_offset += 1;

            //Field presence indicator (FPI). If FPI = 1 then the next field is presence. If it = 0 than it is absence.
            if(fpi == 1)
            {
            //Data Compression type
                proto_tree_add_item(vmf_sub_tree,hf_vmf_datacompressiontype, tvb, offset, 1, FALSE);
                bit_offset += 2;
            }


            //GPI
            gpi = tvb_get_bits8(tvb, bit_offset, 1);
            proto_tree_add_item(vmf_sub_tree,hf_vmf_gpi, tvb, offset, 1, FALSE);
            bit_offset += 1;

            //Group presence indicator (GPI). If GPI = 1 then the next field is presence. If it = 0 than it is absence.
            if(gpi == 1)
            {

            //FPI
              fpi2 = tvb_get_bits8(tvb, bit_offset, 1);
              proto_tree_add_item(vmf_sub_tree,hf_vmf_fpi2, tvb, offset, 1, FALSE);
              bit_offset += 1;

             if(fpi2 == 1)
                {
                //URN
                proto_tree_add_item(vmf_sub_tree,hf_vmf_urn, tvb, offset, 3, FALSE);
                bit_offset += 24;

                //FPI
                fpi3 = tvb_get_bits8(tvb, bit_offset, 1);
                  proto_tree_add_item(vmf_sub_tree,hf_vmf_fpi3, tvb, offset, 1, FALSE);
                  bit_offset += 1;

                      if(fpi3 == 1)
                    {
                    //UNIT NAME (this is a string) I need to figure out how to deal with a string (this is a max field size of 448 bits)
                    }
                }

            }

        }
    }
}


Below is a screen shot.
If FPI = 0 then the next field is not present.....so I should NOT skip bits 3 and 2. But I am because in my void proto_register_vmf(void)  routine I am selecting certain bits.

Any help with this is greatly appreciated.

Thanks,
Brian







On 5/10/2011 12:00 AM, Ankith Agarwal wrote:
Hi

I found these routines in the wireshark.README file:

guint8 tvb_get_bits8(tvbuff_t *tvb, gint bit_offset, gint no_of_bits);
guint16 tvb_get_bits16(tvbuff_t *tvb, gint bit_offset, gint 
no_of_bits,gboolean little_endian);
guint32 tvb_get_bits32(tvbuff_t *tvb, gint bit_offset, gint 
no_of_bits,gboolean little_endian);
guint64 tvb_get_bits64(tvbuff_t *tvb, gint bit_offset, gint 
no_of_bits,gboolean little_endian);

Is there a way to get a String...??
The tvb pointer which is present in the context is an array of
characters..indirectly a string.. so, you can copy the values of tvb into
a local string variable...(don't forget to get the size of the string)

The string that I have ends with a special value of 0xFF ......
if this is the case you can copy a character and loop it till the
condition of 0xFF doesn't satisfy...

string it's self has a bit_offset
that is determined at runtime. How do I read this..??

You can work out from the previous mails, on how to read a bit_offset...

Also...I have a series of bits fields that span bytes....is there an 
example out there where somebody already dissected
a stream of bits not bytes..??

For example:  How would I dissect an 18 bit field that starts at an 
offset of 2 bits..?

You cannot dissect the bit fields directly... you have to take the largest
container of it and the put a mask to obtain the values...
As for your example... for 18 bit field, just get the next power of 2 ie,
32 and put the mask, or do an and operation with
(11111111111111111100000000000000) 0xFFFFC000, and you will be extract
your 18 bits into a local variable... Then by further processing you can
get your bit fields dissected completely...

Regards
Ankith