in reply to Re: IP Header
in thread IP Header

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?

Replies are listed 'Best First'.
Re^3: IP Header
by Aristotle (Chancellor) on Nov 02, 2002 at 23:13 UTC
    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.
        In addition to the problems Aristotle outlined above, there is one more problem. The functions unpack("b") and vec() unpack the bits in the wrong order within bytes.

        If you unpack("B*", $foo), you will get all the bits (as a string) in the right order. Here is one way to get your final answer, although I'm not sure that eval "0b$_" is the best solution:

        ($ver, $hlen, $tos, $len) = map { eval "0b$_" } unpack "A4A4A8A16", un +pack("B*", $a);
        Argh. This ain't my day. My parameters were in the wrong order, it's my ($ver, $hlen) = (vec($ver_hlen, 0, 4), vec($ver_hlen, 1, 4)); or also my ($ver, $hlen) = map(vec($ver_hlen, $_, 4), (0 .. 1)); The 4 means I want to treat this as an "array" of 4-bit-elements, and the offset specifies the "index" in that "array". I hope I haven't left any errors still to correct this time. grumble

        Makeshifts last the longest.