/* packet-ixiatrailer.c * Routines for Ixia trailer parsing * * Dissector for Ixia Network Visibility Solutions trailer * Copyright Ixia 2012 * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "config.h" #include #include #include #include #include void proto_register_ixiatrailer(void); void proto_reg_handoff_ixiatrailer(void); /* Trailer "magic number". */ #define IXIA_PATTERN 0xAF12 /* Trailer TLV types. TODO: which of these typestamp types are currently supported? Should lose the rest!! */ #define IXIATRAILER_FTYPE_ORIGINAL_PACKET_SIZE 1 #define IXIATRAILER_FTYPE_TIMESTAMP_LOCAL 3 #define IXIATRAILER_FTYPE_TIMESTAMP_NTP 4 #define IXIATRAILER_FTYPE_TIMESTAMP_GPS 5 #define IXIATRAILER_FTYPE_TIMESTAMP_1588 6 /* PTP */ #define IXIATRAILER_FTYPE_TIMESTAMP_HOLDOVER 7 static const value_string ixiatrailer_ftype_timestamp[] = { { IXIATRAILER_FTYPE_TIMESTAMP_LOCAL, "Local" }, { IXIATRAILER_FTYPE_TIMESTAMP_NTP, "NTP" }, { IXIATRAILER_FTYPE_TIMESTAMP_GPS, "GPS" }, { IXIATRAILER_FTYPE_TIMESTAMP_1588, "PTP" }, { IXIATRAILER_FTYPE_TIMESTAMP_HOLDOVER, "Holdover" }, { 0, NULL } }; /* Preference settings */ static gboolean ixiatrailer_summary_in_tree = TRUE; static int proto_ixiatrailer = -1; static gint ett_ixiatrailer = -1; static int hf_ixiatrailer_packetlen = -1; static int hf_ixiatrailer_timestamp = -1; static int hf_ixiatrailer_generic = -1; static expert_field ei_ixiatrailer_field_length_invalid = EI_INIT; /* The trailer begins with a sequence of TLVs, each of which has a 1-byte type, a 1-byte value length (not TLV length, so the TLV length is the value length + 2), and a variable-length value. Following the sequence of TLVs is: a 1-byte field giving the length of the sequence of TLVs; a 2-byte big-endian signature field with the value 0xAF12; a 2-byte big-endian checksum field, covering the sequence of TLVs, the sequence length, and the signature. */ static int dissect_ixiatrailer(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_) { proto_tree *ti; guint tvblen, trailer_length, field_length; gboolean matched_without_fcs, matched_with_fcs; proto_tree *ixiatrailer_tree = NULL; guint offset = 0; guint16 cksum, comp_cksum; vec_t vec; guint8 field_type; /* A trailer must, at minimum, include: a "original packet size" TLV, with 1 byte of type, 1 byte of value length, and 2 bytes of original packet ize; 1 byte of trailer length; 2 bytes of signature; 2 bytes of trailer checksum; for a total of 9 bytes. */ tvblen = tvb_reported_length(tvb); if (tvblen != tvb_captured_length(tvb)) { /* The heuristic check includes a checksum check, so we need the *entire* trailer to have been captured; if it wasn't, we don't try to check it. */ return 0; } if (tvblen < 9) { /* This is too short, so it cannot be a valid Ixia trailer. */ return 0; } /* Depending upon the ethernet preference "Assume packets have FCS", we may be given those 4 bytes too. Try checking two locations for our pattern. */ if (tvblen == 23) { tvblen = 19; } /* 3rd & 4th bytes from the end must match our pattern. First, try under the assumption that the tvbuff doesn't include the FCS. */ matched_without_fcs = (tvb_get_ntohs(tvb, tvblen-4) == IXIA_PATTERN); /* If that didn't match, is the tvbuff big enough to include an Ixia trailer *and* an FCS? If so, try under that assumption. */ if (!matched_without_fcs && tvblen >= 13) matched_with_fcs = (tvb_get_ntohs(tvb, tvblen-(4+4)) == IXIA_PATTERN); else matched_with_fcs = FALSE; if (!matched_without_fcs) { if (!matched_with_fcs) { /* Neither matched, so no Ixia trailer. */ return 0; } /* Matched under the assumption that we have an FCS, so let's act as if that's the case. Remove the FCS length from the tvbuff. */ tvblen -= 4; } /* Read Trailer-length field */ trailer_length = tvb_get_guint8(tvb, tvblen-5); /* Should match overall length of trailer */ if ((tvblen-5) != trailer_length) { return 0; } /* Last 2 bytes are the checksum */ cksum = tvb_get_ntohs(tvb, tvblen-2); /* Verify the checksum; if not valid, it means that the trailer is not valid */ SET_CKSUM_VEC_TVB(vec, tvb, offset, trailer_length + 3); comp_cksum = in_cksum(&vec, 1); if (pntoh16(&comp_cksum) != cksum) { return 0; } /* OK: We have our trailer - create protocol root */ ti = proto_tree_add_item(tree, proto_ixiatrailer, tvb, offset, trailer_length + 5, ENC_NA); /* Append summary to item, if configured to */ if (ixiatrailer_summary_in_tree) { proto_item_append_text(ti, ", Length: %u, Checksum: 0x%x", trailer_length, cksum); } /* Create subtree */ ixiatrailer_tree = proto_item_add_subtree(ti, ett_ixiatrailer); while (offset < trailer_length - 2) { field_type = tvb_get_guint8(tvb, offset++); field_length = tvb_get_guint8(tvb, offset++); switch (field_type) { case IXIATRAILER_FTYPE_ORIGINAL_PACKET_SIZE: if (field_length != 2){ expert_add_info_format(pinfo, ti, &ei_ixiatrailer_field_length_invalid, "Field length %u invalid", field_length); break; } ti = proto_tree_add_item(ixiatrailer_tree, hf_ixiatrailer_packetlen, tvb, offset, field_length, ENC_BIG_ENDIAN); proto_item_append_text(ti, " bytes"); break; case IXIATRAILER_FTYPE_TIMESTAMP_LOCAL: case IXIATRAILER_FTYPE_TIMESTAMP_NTP: case IXIATRAILER_FTYPE_TIMESTAMP_GPS: case IXIATRAILER_FTYPE_TIMESTAMP_1588: case IXIATRAILER_FTYPE_TIMESTAMP_HOLDOVER: if (field_length != 8) { expert_add_info_format(pinfo, ti, &ei_ixiatrailer_field_length_invalid, "Field length %u invalid", field_length); break; } /* Timestamp */ ti = proto_tree_add_item(ixiatrailer_tree, hf_ixiatrailer_timestamp, tvb, offset, field_length, ENC_TIME_SECS_NSECS|ENC_BIG_ENDIAN); proto_item_append_text(ti, "; Source: %s", val_to_str_const(field_type, ixiatrailer_ftype_timestamp, "Unknown")); break; default: /* Not a recognized time format - just show as bytes */ ti = proto_tree_add_item(ixiatrailer_tree, hf_ixiatrailer_generic, tvb, offset, field_length, ENC_NA); proto_item_append_text(ti, " [Id: %u, Length: %u bytes]", field_type, field_length); break; }; offset += field_length; } /* We are claiming all of the bytes */ return tvblen; } void proto_register_ixiatrailer(void) { static hf_register_info hf[] = { { &hf_ixiatrailer_packetlen, { "Original packet length", "ixiatrailer.packetlen", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_ixiatrailer_timestamp, { "Time Stamp", "ixiatrailer.timestamp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL }}, { &hf_ixiatrailer_generic, { "Generic Field", "ixiatrailer.generic", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, }; static gint *ixiatrailer_ett[] = { &ett_ixiatrailer }; static ei_register_info ei[] = { { &ei_ixiatrailer_field_length_invalid, { "ixiatrailer.field_length_invalid", PI_MALFORMED, PI_ERROR, "Field length invalid", EXPFILL }}, }; module_t *ixiatrailer_module; expert_module_t* expert_ixiatrailer; proto_ixiatrailer = proto_register_protocol("Ixia Trailer", "IXIATRAILER", "ixiatrailer"); proto_register_field_array(proto_ixiatrailer, hf, array_length(hf)); proto_register_subtree_array(ixiatrailer_ett, array_length(ixiatrailer_ett)); expert_ixiatrailer = expert_register_protocol(proto_ixiatrailer); expert_register_field_array(expert_ixiatrailer, ei, array_length(ei)); ixiatrailer_module = prefs_register_protocol(proto_ixiatrailer, NULL); prefs_register_bool_preference(ixiatrailer_module, "summary_in_tree", "Show trailer summary in protocol tree", "Whether the trailer summary line should be shown in the protocol tree", &ixiatrailer_summary_in_tree); } void proto_reg_handoff_ixiatrailer(void) { /* Check for Ixia format in the ethernet trailer */ heur_dissector_add("eth.trailer", dissect_ixiatrailer, "Ixia Trailer", "ixiatrailer_eth", proto_ixiatrailer, HEURISTIC_ENABLE); } /* * Editor modelines - http://www.wireshark.org/tools/modelines.html * * Local Variables: * c-basic-offset: 2 * tab-width: 8 * indent-tabs-mode: nil * End: * * ex: set shiftwidth=2 tabstop=8 expandtab: * :indentSize=2:tabSize=8:noTabs=true: */