Mailing List archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[linux-dvb] [PATCH] Ultra Light Encapsulation



Hi,

we have been implementing the Ultra-Light-Encapsualtion http://www.ietf.org/internet-drafts/draft-ietf-ipdvb-ule-00.txt for the LinuxTV DVB 1.1.1 driver as part of an ESA project. ULE should hopefully replace the Multi-Protocol-Encapsualtion in near future as it adds less overhead and is easier to process (especially for IPv6). At the moment there are no public broadcasters that use this new encapsulation (at least to my knowledge) but we expect that with the availability of ULE capable DVB receiver cards this will change.

The ULE implemetation is attached to this message as a patch against the linux-dvb-1.1.1 driver and the linux-dvb-apps-1.1.0.

This implementation has already been fully tested for cross-interoperability with different IP/DVB manufacturers and should be fairly stable.

We would like to see this patch go into the CVS as well.

Comments are welcome.

-Hilmar

diff -ru linuxtv-dvb-1.1.1/linux/drivers/media/dvb/dvb-core/dvb_net.c linuxtv-dvb-1.1.1-ULE/linux/drivers/media/dvb/dvb-core/dvb_net.c
--- linuxtv-dvb-1.1.1/linux/drivers/media/dvb/dvb-core/dvb_net.c	2004-02-23 20:08:36.000000000 +0100
+++ linuxtv-dvb-1.1.1-ULE/linux/drivers/media/dvb/dvb-core/dvb_net.c	2004-03-30 11:33:58.000000000 +0200
@@ -4,6 +4,15 @@
  * Copyright (C) 2001 Convergence integrated media GmbH
  *                    Ralph Metzler <ralph@convergence.de>
  * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
+ * 
+ * ULE Decapsulation code:
+ * Copyright (C) 2003 gcs - Global Communication & Services GmbH.
+ *                and Institute for Computer Sciences
+ *                    Salzburg University.
+ *                    Hilmar Linder <hlinder@cosy.sbg.ac.at>
+ *                and Wolfram Stering <wstering@cosy.sbg.ac.at>
+ *
+ * ULE Decaps according to draft-fair-ipdvb-ule-01.txt.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -24,7 +33,11 @@
  * 
  */
 
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
 #include <linux/dvb/net.h>
+#include <linux/uio.h>
 #include <asm/uaccess.h>
 
 #include "dvb_demux.h"
@@ -32,6 +45,15 @@
 #include "dvb_functions.h"
 
 
+static inline __u32 iov_crc32( __u32 c, struct iovec *iov, unsigned int cnt )
+{
+	unsigned int j;
+	for (j = 0; j < cnt; j++)
+		c = crc32_be( c, iov[j].iov_base, iov[j].iov_len );
+	return c;
+}
+
+
 #if 1
 #define dprintk(x...) printk(x)
 #else
@@ -41,6 +63,36 @@
 
 #define DVB_NET_MULTICAST_MAX 10
 
+#define isprint(c)	((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
+
+static void hexdump( const unsigned char *buf, unsigned short len )
+{
+	char str[80], octet[10];
+	int ofs, i, l;
+
+	for (ofs = 0; ofs < len; ofs += 16) {
+		sprintf( str, "%03d: ", ofs );
+
+		for (i = 0; i < 16; i++) {
+			if ((i + ofs) < len)
+				sprintf( octet, "%02x ", buf[ofs + i] );
+			else
+				strcpy( octet, "   " );
+
+			strcat( str, octet );
+		}
+		strcat( str, "  " );
+		l = strlen( str );
+
+		for (i = 0; (i < 16) && ((i + ofs) < len); i++)
+			str[l++] = isprint( buf[ofs + i] ) ? buf[ofs + i] : '.';
+
+		str[l] = '\0';
+		printk( KERN_WARNING "%s\n", str );
+	}
+}
+
+
 struct dvb_net_priv {
 	int in_use;
         struct net_device_stats stats;
@@ -49,6 +101,7 @@
         struct dmx_demux *demux;
 	struct dmx_section_feed *secfeed;
 	struct dmx_section_filter *secfilter;
+	struct dmx_ts_feed *tsfeed;
 	int multi_num;
 	struct dmx_section_filter *multi_secfilter[DVB_NET_MULTICAST_MAX];
 	unsigned char multi_macs[DVB_NET_MULTICAST_MAX][6];
@@ -59,6 +112,16 @@
 #define RX_MODE_PROMISC 3
 	struct work_struct set_multicast_list_wq;
 	struct work_struct restart_net_feed_wq;
+    unsigned char feedtype;
+    int need_pusi;
+    unsigned char tscc;     // TS continuity counter after sync.
+    struct sk_buff *ule_skb;
+    unsigned short ule_sndu_len;
+    unsigned short ule_sndu_type;
+    unsigned char ule_sndu_type_1;
+    unsigned char ule_dbit;     // whether the DestMAC address present bit is set or not.
+    unsigned char ule_ethhdr_complete;  // whether we have completed the Ethernet header for the current ULE SNDU.
+    int ule_sndu_remain;
 };
 
 
