in reply to Re: Re: IP Header
in thread IP Header

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.

Replies are listed 'Best First'.
Re: Re^3: IP Header
by Anonymous Monk on Nov 02, 2002 at 23:39 UTC
    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);
        ++ for pointing out the B vs b concern, but you're wrong about vec. And that code is an eval $REDFLAG;, you should do it thusly: my ($ver, $hlen, $tos, $len) = map pack "B*", unpack "A4A4A8A16", unpack "B*", $foo; However, that will not honour the network byte ordering in $len.

        Makeshifts last the longest.

      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.