/* packet-dcp-etsi.c
- * Routines for ETSI Distribution & Communication Protocol
- * Copyright 2006, British Broadcasting Corporation
+ * Routines for ETSI Distribution & Communication Protocol
+ * Copyright 2006, British Broadcasting Corporation
*
- * $Id:$
+ * $Id$
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
#include <gmodule.h>
#include <epan/packet.h>
-#include <epan/prefs.h>
#include <epan/reassemble.h>
#include <epan/crcdrm.h>
#include <epan/reedsolomon.h>
+#include <epan/emem.h>
#include <string.h>
/* forward reference */
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;
{
guint8 *sync;
proto_tree *dcp_tree = NULL;
- sync = tvb_get_string (tvb, 0, 2);
+ sync = tvb_get_ephemeral_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);
}
dissector_try_string(dcp_dissector_table, (char*)sync, tvb, pinfo, dcp_tree);
- g_free (sync);
return TRUE;
}
#define PFT_RS_P (PFT_RS_K - PFT_RS_N_MAX)
-static
+static
void rs_deinterleave(const guint8 *input, guint8 *output, guint16 plen, guint32 fcount)
{
guint fidx;
}
}
-static
-gboolean rs_correct_data(guint8 *deinterleaved, guint8 *output,
- guint32 c_max, guint16 rsk, guint16 rsz)
+static
+gboolean rs_correct_data(guint8 *deinterleaved, guint8 *output,
+ guint32 c_max, guint16 rsk, guint16 rsz _U_)
{
guint32 i, index_coded = 0, index_out = 0;
int err_corr;
return TRUE;
}
-
+/* Don't attempt reassembly if we have a huge number of fragments. */
+#define MAX_FRAGMENTS ((1 * 1024 * 1024) / sizeof(guint32))
static tvbuff_t *
dissect_pft_fec_detailed(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
guint16 seq,
gint offset,
guint16 plen,
- gboolean fec,
+ gboolean fec _U_,
guint16 rsk,
guint16 rsz,
- fragment_data *fd
+ fragment_data *fdx
)
{
guint16 decoded_size;
guint32 c_max;
guint32 rx_min;
- gboolean first, last, decoded = TRUE;
+ gboolean first, last;
tvbuff_t *new_tvb=NULL;
+ if (fcount > MAX_FRAGMENTS) {
+ if (tree)
+ proto_tree_add_text(tree, tvb , 0, -1, "[Reassembly of %d fragments not attempted]", fcount);
+ return NULL;
+ }
+
first = findex == 0;
last = fcount == (findex+1);
decoded_size = fcount*plen;
rx_min = c_max*rsk/plen;
if(rx_min*plen<c_max*rsk)
rx_min++;
- if (fd)
+ if (fdx)
new_tvb = process_reassembled_data (tvb, offset, pinfo,
"Reassembled Message",
- fd, &dcp_frag_items,
+ fdx, &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);
+ guint32 *got;
+ fragment_data *fd;
fragment_data *fd_head;
+
+ if(tree)
+ proto_tree_add_text (tree, tvb, 0, -1, "want %d, got %d need %d",
+ fcount, fragments, rx_min
+ );
+ got = ep_alloc(fcount*sizeof(guint32));
+
+ /* make a list of the findex (offset) numbers of the fragments we have */
+ fd = fragment_get(pinfo, seq, dcp_fragment_table);
for (fd_head = fd; fd_head != NULL; fd_head = fd_head->next) {
if(fd_head->data) {
- got[fragments] = fd_head->offset;
- fragments++;
+ got[fragments++] = fd_head->offset; /* this is the findex of the fragment */
}
}
- if(fragments>=rx_min) {
- guint i,j;
+ /* put a sentinel at the end */
+ got[fragments++] = fcount;
+ /* have we got enough for Reed Solomon to try to correct ? */
+ if(fragments>=rx_min) { /* yes, in theory */
+ guint i,current_findex;
fragment_data *frag=NULL;
- guint8 *dummy_data = (guint8*) g_malloc (plen);
+ guint8 *dummy_data = (guint8*) ep_alloc0 (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++;
+ /* fill the fragment table with empty fragments */
+ current_findex = 0;
+ for(i=0; i<fragments; i++) {
+ guint next_fragment_we_have = got[i];
+ if (next_fragment_we_have > MAX_FRAGMENTS) {
+ if (tree)
+ proto_tree_add_text(tree, tvb , 0, -1, "[Reassembly of %d fragments not attempted]", next_fragment_we_have);
+ return NULL;
+ }
+ for(; current_findex<next_fragment_we_have; current_findex++) {
+ frag = fragment_add_seq_check (dummytvb, 0, pinfo, seq,
+ dcp_fragment_table, dcp_reassembled_table, current_findex, plen, (current_findex+1!=fcount));
}
+ current_findex++; /* skip over the fragment we have */
}
if(frag)
new_tvb = process_reassembled_data (tvb, offset, pinfo,
frag, &dcp_frag_items,
NULL, tree);
}
- g_free(got);
}
if(new_tvb) {
+ gboolean decoded = TRUE;
tvbuff_t *dtvb = NULL;
const guint8 *input = tvb_get_ptr(new_tvb, 0, -1);
guint16 reassembled_size = tvb_length(new_tvb);
/** Handle a PFT packet which has the fragmentation header. This uses the
- * standard ethereal methods for reassembling fragments. If FEC is used,
+ * standard wireshark 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
last = fcount == (findex+1);
frag_edcp = fragment_add_seq_check (
tvb, offset, pinfo,
- seq,
- dcp_fragment_table, dcp_reassembled_table,
+ seq,
+ dcp_fragment_table, dcp_reassembled_table,
findex,
- plen,
+ plen,
!last);
if(fec) {
new_tvb = dissect_pft_fec_detailed(
if (tree) {
proto_item *ci = NULL;
guint header_len = offset+2;
- const guint8 *crc_buf = tvb_get_ptr(tvb, 0, header_len);
+ const char *crc_buf = (const char *) 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");
if(li)
proto_item_append_text(li, " (length error (%d))", real_len);
}
- next_tvb = dissect_pft_fragmented(tvb, pinfo, pft_tree,
+ next_tvb = dissect_pft_fragmented(tvb, pinfo, pft_tree,
findex, fcount, seq, offset, real_len,
fec, rsk, rsz
);
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);
+ const char *crc_buf = (const char *) 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");
dissector_try_port(af_dissector_table, pt, next_tvb, pinfo, tree);
}
-/** Dissect the Tag Packet Layer.
+/** 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.
{
proto_tree *tpl_tree = NULL;
guint offset=0;
- char *prot=NULL;
+ 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) {
+ guint32 bits;
+ guint32 bytes;
+ char *tag = (char*)tvb_get_ephemeral_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);
+ prot = (char*)tvb_get_ephemeral_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);
+ 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,
+ 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);
- }
+ if(prot) { /* prot is non-NULL only if we have our tree. */
+ dissector_try_string(tpl_dissector_table, prot, tvb, pinfo, tree->parent);
}
}
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);
- }
+ dissector_handle_t af_handle;
+ dissector_handle_t pft_handle;
+ dissector_handle_t tpl_handle;
+
+ 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",
&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");
+ 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));