@@ -107,6 +170,361 @@
 	return htons(ETH_P_802_2);
 }
 
+#define TS_SZ	188
+#define TS_SYNC	0x47
+#define TS_TEI	0x80
+#define TS_PUSI	0x40
+#define TS_AF_A	0x20
+#define TS_AF_D	0x10
+
+#define ULE_TEST	0
+#define ULE_BRIDGED	1
+#define ULE_LLC		2
+
+static inline void reset_ule( struct dvb_net_priv *p )
+{
+	p->ule_skb = NULL;
+	p->ule_sndu_len = 0;
+	p->ule_sndu_type = 0;
+	p->ule_sndu_type_1 = 0;
+	p->ule_sndu_remain = 0;
+	p->ule_dbit = 0xFF;
+	p->ule_ethhdr_complete = 0;
+}
+
+static const char eth_dest_addr[] = { 0x0b, 0x0a, 0x09, 0x08, 0x04, 0x03 };
+
+static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
+{
+	struct dvb_net_priv *priv = (struct dvb_net_priv *)dev->priv;
+	unsigned long skipped = 0L, skblen = 0L;
+	u8 *ts, *ts_end, *from_where = NULL, ts_remain = 0, how_much = 0, new_ts = 1;
+	struct ethhdr *ethh = NULL;
+	unsigned int emergency_count = 0;
+
+	if (dev == NULL) {
+		printk( KERN_ERR "NO netdev struct!\n" );
+		return;
+	}
+
+	for (ts = (char *)buf, ts_end = (char *)buf + buf_len; ts < ts_end;) {
+
+		if (emergency_count++ > 200) {
+			// Huh??
+			hexdump( ts, TS_SZ );
+			printk( KERN_WARNING "*** LOOP ALERT! ts %p ts_remain %u how_much %u, ule_skb %p, ule_len %u, ule_remain %u\n",
+					ts, ts_remain, how_much, priv->ule_skb, priv->ule_sndu_len, priv->ule_sndu_remain );
+			break;
+		}
+
+		if (new_ts) {
+			if ((ts[0] != TS_SYNC) || (ts[1] & TS_TEI)) {
+				printk( KERN_WARNING "Invalid TS cell: SYNC %#x, TEI %u.\n", ts[0], ts[1] & TS_TEI >> 7 );
+				continue;
+			}
+			ts_remain = 184;
+			from_where = ts + 4;
+		}
+		// Synchronize on PUSI, if required.
+		if (priv->need_pusi) {
+			if (ts[1] & TS_PUSI) {
+				// Find beginning of first ULE SNDU in current TS cell.
+				// priv->need_pusi = 0;
+				priv->tscc = ts[3] & 0x0F;
+				// There is a pointer field here.
+				if (ts[4] > ts_remain) {
+					printk( KERN_ERR "Invalid ULE packet (pointer field %d)\n", ts[4] );
+					continue;
+				}
+				from_where = &ts[5] + ts[4];
+				ts_remain -= 1 + ts[4];
+				skipped = 0;
+			} else {
+				skipped++;
+				continue;
+			}
+		}
+
+		// Check continuity counter.
+		if (new_ts) {
+			if ((ts[3] & 0x0F) == priv->tscc)
+				priv->tscc = (priv->tscc + 1) & 0x0F;
+			else {
+				// TS discontinuity handling:
+				if (priv->ule_skb) {
+					dev_kfree_skb( priv->ule_skb );
+					// Prepare for next SNDU.
+					reset_ule( priv );
+					((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
+					((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++;
+				}
+				//	skip to next PUSI.
+				printk( KERN_WARNING "TS discontinuity: got %#x, exptected %#x.\n", ts[3] & 0x0F, priv->tscc );
+				priv->need_pusi = 1;
+				continue;
+			}
+			// If we still have an incomplete payload, but PUSI is set, some TS cells are missing.
+			// This is only possible here, if we missed exactly 16 TS cells (continuity counter).
+			if (ts[1] & TS_PUSI) {
+				if (! priv->need_pusi) {
+					// printk( KERN_WARNING "Skipping pointer field %u.\n", *from_where );
+					if (*from_where > 181) {
+						printk( KERN_WARNING "*** Invalid pointer field: %u.  Current TS cell follows:\n", *from_where );
+						hexdump( ts, TS_SZ );
+						printk( KERN_WARNING "-------------------------------------------------------------\n" );
+					}
+					// Skip pointer field (we're processing a packed payload).
+					from_where += 1;
+					ts_remain -= 1;
+				} else 
+					priv->need_pusi = 0;
+
+				if (priv->ule_sndu_remain > 183) {
+					((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
+					((struct dvb_net_priv *) dev->priv)->stats.rx_length_errors++;
+					printk( KERN_WARNING "Expected %d more SNDU bytes, but got PUSI.  Flushing incomplete payload.\n", priv->ule_sndu_remain );
+					dev_kfree_skb( priv->ule_skb );
+					// Prepare for next SNDU.
+					reset_ule( priv );
+				}
+			}
+		}
+
+		// Check if new payload needs to be started.
+		if (priv->ule_skb == NULL) {
+			// Start a new payload w/ skb.
+			// Find ULE header.  It is only guaranteed that the length field (2 bytes) is contained in the current TS.
+			// Check ts_remain has to be >= 2 here.
+			if (ts_remain < 2) {
+				printk( KERN_WARNING "Invalid payload packing: only %d bytes left in TS.  Resyncing.\n", ts_remain );
+				priv->ule_sndu_len = 0;
+				priv->need_pusi = 1;
+				continue;
+			}
+
+			if (! priv->ule_sndu_len) {
+				priv->ule_sndu_len = from_where[0] << 8 | from_where[1];
+				if (priv->ule_sndu_len & 0x8000) {
+					// D-Bit is set: no dest mac present.
+					priv->ule_sndu_len &= 0x7FFF;
+					priv->ule_dbit = 1;
+				} else
+					priv->ule_dbit = 0;
+
+				// printk( KERN_WARNING "ULE D-Bit: %d, SNDU len %u.\n", priv->ule_dbit, priv->ule_sndu_len );
+
+				if (priv->ule_sndu_len > 32763) {
+					printk( KERN_WARNING "Invalid ULE SNDU length %u.  Resyncing.\n", priv->ule_sndu_len );
+					hexdump( ts, TS_SZ );
+					priv->ule_sndu_len = 0;
+					priv->need_pusi = 1;
+					new_ts = 1;
+					ts += TS_SZ;
+					continue;
+				}
+				ts_remain -= 2;	// consume the 2 bytes SNDU length.
+				from_where += 2;
+			}
+
+			/*
+			 * State of current TS:
+			 *   ts_remain (remaining bytes in the current TS cell)
+			 *   0	ule_type is not available now, we need the next TS cell
+			 *   1	the first byte of the ule_type is present
+			 * >=2	full ULE header present, maybe some payload data as well.
+			 */
+			switch (ts_remain) {
+				case 1:
+					priv->ule_sndu_type = from_where[0] << 8;
+					priv->ule_sndu_type_1 = 1;	// first byte of ule_type is set.
+					// ts_remain -= 1; from_where += 1; here not necessary, because we continue.
+				case 0:
+					new_ts = 1; 
+					ts += TS_SZ;
+					continue;
+
+				default:	// complete ULE header is present in current TS.
+					// Extract ULE type field.
+					if (priv->ule_sndu_type_1) {
+						priv->ule_sndu_type |= from_where[0];
+						from_where += 1;	// points to payload start.
+						ts_remain -= 1;
+					} else {
+						// Complete type is present in new TS.
+						priv->ule_sndu_type = from_where[0] << 8 | from_where[1];
+						from_where += 2;	// points to payload start.
+						ts_remain -= 2;
+					}
+					break;
+			}
+
+			if (priv->ule_sndu_type == ULE_TEST) {
+				// Test SNDU, discarded by the receiver.
+				printk( KERN_WARNING "Discarding ULE Test SNDU (%d bytes).  Resyncing.\n", priv->ule_sndu_len );
+				priv->ule_sndu_len = 0;
+				priv->need_pusi = 1;
+				continue;
+			}
+
+			skblen = priv->ule_sndu_len;	// Including CRC32
+			if (priv->ule_sndu_type != ULE_BRIDGED) {
+				skblen += ETH_HLEN;
+#if 1
+				if (! priv->ule_dbit)
+					skblen -= ETH_ALEN;
+#endif
+			}
+			priv->ule_skb = dev_alloc_skb( skblen );
+			if (priv->ule_skb == NULL) {
+				printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+				((struct dvb_net_priv *)dev->priv)->stats.rx_dropped++;
+				return;
+			}
+
+#if 0
+			if (priv->ule_sndu_type != ULE_BRIDGED) {
+				// skb_reserve(priv->ule_skb, 2);    /* longword align L3 header */
+				// Create Ethernet header.
+				ethh = (struct ethhdr *)skb_put( priv->ule_skb, ETH_HLEN );
+				memset( ethh->h_source, 0x00, ETH_ALEN );
+				if (priv->ule_dbit) {
+					// Dest MAC address not present --> generate our own.
+					memcpy( ethh->h_dest, eth_dest_addr, ETH_ALEN );
+				} else {
+					// Dest MAC address could be split across two TS cells.
+					// FIXME: implement.
+
+					printk( KERN_WARNING "%s: got destination MAC address.\n", dev->name );
+					memcpy( ethh->h_dest, eth_dest_addr, ETH_ALEN );
+				}
+				ethh->h_proto = htons( priv->ule_sndu_type == ULE_LLC ? priv->ule_sndu_len : priv->ule_sndu_type );
+			}
+#endif
+			priv->ule_sndu_remain = priv->ule_sndu_len;	// this includes the CRC32 _and_ dest mac, if !dbit!
+			priv->ule_skb->dev = dev;
+		}
+
+		// Copy data into our current skb.
+		how_much = min( priv->ule_sndu_remain, (int)ts_remain );
+		if ((priv->ule_ethhdr_complete < ETH_ALEN) && (priv->ule_sndu_type != ULE_BRIDGED)) {
+			ethh = (struct ethhdr *)priv->ule_skb->data;
+			if (! priv->ule_dbit) {
+				if (how_much >= (ETH_ALEN - priv->ule_ethhdr_complete)) {
+					// copy dest mac address.
+					memcpy( skb_put( priv->ule_skb, (ETH_ALEN - priv->ule_ethhdr_complete) ), from_where, (ETH_ALEN - priv->ule_ethhdr_complete) );
+					memset( ethh->h_source, 0x00, ETH_ALEN );
+					ethh->h_proto = htons( priv->ule_sndu_type == ULE_LLC ? priv->ule_sndu_len : priv->ule_sndu_type );
+					(void)skb_put( priv->ule_skb, ETH_ALEN + 2 );
+
+					how_much -= (ETH_ALEN - priv->ule_ethhdr_complete);
+					priv->ule_sndu_remain -= (ETH_ALEN - priv->ule_ethhdr_complete);
+					ts_remain -= (ETH_ALEN - priv->ule_ethhdr_complete);
+					from_where += (ETH_ALEN - priv->ule_ethhdr_complete);
+					priv->ule_ethhdr_complete = ETH_ALEN;
+				}
+			} else {
+				// Generate whole Ethernet header.
+				memcpy( ethh->h_dest, eth_dest_addr, ETH_ALEN );
+				memset( ethh->h_source, 0x00, ETH_ALEN );
+				ethh->h_proto = htons( priv->ule_sndu_type == ULE_LLC ? priv->ule_sndu_len : priv->ule_sndu_type );
+				(void)skb_put( priv->ule_skb, ETH_HLEN );
+				priv->ule_ethhdr_complete = ETH_ALEN;
+			}
+		}
+		// printk( KERN_WARNING "Copying %u bytes, ule_sndu_remain = %u, ule_sndu_len = %u.\n", how_much, priv->ule_sndu_remain, priv->ule_sndu_len );
+		memcpy( skb_put( priv->ule_skb, how_much ), from_where, how_much );
+		priv->ule_sndu_remain -= how_much;
+		ts_remain -= how_much;
+		from_where += how_much;
+
+		// 
+		if ((priv->ule_ethhdr_complete < ETH_ALEN) && (priv->ule_sndu_type != ULE_BRIDGED)) {
+			priv->ule_ethhdr_complete += how_much;
+		}
+
+		// Check for complete payload.
+		if (priv->ule_sndu_remain <= 0) {
+			// Check CRC32, we've got it in our skb already.
+			unsigned short ulen = htons( priv->ule_sndu_len );
+			unsigned short utype = htons( priv->ule_sndu_type );
+			struct iovec iov[4] = { { &ulen, sizeof ulen },
+									{ &utype, sizeof utype },
+									{ NULL, 0 },
+									{ priv->ule_skb->data + ETH_HLEN, priv->ule_skb->len - ETH_HLEN - 4 } };
+			unsigned long ule_crc = ~0L, expected_crc;
+			if (priv->ule_dbit) {
+				ulen |= 0x0080;	// Set D-bit for CRC32 verification, if it was set originally.
+			} else {
+				iov[2].iov_base = priv->ule_skb->data;
+				iov[2].iov_len = ETH_ALEN;
+			}
+			ule_crc = iov_crc32( ule_crc, iov, 4 );
+			expected_crc = *((u8 *)priv->ule_skb->tail - 4) << 24 | *((u8 *)priv->ule_skb->tail - 3) << 16 |
+						   *((u8 *)priv->ule_skb->tail - 2) << 8 | *((u8 *)priv->ule_skb->tail - 1);
+			if (ule_crc != expected_crc) {
+				printk( KERN_WARNING "CRC32 check %s: %#lx / %#lx.\n",
+						ule_crc != expected_crc ? "FAILED" : "OK", ule_crc, expected_crc );
+				hexdump( priv->ule_skb->data + ETH_HLEN, priv->ule_skb->len - ETH_HLEN );
+
+				((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
+				((struct dvb_net_priv *) dev->priv)->stats.rx_crc_errors++;
+				dev_kfree_skb( priv->ule_skb );
+			} else {
+				// CRC32 was OK. Remove it from skb.
+				priv->ule_skb->tail -= 4;
+				priv->ule_skb->len -= 4;
+				// Stuff into kernel's protocol stack.
+				priv->ule_skb->protocol = dvb_net_eth_type_trans( priv->ule_skb, dev );
+				// If D-bit is set (i.e. destination MAC address not present), receive the packet anyhw.
+				// if (priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST)
+					priv->ule_skb->pkt_type = PACKET_HOST;
+				((struct dvb_net_priv *) dev->priv)->stats.rx_packets++;
+				((struct dvb_net_priv *) dev->priv)->stats.rx_bytes += priv->ule_skb->len;
+				netif_rx( priv->ule_skb );
+			}
+			// Prepare for next SNDU.
+			reset_ule( priv );
+		}
+
+		// More data in current TS (look at the bytes following the CRC32)?
+		if (ts_remain >= 2 && *((unsigned short *)from_where) != 0xFFFF) {
+			// Next ULE SNDU starts right there.
+			new_ts = 0;
+			priv->ule_skb = NULL;
+			priv->ule_sndu_type_1 = 0;
+			priv->ule_sndu_len = 0;
+			// printk( KERN_WARNING "More data in current TS: [%#x %#x %#x %#x]\n", 
+			// 	*(from_where + 0), *(from_where + 1),
+			// 	*(from_where + 2), *(from_where + 3) );
+			// printk( KERN_WARNING "ts @ %p, stopped @ %p:\n", ts, from_where + 0 );
+			// hexdump( ts, 188 );
+		} else {
+			new_ts = 1;
+			ts += TS_SZ;
+			if (priv->ule_skb == NULL) {
+				priv->need_pusi = 1;
+				priv->ule_sndu_type_1 = 0;
+				priv->ule_sndu_len = 0;
+			}
+		}
+	}	// for all available TS cells
+}
+
+static int dvb_net_ts_callback( const u8 *buffer1, size_t buffer1_len,
+								const u8 *buffer2, size_t buffer2_len,
+								struct dmx_ts_feed *feed, enum dmx_success success )
+{
+	struct net_device *dev = (struct net_device *)feed->priv;
+
+	if (buffer2 != 0)
+		printk( KERN_WARNING "buffer2 not 0: %p.\n", buffer2 );
+	if (buffer1_len > 32768)
+		printk( KERN_WARNING "length > 32k: %u.\n", buffer1_len );
+	// printk( "TS callback: %u bytes, %u TS cells @ %p.\n", buffer1_len, buffer1_len / TS_SZ, buffer1 );
+	dvb_net_ule( dev, buffer1, buffer1_len );
+	return 0;
+}
+
 
 static void dvb_net_sec(struct net_device *dev, u8 *pkt, int pkt_len)
 {
@@ -182,7 +600,7 @@
         netif_rx(skb);
 }
 
-static int dvb_net_callback(const u8 *buffer1, size_t buffer1_len,
+static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len,
 		 const u8 *buffer2, size_t buffer2_len,
 		 struct dmx_section_filter *filter,
 		 enum dmx_success success)
@@ -207,7 +625,7 @@
 static u8 mac_allmulti[6]={0x01, 0x00, 0x5e, 0x00, 0x00, 0x00};
 static u8 mask_promisc[6]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
 
-static int dvb_net_filter_set(struct net_device *dev, 
+static int dvb_net_filter_sec_set(struct net_device *dev, 
 		   struct dmx_section_filter **secfilter,
 		   u8 *mac, u8 *mac_mask)
 {
@@ -265,52 +683,88 @@
 
 	priv->secfeed=0;
 	priv->secfilter=0;
+	priv->tsfeed = 0;
 
-	dprintk("%s: alloc secfeed\n", __FUNCTION__);
-	ret=demux->allocate_section_feed(demux, &priv->secfeed, 
-					 dvb_net_callback);
-	if (ret<0) {
-		printk("%s: could not allocate section feed\n", dev->name);
-		return ret;
-	}
+	if (priv->feedtype == FEEDTYPE_SEC) {
+		dprintk("%s: alloc secfeed\n", __FUNCTION__);
+		ret=demux->allocate_section_feed(demux, &priv->secfeed, 
+					 dvb_net_sec_callback);
+		if (ret<0) {
+			printk("%s: could not allocate section feed\n", dev->name);
+			return ret;
+		}
 
-	ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 0, 1);
+		ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 0, 1);
 
-	if (ret<0) {
-		printk("%s: could not set section feed\n", dev->name);
-		priv->demux->release_section_feed(priv->demux, priv->secfeed);
-		priv->secfeed=0;
-		return ret;
-	}
+		if (ret<0) {
+			printk("%s: could not set section feed\n", dev->name);
+			priv->demux->release_section_feed(priv->demux, priv->secfeed);
+			priv->secfeed=0;
+			return ret;
+		}
 
-	if (priv->rx_mode != RX_MODE_PROMISC) {
-		dprintk("%s: set secfilter\n", __FUNCTION__);
-		dvb_net_filter_set(dev, &priv->secfilter, mac, mask_normal);
-	}
+		if (priv->rx_mode != RX_MODE_PROMISC) {
+			dprintk("%s: set secfilter\n", __FUNCTION__);
+			dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_normal);
+		}
 
-	switch (priv->rx_mode) {
-	case RX_MODE_MULTI:
-		for (i = 0; i < priv->multi_num; i++) {
-			dprintk("%s: set multi_secfilter[%d]\n", __FUNCTION__, i);
-			dvb_net_filter_set(dev, &priv->multi_secfilter[i],
-					   priv->multi_macs[i], mask_normal);
+		switch (priv->rx_mode) {
+		case RX_MODE_MULTI:
+			for (i = 0; i < priv->multi_num; i++) {
+				dprintk("%s: set multi_secfilter[%d]\n", __FUNCTION__, i);
+				dvb_net_filter_sec_set(dev, &priv->multi_secfilter[i],
+					   	priv->multi_macs[i], mask_normal);
+			}
+			break;
+		case RX_MODE_ALL_MULTI:
+			priv->multi_num=1;
+			dprintk("%s: set multi_secfilter[0]\n", __FUNCTION__);
+			dvb_net_filter_sec_set(dev, &priv->multi_secfilter[0],
+				   	mac_allmulti, mask_allmulti);
+			break;
+		case RX_MODE_PROMISC:
+			priv->multi_num=0;
+			dprintk("%s: set secfilter\n", __FUNCTION__);
+			dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_promisc);
+			break;
 		}
-		break;
-	case RX_MODE_ALL_MULTI:
-		priv->multi_num=1;
-		dprintk("%s: set multi_secfilter[0]\n", __FUNCTION__);
-		dvb_net_filter_set(dev, &priv->multi_secfilter[0],
-				   mac_allmulti, mask_allmulti);
-		break;
-	case RX_MODE_PROMISC:
-		priv->multi_num=0;
-		dprintk("%s: set secfilter\n", __FUNCTION__);
-		dvb_net_filter_set(dev, &priv->secfilter, mac, mask_promisc);
-		break;
+	
+		dprintk("%s: start filtering\n", __FUNCTION__);
+		priv->secfeed->start_filtering(priv->secfeed);
 	}
+	else {
+        struct timespec timeout = { 0, 30000000 }; // 30 msec
+                                                                                           
+        // we have payloads encapsulated in TS
+        dprintk("%s: alloc tsfeed\n", __FUNCTION__);
+        ret = demux->allocate_ts_feed( demux, &priv->tsfeed, dvb_net_ts_callback );
+        if (ret < 0) {
+            printk("%s: could not allocate ts feed\n", dev->name);
+            return ret;
+        }
+                                                                                           
+        // Set netdevice pointer for ts decaps callback.
+        priv->tsfeed->priv = (void *)dev;
+        ret = priv->tsfeed->set(priv->tsfeed,   // dmx_ts_feed_s
+                    priv->pid,          // PID
+                    TS_PACKET,          // packet type
+                    DMX_TS_PES_OTHER,   // PES type
+                    188 * 100,          // nr. of bytes delivered per callback
+                    32768,              // circular buffer size
+                    0,                  // descramble
+                    timeout);           // timeout
+                                                                                           
+        if (ret < 0) {
+            printk("%s: could not set ts feed\n", dev->name);
+            priv->demux->release_ts_feed(priv->demux, priv->tsfeed);
+            priv->tsfeed = 0;
+            return ret;
+        }
+                                                                                           
+        dprintk("%s: start filtering\n", __FUNCTION__);
+        priv->tsfeed->start_filtering(priv->tsfeed);
+    }
 	
-	dprintk("%s: start filtering\n", __FUNCTION__);
-	priv->secfeed->start_filtering(priv->secfeed);
 	return 0;
 }
 
@@ -320,32 +774,46 @@
 	int i;
 
 	dprintk("%s\n", __FUNCTION__);
+	if (priv->feedtype == FEEDTYPE_SEC) {
         if (priv->secfeed) {
-		if (priv->secfeed->is_filtering) {
-			dprintk("%s: stop secfeed\n", __FUNCTION__);
-		        priv->secfeed->stop_filtering(priv->secfeed);
-		}
+			if (priv->secfeed->is_filtering) {
+				dprintk("%s: stop secfeed\n", __FUNCTION__);
+		    	    priv->secfeed->stop_filtering(priv->secfeed);
+			}
 
-		if (priv->secfilter) {
-			dprintk("%s: release secfilter\n", __FUNCTION__);
-			priv->secfeed->release_filter(priv->secfeed,
-					       priv->secfilter);
-		priv->secfilter=0;
-		}
-
-		for (i=0; i<priv->multi_num; i++) {
-			if (priv->multi_secfilter[i]) {
-				dprintk("%s: release multi_filter[%d]\n", __FUNCTION__, i);
+			if (priv->secfilter) {
+				dprintk("%s: release secfilter\n", __FUNCTION__);
 				priv->secfeed->release_filter(priv->secfeed,
-						       priv->multi_secfilter[i]);
-			priv->multi_secfilter[i]=0;
-		}
-		}
-
-		priv->demux->release_section_feed(priv->demux, priv->secfeed);
-		priv->secfeed=0;
-	} else
-		printk("%s: no feed to stop\n", dev->name);
+						       priv->secfilter);
+				priv->secfilter=0;
+			}
+
+			for (i=0; i<priv->multi_num; i++) {
+				if (priv->multi_secfilter[i]) {
+					dprintk("%s: release multi_filter[%d]\n", __FUNCTION__, i);
+					priv->secfeed->release_filter(priv->secfeed,
+							       priv->multi_secfilter[i]);
+					priv->multi_secfilter[i]=0;
+				}
+			}
+
+			priv->demux->release_section_feed(priv->demux, priv->secfeed);
+			priv->secfeed=0;
+		} else
+			printk("%s: no feed to stop\n", dev->name);
+	}
+	else {
+        if (priv->tsfeed) {
+            if (priv->tsfeed->is_filtering) {
+                dprintk("%s: stop tsfeed\n", __FUNCTION__);
+                priv->tsfeed->stop_filtering(priv->tsfeed);
+            }
+            priv->demux->release_ts_feed(priv->demux, priv->tsfeed);
+            priv->tsfeed = 0;
+        }
+        else
+            printk("%s: no ts feed to stop\n", dev->name);
+    }
 }
 
 
@@ -504,7 +972,7 @@
 }
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid)
+static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype)
 {
         struct net_device *net;
 	struct dmx_demux *demux;
@@ -536,6 +1004,10 @@
 	priv->demux = demux;
         priv->pid = pid;
 	priv->rx_mode = RX_MODE_UNI;
+	priv->need_pusi = 1;
+	priv->tscc = 0;
+	priv->feedtype = feedtype;
+	reset_ule( priv );
 
 	INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list, net);
 	INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed, net);
