Wireshark-dev: Re: [Wireshark-dev] tvb_get_ntohl with reversed data
From: Guy Harris <guy@xxxxxxxxxxxx>
Date: Tue, 6 Dec 2011 00:52:04 -0800
On Dec 6, 2011, at 12:21 AM, Yegor Yefremov wrote:

> In CANOpen protocol there is a packet type TIME_STAMP. It is
> constructed in the following way:
> 
> 1. first 4 bytes are milliseconds since midnight, but in LSB first
> form (0x10 0x20 0x30 0x40 is actually 0x40 0x30 0x20 0x10)
> 2. next 2 bytes are days since 01.01.1984

OK, that's about 179 years, so it's not *too* badly non-future-proof. :-)

> Is there some build-in method to get milliseconds without changing the
> byte order?

tvb_get_ntohl() fetches a 4-byte big-endian value.  "n" stands for "network byte order", meaning "big-endian".

I know of no term similar to "network byte order" for little-endian, so the routine to fetch a 4-byte little-endian value is called tvb_get_letohl().  That's the routine you want.

If the days-since-1984-01-01 is also little-endian, you'd want tvb_get_letohs() ("s" for "short", as in "16-bit integer in C on 32-bit and 64-bit platforms", just as it's "l" for "long", as in "32-bit integer in C on most if not all 32-bit platforms - 64-bit C platforms first showed up long after the Berkeley folks, or whoever introduced ntohs(), ntohl(), etc. added them to UN*X, so it's not really 'long' on a lot of machines these days".  I suppose you could argue that they should be tvb_get_betoh16(), tvb_get_betoh24(), tvb_get_betoh32(), tvb_get_betoh48(), tvb_get_betoh64(), tvb_get_letoh16(), tvb_get_letoh24(), etc..)

> What is the OS independent way to get UTC date from milliseconds (I
> guess I'll also need to make correction related to 1970)?

Yes - the "days since 01.01.1984" is actually far more significant (in both the conversational and mathematical senses of "significant") than the "milliseconds since midnight" if you're trying to convert it to a date!

Is that 1984-01-01 at the Greenwich Meridian, or is that 1984-01-01 in local time?

If it's at the Greenwich Meridian, then you take the "days since 01.01.1984" value, add to it the number of days between 1970-01-01 and 1984-01-01 (to convert it to days since 1970-01-01 - for at least a little future-proofing, do that in a 32-bit integer), multiply that by 86400 to convert it to seconds (we don't worry about leap seconds here - the POSIX spec requires that they be treated in a somewhat bizarre manner, whether any UN*X systems actually do so or not), and put that into the "secs" field of an nstime_t structure as defined in <epan/nstime.h> in the Wireshark source.

Then take the milliseconds-since-midnight value, multiply it by 1000000 to convert it to nanoseconds, and put that into the "nsecs" field of the nstime_t.

You can then use that nstime_t to add an FT_ABSOLUTE_TIME field into the protocol tree for those 6 bytes.  (It will be displayed as if it had nanosecond resolution, with a whole bunch of bogus zeroes after the least significant digit, which is not ideal; we need to come up with a better way to handle that.)

If it's 1984-01-01 in local time, let us know; it's getting late and my brain's beginning to overheat from several hours spent beating libpcap and Wireshark's capture dialog box over the head to handle an annoying issue with monitor mode and libpcap on at least some Linux distributions (Debian and its derivatives, possibly others if they have libpcap 1.0.x or have libpcap 1.1.x and it's not linked with libnl), so I'll think about how best to handle local time, if necessary, later.