From 0d834635a35a98d0dced54da7695ccab4464854d Mon Sep 17 00:00:00 2001
From: Abylay Ospan <aospan@netup.ru>
Date: Sat, 6 Jun 2009 09:31:34 -0300
Subject: [PATCH] V4L/DVB (11930): TS continuity check: show error message when
 discontinuity detected or TEI flag detected in header

Signed-off-by: Abylay Ospan <aospan@netup.ru>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
---
 drivers/media/dvb/dvb-core/dvb_demux.c | 42 ++++++++++++++++++++++++++
 drivers/media/dvb/dvb-core/dvb_demux.h |  4 +++
 2 files changed, 46 insertions(+)

diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index e2eca0b1fe7c..cfe2768d24af 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -38,6 +38,16 @@
 */
 // #define DVB_DEMUX_SECTION_LOSS_LOG
 
+static int dvb_demux_tscheck;
+module_param(dvb_demux_tscheck, int, 0644);
+MODULE_PARM_DESC(dvb_demux_tscheck,
+		"enable transport stream continuity and TEI check");
+
+#define dprintk_tscheck(x...) do {                              \
+		if (dvb_demux_tscheck && printk_ratelimit())    \
+			printk(x);                              \
+	} while (0)
+
 /******************************************************************************
  * static inlined helper functions
  ******************************************************************************/
@@ -376,6 +386,36 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
 	u16 pid = ts_pid(buf);
 	int dvr_done = 0;
 
+	if (dvb_demux_tscheck) {
+		if (!demux->cnt_storage)
+			demux->cnt_storage = vmalloc(MAX_PID + 1);
+
+		if (!demux->cnt_storage) {
+			printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n");
+			dvb_demux_tscheck = 0;
+			goto no_dvb_demux_tscheck;
+		}
+
+		/* check pkt counter */
+		if (pid < MAX_PID) {
+			if (buf[1] & 0x80)
+				dprintk_tscheck("TEI detected. "
+						"PID=0x%x data1=0x%x\n",
+						pid, buf[1]);
+
+			if ((buf[3] & 0xf) != demux->cnt_storage[pid])
+				dprintk_tscheck("TS packet counter mismatch. "
+						"PID=0x%x expected 0x%x "
+						"got 0x%x\n",
+						pid, demux->cnt_storage[pid],
+						buf[3] & 0xf);
+
+			demux->cnt_storage[pid] = ((buf[3] & 0xf) + 1)&0xf;
+		};
+		/* end check */
+	};
+no_dvb_demux_tscheck:
+
 	list_for_each_entry(feed, &demux->feed_list, list_head) {
 		if ((feed->pid != pid) && (feed->pid != 0x2000))
 			continue;
@@ -1160,6 +1200,7 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
 	int i;
 	struct dmx_demux *dmx = &dvbdemux->dmx;
 
+	dvbdemux->cnt_storage = NULL;
 	dvbdemux->users = 0;
 	dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter));
 
@@ -1226,6 +1267,7 @@ EXPORT_SYMBOL(dvb_dmx_init);
 
 void dvb_dmx_release(struct dvb_demux *dvbdemux)
 {
+	vfree(dvbdemux->cnt_storage);
 	vfree(dvbdemux->filter);
 	vfree(dvbdemux->feed);
 }
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index 2c5f915329ca..2fe05d03240d 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -42,6 +42,8 @@
 
 #define DVB_DEMUX_MASK_MAX 18
 
+#define MAX_PID 0x1fff
+
 struct dvb_demux_filter {
 	struct dmx_section_filter filter;
 	u8 maskandmode[DMX_MAX_FILTER_SIZE];
@@ -127,6 +129,8 @@ struct dvb_demux {
 
 	struct mutex mutex;
 	spinlock_t lock;
+
+	uint8_t *cnt_storage; /* for TS continuity check */
 };
 
 int dvb_dmx_init(struct dvb_demux *dvbdemux);