@@ -549,7 +1021,7 @@
         return if_num;
 }
 #else
-static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid)
+static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype)
 {
         struct net_device *net;
 	struct dvb_net_priv *priv;
@@ -575,6 +1047,10 @@
         priv->demux = dvbnet->demux;
         priv->pid = pid;
 	priv->rx_mode = RX_MODE_UNI;
+	priv->need_pusi = 1;
+	priv->tscc = 0;
+	priv->feedtype = feedtype;
+	reset_ule( priv );
 
 	INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list, net);
 	INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed, net);
@@ -647,7 +1123,7 @@
 		
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		result=dvb_net_add_if(dvbnet, dvbnetif->pid);
+		result=dvb_net_add_if(dvbnet, dvbnetif->pid, dvbnetif->feedtype);
 		if (result<0)
 			return result;
 		dvbnetif->if_num=result;
diff -ru linuxtv-dvb-1.1.1/linux/include/linux/dvb/net.h linuxtv-dvb-1.1.1-ULE/linux/include/linux/dvb/net.h
--- linuxtv-dvb-1.1.1/linux/include/linux/dvb/net.h	2003-03-21 16:09:55.000000000 +0100
+++ linuxtv-dvb-1.1.1-ULE/linux/include/linux/dvb/net.h	2004-03-30 11:14:41.000000000 +0200
@@ -30,6 +30,9 @@
 struct dvb_net_if {
 	__u16 pid;
 	__u16 if_num;
+	__u8 feedtype;
+#define FEEDTYPE_SEC	0
+#define FEEDTYPE_TS		1
 };
 
 
