diff options
Diffstat (limited to 'linux')
-rw-r--r-- | linux/drivers/media/dvb/dvb-core/dvb_net.c | 610 | ||||
-rw-r--r-- | linux/include/linux/dvb/net.h | 3 |
2 files changed, 546 insertions, 67 deletions
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_net.c b/linux/drivers/media/dvb/dvb-core/dvb_net.c index 427c314e3..2cb4a4baa 100644 --- a/linux/drivers/media/dvb/dvb-core/dvb_net.c +++ b/linux/drivers/media/dvb/dvb-core/dvb_net.c @@ -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; @@ -50,6 +102,7 @@ struct dvb_net_priv { 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]; @@ -60,6 +113,16 @@ struct dvb_net_priv { #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; }; @@ -108,6 +171,361 @@ static unsigned short dvb_net_eth_type_trans(struct sk_buff *skb, 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) { @@ -183,7 +601,7 @@ static void dvb_net_sec(struct net_device *dev, u8 *pkt, int pkt_len) 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) @@ -208,7 +626,7 @@ static u8 mask_allmulti[6]={0xff, 0xff, 0xff, 0x00, 0x00, 0x00}; 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) { @@ -266,52 +684,88 @@ static int dvb_net_feed_start(struct net_device *dev) priv->secfeed=0; priv->secfilter=0; + priv->tsfeed = 0; + + 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; + } - 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; - } - - 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; } @@ -321,32 +775,46 @@ static void dvb_net_feed_stop(struct net_device *dev) 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->secfilter) { - dprintk("%s: release secfilter\n", __FUNCTION__); - priv->secfeed->release_filter(priv->secfeed, - priv->secfilter); - priv->secfilter=0; - } + if (priv->secfeed->is_filtering) { + dprintk("%s: stop secfeed\n", __FUNCTION__); + priv->secfeed->stop_filtering(priv->secfeed); + } - 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); + } } @@ -508,7 +976,7 @@ static int get_if(struct dvb_net *dvbnet) } #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; @@ -554,7 +1022,7 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid) 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; @@ -580,6 +1048,14 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid) 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 ); + 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); @@ -652,7 +1128,7 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file, 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 --git a/linux/include/linux/dvb/net.h b/linux/include/linux/dvb/net.h index 4b8fa5177..ba44c6188 100644 --- a/linux/include/linux/dvb/net.h +++ b/linux/include/linux/dvb/net.h @@ -30,6 +30,9 @@ struct dvb_net_if { __u16 pid; __u16 if_num; + __u8 feedtype; +#define FEEDTYPE_SEC 0 +#define FEEDTYPE_TS 1 }; |