Ethereal-dev: Re: [Ethereal-dev] patch to packet-tcp.c to display up times if timestamps

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Charles Levert <chuck@xxxxxxxxxxxxxxxx>
Date: Sat, 30 Oct 2004 20:17:40 -0400
* On Saturday 2004-10-30 at 03:08:19 -0700, Guy Harris wrote:
> Charles Levert wrote:
> >Since not all OSes use a 100 Hz aka 10 ms clock,
> 
> And, as per your note, not all OSes even put an uptime in there.
> 
> Perhaps there should be some protocol preference settings for the TCP 
> dissector, a Boolean indicating whether to interpret it as an uptime, 
> defaulting to TRUE, and an integer preference indicating the frequency 
> of the clock, defaulting to 100.

I have added one preference setting for the clock frequency.  The code
doesn't perform the decomposition in time units if the user-preferred
frequency is zero (an unusable value that would result in a division
by zero anyway), so no additional boolean preference setting is needed.

The default is 100 Hz.

The long description of the new setting explains the caveats.



[ Generated with ude,
    the unified-format diff-output ("unidiff") editor,
    version 0.1 of 2004-10-23.  ]
--- epan/dissectors/packet-tcp.c.svn-12259	2004-10-11 04:12:34 -0400
+++ epan/dissectors/packet-tcp.c	2004-10-30 19:09:09 -0400
@@ -4 +4 @@
  * $Id: packet-tcp.c 12259 2004-10-11 08:12:34Z sahlberg $
@@ -132,6 +132,7 @@
 static gint ett_tcp_flags = -1;
 static gint ett_tcp_options = -1;
 static gint ett_tcp_option_sack = -1;
+static gint ett_tcp_option_timestamp = -1;
 static gint ett_tcp_analysis = -1;
 static gint ett_tcp_analysis_faults = -1;
 static gint ett_tcp_segments = -1;
@@ -2205,18 +2206,85 @@ dissect_tcpopt_echo(const ip_tcp_opt *op
   tcp_info_append_uint(pinfo, "ECHO", echo);
 }
 
+static guint clock_frequency = 100;
+
+static void
+dissect_tcpopt_timestamp_field(const proto_tree *ts_tree,
+    tvbuff_t *tvb, int offset,
+    const char *name, guint32 value)
+{
+  /* Always use correct unit symbols.  Leading zeros are not really printed.  */
+  /* " (up time if 1 Hz clock: 49710 d + 06 h + 28 min + 15 s)" */
+  /* " (up time if 2 Hz clock: 24855 d + 03 h + 14 min + 07 1/2 s)" */
+  /* " (up time if 10 Hz clock: 4971 d + 00 h + 38 min + 49 5/10 s)" */
+  /* " (up time if 100 Hz clock: 497 d + 02 h + 27 min + 52 95/100 s)" */
+  /* " (up time if 1000 Hz clock: 49 d + 17 h + 02 min + 47 295/1000 s)" */
+  /* " (up time if 4294967295 Hz clock: 49710 d + xx h + yy min + zz 4294967294/4294967295 s)" */
+  char up[88]; /* exaggerated worst case from line above */
+
+  if (value && clock_frequency) {
+    char *s = "";
+    const char sp[] = " + ";
+    guint32 r, q, frac;
+
+    sprintf(up, " (up time if %u Hz clock: ", clock_frequency);
+    r = value / clock_frequency;
+    frac = value - r * clock_frequency;
+    q = r / 86400;
+    if (q) {
+      r -= q * 86400;
+      sprintf(up + strlen(up), "%u d", q);
+      s = sp;
+    }
+    q = r / 3600;
+    if (q) {
+      r -= q * 3600;
+      sprintf(up + strlen(up), "%s%u h", s, q);
+      s = sp;
+    }
+    q = r / 60;
+    if (q) {
+      r -= q * 60;
+      sprintf(up + strlen(up), "%s%u min", s, q);
+      s = sp;
+    }
+    if (r || frac) {
+      strcpy(up + strlen(up), s);
+      /* Print seconds as a mixed number (e.g., "52 95/100 s").  */
+      if (r)
+        sprintf(up + strlen(up), "%u ", r);
+      if (frac)
+        sprintf(up + strlen(up), "%u/%u ", frac, clock_frequency);
+      strcpy(up + strlen(up), "s");
+    }
+    strcpy(up + strlen(up), ")");
+  } else
+    up[0] = '\0';
+
+  proto_tree_add_text(ts_tree, tvb, offset, 4,
+    "%s: %u%s", name, value, up);
+}
+
 static void
 dissect_tcpopt_timestamp(const ip_tcp_opt *optp, tvbuff_t *tvb,
     int offset, guint optlen, packet_info *pinfo, proto_tree *opt_tree)
 {
   guint32 tsv, tser;
+  proto_item *tf;
+  proto_tree *ts_tree;
 
   tsv = tvb_get_ntohl(tvb, offset + 2);
   tser = tvb_get_ntohl(tvb, offset + 6);
   proto_tree_add_boolean_hidden(opt_tree, hf_tcp_option_time_stamp, tvb, 
 				offset, optlen, TRUE);
-  proto_tree_add_text(opt_tree, tvb, offset,      optlen,
+  tf = proto_tree_add_text(opt_tree, tvb, offset, optlen,
     "%s: tsval %u, tsecr %u", optp->name, tsv, tser);
+  ts_tree = proto_item_add_subtree(tf, *optp->subtree_index);
+  dissect_tcpopt_timestamp_field(ts_tree, tvb, offset + 2,
+    "Timestamp Value", tsv);
+  /* XXX:  TSecr invalid unless ACK; we should warn.  */
+  dissect_tcpopt_timestamp_field(ts_tree, tvb, offset + 6,
+    "Timestamp Echo Reply", tser);
   tcp_info_append_uint(pinfo, "TSV", tsv);
   tcp_info_append_uint(pinfo, "TSER", tser);
 }
@@ -2303,7 +2371,7 @@ static const ip_tcp_opt tcpopts[] = {
   {
     TCPOPT_TIMESTAMP,
     "Time stamp",
-    NULL,
+    &ett_tcp_option_timestamp,
     FIXED_LENGTH,
     TCPOLEN_TIMESTAMP,
     dissect_tcpopt_timestamp
@@ -3223,6 +3291,7 @@ proto_register_tcp(void)
 		&ett_tcp_flags,
 		&ett_tcp_options,
 		&ett_tcp_option_sack,
+		&ett_tcp_option_timestamp,
 		&ett_tcp_analysis_faults,
 		&ett_tcp_analysis,
 		&ett_tcp_segments,
@@ -3268,6 +3337,11 @@ proto_register_tcp(void)
 	    "Try heuristic sub-dissectors first",
 	    "Try to decode a packet using an heuristic sub-dissector before using a sub-dissector registered to a specific port",
 	    &try_heuristic_first);
+	prefs_register_uint_preference(tcp_module, "clock_frequency",
+	    "Clock frequency (in Hz) for RFC 1323 TCP Timestamps option",
+	    "Decomposition in time units of all 32-bit TCP timestamps will assume this (integral) frequency which RFC 1323 places in the 1 Hz to 1000 Hz range (the 100 Hz default is typical); a zero timestamp is used as the epoch, but the clock may not have started at zero at boot time or it may have wrapped (so the \"up time\" label might be misleading)",
+	    10,
+	    &clock_frequency);
 
 	register_init_routine(tcp_analyze_seq_init);
 	register_init_routine(tcp_desegment_init);