diff -ru linuxtv-dvb-apps-1.1.0/include/linux/dvb/net.h linuxtv-dvb-apps-1.1.0-ULE/include/linux/dvb/net.h
--- linuxtv-dvb-apps-1.1.0/include/linux/dvb/net.h	2004-01-17 17:59:46.000000000 +0100
+++ linuxtv-dvb-apps-1.1.0-ULE/include/linux/dvb/net.h	2004-03-30 11:36:33.000000000 +0200
@@ -30,6 +30,9 @@
 struct dvb_net_if {
 	__u16 pid;
 	__u16 if_num;
+	__u8 feedtype;
+#define FEEDTYPE_SEC	0
+#define FEEDTYPE_TS		1
 };
 
 
diff -ru linuxtv-dvb-apps-1.1.0/util/dvbnet/dvbnet.c linuxtv-dvb-apps-1.1.0-ULE/util/dvbnet/dvbnet.c
--- linuxtv-dvb-apps-1.1.0/util/dvbnet/dvbnet.c	2004-01-17 17:59:46.000000000 +0100
+++ linuxtv-dvb-apps-1.1.0-ULE/util/dvbnet/dvbnet.c	2004-03-30 10:54:31.000000000 +0200
@@ -152,7 +152,8 @@
 {
 	char c, *s;
 	op_mode = UNKNOWN;
-	while ((c = getopt(argc, argv, "a:n:p:d:lvh")) != EOF) {
+	net_data.feedtype = FEEDTYPE_SEC;
+	while ((c = getopt(argc, argv, "a:n:p:d:lUvh")) != EOF) {
 		switch (c) {
 		case 'a':
 			adapter = strtol(optarg, NULL, 0);
@@ -171,6 +172,9 @@
 		case 'l':
 			op_mode = LST_INTERFACE;
 			break;
+		case 'U':
+			net_data.feedtype = FEEDTYPE_TS;
+			break;
 		case 'v':
 			exit(OK);
 		case 'h':
@@ -193,6 +197,7 @@
 	fprintf(stderr, "\t-d NUM : Remove interface dvbAD_NUM\n");
 	fprintf(stderr,
 		"\t-l     : List currently available interfaces\n");
+	fprintf(stderr, "\t-U     : use ULE framing (defualt: MPE)\n" );
 	fprintf(stderr, "\t-v     : Print current version\n\n");
 }
 

Home | Main Index | Thread Index