mako: Updated Metamako trailer dissection

packet-metamako.c: Made heuristic variables available for the user to change via the UI, updated the display strings of the Clause 49 BTF value and the Original FCS status, simplified the heuristic function, added UI options to force trailer dissection (override heuristics), and allow for user specification of whether an FCS is present in the capture, fixed TLV walking bug if the heuristic picks up an invalid TLV length, appends the Info column with a message if the trailer is found, added a generated timestamp field to display the epoch seconds, added total-frame FCS display if total-frame FCS is detected, along with its status.
This commit is contained in:
PMcL 2023-01-03 18:27:54 +11:00 committed by Alexis La Goutte
parent 4d38cf9ec6
commit 1fc516739e
1 changed files with 346 additions and 182 deletions

View File

@ -19,14 +19,52 @@
#include "config.h"
#include <epan/packet.h>
#include <epan/etypes.h>
#include <epan/expert.h>
#include <epan/crc32-tvb.h>
#include <glib/gprintf.h>
#define TRAILER_MIN_LENGTH_NO_FCS 16
#define TRAILER_NS_UPPER_BOUND 1000000000
#define TRAILER_SECS_BOUNDS_DFLT "3600-"
#define TRAILER_DAYS_DIFF_LIMIT_DFLT 30
#define SECS_IN_ONE_DAY (60 * 60 * 24)
void proto_register_metamako(void);
void proto_reg_handoff_metamako(void);
/* FCS Options */
static gboolean metamako_check_fcs = TRUE;
static gint metamako_fcs_len = -1; /* By default, try to autodetect the FCS. */
/* Heuristic Options */
static gint metamako_trailer_present = -1; /* By default, try to autodetect the trailer. */
static range_t* metamako_trailer_secs_bounds = NULL;
static guint metamako_trailer_days_diff_limit = TRAILER_DAYS_DIFF_LIMIT_DFLT;
/* Protocols and Header Fields */
static int proto_metamako = -1;
/*
Metamako trailer format
0.............7...............15..............23..............31
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Original FCS |
+---------------+---------------+---------------+---------------+
| ... |
+---------------+---------------+---------------+---------------+
| TLV Extensions |
+---------------+---------------+---------------+---------------+
| ... |
+---------------+---------------+---------------+---------------+
| Seconds |
+---------------+---------------+---------------+---------------+
| Nanoseconds |
+---------------+---------------+---------------+---------------+
| Flags | Device ID | Port ID |
+---------------+---------------+---------------+---------------+
*/
static int hf_metamako_origfcs = -1;
static int hf_metamako_trailerext = -1;
static int hf_metamako_unknownext = -1;
@ -35,11 +73,14 @@ static int hf_metamako_tagstring = -1;
static int hf_metamako_fracns = -1;
static int hf_metamako_crchash = -1;
static int hf_metamako_egress_seqnum = -1;
static int hf_metamako_time = -1;
static int hf_metamako_time_abs = -1;
static int hf_metamako_time_rel = -1;
static int hf_metamako_flags = -1;
static int hf_metamako_srcport = -1;
static int hf_metamako_srcdevice = -1;
static int hf_metamako_tdiff = -1;
static int hf_metamako_time_diff = -1;
static int hf_metamako_fcs = -1;
static int hf_metamako_fcs_status = -1;
static int hf_metamako_flags_orig_fcs_vld = -1;
static int hf_metamako_flags_has_ext = -1;
@ -53,9 +94,33 @@ static gint ett_metamako_timestamp = -1;
static gint ett_metamako_extensions = -1;
static gint ett_metamako_flags = -1;
static const true_false_string tfs_pcs49_btf = {"0x78", "0x33 or 0x66"};
static const enum_val_t metamako_fcs_vals[] = {
{"heuristic", "According to heuristic", -1},
{"never", "Never", 0},
{"always", "Always", 4},
{NULL, NULL, 0}
};
static int * const flags[] = {
static const enum_val_t metamako_trailer_present_vals[] = {
{"heuristic", "According to heuristic", -1},
{"never", "Never", 0},
{"always", "Always", 1},
{NULL, NULL, 0}
};
static const value_string tfs_pcs49_btf_vals[] = {
{ 0x0, "0x33 or 0x66" },
{ 0x1, "0x78"},
{ 0, NULL }
};
static const value_string tfs_orig_fcs_status_vals[] = {
{ 0x0, "Bad" },
{ 0x1, "Good"},
{ 0, NULL }
};
static int* const flags[] = {
&hf_metamako_flags_control_block_type,
&hf_metamako_flags_ts_degraded,
&hf_metamako_flags_duplicate,
@ -65,50 +130,63 @@ static int * const flags[] = {
NULL
};
static expert_field ei_metamako_fcs_bad = EI_INIT;
static void
sub_nanos_base_custom(gchar *result, guint32 value)
sub_nanos_base_custom(gchar* result, guint32 value)
{
double temp_double;
temp_double = ((double)value) / (1U << 24);
temp_double = ((double)value) / (1ULL << 24);
snprintf(result, ITEM_LABEL_LENGTH, "%1.9fns", temp_double);
}
static int
validate_metamako_timestamp(nstime_t *metamako_time, packet_info *pinfo)
validate_metamako_timestamp(nstime_t* metamako_time, packet_info* pinfo)
{
if ( metamako_time->secs > 3600 && metamako_time->nsecs < 1000000000 ) {
if ( metamako_time->secs > pinfo->abs_ts.secs ) {
if ( metamako_time->secs - pinfo->abs_ts.secs > 2592000 ) /* 30 days */
return 0;
} else {
if ( pinfo->abs_ts.secs - metamako_time->secs > 2592000 ) /* 30 days */
return 0;
}
/* Check that we have a valid nanoseconds field. */
if (metamako_time->nsecs >= TRAILER_NS_UPPER_BOUND)
return 0;
/* Check that the seconds in the trailer timestamp are in the user-specified bounds. */
if (!value_is_in_range(metamako_trailer_secs_bounds, (guint32)metamako_time->secs))
return 0;
/* Check that the number of days between the trailer timestamp
and the capture timestamp are within the user-specified bounds.
Don't use the abs() function because it is not supported on all
platforms and has type ambiguity. */
if (metamako_time->secs > pinfo->abs_ts.secs) {
if (metamako_time->secs - pinfo->abs_ts.secs > (time_t)metamako_trailer_days_diff_limit * SECS_IN_ONE_DAY)
return 0;
}
else {
return 0;
if (pinfo->abs_ts.secs - metamako_time->secs > (time_t)metamako_trailer_days_diff_limit * SECS_IN_ONE_DAY)
return 0;
}
return 1;
}
static int
dissect_metamako(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
dissect_metamako(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data _U_)
{
guint i, j;
guint i, i_start, i_end, j;
proto_tree *ti, *parent, *item;
proto_tree *metamako_tree, *timestamp_tree;
proto_tree *extensions_tree;
proto_tree* ti, * parent, * item;
proto_tree* metamako_tree, * timestamp_tree;
proto_tree* extensions_tree;
guint offset = 0;
guint captured_trailer_bytes;
guint metamako_trailer_bytes;
guint trailer_valid;
guint trailer_min_length;
gboolean trailer_valid;
gboolean has_fcs;
nstime_t metamako_time, timediff;
nstime_t metamako_time, time_diff, time_rel;
guint metamako_meta;
guint metamako_tlv_present;
guint metamako_tlv_count;
guint metamako_tlv_firstword;
@ -121,7 +199,7 @@ dissect_metamako(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data
guint16 metamako_srcdevice;
guint8 metamako_flags;
struct tm *tmp;
struct tm* tmp;
/* The Metamako trailer is made up of:
4 bytes -- original FCS
@ -131,53 +209,69 @@ dissect_metamako(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data
1 byte -- flags
2 bytes -- device ID
1 byte -- port ID
The new FCS is not a part of the trailer specification,
but it may be passed to this dissector in the course of
dissecting the Ethernet trailer.
If `metamako_fcs_len` is 0, we know it's not present;
if `metamako_fcs_len` is 4, we know it's present;
if `metamako_fcs_len` is -1, we need some heuristics to
determine whether it's present.
4 bytes -- New (valid) FCS (may or may not have been captured)
*/
/* First get the captured length of the trailer */
captured_trailer_bytes = tvb_captured_length(tvb);
/* If we have less than 12 bytes captured, we can't
read the timestamp to confirm the heuristic */
if ( captured_trailer_bytes < 12 )
/* If the user has told us that the Metamako trailer is not present,
then exit immediately. */
if (metamako_trailer_present == 0)
return 0;
/* Init variables before loop */
metamako_trailer_bytes = captured_trailer_bytes;
metamako_tlv_count = 0;
metamako_tlv_bytes = 0;
metamako_tlv_present = 0;
/* First get the captured length of the trailer. */
captured_trailer_bytes = tvb_captured_length(tvb);
/* Default state is no valid trailer found */
trailer_valid = 0;
/* Determine the minimum trailer length required, based on the user's
setting of the assumed FCS capture. */
trailer_min_length = metamako_fcs_len == 4 ? TRAILER_MIN_LENGTH_NO_FCS + 4 : TRAILER_MIN_LENGTH_NO_FCS;
/* Loop through the trailer bytes, try to find a valid trailer.
* Only try twice:
* - First try the case where IS NO trailing FCS
* - Second try the case where there IS a trailing FCS
/* If we have less than `trailer_min_length` bytes captured, we can't
read the trailer. */
if (captured_trailer_bytes < trailer_min_length)
return 0;
/* Adjust the state of the loop variables to account for the user options. */
trailer_valid = FALSE;
i_start = metamako_fcs_len == 4 ? 1 : 0;
i_end = metamako_fcs_len == 0 ? 1 : 2;
/* Loop through the trailer bytes, trying to find a valid trailer.
* When:
* i == 0, we assume there IS NO trailing FCS
* i == 1, we assume ther IS a trailing FCS
*/
for ( i = 0; i < 2 && metamako_trailer_bytes >= 12 && !trailer_valid; i++ ) {
/* Start at the tail of the trailer and work inwards */
metamako_meta = tvb_get_ntohl(tvb, metamako_trailer_bytes - 4);
metamako_flags = (metamako_meta >> 24) & 0xFF;
for (i = i_start; i < i_end && !trailer_valid; i++) {
has_fcs = i == 1;
captured_trailer_bytes -= 4 * i;
metamako_trailer_bytes = captured_trailer_bytes;
/* Start at the tail of the trailer and work inwards. */
metamako_meta = tvb_get_ntohl(tvb, metamako_trailer_bytes - 4);
metamako_flags = (metamako_meta >> 24) & 0xFF;
metamako_trailer_bytes -= 4;
metamako_time.nsecs = tvb_get_ntohl(tvb, metamako_trailer_bytes - 4);
metamako_trailer_bytes -= 4;
metamako_time.secs = tvb_get_ntohl(tvb, metamako_trailer_bytes - 4);
metamako_time.secs = tvb_get_ntohl(tvb, metamako_trailer_bytes - 4);
metamako_trailer_bytes -= 4;
/* Check the validity of the candidate timestamp */
if ( validate_metamako_timestamp(&metamako_time, pinfo) ) {
/* Check if the trailer has tlv extensions */
metamako_tlv_present = metamako_flags & 0x2;
/* Check the validity of the candidate timestamp. */
if ((metamako_trailer_present == 1) || validate_metamako_timestamp(&metamako_time, pinfo)) {
metamako_tlv_bytes = 0;
metamako_tlv_count = 0;
if ( metamako_tlv_present ) {
/* If the trailer has TLV extensions, "walk" them backwards to the Orig FCS field. */
if (metamako_flags & 0x2) {
/* Extensions are flagged as included, check if there is bytes
* to support this, and try to decode.
*/
while ( metamako_trailer_bytes >= 4 ) {
/* Bytes are here, decode as TLVs */
while (metamako_trailer_bytes >= 4) {
/* Bytes are here, decode as TLVs. */
metamako_tlv_firstword = tvb_get_ntohl(tvb, metamako_trailer_bytes - 4);
metamako_tlv_count++;
metamako_tlv_bytes += 4;
@ -186,51 +280,47 @@ dissect_metamako(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data
/* Extract length */
metamako_tlv_len = (metamako_tlv_firstword >> 6) & 0x3;
/* If its a secondary tag header, extract the extended length */
if ( ( metamako_tlv_firstword & 0x1F ) == 0x1F )
metamako_tlv_len = ( (metamako_tlv_firstword >> 6) & 0x3FF ) + 1;
/* If it's a secondary tag header, extract the extended length. */
if ((metamako_tlv_firstword & 0x1F) == 0x1F)
metamako_tlv_len = ((metamako_tlv_firstword >> 6) & 0x3FF) + 1;
/* Skip over the data, find the next tag */
while ( metamako_tlv_len > 0 ) {
/* Skip over the data and find the next tag. We do this in a loop
rather than subtracting `4 * metamako_tlv_len` in case the
dissection has picked up an invalid TLV length in its
heuristic search. This prevents the "walk" from going past the
original length of the trailer. */
while ((metamako_tlv_len > 0) && (metamako_trailer_bytes >= 4)) {
metamako_tlv_len--;
metamako_tlv_bytes += 4;
metamako_trailer_bytes -= 4;
}
/* If this is flagged as the last TLV, stop */
if ( ( metamako_tlv_firstword >> 5 ) & 0x1 ) {
/* If this is flagged as the last TLV, stop. */
if ((metamako_tlv_firstword >> 5) & 0x1) {
break;
}
}
}
/* There should be at least enough bytes for the Orig FCS left
* any bytes before this are padding
*/
if ( metamako_trailer_bytes >= 4 ) {
/* Decrement by the number of bytes in the Orig FCS field */
/* There should be at least enough bytes for the Orig FCS field.
* Any bytes before this are padding. */
if (metamako_trailer_bytes >= 4) {
/* Decrement by the number of bytes in the Orig FCS field. */
metamako_trailer_bytes -= 4;
/* This byte offset is the beginning of the Metamako trailer */
/* This byte offset is the beginning of the Metamako trailer. */
offset = metamako_trailer_bytes;
/* If we've made it this far, it appears we've got a valid trailer */
trailer_valid = 1;
/* If we've made it this far, it appears we've got a valid trailer. */
trailer_valid = TRUE;
}
}
/* If we didn't find a valid metamako trailer, try again using 4 bytes less */
if ( !trailer_valid ) {
captured_trailer_bytes -= 4;
metamako_trailer_bytes = captured_trailer_bytes;
}
}
/* Did we find a valid trailer? */
if ( !trailer_valid )
if (!trailer_valid)
return 0;
/* Everything looks good! Now dissect the trailer. */
col_append_str(pinfo->cinfo, COL_INFO, " with Metamako trailer");
ti = proto_tree_add_item(tree, proto_metamako, tvb, offset, (captured_trailer_bytes - offset), ENC_NA);
metamako_tree = proto_item_add_subtree(ti, ett_metamako);
@ -239,121 +329,109 @@ dissect_metamako(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data
offset += 4;
/* TLV Extensions */
if ( metamako_tlv_present ) {
if (metamako_tlv_bytes > 0) {
parent = proto_tree_add_item(metamako_tree, hf_metamako_trailerext, tvb, captured_trailer_bytes - 12 - metamako_tlv_bytes, metamako_tlv_bytes, ENC_NA);
extensions_tree = proto_item_add_subtree(parent, ett_metamako_extensions);
while ( metamako_tlv_count > 0 ) {
while (metamako_tlv_count > 0) {
metamako_tlv_pos = captured_trailer_bytes - 16;
i = metamako_tlv_count;
do {
/* Read TLV word and decode */
/* Read TLV word and decode. */
metamako_tlv_firstword = tvb_get_ntohl(tvb, metamako_tlv_pos);
metamako_tlv_len = ( metamako_tlv_firstword >> 6 ) & 0x3;
metamako_tlv_bytes = ( metamako_tlv_len * 4 ) + 3;
metamako_tlv_tag = ( metamako_tlv_firstword & 0x1F );
metamako_tlv_len = (metamako_tlv_firstword >> 6) & 0x3;
metamako_tlv_bytes = (metamako_tlv_len * 4) + 3;
metamako_tlv_tag = (metamako_tlv_firstword & 0x1F);
/* If this is a Secondary Tag Header, decode the tag extensions */
if ( ( metamako_tlv_firstword & 0x1F ) == 0x1F ) {
metamako_tlv_len = ( ( metamako_tlv_firstword >> 6 ) & 0x3FF ) + 1;
metamako_tlv_bytes = ( metamako_tlv_len * 4 );
metamako_tlv_tag += ( ( metamako_tlv_firstword >> 16 ) & 0xFFFF );
/* If this is a Secondary Tag Header, decode the tag extensions. */
if ((metamako_tlv_firstword & 0x1F) == 0x1F) {
metamako_tlv_len = ((metamako_tlv_firstword >> 6) & 0x3FF) + 1;
metamako_tlv_bytes = (metamako_tlv_len * 4);
metamako_tlv_tag += ((metamako_tlv_firstword >> 16) & 0xFFFF);
}
/* Decrement TLV count */
/* Decrement TLV count. */
i--;
/* Skip over the data if this is not our destination */
if ( i != 0 )
metamako_tlv_pos -= ( metamako_tlv_len + 1 ) * 4;
}
while ( i > 0 );
/* Skip over the data if this is not our destination. */
if (i != 0)
metamako_tlv_pos -= (metamako_tlv_len + 1) * 4;
} while (i > 0);
/* We've skipped to the i-th TLV, decode it */
switch ( metamako_tlv_tag ) {
case 0:
/* Sequence Number */
metamako_tlv_pos -= ( metamako_tlv_len + 1 ) * 4;
proto_tree_add_item(extensions_tree, hf_metamako_seqnum, tvb, metamako_tlv_pos + 5, 2, ENC_BIG_ENDIAN);
proto_item_append_text(parent, ", Sequence No: %d", tvb_get_ntohs(tvb, metamako_tlv_pos + 5));
/* Increment the offset by the Data + Tag size */
offset += ( metamako_tlv_len + 1 ) * 4;
break;
metamako_tlv_pos -= (metamako_tlv_len + 1) * 4;
/* We've skipped to the i-th TLV, decode it. */
switch (metamako_tlv_tag) {
case 0x00:
/* Ingress Sequence Number */
proto_tree_add_item(extensions_tree, hf_metamako_seqnum, tvb, metamako_tlv_pos + 5, 2, ENC_BIG_ENDIAN);
proto_item_append_text(parent, ", Sequence No: %d", tvb_get_ntohs(tvb, metamako_tlv_pos + 5));
break;
case 1:
/* Sub-nanoseconds */
metamako_tlv_pos -= ( metamako_tlv_len + 1 ) * 4;
proto_tree_add_item(extensions_tree, hf_metamako_fracns, tvb, metamako_tlv_pos + 4, 3, ENC_BIG_ENDIAN);
proto_item_append_text(parent, ", Sub-nanoseconds: %1.9fns", ((double)(tvb_get_ntohl(tvb, metamako_tlv_pos + 3) & 0x00FFFFFF)) / (1U << 24));
/* Increment the offset by the Data + Tag size */
offset += ( metamako_tlv_len + 1 ) * 4;
break;
case 0x01:
/* Sub-nanoseconds */
proto_tree_add_item(extensions_tree, hf_metamako_fracns, tvb, metamako_tlv_pos + 4, 3, ENC_BIG_ENDIAN);
proto_item_append_text(parent, ", Sub-nanoseconds: %1.9fns", ((double)(tvb_get_ntohl(tvb, metamako_tlv_pos + 3) & 0x00FFFFFF)) / (1ULL << 24));
break;
case 2:
/* De-duplication CRC64 Hash */
metamako_tlv_pos -= ( metamako_tlv_len + 1 ) * 4;
proto_tree_add_item(extensions_tree, hf_metamako_crchash, tvb, metamako_tlv_pos + 4, 8, ENC_BIG_ENDIAN);
proto_item_append_text(parent, ", CRC64 ECMA Hash: 0x%" PRIx64, tvb_get_ntoh64(tvb, metamako_tlv_pos + 4));
/* Increment the offset by the Data + Tag size */
offset += ( metamako_tlv_len + 1 ) * 4;
break;
case 0x02:
/* Deduplication CRC64 Hash */
proto_tree_add_item(extensions_tree, hf_metamako_crchash, tvb, metamako_tlv_pos + 4, 8, ENC_BIG_ENDIAN);
proto_item_append_text(parent, ", CRC64 ECMA Hash: 0x%" PRIx64, tvb_get_ntoh64(tvb, metamako_tlv_pos + 4));
break;
case 3:
/* Egress Sequence Number */
metamako_tlv_pos -= ( metamako_tlv_len + 1 ) * 4;
proto_tree_add_item(extensions_tree, hf_metamako_egress_seqnum, tvb, metamako_tlv_pos + 4, 3, ENC_BIG_ENDIAN);
proto_item_append_text(parent, ", Egress Sequence No: %d", tvb_get_ntohl(tvb, metamako_tlv_pos + 3) & 0x000FFFFF);
/* Increment the offset by the Data + Tag size */
offset += ( metamako_tlv_len + 1 ) * 4;
break;
case 0x03:
/* Egress Sequence Number */
proto_tree_add_item(extensions_tree, hf_metamako_egress_seqnum, tvb, metamako_tlv_pos + 4, 3, ENC_BIG_ENDIAN);
proto_item_append_text(parent, ", Egress Sequence No: %d", tvb_get_ntohl(tvb, metamako_tlv_pos + 3) & 0x000FFFFF);
break;
case 31:
/* Tag String */
metamako_tlv_pos -= ( metamako_tlv_len + 1 ) * 4;
proto_tree_add_item(extensions_tree, hf_metamako_tagstring, tvb, metamako_tlv_pos + 4, metamako_tlv_len * 4, ENC_ASCII);
/* Increment the offset by the Data + Tag size */
offset += ( metamako_tlv_len + 1 ) * 4;
break;
case 0x1F:
/* Tag String */
proto_tree_add_item(extensions_tree, hf_metamako_tagstring, tvb, metamako_tlv_pos + 4, metamako_tlv_len * 4, ENC_ASCII);
break;
default:
/* Unknown tag: just print it's ID and Data */
metamako_tlv_pos -= ( metamako_tlv_len + 1 ) * 4;
item = proto_tree_add_item(extensions_tree, hf_metamako_unknownext, tvb, metamako_tlv_pos + 4, metamako_tlv_bytes, ENC_NA);
/* Start with the Tag */
proto_item_set_text(item, "Unknown Tag [0x%05x]: ", metamako_tlv_tag);
/* Iterate through the data appending as we go */
for ( j = 0; j < metamako_tlv_bytes; j++ ) {
proto_item_append_text(item, "%02x", tvb_get_guint8(tvb, metamako_tlv_pos + 4 + j));
if ( (28 + j*2) >= ITEM_LABEL_LENGTH ) {
proto_item_append_text(item, "...");
break;
}
default:
/* Unknown tag: just print it's ID and Data. */
item = proto_tree_add_item(extensions_tree, hf_metamako_unknownext, tvb, metamako_tlv_pos + 4, metamako_tlv_bytes, ENC_NA);
/* Start with the Tag */
proto_item_set_text(item, "Unknown Tag [0x%05" PRIx32 "]: ", metamako_tlv_tag);
/* Iterate through the data appending as we go */
for (j = 0; j < metamako_tlv_bytes; j++) {
proto_item_append_text(item, "%02" PRIx8, tvb_get_guint8(tvb, metamako_tlv_pos + 4 + j));
if ((28 + j * 2) >= ITEM_LABEL_LENGTH) {
proto_item_append_text(item, "...");
break;
}
/* Increment the offset by the Data + Tag size */
offset += ( metamako_tlv_len + 1 ) * 4;
break;
}
break;
}
/* Increment the offset by the Data + Tag size */
offset += (metamako_tlv_len + 1) * 4;
/* Decrement count as we've just decoded a TLV */
metamako_tlv_count--;
}
}
/* Timestamp */
item = proto_tree_add_time(metamako_tree, hf_metamako_time, tvb, offset, 8, &metamako_time);
item = proto_tree_add_time(metamako_tree, hf_metamako_time_abs, tvb, offset, 8, &metamako_time);
timestamp_tree = proto_item_add_subtree(item, ett_metamako_timestamp);
tmp = localtime(&metamako_time.secs);
if (tmp)
proto_item_append_text(ti, ", Timestamp: %02d:%02d:%02d.%09ld",
tmp->tm_hour, tmp->tm_min, tmp->tm_sec,(long)metamako_time.nsecs);
tmp->tm_hour, tmp->tm_min, tmp->tm_sec, (long)metamako_time.nsecs);
else
proto_item_append_text(ti, ", Timestamp: <Not representable>");
/* [Timestamp difference from pcap time] */
nstime_delta(&timediff, &metamako_time, &pinfo->abs_ts);
item = proto_tree_add_time(timestamp_tree, hf_metamako_tdiff, tvb, offset, 8, &timediff);
/* [Timestamp in seconds] */
item = proto_tree_add_time_item(timestamp_tree, hf_metamako_time_rel, tvb, offset, 8,
ENC_BIG_ENDIAN, &time_rel, NULL, NULL);
proto_item_set_generated(item);
/* [Timestamp difference from pcap time] */
nstime_delta(&time_diff, &metamako_time, &pinfo->abs_ts);
item = proto_tree_add_time(timestamp_tree, hf_metamako_time_diff, tvb, offset, 8, &time_diff);
proto_item_set_generated(item);
offset += 8;
/* Flags */
@ -372,6 +450,23 @@ dissect_metamako(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data
proto_item_append_text(ti, ", Source Port: %d", metamako_srcport);
offset++;
if (has_fcs) {
guint32 sent_fcs = tvb_get_ntohl(tvb, offset);
if (metamako_check_fcs) {
tvbuff_t* parent_tvb = tvb_get_ds_tvb(tvb);
guint32 fcs = crc32_802_tvb(parent_tvb, tvb_captured_length(parent_tvb) - 4);
proto_tree_add_checksum(tree, tvb, offset, hf_metamako_fcs, hf_metamako_fcs_status, &ei_metamako_fcs_bad, pinfo, fcs, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY);
if (fcs != sent_fcs) {
col_append_str(pinfo->cinfo, COL_INFO, " [ETHERNET FRAME CHECK SEQUENCE INCORRECT]");
}
}
else {
proto_tree_add_checksum(tree, tvb, offset, hf_metamako_fcs, hf_metamako_fcs_status, &ei_metamako_fcs_bad, pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
}
offset += 4;
}
return offset;
}
@ -419,29 +514,34 @@ proto_register_metamako(void)
FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_metamako_time, {
"Time Stamp", "metamako.time",
{ &hf_metamako_time_abs, {
"Time Stamp", "metamako.time.abs",
FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0,
NULL, HFILL }},
{&hf_metamako_flags, {
{ &hf_metamako_time_rel, {
"Time Stamp", "metamako.time.rel",
FT_RELATIVE_TIME, ENC_BIG_ENDIAN, NULL, 0x0,
NULL, HFILL }},
{ &hf_metamako_time_diff, {
"Time Difference", "metamako.time.diff",
FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
"Difference from capture timestamp", HFILL }},
{&hf_metamako_flags, {
"Flags", "metamako.flags",
FT_UINT8, BASE_HEX, NULL, 0x0,
NULL, HFILL}},
{&hf_metamako_flags_orig_fcs_vld, {
"Original FCS Valid", "metamako.flags.orig_fcs_vld",
FT_BOOLEAN, 8, TFS(&tfs_valid_invalid), 0x01,
{&hf_metamako_reserved, {
"Reserved", "metamako.reserved",
FT_UINT8, BASE_HEX, NULL, 0xC8,
NULL, HFILL}},
{&hf_metamako_flags_has_ext, {
"Has Trailer Extensions", "metamako.flags.has_extensions",
FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x02,
NULL, HFILL}},
{&hf_metamako_flags_duplicate, {
"Duplicate Packet", "metamako.flags.is_duplicate",
FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x04,
{&hf_metamako_flags_control_block_type, {
"Clause 49 BTF", "metamako.flags.pcs49_btf",
FT_UINT8, BASE_HEX, VALS(tfs_pcs49_btf_vals), 0x20,
NULL, HFILL}},
{&hf_metamako_flags_ts_degraded, {
@ -449,14 +549,19 @@ proto_register_metamako(void)
FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x10,
NULL, HFILL}},
{&hf_metamako_flags_control_block_type, {
"Clause 49 BTF", "metamako.flags.pcs49_btf",
FT_BOOLEAN, 8, TFS(&tfs_pcs49_btf), 0x20,
{&hf_metamako_flags_duplicate, {
"Duplicate Packet", "metamako.flags.is_duplicate",
FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x04,
NULL, HFILL}},
{&hf_metamako_reserved, {
"Reserved", "metamako.reserved",
FT_UINT8, BASE_HEX, NULL, 0xC8,
{&hf_metamako_flags_has_ext, {
"Has Trailer Extensions", "metamako.flags.has_extensions",
FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x02,
NULL, HFILL}},
{&hf_metamako_flags_orig_fcs_vld, {
"Original FCS Status", "metamako.flags.orig_fcs_status",
FT_UINT8, BASE_HEX, VALS(tfs_orig_fcs_status_vals), 0x01,
NULL, HFILL}},
{ &hf_metamako_srcdevice, {
@ -469,22 +574,81 @@ proto_register_metamako(void)
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_metamako_tdiff, {
"Time Difference", "metamako.tdiff",
FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
"Difference from capture timestamp", HFILL }}
{ &hf_metamako_fcs, {
"Frame check sequence", "metamako.fcs",
FT_UINT32, BASE_HEX, NULL, 0x0,
"Ethernet checksum", HFILL }},
{ &hf_metamako_fcs_status, {
"FCS Status", "metamako.fcs.status",
FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0,
NULL, HFILL }},
};
static gint *ett[] = {
static gint* ett[] = {
&ett_metamako,
&ett_metamako_extensions,
&ett_metamako_timestamp,
&ett_metamako_flags
};
static ei_register_info ei[] = {
{ &ei_metamako_fcs_bad, { "metamako.fcs_bad", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }},
};
module_t* metamako_module;
/* Register the Metamako trailer. */
proto_metamako = proto_register_protocol("Metamako ethernet trailer", "Metamako", "metamako");
/* Register header fields. */
proto_register_field_array(proto_metamako, hf, array_length(hf));
/* Register subtree types. */
proto_register_subtree_array(ett, array_length(ett));
/* Register the expert module. */
expert_register_field_array(expert_register_protocol(proto_metamako), ei, array_length(ei));
/* Register configuration preferences */
metamako_module = prefs_register_protocol(proto_metamako, NULL);
range_convert_str(wmem_epan_scope(), &metamako_trailer_secs_bounds, TRAILER_SECS_BOUNDS_DFLT, 0xffffffff);
prefs_register_range_preference(metamako_module, "secs_bounds",
"Heuristic: Bounds of the seconds value in the trailer timestamp",
"If the trailer is found using heuristics, then the trailer may or may not be added "
"and the FCS may or may not be captured. One of the heuristics is the timestamp seconds "
"value being within specified bounds. "
"Set ranges of valid seconds to adjust this particular heuristic.",
&metamako_trailer_secs_bounds, 0xffffffff);
prefs_register_uint_preference(metamako_module, "days_diff_limit",
"Heuristic: Max. number of days difference between capture and trailer timestamps",
"If the trailer is found using heuristics, then the trailer may or may not be added "
"and the FCS may or may not be captured. One of the heuristics is the number of days "
"difference between the capture (PCAP) timestamp and the Ethernet trailer timestamp. "
"Set an upper bound (in days) to adjust this particular heuristic.",
10, &metamako_trailer_days_diff_limit);
prefs_register_enum_preference(metamako_module, "trailer_present",
"Assume packets have a Metamako trailer",
"This option can override the trailer detection heuristic so that the Metamako "
"trailer is either never or always present.",
&metamako_trailer_present, metamako_trailer_present_vals, FALSE);
prefs_register_enum_preference(metamako_module, "fcs",
"Assume packets have FCS",
"Some Ethernet adapters and drivers include the FCS at the end of a packet, others do not. "
"Some capture file formats and protocols do not indicate whether or not the FCS is included. "
"The Metamako dissector attempts to guess whether a captured packet has an FCS, "
"but it cannot always guess correctly. This option can override that heuristic "
"and assume that the FCS is either never or always present.",
&metamako_fcs_len, metamako_fcs_vals, FALSE);
prefs_register_bool_preference(metamako_module, "check_fcs",
"Validate the Ethernet checksum if possible",
"Whether to validate the Frame Check Sequence",
&metamako_check_fcs);
}
void