aboutsummaryrefslogtreecommitdiffstats
path: root/epan
diff options
context:
space:
mode:
authorAnders Broman <anders.broman@ericsson.com>2009-02-05 21:02:50 +0000
committerAnders Broman <anders.broman@ericsson.com>2009-02-05 21:02:50 +0000
commitdf6d3da58699f0a073afe47429c1967e54eba210 (patch)
treef03399939b37219a5bf60176051501361d9326d8 /epan
parent48bf9f396ed533ce5bfdb9cd7f98f75bab105f50 (diff)
Signed-off-by: Jesper Dangaard Brouer <hawk@comx.dk>
Reviewed-by: Martin Philip Topholm <mph@comx.dk> Implement packet loss detection in for MPEG2 Transport Streams Second Part of https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=3227 svn path=/trunk/; revision=27381
Diffstat (limited to 'epan')
-rw-r--r--epan/dissectors/packet-mp2t.c273
1 files changed, 270 insertions, 3 deletions
diff --git a/epan/dissectors/packet-mp2t.c b/epan/dissectors/packet-mp2t.c
index 149a23e53e..063a1fc0f0 100644
--- a/epan/dissectors/packet-mp2t.c
+++ b/epan/dissectors/packet-mp2t.c
@@ -38,6 +38,10 @@
#include <epan/rtp_pt.h>
#include "packet-frame.h"
+#include <epan/emem.h>
+#include <epan/conversation.h>
+#include <epan/expert.h>
+
/* The MPEG2 TS packet size */
#define MP2T_PACKET_SIZE 188
#define MP2T_SYNC_BYTE 0x47
@@ -58,6 +62,7 @@ static int hf_mp2t_pid = -1;
static int hf_mp2t_tsc = -1;
static int hf_mp2t_afc = -1;
static int hf_mp2t_cc = -1;
+static int hf_mp2t_cc_drop = -1;
#define MP2T_SYNC_BYTE_MASK 0xFF000000
#define MP2T_TEI_MASK 0x00800000
@@ -187,14 +192,267 @@ static const value_string mp2t_afc_vals[] = {
{ 0, NULL }
};
+/* Data structure used for detecting CC drops
+ *
+ * conversation
+ * |
+ * +-> mp2t_analysis_data
+ * |
+ * +-> pid_table (RB tree)
+ * | |
+ * | +-> pid_analysis_data (per pid)
+ * | +-> pid_analysis_data
+ * | +-> pid_analysis_data
+ * |
+ * +-> frame_table (RB tree)
+ * |
+ * +-> frame_analysis_data (only created if drop detected)
+ * |
+ * +-> ts_table (RB tree)
+ * |
+ * +-> pid_analysis_data (per TS subframe)
+ * +-> pid_analysis_data
+ * +-> pid_analysis_data
+ */
+
+typedef struct mp2t_analysis_data {
+
+ /* This structure contains a tree containing data for the
+ * individual pid's, this is only used when packets are
+ * processed sequencially.
+ */
+ emem_tree_t *pid_table;
+
+ /* When detecting a CC drop, store that information for the
+ * given frame. This info is needed, when clicking around in
+ * wireshark, as the pid table data only makes sence during
+ * sequencial processing. The flag pinfo->fd->flags.visited is
+ * used to tell the difference.
+ *
+ */
+ emem_tree_t *frame_table;
+
+ guint32 cc_drops; /* Number of detected CC losses per conv */
+
+} mp2t_analysis_data_t;
+
+typedef struct pid_analysis_data {
+ guint16 pid;
+ gint16 cc_prev; /* Previous CC number */
+} pid_analysis_data_t;
+
+typedef struct frame_analysis_data {
+
+ /* As each frame has several pid's, thus need a pid data
+ * structure per TS frame.
+ */
+ emem_tree_t *ts_table;
+
+} frame_analysis_data_t;
+
+conversation_t *
+get_the_conversation(packet_info *pinfo)
+{
+ conversation_t *conv = NULL;
+
+ conv = find_conversation(pinfo->fd->num, &pinfo->src,
+ &pinfo->dst, pinfo->ptype,
+ pinfo->srcport, pinfo->destport, 0);
+
+ if (conv == NULL) { /* Create a new conversation */
+ conv = conversation_new(pinfo->fd->num, &pinfo->src,
+ &pinfo->dst, pinfo->ptype,
+ pinfo->srcport, pinfo->destport, 0);
+ }
+ return conv;
+}
+
+mp2t_analysis_data_t *
+init_mp2t_conversation_data()
+{
+ mp2t_analysis_data_t *mp2t_data = NULL;
+
+ mp2t_data = se_alloc0(sizeof(struct mp2t_analysis_data));
+
+ mp2t_data->pid_table =
+ se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK,
+ "mp2t_pid_table");
+ mp2t_data->frame_table =
+ se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK,
+ "mp2t_frame_table");
+ mp2t_data->cc_drops = 0;
+
+ return mp2t_data;
+}
+
+mp2t_analysis_data_t *
+get_mp2t_conversation_data(conversation_t *conv)
+{
+ mp2t_analysis_data_t *mp2t_data = NULL;
+
+ mp2t_data = conversation_get_proto_data(conv, proto_mp2t);
+ if (!mp2t_data) {
+ mp2t_data = init_mp2t_conversation_data();
+ conversation_add_proto_data(conv, proto_mp2t, mp2t_data);
+ }
+
+ return mp2t_data;
+}
+
+frame_analysis_data_t *
+init_frame_analysis_data(mp2t_analysis_data_t *mp2t_data, packet_info *pinfo)
+{
+ frame_analysis_data_t *frame_data = NULL;
+
+ frame_data = se_alloc0(sizeof(struct frame_analysis_data));
+ frame_data->ts_table =
+ se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK,
+ "mp2t_frame_pid_table");
+ /* Insert into mp2t tree */
+ se_tree_insert32(mp2t_data->frame_table, pinfo->fd->num,
+ (void *)frame_data);
+
+ return frame_data;
+}
+
+
+frame_analysis_data_t *
+get_frame_analysis_data(mp2t_analysis_data_t *mp2t_data, packet_info *pinfo)
+{
+ frame_analysis_data_t *frame_data = NULL;
+ frame_data = se_tree_lookup32(mp2t_data->frame_table, pinfo->fd->num);
+ return frame_data;
+}
+
+pid_analysis_data_t *
+get_pid_analysis(guint32 pid, conversation_t *conv)
+{
+
+ pid_analysis_data_t *pid_data = NULL;
+ mp2t_analysis_data_t *mp2t_data = NULL;
+ mp2t_data = get_mp2t_conversation_data(conv);
+
+ pid_data = se_tree_lookup32(mp2t_data->pid_table, pid);
+ if (!pid_data) {
+ pid_data = se_alloc0(sizeof(struct pid_analysis_data));
+ pid_data->cc_prev = -1;
+ pid_data->pid = pid;
+
+ se_tree_insert32(mp2t_data->pid_table, pid, (void *)pid_data);
+ }
+ return pid_data;
+}
+
+#define KEY(pid, cc) ((pid << 4)|cc)
+
+void
+detect_cc_drops(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo,
+ guint32 pid, gint32 cc_curr, conversation_t *conv)
+{
+ gint32 cc_prev;
+ pid_analysis_data_t *pid_data = NULL;
+ pid_analysis_data_t *ts_data = NULL;
+ mp2t_analysis_data_t *mp2t_data = NULL;
+ frame_analysis_data_t *frame_data = NULL;
+ proto_item *flags_item;
+
+ guint32 detected_drop = 0;
+
+ mp2t_data = get_mp2t_conversation_data(conv);
+
+ /* The initial sequencial processing stage */
+ if (!pinfo->fd->flags.visited) {
+
+ /* This is the sequencial processing stage */
+ pid_data = get_pid_analysis(pid, conv);
+
+ cc_prev = pid_data->cc_prev;
+ pid_data->cc_prev = cc_curr;
+
+ /* Null packet always have a CC value equal 0 */
+ if (pid == 0x1fff)
+ return;
+
+ /* Its allowed that (cc_prev == cc_curr) if adaptation field */
+ if (cc_prev == cc_curr)
+ return;
+
+ /* Have not seen this pid before */
+ if (cc_prev == -1)
+ return;
+
+ /* Detect if CC is not increasing by one all the time */
+ if (cc_curr != ((cc_prev+1) & MP2T_CC_MASK)) {
+ detected_drop = 1;
+ mp2t_data->cc_drops++;
+ }
+ }
+
+ /* Save the info about the dropped packet */
+ if (detected_drop && !pinfo->fd->flags.visited) {
+
+ /* Lookup frame data, contains TS pid data objects */
+ frame_data = get_frame_analysis_data(mp2t_data, pinfo);
+ if (!frame_data)
+ frame_data = init_frame_analysis_data(mp2t_data, pinfo);
+
+ /* Create and store a new TS frame pid_data object.
+ This indicate that we have a drop
+ */
+ ts_data = se_alloc0(sizeof(struct pid_analysis_data));
+ ts_data->cc_prev = cc_prev;
+ ts_data->pid = pid;
+ se_tree_insert32(frame_data->ts_table, KEY(pid, cc_curr),
+ (void *)ts_data);
+ }
+
+ /* See if we stored info about drops */
+ if (pinfo->fd->flags.visited) {
+
+ /* Lookup frame data, contains TS pid data objects */
+ frame_data = get_frame_analysis_data(mp2t_data, pinfo);
+ if (!frame_data)
+ return; /* No stored frame data -> no drops*/
+ else {
+ ts_data = se_tree_lookup32(frame_data->ts_table,
+ KEY(pid, cc_curr));
+ if (ts_data)
+ detected_drop = 1;
+ }
+
+ }
+
+ /* Add info to the proto tree about drops */
+ if (detected_drop) {
+
+ flags_item =
+ proto_tree_add_none_format(
+ tree, hf_mp2t_cc_drop, tvb, 0, 0,
+ "Detected missing CC frame before this"
+ " (accumulated CC loss count:%d)",
+ mp2t_data->cc_drops
+ );
+
+ PROTO_ITEM_SET_GENERATED(flags_item);
+ expert_add_info_format(pinfo, flags_item, PI_MALFORMED,
+ PI_ERROR, "Detected CC loss");
+
+ }
+}
+
+
static gint
-dissect_tsp( tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree )
+dissect_tsp(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree,
+ conversation_t *conv)
{
guint32 header;
guint afc;
gint start_offset = offset;
gint payload_len;
+ guint32 pid;
+ guint32 cc;
+
proto_item *ti = NULL;
proto_item *hi = NULL;
proto_tree *mp2t_tree = NULL;
@@ -206,8 +464,11 @@ dissect_tsp( tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree )
header = tvb_get_ntohl(tvb, offset);
- proto_item_append_text(ti, " PID=0x%x CC=%d", (header & MP2T_PID_MASK) >> MP2T_PID_SHIFT, (header & MP2T_CC_MASK) >> MP2T_CC_SHIFT );
+ pid = (header & MP2T_PID_MASK) >> MP2T_PID_SHIFT;
+ cc = (header & MP2T_CC_MASK) >> MP2T_CC_SHIFT;
+ proto_item_append_text(ti, " PID=0x%x CC=%d", pid, cc);
+ detect_cc_drops(tvb, tree, pinfo, pid, cc, conv);
hi = proto_tree_add_item( mp2t_tree, hf_mp2t_header, tvb, offset, 4, FALSE);
mp2t_header_tree = proto_item_add_subtree( hi, ett_mp2t_header );
@@ -452,9 +713,11 @@ static void
dissect_mp2t( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
{
guint offset = 0;
+ conversation_t *conv;
+ conv = get_the_conversation(pinfo);
while ( tvb_reported_length_remaining(tvb, offset) >= MP2T_PACKET_SIZE ) {
- offset = dissect_tsp( tvb, offset, pinfo, tree);
+ offset = dissect_tsp(tvb, offset, pinfo, tree, conv);
}
}
@@ -517,6 +780,10 @@ proto_register_mp2t(void)
"Continuity Counter", "mp2t.cc",
FT_UINT32, BASE_DEC, NULL, MP2T_CC_MASK, NULL, HFILL
} } ,
+ { &hf_mp2t_cc_drop, {
+ "Continuity Counter Drops", "mp2t.cc.drop",
+ FT_NONE, BASE_DEC, NULL, 0x0, NULL, HFILL
+ } } ,
{ &hf_mp2t_af, {
"Adaption field", "mp2t.af",
FT_NONE, BASE_HEX, NULL, 0, NULL, HFILL