diff options
Diffstat (limited to 'epan/dissectors/packet-sync.c')
-rw-r--r-- | epan/dissectors/packet-sync.c | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/epan/dissectors/packet-sync.c b/epan/dissectors/packet-sync.c new file mode 100644 index 00000000..689f6f55 --- /dev/null +++ b/epan/dissectors/packet-sync.c @@ -0,0 +1,309 @@ +/* packet-sync.c + * Routines for MBMS synchronisation protocol dissection + * Copyright 2012, David Wei <davidwei@lavabit.com> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Ref 3GPP TS 25.446 + */ + +#include "config.h" + +#include <epan/packet.h> +#include <epan/expert.h> +#include <epan/crc6-tvb.h> + +#define TYPE_0_LEN 17 +#define TYPE_1_LEN 11 +#define TYPE_2_LEN 12 +#define TYPE_3_LEN 19 + +void proto_register_sync(void); +void proto_reg_handoff_sync(void); + +/* Initialize the protocol and registered fields */ +static int proto_sync = -1; +static int hf_sync_type = -1; +static int hf_sync_spare4 = -1; +static int hf_sync_timestamp = -1; +static int hf_sync_packet_nr = -1; +static int hf_sync_elapsed_octet_ctr = -1; +static int hf_sync_total_nr_of_packet = -1; +static int hf_sync_total_nr_of_octet = -1; +static int hf_sync_header_crc = -1; +static int hf_sync_payload_crc = -1; +static int hf_sync_length_of_packet = -1; + +/* Initialize the subtree pointers */ +static gint ett_sync = -1; + +static expert_field ei_sync_pdu_type2 = EI_INIT; +static expert_field ei_sync_type = EI_INIT; + +static dissector_handle_t sync_handle; +static dissector_handle_t ip_handle; + +static const value_string sync_type_vals[] = { + { 0, "Synchronisation frame without payload" }, + { 1, "User data with synchronisation frame for uncompressed headers" }, + { 2, "User data with synchronisation frame for compressed headers" }, + { 3, "Synchronisation frame with Length of Packets" }, + /* 4-15 reserved for future PDU type extensions */ + { 0, NULL} +}; + +static int +dissect_sync(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) +{ + proto_item *ti, *item, *type_item; + proto_tree *sync_tree; + guint8 type, spare; + guint16 packet_nr, packet_len1, packet_len2; + guint32 timestamp, total_nr_of_packet; + int offset = 0; + tvbuff_t *next_tvb; + + type = tvb_get_guint8(tvb, offset) >> 4; + spare = tvb_get_guint8(tvb, offset) & 0x0F; + + /* Heuristics to check if packet is really MBMS sync */ +#if 0 + if ( type > 3 ) + return 0; + + if ( type == 0 && tvb_captured_length(tvb) < 18) { + return 0; + } else if ( type == 1 && tvb_captured_length(tvb) < 11 ) { + return 0; + } else if ( type == 3 && tvb_captured_length(tvb) < 19 ) { + return 0; + } + + if ( (type != 2) && (spare != 0) ) + return 0; +#endif + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "SYNC"); + col_set_str(pinfo->cinfo, COL_INFO, "MBMS synchronisation protocol"); + + /* Ugly, but necessary to get the correct length for type 3 */ + packet_nr = tvb_get_ntohs(tvb, offset+3) + 1; + + /* The length varies depending on PDU type */ + switch (type) { + case 0: + ti = proto_tree_add_item(tree, proto_sync, tvb, 0, TYPE_0_LEN, ENC_NA); + break; + case 1: + ti = proto_tree_add_item(tree, proto_sync, tvb, 0, TYPE_1_LEN, ENC_NA); + break; + case 2: + ti = proto_tree_add_item(tree, proto_sync, tvb, 0, TYPE_2_LEN + (spare & 0x01 ? 40 : 20), ENC_NA); + break; + case 3: + ti = proto_tree_add_item(tree, proto_sync, tvb, 0, + TYPE_3_LEN + (gint16)(packet_nr % 2 == 0 ? + 1.5*packet_nr : 1.5*(packet_nr-1)+2), + ENC_NA); + break; + default: + ti = proto_tree_add_item(tree, proto_sync, tvb, 0, -1, ENC_NA); + break; + } + + sync_tree = proto_item_add_subtree(ti, ett_sync); + + /* Octet 1 - PDU Type */ + type_item = proto_tree_add_item(sync_tree, hf_sync_type, tvb, offset, 1, ENC_BIG_ENDIAN); + proto_tree_add_item(sync_tree, hf_sync_spare4, tvb, offset, 1, ENC_BIG_ENDIAN); + offset++; + + /* Octet 2 - Time Stamp */ + timestamp = tvb_get_ntohs(tvb, offset) * 10; + proto_tree_add_uint(sync_tree, hf_sync_timestamp, tvb, offset, 2, timestamp); + offset += 2; + + /* Octet 4 - Packet Number */ + proto_tree_add_uint(sync_tree, hf_sync_packet_nr, tvb, offset, 2, packet_nr); + offset += 2; + + /* Octet 6 - Elapsed Octet Counter */ + proto_tree_add_item(sync_tree, hf_sync_elapsed_octet_ctr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + switch (type) { + case 0: + /* SYNC PDU Type 0 */ + proto_tree_add_item(sync_tree, hf_sync_total_nr_of_packet, tvb, offset, 3, ENC_BIG_ENDIAN); + offset += 3; + proto_tree_add_item(sync_tree, hf_sync_total_nr_of_octet, tvb, offset, 5, ENC_BIG_ENDIAN); + offset += 5; + proto_tree_add_item(sync_tree, hf_sync_header_crc, tvb, offset, 1, ENC_BIG_ENDIAN); + offset++; + break; + case 1: + /* SYNC PDU Type 1 */ + /* XXX - Calculate the CRC and check against this value? */ + item = proto_tree_add_item(sync_tree, hf_sync_header_crc, tvb, offset, 1, ENC_BIG_ENDIAN); + proto_tree_add_item(sync_tree, hf_sync_payload_crc, tvb, offset, 2, ENC_BIG_ENDIAN); + proto_item_append_text(item, " [Calculated CRC 0x%x]", + crc6_compute_tvb(tvb, offset)); + offset += 2; + + /* XXX - The payload may not always be present? */ + next_tvb = tvb_new_subset_remaining(tvb, offset); + /* XXX - The payload may not always be IP? */ + call_dissector(ip_handle, next_tvb, pinfo, tree); + break; + case 2: + /* SYNC PDU Type 2 */ + expert_add_info(pinfo, ti, &ei_sync_pdu_type2); + break; + case 3: + /* SYNC PDU Type 3 */ + total_nr_of_packet = tvb_get_ntoh24(tvb, offset); + proto_tree_add_item(sync_tree, hf_sync_total_nr_of_packet, tvb, offset, 3, ENC_BIG_ENDIAN); + offset += 3; + proto_tree_add_item(sync_tree, hf_sync_total_nr_of_octet, tvb, offset, 5, ENC_BIG_ENDIAN); + offset += 5; + proto_tree_add_item(sync_tree, hf_sync_header_crc, tvb, offset, 1, ENC_BIG_ENDIAN); + proto_tree_add_item(sync_tree, hf_sync_payload_crc, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + if (offset < (gint)tvb_reported_length(tvb)) { + int i; + + if (total_nr_of_packet != 0 && packet_nr % 2 == 0) { + /* Even number of packets */ + for (i = 1; i < packet_nr; i+=2, offset+=3) { + packet_len1 = tvb_get_bits16(tvb, offset*8, 12, ENC_BIG_ENDIAN); + packet_len2 = tvb_get_bits16(tvb, offset*8+12, 12, ENC_BIG_ENDIAN); + proto_tree_add_uint_format(sync_tree, hf_sync_length_of_packet, tvb, offset, 2, packet_len1, "Length of Packet %u : %hu", i, packet_len1); + proto_tree_add_uint_format(sync_tree, hf_sync_length_of_packet, tvb, offset+1, 2, packet_len2, "Length of Packet %u : %hu", i+1, packet_len2); + } + } else { + /* Odd number of packets */ + for (i = 1; i < packet_nr; i+=2, offset+=3) { + packet_len1 = tvb_get_bits16(tvb, offset*8, 12, ENC_BIG_ENDIAN); + packet_len2 = tvb_get_bits16(tvb, offset*8+12, 12, ENC_BIG_ENDIAN); + proto_tree_add_uint_format(sync_tree, hf_sync_length_of_packet, tvb, offset, 2, packet_len1, "Length of Packet %u : %hu", i, packet_len1); + proto_tree_add_uint_format(sync_tree, hf_sync_length_of_packet, tvb, offset+1, 2, packet_len2, "Length of Packet %u : %hu", i+1, packet_len2); + } + packet_len1 = tvb_get_bits16(tvb, offset*8, 12, ENC_BIG_ENDIAN); + proto_tree_add_uint_format(sync_tree, hf_sync_length_of_packet, tvb, offset, 2, packet_len1, "Length of Packet %u : %hu", packet_nr, packet_len1); + offset++; + proto_tree_add_item(sync_tree, hf_sync_spare4, tvb, offset, 1, ENC_BIG_ENDIAN); + } + + } + break; + default: + expert_add_info(pinfo, type_item, &ei_sync_type); + break; + } + + return tvb_captured_length(tvb); + +} + +void +proto_register_sync(void) +{ + static hf_register_info hf_sync[] = { + { &hf_sync_type, + { "PDU Type", "sync.type", + FT_UINT8, BASE_DEC, VALS(sync_type_vals), 0xF0, + NULL, HFILL } + }, + { &hf_sync_spare4, + { "Spare", "sync.spare", + FT_UINT8, BASE_DEC, NULL, 0x0F, + NULL, HFILL } + }, + { &hf_sync_timestamp, + { "Timestamp", "sync.timestamp", + FT_UINT16, BASE_DEC|BASE_UNIT_STRING, &units_milliseconds, 0x0, + "Relative time value for the starting time of a synchronisation sequence within the synchronisation period.", HFILL } + }, + { &hf_sync_packet_nr, + { "Packet Number", "sync.packet_nr", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Number of elapsed SYNC PDUs cumulatively within the synchronisation sequence.", HFILL } + }, + { &hf_sync_elapsed_octet_ctr, + { "Elapsed Octet Counter", "sync.elapsed_octet_ctr", + FT_UINT32, BASE_DEC, NULL, 0x0, + "Number of elapsed cumulative octets cumulatively within one synchronisation sequence.", HFILL } + }, + { &hf_sync_total_nr_of_packet, + { "Total Number of Packet", "sync.total_nr_of_packet", + FT_UINT24, BASE_DEC, NULL, 0x0, + "Cumulatively the number of the packets for the MBMS service within one synchronisation period.", HFILL } + }, + { &hf_sync_total_nr_of_octet, + { "Total Number of Octet", "sync.total_nr_of_octet", + FT_UINT64, BASE_DEC, NULL, 0x0, + "Cumulatively the number of the octets for the MBMS service within one synchronisation period.", HFILL } + }, + { &hf_sync_header_crc, + { "Header CRC", "sync.header_crc", + FT_UINT8, BASE_HEX, NULL, 0xFC, + NULL, HFILL } + }, + { &hf_sync_payload_crc, + { "Payload CRC", "sync.payload_crc", + FT_UINT16, BASE_HEX, NULL, 0x03FF, + NULL, HFILL } + }, + { &hf_sync_length_of_packet, + { "Length of Packet", "sync.length_of_packet", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + }; + + static gint *ett_sync_array[] = { + &ett_sync + }; + + static ei_register_info ei[] = { + { &ei_sync_pdu_type2, { "sync.pdu_type2", PI_UNDECODED, PI_WARN, "SYNC PDU type 2 unsupported", EXPFILL }}, + { &ei_sync_type, { "sync.type.unknown", PI_PROTOCOL, PI_WARN, "Unknown SYNC PDU type", EXPFILL }}, + }; + + expert_module_t* expert_sync; + + proto_sync = proto_register_protocol("MBMS synchronisation protocol", "SYNC", "sync"); + + proto_register_field_array(proto_sync, hf_sync, array_length(hf_sync)); + proto_register_subtree_array(ett_sync_array, array_length(ett_sync_array)); + expert_sync = expert_register_protocol(proto_sync); + expert_register_field_array(expert_sync, ei, array_length(ei)); + + sync_handle = register_dissector("sync", dissect_sync, proto_sync); +} + +void +proto_reg_handoff_sync(void) +{ + ip_handle = find_dissector_add_dependency("ip", proto_sync); + + dissector_add_for_decode_as_with_preference("udp.port", sync_handle); +} + +/* + * Editor modelines - https://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: + */ |