aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-dcp-etsi.c
diff options
context:
space:
mode:
authoretxrab <etxrab@f5534014-38df-0310-8fa8-9805f1628bb7>2006-11-25 13:03:48 +0000
committeretxrab <etxrab@f5534014-38df-0310-8fa8-9805f1628bb7>2006-11-25 13:03:48 +0000
commit5fa9563528ec2c4cce2bb84f36aae442076ea5da (patch)
treedbd938e73eb5e0a53f5b94c790e247d832ea992b /epan/dissectors/packet-dcp-etsi.c
parent7354d83c066ab5847fab622afa8ba802b3068571 (diff)
From Julian Cable:
New dissector for ETSI DCP (ETSI TS 102 821). Code rearranged to look more like other Wireshark dissectors and some warnings/errors on Windows fixed. git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@19981 f5534014-38df-0310-8fa8-9805f1628bb7
Diffstat (limited to 'epan/dissectors/packet-dcp-etsi.c')
-rw-r--r--epan/dissectors/packet-dcp-etsi.c878
1 files changed, 878 insertions, 0 deletions
diff --git a/epan/dissectors/packet-dcp-etsi.c b/epan/dissectors/packet-dcp-etsi.c
new file mode 100644
index 0000000000..42e475f75f
--- /dev/null
+++ b/epan/dissectors/packet-dcp-etsi.c
@@ -0,0 +1,878 @@
+/* packet-dcp-etsi.c
+ * Routines for ETSI Distribution & Communication Protocol
+ * Copyright 2006, British Broadcasting Corporation
+ *
+ * $Id:$
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Protocol info
+ * Ref: ETSI DCP (ETSI TS 102 821)
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gmodule.h>
+#include <epan/packet.h>
+#include <epan/prefs.h>
+#include <epan/reassemble.h>
+#include <epan/crcdrm.h>
+#include <epan/reedsolomon.h>
+#include <string.h>
+
+/* forward reference */
+
+static gboolean dissect_dcp_etsi (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree);
+static void dissect_af (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree);
+static void dissect_pft (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree);
+static void dissect_tpl(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree);
+
+static dissector_table_t dcp_dissector_table;
+static dissector_table_t af_dissector_table;
+static dissector_table_t tpl_dissector_table;
+
+static int proto_dcp_etsi = -1;
+static int proto_af = -1;
+static int proto_pft = -1;
+static int proto_tpl = -1;
+static dissector_handle_t af_handle;
+static dissector_handle_t pft_handle;
+static dissector_handle_t tpl_handle;
+static int hf_edcp_sync = -1;
+static int hf_edcp_len = -1;
+static int hf_edcp_seq = -1;
+static int hf_edcp_crcflag = -1;
+static int hf_edcp_maj = -1;
+static int hf_edcp_min = -1;
+static int hf_edcp_pt = -1;
+static int hf_edcp_crc = -1;
+static int hf_edcp_crc_ok = -1;
+static int hf_edcp_pft_pt = -1;
+static int hf_edcp_pseq = -1;
+static int hf_edcp_findex = -1;
+static int hf_edcp_fcount = -1;
+static int hf_edcp_fecflag = -1;
+static int hf_edcp_addrflag = -1;
+static int hf_edcp_plen = -1;
+static int hf_edcp_rsk = -1;
+static int hf_edcp_rsz = -1;
+static int hf_edcp_source = -1;
+static int hf_edcp_dest = -1;
+static int hf_edcp_hcrc = -1;
+static int hf_edcp_hcrc_ok = -1;
+static int hf_edcp_c_max = -1;
+static int hf_edcp_rx_min = -1;
+static int hf_edcp_rs_corrected = -1;
+static int hf_edcp_rs_ok = -1;
+static int hf_edcp_pft_payload = -1;
+
+static int hf_tpl_tlv = -1;
+static int hf_tpl_ptr = -1;
+
+static int hf_edcp_fragments = -1;
+static int hf_edcp_fragment = -1;
+static int hf_edcp_fragment_overlap = -1;
+static int hf_edcp_fragment_overlap_conflicts = -1;
+static int hf_edcp_fragment_multiple_tails = -1;
+static int hf_edcp_fragment_too_long_fragment = -1;
+static int hf_edcp_fragment_error = -1;
+static int hf_edcp_reassembled_in = -1;
+
+/* Initialize the subtree pointers */
+static gint ett_edcp = -1;
+static gint ett_af = -1;
+static gint ett_pft = -1;
+static gint ett_tpl = -1;
+static gint ett_edcp_fragment = -1;
+static gint ett_edcp_fragments = -1;
+
+static GHashTable *dcp_fragment_table = NULL;
+static GHashTable *dcp_reassembled_table = NULL;
+
+static const fragment_items dcp_frag_items = {
+/* Fragment subtrees */
+ &ett_edcp_fragment,
+ &ett_edcp_fragments,
+/* Fragment fields */
+ &hf_edcp_fragments,
+ &hf_edcp_fragment,
+ &hf_edcp_fragment_overlap,
+ &hf_edcp_fragment_overlap_conflicts,
+ &hf_edcp_fragment_multiple_tails,
+ &hf_edcp_fragment_too_long_fragment,
+ &hf_edcp_fragment_error,
+/* Reassembled in field */
+ &hf_edcp_reassembled_in,
+/* Tag */
+ "Message fragments"
+};
+
+/** initialise the DCP protocol. Details follow
+ * here.
+ */
+static void
+dcp_init_protocol(void)
+{
+ fragment_table_init (&dcp_fragment_table);
+ reassembled_table_init (&dcp_reassembled_table);
+}
+
+
+/** Dissect a DCP packet. Details follow
+ * here.
+ * \param[in,out] tvb The buffer containing the packet
+ * \param[in,out] pinfo The packet info structure
+ * \param[in,out] tree The structure containing the details which will be displayed, filtered, etc.
+static void
+ */
+static gboolean
+dissect_dcp_etsi (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
+{
+ guint8 *sync;
+ proto_tree *dcp_tree = NULL;
+ sync = tvb_get_string (tvb, 0, 2);
+ if((sync[0]!='A' && sync[0]!='P') || sync[1]!='F')
+ return FALSE;
+
+ pinfo->current_proto = "DCP (ETSI)";
+
+ /* Clear out stuff in the info column */
+ if (check_col (pinfo->cinfo, COL_INFO)) {
+ col_clear (pinfo->cinfo, COL_INFO);
+ }
+ if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
+ col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCP (ETSI)");
+ /*col_append_fstr (pinfo->cinfo, COL_INFO, " tvb %d", tvb_length(tvb));*/
+ }
+
+ if(tree) {
+ proto_item *ti = NULL;
+ ti = proto_tree_add_item (tree, proto_dcp_etsi, tvb, 0, -1, FALSE);
+ dcp_tree = proto_item_add_subtree (ti, ett_edcp);
+ }
+
+ dissector_try_string(dcp_dissector_table, (char*)sync, tvb, pinfo, dcp_tree);
+ g_free (sync);
+ return TRUE;
+}
+
+#define PFT_RS_N_MAX 207
+#define PFT_RS_K 255
+#define PFT_RS_P (PFT_RS_K - PFT_RS_N_MAX)
+
+
+static
+void rs_deinterleave(const guint8 *input, guint8 *output, guint16 plen, guint32 fcount)
+{
+ guint fidx;
+ for(fidx=0; fidx<fcount; fidx++)
+ {
+ int r;
+ for (r=0; r<plen; r++)
+ {
+ output[fidx+r*fcount] = input[fidx*plen+r];
+ }
+ }
+}
+
+static
+gboolean rs_correct_data(guint8 *deinterleaved, guint8 *output,
+ guint32 c_max, guint16 rsk, guint16 rsz)
+{
+ guint32 i, index_coded = 0, index_out = 0;
+ int err_corr;
+ for (i=0; i<c_max; i++)
+ {
+ memcpy(output+index_out, deinterleaved+index_coded, rsk);
+ index_coded += rsk;
+ memcpy(output+index_out+PFT_RS_N_MAX, deinterleaved+index_coded, PFT_RS_P);
+ index_coded += PFT_RS_P;
+ err_corr = eras_dec_rs(output+index_out, NULL, 0);
+ if (err_corr<0) {
+ return FALSE;
+ }
+ index_out += rsk;
+ }
+ return TRUE;
+}
+
+
+
+static tvbuff_t *
+dissect_pft_fec_detailed(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
+ guint32 findex,
+ guint32 fcount,
+ guint16 seq,
+ gint offset,
+ guint16 plen,
+ gboolean fec,
+ guint16 rsk,
+ guint16 rsz,
+ fragment_data *fd
+)
+{
+ guint16 decoded_size;
+ guint32 c_max;
+ guint32 rx_min;
+ gboolean first, last, decoded = TRUE;
+ tvbuff_t *new_tvb=NULL;
+
+ first = findex == 0;
+ last = fcount == (findex+1);
+ decoded_size = fcount*plen;
+ c_max = fcount*plen/(rsk+PFT_RS_P); /* rounded down */
+ rx_min = c_max*rsk/plen;
+ if(rx_min*plen<c_max*rsk)
+ rx_min++;
+ if (fd)
+ new_tvb = process_reassembled_data (tvb, offset, pinfo,
+ "Reassembled Message",
+ fd, &dcp_frag_items,
+ NULL, tree);
+ else {
+ guint fragments=0;
+ guint32 *got = g_malloc(fcount*sizeof(guint32));
+
+ fragment_data *fd = fragment_get(pinfo, seq, dcp_fragment_table);
+ fragment_data *fd_head;
+ for (fd_head = fd; fd_head != NULL; fd_head = fd_head->next) {
+ if(fd_head->data) {
+ got[fragments] = fd_head->offset;
+ fragments++;
+ }
+ }
+ if(fragments>=rx_min) {
+ guint i,j;
+ fragment_data *frag=NULL;
+ guint8 *dummy_data = (guint8*) g_malloc (plen);
+ tvbuff_t *dummytvb = tvb_new_real_data(dummy_data, plen, plen);
+ /* try and decode with missing fragments */
+ if(tree)
+ proto_tree_add_text (tree, tvb, 0, -1, "want %d, got %d need %d",
+ fcount, fragments, rx_min
+ );
+ memset(dummy_data, 0, plen);
+ for(i=0,j=0; i<fragments; i++,j++) {
+ while(j<got[i]) {
+ frag = fragment_add_seq_check (dummytvb, 0, pinfo, seq,
+ dcp_fragment_table, dcp_reassembled_table, j, plen, (j+1!=fcount));
+ if(tree) {
+ proto_tree_add_text (tree, tvb, 0, -1, "missing %d", j);
+ if(frag) {
+ proto_tree_add_text (tree, tvb, 0, -1, "fragment %d was what we needed", j);
+ break;
+ } else {
+ proto_tree_add_text (tree, tvb, 0, -1, "added %d but still not reassembled", j);
+ }
+ }
+ j++;
+ }
+ }
+ if(frag)
+ new_tvb = process_reassembled_data (tvb, offset, pinfo,
+ "Reassembled Message",
+ frag, &dcp_frag_items,
+ NULL, tree);
+ }
+ g_free(got);
+ }
+ if(new_tvb) {
+ tvbuff_t *dtvb = NULL;
+ const guint8 *input = tvb_get_ptr(new_tvb, 0, -1);
+ guint16 reassembled_size = tvb_length(new_tvb);
+ guint8 *deinterleaved = (guint8*) g_malloc (reassembled_size);
+ guint8 *output = (guint8*) g_malloc (decoded_size);
+ rs_deinterleave(input, deinterleaved, plen, fcount);
+
+ dtvb = tvb_new_real_data(deinterleaved, reassembled_size, reassembled_size);
+ tvb_set_child_real_data_tvbuff(tvb, dtvb);
+ add_new_data_source(pinfo, dtvb, "Deinterleaved");
+ tvb_set_free_cb(dtvb, g_free);
+
+ decoded = rs_correct_data(deinterleaved, output, c_max, rsk, rsz);
+ if(tree)
+ proto_tree_add_boolean (tree, hf_edcp_rs_ok, tvb, offset, 2, decoded);
+
+ new_tvb = tvb_new_real_data(output, decoded_size, decoded_size);
+ tvb_set_child_real_data_tvbuff(dtvb, new_tvb);
+ add_new_data_source(pinfo, new_tvb, "RS Error Corrected Data");
+ tvb_set_free_cb(new_tvb, g_free);
+ }
+ return new_tvb;
+}
+
+
+/** Handle a PFT packet which has the fragmentation header. This uses the
+ * standard ethereal methods for reassembling fragments. If FEC is used,
+ * the FEC is handled too. For the moment, all the fragments must be
+ * available but this could be improved.
+ * \param[in,out] tvb The buffer containing the current fragment
+ * \param[in,out] pinfo The packet info structure
+ * \param[in,out] tree The structure containing the details which will be displayed, filtered, etc.
+ * \param[in] findex the fragment count
+ * \param[in] fcount the number of fragments
+ * \param[in] seq the sequence number of the reassembled packet
+ * \param[in] offset the offset into the tvb of the fragment
+ * \param[in] plen the length of each fragment
+ * \param[in] fec is fec used
+ * \param[in] rsk the number of useful bytes in each chunk
+ * \param[in] rsz the number of padding bytes in each chunk
+ */
+static tvbuff_t *
+dissect_pft_fragmented(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
+ guint32 findex,
+ guint32 fcount,
+ guint16 seq,
+ gint offset,
+ guint16 plen,
+ gboolean fec,
+ guint16 rsk,
+ guint16 rsz
+)
+{
+ gboolean first, last;
+ tvbuff_t *new_tvb=NULL;
+ fragment_data *frag_edcp = NULL;
+ pinfo->fragmented = TRUE;
+ first = findex == 0;
+ last = fcount == (findex+1);
+ frag_edcp = fragment_add_seq_check (
+ tvb, offset, pinfo,
+ seq,
+ dcp_fragment_table, dcp_reassembled_table,
+ findex,
+ plen,
+ !last);
+ if(fec) {
+ new_tvb = dissect_pft_fec_detailed(
+ tvb, pinfo, tree, findex, fcount, seq, offset, plen, fec, rsk, rsz, frag_edcp
+ );
+ } else {
+ new_tvb = process_reassembled_data (tvb, offset, pinfo,
+ "Reassembled Message",
+ frag_edcp, &dcp_frag_items,
+ NULL, tree);
+ }
+ if (check_col (pinfo->cinfo, COL_INFO)) {
+ if(new_tvb) {
+ col_append_str (pinfo->cinfo, COL_INFO, " (Message Reassembled)");
+ } else {
+ if(last) {
+ col_append_str (pinfo->cinfo, COL_INFO, " (Message Reassembly failure)");
+ } else {
+ col_append_fstr (pinfo->cinfo, COL_INFO, " (Message fragment %u)", findex);
+ }
+ }
+ if(first)
+ col_append_str (pinfo->cinfo, COL_INFO, " (first)");
+ if(last)
+ col_append_str (pinfo->cinfo, COL_INFO, " (last)");
+ }
+ return new_tvb;
+}
+
+/** Dissect a PFT packet. Details follow
+ * here.
+ * \param[in,out] tvb The buffer containing the packet
+ * \param[in,out] pinfo The packet info structure
+ * \param[in,out] tree The structure containing the details which will be displayed, filtered, etc.
+ */
+static void
+dissect_pft(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
+{
+ guint16 plen;
+ gint offset = 0;
+ guint16 seq, payload_len, hcrc;
+ guint32 findex, fcount;
+ proto_tree *pft_tree = NULL;
+ proto_item *ti = NULL, *li = NULL;
+ tvbuff_t *next_tvb = NULL;
+ gboolean fec = FALSE;
+ guint16 rsk=0, rsz=0;
+
+ pinfo->current_proto = "DCP-PFT";
+ if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
+ col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCP-PFT");
+ }
+
+ if (tree) { /* we are being asked for details */
+ ti = proto_tree_add_item (tree, proto_pft, tvb, 0, -1, FALSE);
+ pft_tree = proto_item_add_subtree (ti, ett_pft);
+ proto_tree_add_item (pft_tree, hf_edcp_sync, tvb, offset, 2, FALSE);
+ }
+ offset += 2;
+ seq = tvb_get_ntohs (tvb, offset);
+ if (tree) {
+ proto_tree_add_item (pft_tree, hf_edcp_pseq, tvb, offset, 2, FALSE);
+ }
+ offset += 2;
+ findex = tvb_get_ntoh24 (tvb, offset);
+ if (tree) {
+ proto_tree_add_item (pft_tree, hf_edcp_findex, tvb, offset, 3, FALSE);
+ }
+ offset += 3;
+ fcount = tvb_get_ntoh24 (tvb, offset);
+ if (tree) {
+ proto_tree_add_item (pft_tree, hf_edcp_fcount, tvb, offset, 3, FALSE);
+ }
+ offset += 3;
+ plen = tvb_get_ntohs (tvb, offset);
+ payload_len = plen & 0x3fff;
+ if (tree) {
+ proto_tree_add_item (pft_tree, hf_edcp_fecflag, tvb, offset, 2, FALSE);
+ proto_tree_add_item (pft_tree, hf_edcp_addrflag, tvb, offset, 2, FALSE);
+ li = proto_tree_add_item (pft_tree, hf_edcp_plen, tvb, offset, 2, FALSE);
+ }
+ offset += 2;
+ if (plen & 0x8000) {
+ fec = TRUE;
+ rsk = tvb_get_guint8 (tvb, offset);
+ if (tree)
+ proto_tree_add_item (pft_tree, hf_edcp_rsk, tvb, offset, 1, FALSE);
+ offset += 1;
+ rsz = tvb_get_guint8 (tvb, offset);
+ if (tree)
+ proto_tree_add_item (pft_tree, hf_edcp_rsz, tvb, offset, 1, FALSE);
+ offset += 1;
+ }
+ if (plen & 0x4000) {
+ if (tree)
+ proto_tree_add_item (pft_tree, hf_edcp_source, tvb, offset, 2, FALSE);
+ offset += 2;
+ if (tree)
+ proto_tree_add_item (pft_tree, hf_edcp_dest, tvb, offset, 2, FALSE);
+ offset += 2;
+ }
+ if (tree) {
+ proto_item *ci = NULL;
+ guint header_len = offset+2;
+ const guint8 *crc_buf = tvb_get_ptr(tvb, 0, header_len);
+ unsigned long c = crc_drm(crc_buf, header_len, 16, 0x11021, 1);
+ ci = proto_tree_add_item (pft_tree, hf_edcp_hcrc, tvb, offset, 2, FALSE);
+ proto_item_append_text(ci, " (%s)", (c==0xe2f0)?"Ok":"bad");
+ proto_tree_add_boolean(pft_tree, hf_edcp_hcrc_ok, tvb, offset, 2, c==0xe2f0);
+ }
+ hcrc = tvb_get_ntohs (tvb, offset);
+ offset += 2;
+ if (fcount > 1) { /* fragmented*/
+ gboolean save_fragmented = pinfo->fragmented;
+ guint16 real_len = tvb_length(tvb)-offset;
+ proto_tree_add_item (pft_tree, hf_edcp_pft_payload, tvb, offset, real_len, FALSE);
+ if(real_len != payload_len) {
+ if(li)
+ proto_item_append_text(li, " (length error (%d))", real_len);
+ }
+ next_tvb = dissect_pft_fragmented(tvb, pinfo, pft_tree,
+ findex, fcount, seq, offset, real_len,
+ fec, rsk, rsz
+ );
+ pinfo->fragmented = save_fragmented;
+ } else {
+ next_tvb = tvb_new_subset (tvb, offset, -1, -1);
+ }
+ if(next_tvb) {
+ dissect_af(next_tvb, pinfo, tree);
+ }
+}
+
+/** Dissect an AF Packet. Parse an AF packet, checking the CRC if the CRC valid
+ * flag is set and calling any registered sub dissectors on the payload type.
+ * Currently only a payload type 'T' is defined which is the tag packet layer.
+ * If any others are defined then they can register themselves.
+ * \param[in,out] tvb The buffer containing the packet
+ * \param[in,out] pinfo The packet info structure
+ * \param[in,out] tree The structure containing the details which will be displayed, filtered, etc.
+ */
+static void
+dissect_af (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
+{
+ gint offset = 0;
+ proto_item *ti = NULL;
+ proto_item *li = NULL;
+ proto_item *ci = NULL;
+ proto_tree *af_tree = NULL;
+ guint8 ver, pt;
+ guint32 payload_len;
+ tvbuff_t *next_tvb = NULL;
+
+ pinfo->current_proto = "DCP-AF";
+ if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
+ col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCP-AF");
+ }
+
+ if (tree) { /* we are being asked for details */
+ ti = proto_tree_add_item (tree, proto_af, tvb, 0, -1, FALSE);
+ af_tree = proto_item_add_subtree (ti, ett_af);
+ proto_tree_add_item (af_tree, hf_edcp_sync, tvb, offset, 2, FALSE);
+ }
+ offset += 2;
+ payload_len = tvb_get_ntohl(tvb, offset);
+ if (tree) {
+ guint32 real_payload_len = tvb_length(tvb)-12;
+ li = proto_tree_add_item (af_tree, hf_edcp_len, tvb, offset, 4, FALSE);
+ if(real_payload_len < payload_len) {
+ proto_item_append_text (li, " (wrong len claims %d is %d)",
+ payload_len, real_payload_len
+ );
+ } else if(real_payload_len > payload_len) {
+ proto_item_append_text (li, " (%d bytes in packet after end of AF frame)",
+ real_payload_len-payload_len
+ );
+ }
+ }
+ offset += 4;
+ if (tree)
+ proto_tree_add_item (af_tree, hf_edcp_seq, tvb, offset, 2, FALSE);
+ offset += 2;
+ ver = tvb_get_guint8 (tvb, offset);
+ if (tree) {
+ proto_tree_add_item (af_tree, hf_edcp_crcflag, tvb, offset, 1, FALSE);
+ proto_tree_add_item (af_tree, hf_edcp_maj, tvb, offset, 1, FALSE);
+ proto_tree_add_item (af_tree, hf_edcp_min, tvb, offset, 1, FALSE);
+ }
+ offset += 1;
+ pt = tvb_get_guint8 (tvb, offset);
+ if (tree)
+ proto_tree_add_item (af_tree, hf_edcp_pt, tvb, offset, 1, FALSE);
+ offset += 1;
+ next_tvb = tvb_new_subset (tvb, offset, payload_len, -1);
+ offset += payload_len;
+ if (tree)
+ ci = proto_tree_add_item (af_tree, hf_edcp_crc, tvb, offset, 2, FALSE);
+ if (ver & 0x80) { /* crc valid */
+ guint len = offset+2;
+ const guint8 *crc_buf = tvb_get_ptr(tvb, 0, len);
+ unsigned long c = crc_drm(crc_buf, len, 16, 0x11021, 1);
+ if (tree) {
+ proto_item_append_text(ci, " (%s)", (c==0xe2f0)?"Ok":"bad");
+ proto_tree_add_boolean(af_tree, hf_edcp_crc_ok, tvb, offset, 2, c==0xe2f0);
+ }
+ }
+ offset += 2;
+ dissector_try_port(af_dissector_table, pt, next_tvb, pinfo, tree);
+}
+
+/** Dissect the Tag Packet Layer.
+ * Split the AF packet into its tag items. Each tag item has a 4 character
+ * tag, a length in bits and a value. The *ptr tag is dissected in the routine.
+ * All other tags are listed and may be handled by other dissectors.
+ * Child dissectors are tied to the parent tree, not to this tree, so that
+ * they appear at the same level as DCP.
+ * \param[in,out] tvb The buffer containing the packet
+ * \param[in,out] pinfo The packet info structure
+ * \param[in,out] tree The structure containing the details which will be displayed, filtered, etc.
+ */
+static void
+dissect_tpl(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
+{
+ proto_tree *tpl_tree = NULL;
+ guint offset=0;
+ char *prot=NULL;
+ guint16 maj, min;
+
+ pinfo->current_proto = "DCP-TPL";
+ if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
+ col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCP-TPL");
+ }
+
+ if(tree) {
+ proto_item *ti = NULL;
+ ti = proto_tree_add_item (tree, proto_tpl, tvb, 0, -1, FALSE);
+ tpl_tree = proto_item_add_subtree (ti, ett_tpl);
+ }
+ while(offset<tvb_length(tvb)) {
+ guint32 bits;
+ guint32 bytes;
+ char *tag = (char*)tvb_get_string (tvb, offset, 4); offset += 4;
+ bits = tvb_get_ntohl(tvb, offset); offset += 4;
+ bytes = bits / 8;
+ if(bits % 8)
+ bytes++;
+ if(tree) {
+ proto_item *i = NULL;
+ const guint8 *p = tvb_get_ptr(tvb, offset, bytes);
+ if(strcmp(tag, "*ptr")==0) {
+ prot = (char*)tvb_get_string (tvb, offset, 4);
+ maj = tvb_get_ntohs(tvb, offset+4);
+ min = tvb_get_ntohs(tvb, offset+6);
+ i = proto_tree_add_bytes_format(tpl_tree, hf_tpl_tlv, tvb,
+ offset-8, bytes+8, p, "%s %s rev %d.%d", tag, prot, maj, min);
+ } else {
+ i = proto_tree_add_bytes_format(tpl_tree, hf_tpl_tlv, tvb,
+ offset-8, bytes+8, p, "%s (%u bits)", tag, bits);
+ }
+ }
+ offset += bytes;
+ }
+ if(prot) {
+ if(tree) {
+ dissector_try_string(tpl_dissector_table, prot, tvb, pinfo, tree->parent);
+ } else {
+ dissector_try_string(tpl_dissector_table, prot, tvb, pinfo, NULL);
+ }
+ }
+}
+
+void
+proto_reg_handoff_dcp_etsi (void)
+{
+ static int Initialized = FALSE;
+
+ if (!Initialized) {
+ af_handle = create_dissector_handle(dissect_af, proto_af);
+ pft_handle = create_dissector_handle(dissect_pft, proto_pft);
+ tpl_handle = create_dissector_handle(dissect_tpl, proto_tpl);
+ heur_dissector_add("udp", dissect_dcp_etsi, proto_dcp_etsi);
+ dissector_add_string("dcp-etsi.sync", "AF", af_handle);
+ dissector_add_string("dcp-etsi.sync", "PF", pft_handle);
+ /* if there are ever other payload types ...*/
+ dissector_add("dcp-af.pt", 'T', tpl_handle);
+ }
+}
+
+void
+proto_register_dcp_etsi (void)
+{
+ module_t *dcp_module;
+ static hf_register_info hf_edcp[] = {
+ {&hf_edcp_sync,
+ {"sync", "dcp-etsi.sync",
+ FT_STRING, BASE_NONE, NULL, 0,
+ "AF or PF", HFILL}
+ }
+ };
+ static hf_register_info hf_af[] = {
+ {&hf_edcp_len,
+ {"length", "dcp-af.len",
+ FT_UINT32, BASE_DEC, NULL, 0,
+ "length in bytes of the payload", HFILL}
+ },
+ {&hf_edcp_seq,
+ {"frame count", "dcp-af.seq",
+ FT_UINT16, BASE_DEC, NULL, 0,
+ "Logical Frame Number", HFILL}
+ },
+ {&hf_edcp_crcflag,
+ {"crc flag", "dcp-af.crcflag",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x80,
+ "Frame is protected by CRC", HFILL}
+ },
+ {&hf_edcp_maj,
+ {"Major Revision", "dcp-af.maj",
+ FT_UINT8, BASE_DEC, NULL, 0x70,
+ "Major Protocol Revision", HFILL}
+ },
+ {&hf_edcp_min,
+ {"Minor Revision", "dcp-af.min",
+ FT_UINT8, BASE_DEC, NULL, 0x0f,
+ "Minor Protocol Revision", HFILL}
+ },
+ {&hf_edcp_pt,
+ {"Payload Type", "dcp-af.pt",
+ FT_STRING, BASE_NONE, NULL, 0,
+ "T means Tag Packets, all other values reserved", HFILL}
+ },
+ {&hf_edcp_crc,
+ {"CRC", "dcp-af.crc",
+ FT_UINT16, BASE_HEX, NULL, 0,
+ "CRC", HFILL}
+ },
+ {&hf_edcp_crc_ok,
+ {"CRC OK", "dcp-af.crc_ok",
+ FT_BOOLEAN, BASE_NONE, NULL, 0,
+ "AF CRC OK", HFILL}
+ }
+ };
+
+ static hf_register_info hf_pft[] = {
+ {&hf_edcp_pft_pt,
+ {"Sub-protocol", "dcp-pft.pt",
+ FT_UINT8, BASE_DEC, NULL, 0,
+ "Always AF", HFILL}
+ },
+ {&hf_edcp_pseq,
+ {"Sequence No", "dcp-pft.seq",
+ FT_UINT16, BASE_DEC, NULL, 0,
+ "PFT Sequence No", HFILL}
+ },
+ {&hf_edcp_findex,
+ {"Fragment Index", "dcp-pft.findex",
+ FT_UINT24, BASE_DEC, NULL, 0,
+ "Index of the fragment within one AF Packet", HFILL}
+ },
+ {&hf_edcp_fcount,
+ {"Fragment Count", "dcp-pft.fcount",
+ FT_UINT24, BASE_DEC, NULL, 0,
+ "Number of fragments produced from this AF Packet", HFILL}
+ },
+ {&hf_edcp_fecflag,
+ {"FEC", "dcp-pft.fec",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x8000,
+ "When set the optional RS header is present", HFILL}
+ },
+ {&hf_edcp_addrflag,
+ {"Addr", "dcp-pft.addr",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x4000,
+ "When set the optional transport header is present", HFILL}
+ },
+ {&hf_edcp_plen,
+ {"fragment length", "dcp-pft.len",
+ FT_UINT16, BASE_DEC, NULL, 0x3fff,
+ "length in bytes of the payload of this fragment", HFILL}
+ },
+ {&hf_edcp_rsk,
+ {"RSk", "dcp-pft.rsk",
+ FT_UINT8, BASE_DEC, NULL, 0,
+ "The length of the Reed Solomon data word", HFILL}
+ },
+ {&hf_edcp_rsz,
+ {"RSz", "dcp-pft.rsz",
+ FT_UINT8, BASE_DEC, NULL, 0,
+ "The number of padding bytes in the last Reed Solomon block", HFILL}
+ },
+ {&hf_edcp_source,
+ {"source addr", "dcp-pft.source",
+ FT_UINT16, BASE_DEC, NULL, 0,
+ "PFT source identifier", HFILL}
+ },
+ {&hf_edcp_dest,
+ {"dest addr", "dcp-pft.dest",
+ FT_UINT16, BASE_DEC, NULL, 0,
+ "PFT destination identifier", HFILL}
+ },
+ {&hf_edcp_hcrc,
+ {"header CRC", "dcp-pft.crc",
+ FT_UINT16, BASE_HEX, NULL, 0,
+ "PFT Header CRC", HFILL}
+ },
+ {&hf_edcp_hcrc_ok,
+ {"PFT CRC OK", "dcp-pft.crc_ok",
+ FT_BOOLEAN, BASE_NONE, NULL, 0,
+ "PFT Header CRC OK", HFILL}
+ },
+ {&hf_edcp_fragments,
+ {"Message fragments", "dcp-pft.fragments",
+ FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL}},
+ {&hf_edcp_fragment,
+ {"Message fragment", "dcp-pft.fragment",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL}},
+ {&hf_edcp_fragment_overlap,
+ {"Message fragment overlap", "dcp-pft.fragment.overlap",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL}},
+ {&hf_edcp_fragment_overlap_conflicts,
+ {"Message fragment overlapping with conflicting data",
+ "dcp-pft.fragment.overlap.conflicts",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL}},
+ {&hf_edcp_fragment_multiple_tails,
+ {"Message has multiple tail fragments",
+ "dcp-pft.fragment.multiple_tails",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL}},
+ {&hf_edcp_fragment_too_long_fragment,
+ {"Message fragment too long", "dcp-pft.fragment.too_long_fragment",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL}},
+ {&hf_edcp_fragment_error,
+ {"Message defragmentation error", "dcp-pft.fragment.error",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL}},
+ {&hf_edcp_reassembled_in,
+ {"Reassembled in", "dcp-pft.reassembled.in",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL}},
+ {&hf_edcp_c_max,
+ {"C max", "dcp-pft.cmax",
+ FT_UINT16, BASE_DEC, NULL, 0,
+ "Maximum number of RS chunks sent", HFILL}
+ },
+ {&hf_edcp_rx_min,
+ {"Rx min", "dcp-pft.rxmin",
+ FT_UINT16, BASE_DEC, NULL, 0,
+ "Minimum number of fragments needed for RS decode", HFILL}
+ },
+ {&hf_edcp_rs_corrected,
+ {"RS Symbols Corrected", "dcp-pft.rs_corrected",
+ FT_INT16, BASE_DEC, NULL, 0,
+ "Number of symbols corrected by RS decode or -1 for failure", HFILL}
+ },
+ {&hf_edcp_rs_ok,
+ {"RS decode OK", "dcp-pft.rs_ok",
+ FT_BOOLEAN, BASE_NONE, NULL, 0,
+ "successfully decoded RS blocks", HFILL}
+ },
+ {&hf_edcp_pft_payload,
+ {"payload", "dcp-pft.payload",
+ FT_BYTES, BASE_HEX, NULL, 0,
+ "PFT Payload", HFILL}
+ }
+ };
+
+ static hf_register_info hf_tpl[] = {
+ {&hf_tpl_tlv,
+ {"tag", "dcp-tpl.tlv",
+ FT_BYTES, BASE_HEX, NULL, 0,
+ "Tag Packet", HFILL}
+ },
+ {&hf_tpl_ptr,
+ {"Type", "dcp-tpl.ptr",
+ FT_STRING, BASE_NONE, NULL, 0,
+ "Protocol Type & Revision", HFILL}
+ }
+ };
+
+/* Setup protocol subtree array */
+ static gint *ett[] = {
+ &ett_edcp,
+ &ett_af,
+ &ett_pft,
+ &ett_tpl,
+ &ett_edcp_fragment,
+ &ett_edcp_fragments
+ };
+
+ if (proto_dcp_etsi == -1) {
+ proto_dcp_etsi = proto_register_protocol ("ETSI Distribution & Communication Protocol (for DRM)", /* name */
+ "DCP (ETSI)", /* short name */
+ "dcp-etsi" /* abbrev */
+ );
+ proto_af = proto_register_protocol ("DCP Application Framing Layer", "DCP-AF", "dcp-af");
+ proto_pft = proto_register_protocol ("DCP Protection, Fragmentation & Transport Layer", "DCP-PFT", "dcp-pft");
+ proto_tpl = proto_register_protocol ("DCP Tag Packet Layer", "DCP-TPL", "dcp-tpl");
+
+
+ }
+ dcp_module = prefs_register_protocol (proto_dcp_etsi, proto_reg_handoff_dcp_etsi);
+ proto_register_field_array (proto_dcp_etsi, hf_edcp, array_length (hf_edcp));
+ proto_register_field_array (proto_af, hf_af, array_length (hf_af));
+ proto_register_field_array (proto_pft, hf_pft, array_length (hf_pft));
+ proto_register_field_array (proto_tpl, hf_tpl, array_length (hf_tpl));
+ proto_register_subtree_array (ett, array_length (ett));
+
+ /* subdissector code */
+ dcp_dissector_table = register_dissector_table("dcp-etsi.sync",
+ "DCP Sync", FT_STRING, BASE_NONE);
+ af_dissector_table = register_dissector_table("dcp-af.pt",
+ "AF Payload Type", FT_UINT8, BASE_DEC);
+
+ tpl_dissector_table = register_dissector_table("dcp-tpl.ptr",
+ "AF Payload Type", FT_STRING, BASE_NONE);
+
+ register_init_routine(dcp_init_protocol);
+
+}
+
+