From e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 10 Apr 2024 22:34:10 +0200 Subject: Adding upstream version 4.2.2. Signed-off-by: Daniel Baumann --- epan/dissectors/packet-amp.c | 835 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 835 insertions(+) create mode 100644 epan/dissectors/packet-amp.c (limited to 'epan/dissectors/packet-amp.c') diff --git a/epan/dissectors/packet-amp.c b/epan/dissectors/packet-amp.c new file mode 100644 index 00000000..fb82ea10 --- /dev/null +++ b/epan/dissectors/packet-amp.c @@ -0,0 +1,835 @@ +/* packet-amp.c + * Routines for Asynchronous management Protocol dissection + * Copyright 2018, Krishnamurthy Mayya (krishnamurthymayya@gmail.com) + * Updated to CBOR encoding: Keith Scott, 2019 (kscott@mitre.org) + * + * 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 "packet-amp.h" + +/* The AMP standard can be found here: + * https://tools.ietf.org/html/draft-birrane-dtn-amp-04 + * https://tools.ietf.org/html/draft-birrane-dtn-amp-03 + */ + +#define AMP_APID 0x000 /* TODO - To be decided. Currently, the function 'dissect_amp_as_subtree' is + being called from dtn.c file when required to decode the bundle protocol's + data-payload as AMP. Later in the future, when a dedicated field is given to + this, this should be filled. */ + +/* + */ +static void +add_value_time_to_tree(guint64 value, int len, proto_tree *tree, tvbuff_t *tvb, int offset, int hf_time_format) +{ + nstime_t dtn_time; + + // If it's a relative time, just make it zero. + if ( value < 558230400 ) { + value = 0; + } + dtn_time.secs = (time_t)(value); + dtn_time.nsecs = 0; + proto_tree_add_time(tree, hf_time_format, tvb, offset, len, &dtn_time); + + return; +} + +#define AMP_HDR_RESERVED 0xC0 +#define AMP_HDR_ACL 0x20 +#define AMP_HDR_NACK 0x10 +#define AMP_HDR_ACK 0x08 +#define AMP_HDR_OPCODE 0x07 + +#define AMP_ARI_NICKNAME 0x80 +#define AMP_ARI_PARAMETERS 0x40 +#define AMP_ARI_ISSUER 0x20 +#define AMP_ARI_TAG 0x10 +#define AMP_ARI_STRUCT 0x0F +#define AMP_ARI_VALUE 0xF0 + +#define AMP_CBOR_UINT_SMALL 0x1F + +#define AMP_TNVC_RESERVED 0xF0 +#define AMP_TNVC_MIXED 0x08 +#define AMP_TNVC_TYPE 0x04 +#define AMP_TNVC_NAME 0x02 +#define AMP_TNVC_VALUE 0x01 + +#define AMP_MSG_REGISTER_AGENT 0x01 +#define AMP_MSG_DATA_REPORT 0x00 +#define AMP_MSG_PERFORM_CONTROL 0x02 + +static dissector_handle_t amp_handle; + +void proto_register_amp(void); +void proto_reg_handoff_amp(void); + +static int hf_amp_message_header = -1; +static int hf_amp_report_bytestring = -1; +static int hf_amp_report_data = -1; +static int hf_amp_report_integer8_small = -1; +static int hf_amp_report_integer = -1; +static int hf_amp_cbor_header = -1; +static int hf_amp_primary_timestamp = -1; +static int hf_amp_agent_name = -1; +static int hf_amp_text_string = -1; +static int hf_amp_ari_flags = -1; +static int hf_ari_value = -1; +static int hf_ari_struct = -1; +static int hf_ari_nickname = -1; +static int hf_ari_parameters = -1; +static int hf_ari_issuer = -1; +static int hf_ari_tag = -1; +static int hf_amp_tnvc_flags = -1; +static int hf_amp_tnvc_reserved = -1; +static int hf_amp_tnvc_mixed = -1; +static int hf_amp_tnvc_typed = -1; +static int hf_amp_tnvc_name = -1; +static int hf_amp_tnvc_values = -1; + +/* Initialize the protocol and registered fields */ +static int proto_amp = -1; + +static gint ett_amp_message_header = -1; +static gint ett_amp_proto = -1; +static gint ett_amp = -1; +static gint ett_amp_cbor_header = -1; +static gint ett_amp_message = -1; +static gint ett_amp_register = -1; +static gint ett_amp_report_set = -1; +static gint ett_amp_report = -1; +static gint ett_amp_tnvc_flags = -1; +static gint ett_amp_ari_flags = -1; + +static int hf_amp_reserved = -1; +static int hf_amp_acl = -1; +static int hf_amp_nack = -1; +static int hf_amp_ack = 0; +static int hf_amp_opcode = -1; +static int hf_amp_rx_name = -1; + +static expert_field ei_amp_cbor_malformed = EI_INIT; + +static const value_string opcode[] = { + { 0, "Register Agent" }, + { 1, "Report Set" }, + { 2, "Perform Control" }, + { 0, NULL } +}; + +static const value_string tnvc_yesno[] = { + { 0, "no" }, + { 1, "yes" }, + { 0, NULL } +}; + +static const value_string tnvc_present_notpresent[] = { + { 0, "not present" }, + { 1, "present" }, + { 0, NULL } +}; + +static const value_string amp_ari_struct_type[] = { + { 0, "Const" }, + { 1, "Control" }, + { 2, "Externally Defined Data" }, + { 3, "Macro" }, + { 4, "Operation" }, + { 5, "Report Template" }, + { 6, "State-Based Rule" }, + { 7, "Table Templates" }, + { 8, "Time-Based Rule" }, + { 9, "Variables" }, + { 10, "Metadata" }, + { 11, "Reserved" }, + { 12, "Reserved" }, + { 13, "Reserved" }, + { 14, "Reserved" }, + { 15, "Reserved" }, + { 16, "Reserved" }, + { 17, "Reserved" }, + { 18, "Reserved" }, + { 19, "Reserved" }, + { 0, NULL } +}; + + +/* AMP Message Header */ +static int * const amp_message_header[] = { + &hf_amp_reserved, + &hf_amp_acl, + &hf_amp_nack, + &hf_amp_ack, + &hf_amp_opcode, + 0 +}; + +/* TNVC Flags */ +static int * const amp_tnvc_flags[] = { + &hf_amp_tnvc_reserved, + &hf_amp_tnvc_mixed, + &hf_amp_tnvc_typed, + &hf_amp_tnvc_name, + &hf_amp_tnvc_values, + 0 +}; + +/* ARI Flags */ +static int * const amp_ari_flags[] = { + &hf_ari_nickname, + &hf_ari_parameters, + &hf_ari_issuer, + &hf_ari_tag, + &hf_ari_struct, + 0 +}; + +/* CBOR Types */ +typedef enum { + CBOR_UNKNOWN = -1, + CBOR_UINT = 0, // Positive, unsigned integer + CBOR_INT = 1, // Negative integer + CBOR_BYTESTRING = 2, + CBOR_TEXTSTRING = 3, + CBOR_ARRAY = 4, + CBOR_MAP = 5, + CBOR_SEMANTIC_TAG = 6, + CBOR_PRIMITIVE = 7 +} CBOR_TYPE; + +typedef struct { + int type; + int size; // for integers, the value + // for bytestrings and textstrings, the size of the string + // for arrays, the number of elements in the array + guint64 totalSize; // total size (including size above and any bytestring + // size). + guint64 uint; +} cborObj; + + +// Decode the CBOR object at the given offset in the tvb. +// The returned cborObj contains the object (with type) and the size +// (including the CBOR identifier). +static cborObj cbor_info(tvbuff_t *tvb, int offset) +{ + int tmp = 0; + cborObj ret; + ret.type = CBOR_UNKNOWN; + ret.size = 0; + ret.totalSize = 0; + ret.uint = -1; + int theSize; + + tmp = tvb_get_guint8(tvb, offset); + + offset += 1; + ret.size += 1; + + ret.type = (tmp & 0xE0)>>5; // Top 3 bits + theSize = (tmp & 0x1F); + + switch ( ret.type ) + { + case 0x00: // Positive / Unsigned integer + if ( theSize<24 ) { + ret.uint = (tmp & 0x1F); // May be actual size or indication of follow-on size + } else if (theSize==24) { // next byte is uint8_t data + ret.uint = tvb_get_guint8(tvb, offset); + ret.size += 1; + } else if (theSize==25) { // next 2 bytes are uint16_t data + ret.uint = tvb_get_guint16(tvb, offset, 0); + ret.size += 2; + } else if (theSize==26) { // next 4 bytes are uint32_t data + ret.uint = tvb_get_guint32(tvb, offset, 0); + ret.size += 4; + } else if (theSize==27) { // next 8 bytes are uint64_t data + ret.uint = tvb_get_guint64(tvb, offset, 0); + ret.size += 8; + } + ret.totalSize = ret.size; + break; + + case 0x02: // Byte string + if ( theSize<24 ) { // Array size is contained in the identifier byte + ret.uint = (tmp & 0x1F); + } else if (theSize==24) { // next byte is uint8_t data (length) + ret.uint = tvb_get_guint8(tvb, offset); + ret.size += 1; + } else if (theSize==25) { // next 2bytes are uint16_t data (length) + ret.uint = tvb_get_guint16(tvb, offset, 0); + ret.size += 2; + } else if (theSize==26) { // next 4bytes are uint32_t data + ret.uint = tvb_get_guint32(tvb, offset, 0); + ret.size += 4; + } else if (theSize==27) { // next byte is uint64_t data + ret.uint = tvb_get_guint64(tvb, offset, 0); + ret.size += 8; + } + ret.totalSize = ret.size+ret.uint; + break; + + case 0x03: // Text string + if ( theSize<24 ) // Array size is contained in the identifier byte + { + ret.uint = (tmp & 0x1F); + } else if (theSize==24) // next byte is uint8_t data + { + ret.uint = tvb_get_guint8(tvb, offset); + ret.size += 1; + } else if (theSize==25) // next 2bytes are uint16_t data + { + ret.uint = tvb_get_guint16(tvb, offset, 0); + ret.size += 2; + } else if (theSize==26) // next 4bytes are uint32_t data + { + ret.uint = tvb_get_guint32(tvb, offset, 0); + ret.size += 4; + } else if (theSize==27) // next byte is uint64_t data + { + ret.uint = tvb_get_guint64(tvb, offset, 0); + ret.size += 8; + } + ret.totalSize = ret.size+ret.uint; + break; + + case 0x04: // Array + if ( theSize<24 ) // Array size is contained in the identifier byte + { + ret.uint = (tmp & 0x1F); + } else if (theSize==24) // next byte is uint8_t data + { + ret.uint = tvb_get_guint8(tvb, offset); + ret.size += 1; + } else if (theSize==25) // next 2bytes are uint16_t data + { + ret.uint = tvb_get_guint16(tvb, offset, 0); + ret.size += 2; + } else if (theSize==26) // next 4bytes are uint32_t data + { + ret.uint = tvb_get_guint32(tvb, offset, 0); + ret.size += 4; + } else if (theSize==27) // next byte is uint64_t data + { + ret.uint = tvb_get_guint64(tvb, offset, 0); + ret.size += 8; + } + // I know how many elements are in the array, but NOT the total + // size of the array data. + ret.totalSize = -1; + break; + + case 0x06: // Semantic tag + if ( theSize<24 ) + { + ret.uint = (tmp & 0x1F); + } + ret.totalSize += ret.uint; + break; + + case 0x01: // Negative integer + case 0x07: // Primitives e.g. break, float, simple values + default: + // TODO -- not supported yet. + break; + } + return(ret); +} + +void +dissect_amp_as_subtree(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset) +{ + guint64 messages = 0; + unsigned int i=0; + unsigned int j=0; + unsigned int k=0; + unsigned int numTNVCEntries = 0; + + proto_tree *amp_tree = NULL; + proto_tree *amp_items_tree = NULL; + proto_tree *amp_register_tree = NULL; + proto_tree *amp_report_set_tree = NULL; + proto_tree *amp_report_tree = NULL; + proto_tree *amp_report_TNVC_tree = NULL; + proto_tree *amp_control_tree = NULL; + proto_tree *amp_table_tree = NULL; + proto_item *payload_item = NULL; + proto_tree *amp_message_tree = NULL; + proto_tree *amp_report_TNVC_sub_tree = NULL; + proto_item *amp_message = NULL; + proto_item *amp_register = NULL; + proto_item *amp_report_set = NULL; + proto_item *amp_report = NULL; + + cborObj myObj; + cborObj tmpObj; + cborObj tmpObj2; + cborObj tmpObj3; + cborObj tmpObj4; + int reportHasTimestamp = 0; + int report_types_offset = 0; + + amp_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_amp_proto, + &payload_item, "Payload Data: AMP Protocol"); + + // First byte is the main CBOR type (probably an array of things) + // e.g. 0x82 (byte array of 2 things) + myObj = cbor_info(tvb, offset); + offset += myObj.size; + messages = myObj.uint; + + // Item 0 is the timestamp + myObj = cbor_info(tvb, offset); + add_value_time_to_tree((int) myObj.uint, MIN(myObj.size-1, 1), amp_tree, tvb, offset, hf_amp_primary_timestamp); + offset += myObj.size; + + for ( i=1; i 0 ) { + DISSECTOR_ASSERT(tmpObj3.totalSize <= G_MAXINT32); + offset += (int)tmpObj3.totalSize; + } else { + break; + } + } + + } + break; + + case 0x02: // Perform Control + // TODO + //amp_control_sub_tree = proto_item_add_subtree(amp_message_tree, ett_amp); + amp_control_tree = proto_tree_add_subtree(amp_message_tree, tvb, offset-1, -1, + ett_amp_message, &_message, "Perform-Control"); + proto_tree_add_item(amp_control_tree, hf_amp_cbor_header, tvb, offset, 1, ENC_BIG_ENDIAN); + break; + + case 0x03: // Table Set + // TODO + //amp_table_sub_tree = proto_item_add_subtree(amp_items_tree, ett_amp); + amp_table_tree = proto_tree_add_subtree(amp_items_tree, tvb, offset, -1, + ett_amp_message, &_message, "AMP Message: Table-Set"); + proto_tree_add_item(amp_table_tree, hf_amp_cbor_header, tvb, offset, 1, ENC_BIG_ENDIAN); + break; + default: + break; + } + } + + return; +} + +/* Code to actually dissect the packets */ +static int +dissect_amp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) +{ + int offset = 0; + proto_item *amp_packet; + proto_item *amp_tree; + gint amp_packet_reported_length; + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "AMP"); + col_clear(pinfo->cinfo, COL_INFO); + + amp_packet_reported_length = tvb_reported_length_remaining(tvb, 0); + + amp_packet = proto_tree_add_item(tree, proto_amp, tvb, 0, amp_packet_reported_length, ENC_NA); + amp_tree = proto_item_add_subtree(amp_packet, ett_amp); + + dissect_amp_as_subtree (tvb, pinfo, amp_tree, offset); + + return tvb_captured_length(tvb); +} + +void +proto_register_amp(void) +{ + static hf_register_info hf[] = { + + { &hf_amp_message_header, + { "AMP Message Header", "amp.message.header", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_amp_report_data, + { "Report-Data", "amp.report.data", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_amp_report_bytestring, + { "Report-Bytestring", "amp.report.bytestring", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_amp_report_integer8_small, + { "Report-Integer8_small", "amp.report.integer8_small", + FT_UINT8, BASE_DEC, NULL, AMP_CBOR_UINT_SMALL, + NULL, HFILL } + }, + { &hf_amp_report_integer, + { "Report-Integer", "amp.report.integer", + FT_UINT64, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_amp_cbor_header, + { "CBOR-Header", "amp.cbor_header", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_amp_primary_timestamp, + { "Timestamp", "amp.primary_timestamp", + FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL} + }, + { &hf_amp_tnvc_flags, + { "TNVC Flags", "amp.tnvc.flags", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_amp_tnvc_reserved, + { "Reserved", "amp.tnvc.reserved", + FT_UINT8, BASE_DEC, NULL, AMP_TNVC_RESERVED, + NULL, HFILL } + }, + { &hf_amp_tnvc_mixed, + { "Mixed", "amp.tnvc.mixed", + FT_UINT8, BASE_DEC, VALS(tnvc_yesno), AMP_TNVC_MIXED, + NULL, HFILL } + }, + { &hf_amp_tnvc_typed, + { "TNVC Values are Typed", "amp.tnvc.typed", + FT_UINT8, BASE_DEC, VALS(tnvc_yesno), AMP_TNVC_TYPE, + NULL, HFILL } + }, + { &hf_amp_tnvc_name, + { "Name", "amp.tnvc.name", + FT_UINT8, BASE_DEC, VALS(tnvc_yesno), AMP_TNVC_NAME, + NULL, HFILL } + }, + { &hf_amp_tnvc_values, + { "Values", "amp.tnvc.value", + FT_UINT8, BASE_DEC, VALS(tnvc_yesno), AMP_TNVC_VALUE, + NULL, HFILL } + }, + { &hf_ari_nickname, + { "Nickname", "amp.nickname", + FT_UINT8, BASE_DEC, VALS(tnvc_present_notpresent), AMP_ARI_NICKNAME, + NULL, HFILL } + }, + { &hf_amp_ari_flags, + { "ARI Flags", "amp.ari.flags", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_ari_parameters, + { "Parameters", "amp.parameters", + FT_UINT8, BASE_DEC, VALS(tnvc_present_notpresent), AMP_ARI_PARAMETERS, + NULL, HFILL } + }, + { &hf_ari_issuer, + { "Issuer", "amp.issuer", + FT_UINT8, BASE_DEC, VALS(tnvc_present_notpresent), AMP_ARI_ISSUER, + NULL, HFILL } + }, + { &hf_ari_tag, + { "Tag", "amp.tag", + FT_UINT8, BASE_DEC, VALS(tnvc_present_notpresent), AMP_ARI_TAG, + NULL, HFILL } + }, + { &hf_ari_value, + { "Value", "amp.value", + FT_UINT8, BASE_DEC, NULL, AMP_ARI_VALUE, + NULL, HFILL } + }, + { &hf_ari_struct, + { "Struct Type", "amp.struct", + FT_UINT8, BASE_DEC, VALS(amp_ari_struct_type), AMP_ARI_STRUCT, + NULL, HFILL } + }, + { &hf_amp_reserved, + { "Reserved", "amp.reserved", + FT_UINT8, BASE_DEC, NULL, AMP_HDR_RESERVED, + NULL, HFILL } + }, + { &hf_amp_acl, + { "ACL", "amp.acl", + FT_UINT8, BASE_DEC, VALS(tnvc_present_notpresent), AMP_HDR_ACL, + NULL, HFILL } + }, + { &hf_amp_nack, + { "NACK", "amp.nack", + FT_UINT8, BASE_DEC, VALS(tnvc_present_notpresent), AMP_HDR_NACK, + NULL, HFILL } + }, + { &hf_amp_ack, + { "ACK", "amp.ack", + FT_UINT8, BASE_DEC, VALS(tnvc_present_notpresent), AMP_HDR_ACK, + NULL, HFILL } + }, + { &hf_amp_opcode, + { "Opcode", "amp.opcode", + FT_UINT8, BASE_DEC, VALS(opcode), AMP_HDR_OPCODE, + NULL, HFILL } + }, + {&hf_amp_agent_name, + {"Agent-Name", "amp.agent_name", + FT_STRINGZPAD, BASE_NONE, NULL, 0x0, NULL, HFILL} + }, + {&hf_amp_text_string, + {"String", "amp.string", + FT_STRINGZPAD, BASE_NONE, NULL, 0x0, NULL, HFILL} + }, + {&hf_amp_rx_name, + {"Rx-Name", "amp.rx_name", + FT_STRINGZPAD, BASE_NONE, NULL, 0x0, NULL, HFILL} + }, + + }; + + /* Setup protocol subtree array */ + static gint *ett[] = { + &ett_amp, + &ett_amp_message_header, + &ett_amp_cbor_header, + &ett_amp_message, + &ett_amp_register, + &ett_amp_report_set, + &ett_amp_report, + &ett_amp_tnvc_flags, + &ett_amp_ari_flags, + &ett_amp_proto + }; + + static ei_register_info ei[] = { + { &ei_amp_cbor_malformed, { "amp.cbor.malformed", PI_MALFORMED, PI_ERROR, "Malformed CBOR object", EXPFILL }}, + }; + + /* Register the protocol name and description */ + proto_amp = proto_register_protocol("AMP", "AMP", "amp"); + + /* Required function calls to register the header fields and subtrees used */ + proto_register_field_array(proto_amp, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + expert_module_t* expert_amp = expert_register_protocol(proto_amp); + expert_register_field_array(expert_amp, ei, array_length(ei)); + + amp_handle = register_dissector("amp", dissect_amp, proto_amp); +} + +void +proto_reg_handoff_amp(void) +{ + dissector_add_uint("ccsds.apid", AMP_APID, amp_handle); + dissector_add_for_decode_as_with_preference("udp.port", amp_handle); +} + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ -- cgit v1.2.3