aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/asn1/tetra/packet-tetra-template.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/dissectors/asn1/tetra/packet-tetra-template.c')
-rw-r--r--epan/dissectors/asn1/tetra/packet-tetra-template.c654
1 files changed, 654 insertions, 0 deletions
diff --git a/epan/dissectors/asn1/tetra/packet-tetra-template.c b/epan/dissectors/asn1/tetra/packet-tetra-template.c
new file mode 100644
index 0000000000..2b8dea2183
--- /dev/null
+++ b/epan/dissectors/asn1/tetra/packet-tetra-template.c
@@ -0,0 +1,654 @@
+/* packet-tetra.c
+ * Routines for TETRA packet dissection
+ *
+ * Copyright (c) 2007 - 2011 Professional Mobile Communication Research Group,
+ * Beijing Institute of Technology, China
+ * Copyright (c) 2011 Holger Hans Peter Freyther
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * REF: ETSI EN 300 392-2 V3.2.1
+ */
+
+#include "config.h"
+
+#include <epan/packet.h>
+#include <epan/expert.h>
+#include <epan/prefs.h>
+#include <epan/oids.h>
+#include <epan/conversation.h>
+#include <epan/asn1.h>
+
+#include "packet-per.h"
+#include "packet-tetra.h"
+
+#define PROTO_TAG_tetra "TETRA"
+
+void proto_register_tetra(void);
+void proto_reg_handoff_tetra(void);
+
+/* Wireshark ID of the tetra protocol */
+static int proto_tetra = -1;
+
+/* These are the handles of our subdissectors */
+static dissector_handle_t data_handle = NULL;
+
+static dissector_handle_t tetra_handle;
+
+static int global_tetra_port = 7074;
+
+/* Whether the capture data include carrier numbers */
+static gboolean include_carrier_number = TRUE;
+
+/* The following hf_* variables are used to hold the Wireshark IDs of
+* our header fields; they are filled out when we call
+* proto_register_field_array() in proto_register_tetra()
+*/
+/** Kts attempt at defining the protocol */
+static gint hf_tetra = -1;
+static gint hf_tetra_header = -1;
+static gint hf_tetra_channels = -1;
+static gint hf_tetra_channel1 = -1;
+static gint hf_tetra_channel2 = -1;
+static gint hf_tetra_channel3 = -1;
+static gint hf_tetra_txreg = -1;
+static gint hf_tetra_timer = -1;
+static gint hf_tetra_pdu = -1;
+static gint hf_tetra_rvstr = -1;
+static gint hf_tetra_carriernumber = -1;
+static gint hf_tetra_rxchannel1 = -1;
+static gint hf_tetra_rxchannel2 = -1;
+static gint hf_tetra_rxchannel3 = -1;
+static gint hf_tetra_crc = -1;
+static gint hf_tetra_len0 = -1;
+
+#include "packet-tetra-hf.c"
+
+/* Initialize the subtree pointers */
+/* These are the ids of the subtrees that we may be creating */
+static gint ett_tetra = -1;
+static gint ett_tetra_header = -1;
+static gint ett_tetra_length = -1;
+static gint ett_tetra_txreg = -1;
+static gint ett_tetra_text = -1;
+
+#include "packet-tetra-ett.c"
+
+static expert_field ei_tetra_channels_incorrect = EI_INIT;
+
+#include "packet-tetra-fn.c"
+
+static const value_string channeltypenames[] = {
+ { 0, "Reserved" },
+ { 1, "AACH" },
+ { 2, "SCH/F" },
+ { 3, "SCH/HD" },
+ { 4, "Unknown" },
+ { 5, "BSCH" },
+ { 6, "BNCH" },
+ { 7, "TCH/F" },
+ { 8, "TCH/H" },
+ { 9, "TCH4.8"},
+ { 10, "TCH7.2"},
+ { 11, "STCH"},
+ { 0, NULL }
+};
+
+static const value_string recvchanneltypenames[] = {
+ { 0, "Reserved" },
+ { 1, "AACH" },
+ { 2, "SCH/F" },
+ { 3, "SCH/HD" },
+ { 4, "Unknown" },
+ { 5, "BSCH" },
+ { 6, "BNCH" },
+ { 7, "TCH/F" },
+ { 8, "TCH/H" },
+ { 9, "TCH4.8"},
+ { 10, "TCH7.2"},
+ { 11, "STCH"},
+ { 15, "SCH/HU"},
+ { 0, NULL }
+};
+
+/* Get the length of received pdu */
+static gint get_rx_pdu_length(guint32 channel_type)
+{
+ gint len = 0;
+
+ switch(channel_type) {
+ case TETRA_CHAN_AACH:
+ len = 14;
+ break;
+ case TETRA_CHAN_SCH_F:
+ len = 268;
+ break;
+ case TETRA_CHAN_SCH_D:
+ len = 124; ;
+ break;
+ case TETRA_CHAN_BSCH:
+ len = 60;
+ break;
+ case TETRA_CHAN_BNCH:
+ len = 124;
+ break;
+ case TETRA_CHAN_TCH_F:
+ len = 274;
+ break;
+ case TETRA_CHAN_TCH_H:
+ len = 137;
+ break;
+ case TETRA_CHAN_TCH_2_4:
+ len = 144;
+ break;
+ case TETRA_CHAN_TCH_4_8:
+ len = 288;
+ break;
+ case TETRA_CHAN_STCH:
+ len = 124;
+ break;
+ case TETRA_CHAN_SCH_HU:
+ len = 92;
+ break;
+ default:
+ len = 0;
+ break;
+ }
+
+ return len;
+}
+
+/* Get the length of transmitted pdu */
+static gint get_tx_pdu_length(guint32 channel_type)
+{
+ gint len = 0;
+
+ switch(channel_type) {
+ case TETRA_CHAN_AACH:
+ len = 14;
+ break;
+ case TETRA_CHAN_SCH_F:
+ len = 268;
+ break;
+ case TETRA_CHAN_SCH_D:
+ len = 124;
+ break;
+ case TETRA_CHAN_BSCH:
+ len = 60;
+ break;
+ case TETRA_CHAN_BNCH:
+ len = 124;
+ break;
+ case TETRA_CHAN_TCH_F:
+ len = 274;
+ break;
+ case TETRA_CHAN_TCH_H:
+ len = 137;
+ break;
+ case TETRA_CHAN_TCH_2_4:
+ len = 144;
+ break;
+ case TETRA_CHAN_TCH_4_8:
+ len = 288;
+ break;
+ case TETRA_CHAN_STCH:
+ len = 124;
+ break;
+ }
+
+ return len;
+}
+
+void tetra_dissect_pdu(int channel_type, int dir, tvbuff_t *pdu, proto_tree *tree, packet_info *pinfo)
+{
+ proto_item *tetra_sub_item;
+ proto_tree *tetra_sub_tree;
+ guint8 p;
+
+ tetra_sub_item = proto_tree_add_item(tree, hf_tetra_pdu,
+ pdu, 0, tvb_captured_length(pdu), ENC_NA);
+
+ tetra_sub_tree = proto_item_add_subtree(tetra_sub_item, ett_tetra);
+
+ switch(channel_type) {
+ case TETRA_CHAN_AACH:
+ dissect_AACH_PDU(pdu, pinfo, tetra_sub_tree, NULL);
+ break;
+ case TETRA_CHAN_SCH_F:
+ p = tvb_get_guint8(pdu, 0);
+ switch(p >> 6) {
+ case 0:
+ if (dir == TETRA_DOWNLINK)
+ dissect_MAC_RESOURCE_PDU(pdu, pinfo, tetra_sub_tree, NULL);
+ else
+ dissect_MAC_DATA_PDU(pdu, pinfo, tetra_sub_tree, NULL);
+ break;
+ case 1: /* MAC-FRAG or MAC-END */
+ if((p >> 5) == 3) {
+ if (dir == TETRA_DOWNLINK)
+ dissect_MAC_END_DOWNLINK_PDU(pdu, pinfo, tetra_sub_tree, NULL);
+ else
+ dissect_MAC_END_UPLINK_PDU(pdu, pinfo, tetra_sub_tree, NULL);
+
+ } else
+ dissect_MAC_FRAG_PDU(pdu, pinfo, tetra_sub_tree, NULL);
+ break;
+ case 2:
+ dissect_MAC_ACCESS_DEFINE_PDU(pdu, pinfo, tetra_sub_tree, NULL);
+ break;
+ }
+ break;
+ case TETRA_CHAN_SCH_D:
+ p = tvb_get_guint8(pdu, 0);
+ switch(p >> 6) {
+ case 0:
+ dissect_MAC_RESOURCE_PDU(pdu, pinfo, tetra_sub_tree, NULL);
+ break;
+ case 1: /* MAC-FRAG or MAC-END */
+ if((p >> 5) == 3)
+ dissect_MAC_END_DOWN111_PDU(pdu, pinfo, tetra_sub_tree, NULL);
+ else
+ dissect_MAC_FRAG120_PDU(pdu, pinfo, tetra_sub_tree, NULL);
+ break;
+ case 2:
+ dissect_MAC_ACCESS_DEFINE_PDU(pdu, pinfo, tetra_sub_tree, NULL);
+ break;
+ }
+ break;
+ case TETRA_CHAN_SCH_HU:
+ p = tvb_get_guint8(pdu, 0);
+ switch(p >> 7) {
+ case 0: /* MAC-ACCESS */
+ dissect_MAC_ACCESS_PDU(pdu, pinfo, tetra_sub_tree, NULL);
+ break;
+ case 1: /* MAC-END-HU */
+ dissect_MAC_END_HU_PDU(pdu, pinfo, tetra_sub_tree, NULL);
+ break;
+ }
+ break;
+ case TETRA_CHAN_BSCH:
+ col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "BSCH");
+ dissect_BSCH_PDU(pdu, pinfo, tetra_sub_tree, NULL);
+ break;
+ case TETRA_CHAN_BNCH:
+ col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "BNCH");
+ dissect_BNCH_PDU(pdu, pinfo, tetra_sub_tree, NULL);
+ break;
+ case TETRA_CHAN_STCH:
+ p = tvb_get_guint8(pdu, 0);
+ switch(p >> 6) {
+ case 0:
+ dissect_MAC_RESOURCE_PDU(pdu, pinfo, tetra_sub_tree, NULL);
+ break;
+ case 1: /* MAC-FRAG or MAC-END */
+ if((p >> 5) == 3) {
+ if (dir == TETRA_DOWNLINK)
+ dissect_MAC_END_DOWN111_PDU(pdu, pinfo, tetra_sub_tree, NULL);
+ else
+ dissect_MAC_END_UP114_PDU(pdu, pinfo, tetra_sub_tree, NULL);
+ } else
+ dissect_MAC_FRAG120_PDU(pdu, pinfo, tetra_sub_tree, NULL);
+ break;
+ case 2:
+ dissect_MAC_ACCESS_DEFINE_PDU(pdu, pinfo, tetra_sub_tree, NULL);
+ break;
+ }
+ break;
+ case TETRA_CHAN_TCH_F:
+ col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "Voice");
+ break;
+ }
+}
+
+static void dissect_tetra_UNITDATA_IND(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tetra_tree, int offset)
+{
+ guint32 rxreg = 0;
+ guint32 channels = 0, i;
+ guint32 channel_type;
+ gint pdu_offset = 0;
+ proto_item *tetra_sub_item;
+ proto_tree *tetra_header_tree = NULL;
+ tvbuff_t *payload_tvb;
+
+ /* Length */
+ rxreg = tvb_get_letohl(tvb, offset);
+ proto_tree_add_uint(tetra_tree, hf_tetra_len0, tvb, offset, 4, rxreg);
+
+ /* RvSteR */
+ offset += 4;
+ rxreg = tvb_get_letohl(tvb, offset);
+ proto_tree_add_uint(tetra_tree, hf_tetra_rvstr, tvb, offset, 4, rxreg);
+
+ /* Logical channels */
+ channels = rxreg & 0x3;
+ tetra_sub_item = proto_tree_add_uint( tetra_tree, hf_tetra_channels, tvb, offset, 4, channels );
+ tetra_header_tree = proto_item_add_subtree(tetra_sub_item, ett_tetra);
+ if (channels > 3) {
+ expert_add_info(pinfo, tetra_sub_item, &ei_tetra_channels_incorrect);
+ channels = 3;
+ }
+
+ pdu_offset = offset + 4;
+ for(i = 0; i < channels; i++) {
+ gint byte_len, bits_len, remaining_bits;
+ gint hf_channel[3];
+
+ hf_channel[0] = hf_tetra_rxchannel1;
+ hf_channel[1] = hf_tetra_rxchannel2;
+ hf_channel[2] = hf_tetra_rxchannel3;
+
+ /* Channel type */
+ channel_type = (rxreg >> ((i + 1) * 4) ) & 0xf;
+ proto_tree_add_uint( tetra_header_tree, hf_channel[i], tvb, offset, 4, channel_type);
+
+ /* CRC */
+ proto_tree_add_boolean( tetra_header_tree, hf_tetra_crc, tvb, offset, 4, !(rxreg >> (i + 2) & 0x01));
+
+ /* PDU */
+ bits_len = get_rx_pdu_length(channel_type);
+ byte_len = bits_len >> 3;
+ remaining_bits = bits_len % 8;
+ if ((remaining_bits)!=0)
+ byte_len++;
+
+ payload_tvb = tvb_new_subset_length(tvb, pdu_offset, byte_len);
+ tetra_dissect_pdu(channel_type, TETRA_UPLINK, payload_tvb, tetra_header_tree, pinfo);
+
+ if ((remaining_bits)!=0)
+ byte_len--;
+ pdu_offset += byte_len;
+ }
+}
+
+static void dissect_tetra_UNITDATA_REQ(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tetra_tree, int offset)
+{
+ guint32 txreg = 0;
+ guint32 channels = 0, i;
+ guint32 channel_type;
+ gint pdu_offset = 0;
+ proto_item *tetra_sub_item = NULL;
+ proto_tree *tetra_header_tree = NULL;
+ tvbuff_t *payload_tvb;
+
+ /* TxR */
+ txreg = tvb_get_letohl(tvb, offset);
+ proto_tree_add_uint(tetra_tree, hf_tetra_txreg, tvb, offset, 4, txreg);
+
+ /* Logical channels */
+ channels = (txreg & 0x3) + 1;
+ tetra_sub_item = proto_tree_add_uint( tetra_tree, hf_tetra_channels, tvb, offset, 4, channels );
+ tetra_header_tree = proto_item_add_subtree(tetra_sub_item, ett_tetra);
+ txreg >>= 2;
+ /* Skip 0000B */
+ if(channels == 2)
+ txreg >>= 4;
+
+ if (channels > 3) {
+ expert_add_info(pinfo, tetra_sub_item, &ei_tetra_channels_incorrect);
+ channels = 3;
+ }
+
+ pdu_offset = offset + 4;
+ for(i = 0; i < channels; i++) {
+ gint byte_len, bits_len, remaining_bits;
+ gint hf_channel[3];
+
+ hf_channel[0] = hf_tetra_channel1;
+ hf_channel[1] = hf_tetra_channel2;
+ hf_channel[2] = hf_tetra_channel3;
+
+ channel_type = txreg & 0xf;
+ proto_tree_add_uint( tetra_header_tree, hf_channel[i], tvb, offset, 4, channel_type);
+ txreg >>= 4;
+ /* PDU */
+ bits_len = get_tx_pdu_length(channel_type);
+ byte_len = bits_len >> 3;
+ remaining_bits = bits_len % 8;
+ if ((remaining_bits)!=0)
+ byte_len++;
+
+ payload_tvb = tvb_new_subset_length(tvb, pdu_offset, byte_len);
+ tetra_dissect_pdu(channel_type, TETRA_DOWNLINK, payload_tvb, tetra_header_tree, pinfo);
+ pdu_offset += byte_len;
+ }
+}
+
+static int
+dissect_tetra(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
+{
+ proto_item *tetra_item = NULL;
+ proto_item *tetra_sub_item = NULL;
+ proto_tree *tetra_tree = NULL;
+ proto_tree *tetra_header_tree = NULL;
+ guint16 type = 0;
+ guint8 carriernumber = -1;
+
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_tetra);
+ /* Clear out stuff in the info column */
+ col_clear(pinfo->cinfo,COL_INFO);
+
+ /*
+ * This is not a good way of dissecting packets. The tvb length should
+ * be sanity checked so we aren't going past the actual size of the buffer.
+ */
+ type = tvb_get_guint8(tvb, 0);
+
+ if(include_carrier_number) {
+ carriernumber = tvb_get_guint8(tvb, 1);
+ }
+
+
+ switch(type) {
+ case 1:
+ if(include_carrier_number)
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Tetra-UNITDATA-REQ, Carrier: %d",
+ carriernumber);
+ else
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Tetra-UNITDATA-REQ");
+ break;
+ case 2:
+ if(include_carrier_number)
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Tetra-UNITDATA-IND, Carrier: %d",
+ carriernumber);
+ else
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Tetra-UNITDATA-IND");
+ break;
+ case 3:
+ if(include_carrier_number)
+ col_add_fstr(pinfo->cinfo, COL_INFO, "MAC-Timer, Carrier: %d",
+ carriernumber);
+ else
+ col_add_fstr(pinfo->cinfo, COL_INFO, "MAC-Timer");
+ break;
+ case 127:
+ if(include_carrier_number)
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Tetra-UNITDATA-IND Done, Carrier: %d",
+ carriernumber);
+ else
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Tetra-UNITDATA-IND Done");
+ break;
+ case 128:
+ if(include_carrier_number)
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Tetra-UNITDATA-REQ Done, Carrier: %d",
+ carriernumber);
+ else
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Tetra-UNITDATA-REQ Done");
+ break;
+ default:
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown command: %d", type);
+ break;
+ }
+
+ /* if (tree) */ { /* we are being asked for details */
+ guint32 offset = 0;
+ guint32 txtimer = 0;
+ guint32 tslot = 0;
+
+ tetra_item = proto_tree_add_item(tree, proto_tetra, tvb, 0, -1, ENC_NA);
+ tetra_tree = proto_item_add_subtree(tetra_item, ett_tetra);
+
+ offset ++;
+
+ /* Carrier number */
+ if(include_carrier_number) {
+ proto_tree_add_uint(tetra_tree, hf_tetra_carriernumber, tvb, offset, 1, carriernumber);
+ offset ++;
+ }
+
+ /* Registers */
+ tetra_sub_item = proto_tree_add_item( tetra_tree, hf_tetra_header, tvb, offset, -1, ENC_NA );
+ tetra_header_tree = proto_item_add_subtree(tetra_sub_item, ett_tetra);
+
+ /* Timer */
+ txtimer = tvb_get_letohl(tvb, offset);
+ tetra_sub_item = proto_tree_add_item(tetra_header_tree, hf_tetra_timer, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ tslot = ((txtimer & 0x7800) >> 11);
+ if(tslot==4)
+ tslot = 3;
+ if(tslot==8)
+ tslot = 4;
+ proto_item_append_text(tetra_sub_item, " (Multiple frame: %d, Frame: %d, Slot: %d)",
+ txtimer & 0x3F, (txtimer & 0x7c0) >> 6,
+ tslot);
+
+ offset += 4;
+
+ switch(type) {
+ case 1: /* tetra-UNITDATA-REQ */
+ case 128: /* tetra-UNITDATA-REQ Done */
+ dissect_tetra_UNITDATA_REQ(tvb, pinfo, tetra_header_tree, offset);
+ break;
+ case 2: /* tetra-UNITDATA-IND */
+ case 127: /* tetra-UNITDATA-IND Done */
+ dissect_tetra_UNITDATA_IND(tvb, pinfo, tetra_header_tree, offset);
+ break;
+ case 3: /* MAC-Timer */
+ break;
+ default:
+ break;
+ }
+ }
+ return tvb_captured_length(tvb);
+}
+
+void proto_reg_handoff_tetra(void)
+{
+ static gboolean initialized=FALSE;
+
+ if (!initialized) {
+ data_handle = find_dissector("data");
+ tetra_handle = create_dissector_handle(dissect_tetra, proto_tetra);
+ dissector_add_uint("udp.port", global_tetra_port, tetra_handle);
+ }
+
+}
+
+
+void proto_register_tetra (void)
+{
+ module_t *tetra_module;
+ expert_module_t* expert_tetra;
+
+ /*
+ * A header field is something you can search/filter on.
+ *
+ * We create a structure to register our fields. It consists of an
+ * array of hf_register_info structures, each of which are of the format
+ * {&(field id), {name, abbrev, type, display, strings, bitmask, blurb, HFILL}}.
+ */
+ static hf_register_info hf[] = {
+ { &hf_tetra,
+ { "Data", "tetra.data", FT_NONE, BASE_NONE, NULL, 0x0,
+ "tetra PDU", HFILL }},
+ { &hf_tetra_header,
+ { "Registers", "tetra.header", FT_NONE, BASE_NONE, NULL, 0x0,
+ "TETRA Registers", HFILL }},
+ { &hf_tetra_channels,
+ { "Logical Channels", "tetra.channels", FT_UINT8, BASE_DEC, NULL, 0x0,
+ "The amount of logical channels", HFILL }},
+ { &hf_tetra_channel1,
+ { "Channel 1", "tetra.txchannel1", FT_UINT8, BASE_DEC, VALS(channeltypenames), 0x0,
+ "Logical channels type", HFILL }},
+ { &hf_tetra_channel2,
+ { "Channel 2", "tetra.txchannel2", FT_UINT8, BASE_DEC, VALS(channeltypenames), 0x0,
+ "Logical channels type", HFILL }},
+ { &hf_tetra_channel3,
+ { "Channel 3", "tetra.txchannel3", FT_UINT8, BASE_DEC, VALS(channeltypenames), 0x0,
+ "Logical channels type", HFILL }},
+ { &hf_tetra_txreg,
+ { "TxR", "tetra.txreg", FT_UINT16, BASE_HEX, NULL, 0x0,
+ "TX Register", HFILL }},
+ { &hf_tetra_rvstr,
+ { "RvSteR", "tetra.rvster", FT_UINT16, BASE_HEX, NULL, 0x0,
+ "Receive Status Register", HFILL }},
+ { &hf_tetra_carriernumber,
+ { "Carrier Number", "tetra.carrier", FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }},
+ { &hf_tetra_rxchannel1,
+ { "Channel 1", "tetra.rxchannel1", FT_UINT8, BASE_DEC, VALS(recvchanneltypenames), 0x0,
+ "Logical channels type", HFILL }},
+ { &hf_tetra_rxchannel2,
+ { "Channel 2", "tetra.rxchannel2", FT_UINT8, BASE_DEC, VALS(recvchanneltypenames), 0x0,
+ "Logical channels type", HFILL }},
+ { &hf_tetra_rxchannel3,
+ { "Channel 3", "tetra.rxchannel3", FT_UINT8, BASE_DEC, VALS(recvchanneltypenames), 0x0,
+ "Logical channels type", HFILL }},
+ { &hf_tetra_timer,
+ { "Timer", "tetra.timer", FT_UINT16, BASE_HEX, NULL, 0x0,
+ "Timer Register", HFILL }},
+ { &hf_tetra_crc,
+ { "CRC", "tetra.crc", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "CRC result", HFILL }},
+ { &hf_tetra_len0,
+ { "Length", "tetra.len0", FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Length of the PDU", HFILL }},
+ { &hf_tetra_pdu,
+ { "PDU", "tetra.pdu", FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }} ,
+
+#include "packet-tetra-hfarr.c"
+ };
+
+ /* List of subtrees */
+ static gint *ett[] = {
+ &ett_tetra,
+ &ett_tetra_header,
+ &ett_tetra_length,
+ &ett_tetra_txreg,
+ &ett_tetra_text,
+#include "packet-tetra-ettarr.c"
+ };
+
+ static ei_register_info ei[] = {
+ { &ei_tetra_channels_incorrect, { "tetra.channels.incorrect", PI_MALFORMED, PI_WARN, "Channel count incorrect, must be <= 3", EXPFILL }},
+ };
+
+ proto_tetra = proto_register_protocol("TETRA Protocol", "tetra", "tetra");
+ proto_register_field_array (proto_tetra, hf, array_length (hf));
+ proto_register_subtree_array (ett, array_length (ett));
+ register_dissector("tetra", dissect_tetra, proto_tetra);
+ expert_tetra = expert_register_protocol(proto_tetra);
+ expert_register_field_array(expert_tetra, ei, array_length(ei));
+
+ tetra_module = prefs_register_protocol(proto_tetra, NULL);
+ prefs_register_bool_preference(tetra_module, "include_carrier_number",
+ "The data include carrier numbers",
+ "Whether the captured data include carrier number",
+ &include_carrier_number);
+}