in reply to IP Header

Your problem is that each unpack starts over at bit 0 of the binary data. But unpack is perfectly capable of returning any number of fields in one fell swoop, so this is what you really wanted: my ($ver, $hlen, $tos, $len) = unpack "b4b4b8n", $foo;

Makeshifts last the longest.

Replies are listed 'Best First'.
Re: Re: IP Header
by Anonymous Monk on Nov 03, 2002 at 00:10 UTC
    Just to throw a wrench in the works ;-) The binary data is packed in Network bit order, won't pulling it out using C2 not respect that? So i tried this:
    my ($data) = unpack "N", $foo; my ($ver, $hlen) = (vec($data,0,4), vec($data,1,4)); my $tos = vec($data, 1, 8); my $len = vec($data, 1, 16);
    Which returned completely un-expected results. Is it not possible to use vec on data pulled using "N"? (yes, i know it can be more compact, split up for readability.)
      You misunderstand the purpose of that format. The network ordering is important for multibyte fields. The order of bytes inside such a field may differ from what the host platform expects. The order of fields however does not change, regardless of platform. Two byte-sized fields are always extracted using C2; a single 16-bit field is extracted using n.

      Makeshifts last the longest.

Re: Re: IP Header
by Anonymous Monk on Nov 02, 2002 at 22:10 UTC
    My understanding of the way IP headers are formed is that $ver should equal 4 when all is said and done. So, while grabbing it all in one swoop solves the repeating data I am still not obtaining the expected results.

    If you have 4 bits that represent, say, an integer how do you unpack to a usable value?
      Oh. Silly me. You have a problem there: unpack consumes its input in byte chunks. Even if you specify b4, it will consume a full byte. (If you specificy b10, it will eat two full bytes.) Note also that b8 will return something of the form 00011111, not 31 - for that purpose you need C (unsigned character). For in-byte bit fiddling, you need vec:
      my ($ver_hlen, $tos, $len) = unpack "C2n", $foo; my ($ver, $hlen) = (vec($ver_hlen, 4, 0), vec($ver_hlen, 4, 1));
      or more compactly my ($ver, $hlen) = map( vec($ver_hlen, 4, $_), (0 .. 1) );
      See perldoc -f vec for details.

      Makeshifts last the longest.

        Thank you for your help thus far. I am now getting the expected results for $tos and $len, however, $ver and $hlen are still not right.

        first, your "vec($ver_hlen, 4, 0)" brings up "illegal number of bits", due to 0 but being a power of 2 between 1 and 32 (from perldoc -f vec).

        I am having trouble understanding exactly what the bits field is. Is that the number of bits that you want to read in? if so, wouldn't:
        my ($ver, $hlen) = (vec($ver_hlen, 0, 4), vec($ver_hlen, 4, 4));
        be better? Using the the changes i made above, I get unexpected results for the values for $ver and $hlen, which leads me to believe I am wrong.