⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dvb_net.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * dvb_net.c * * 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, 2004 gcs - Global Communication & Services GmbH. *                      and Department of Scientific Computing *                          Paris Lodron University of Salzburg. *                          Hilmar Linder <hlinder@cosy.sbg.ac.at> *                      and Wolfram Stering <wstering@cosy.sbg.ac.at> * * ULE Decaps according to draft-ietf-ipdvb-ule-03.txt. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html *//* * ULE ChangeLog: * Feb 2004: hl/ws v1: Implementing draft-fair-ipdvb-ule-01.txt * * Dec 2004: hl/ws v2: Implementing draft-ietf-ipdvb-ule-03.txt: *                       ULE Extension header handling. *                     Bugreports by Moritz Vieth and Hanno Tersteegen, *                       Fraunhofer Institute for Open Communication Systems *                       Competence Center for Advanced Satellite Communications. *                     Bugfixes and robustness improvements. *                     Filtering on dest MAC addresses, if present (D-Bit = 0) *                     ULE_DEBUG compile-time option. *//* * FIXME / TODO (dvb_net.c): * * Unloading does not work for 2.6.9 kernels: a refcount doesn't go to zero. * * TS_FEED callback is called once for every single TS cell although it is * registered (in dvb_net_feed_start()) for 100 TS cells (used for dvb_net_ule()). * */#include <linux/module.h>#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 <linux/crc32.h>#include "dvb_demux.h"#include "dvb_net.h"static int dvb_net_debug;module_param(dvb_net_debug, int, 0444);MODULE_PARM_DESC(dvb_net_debug, "enable debug messages");#define dprintk(x...) do { if (dvb_net_debug) printk(x); } while (0)static inline __u32 iov_crc32( __u32 c, struct kvec *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;}#define DVB_NET_MULTICAST_MAX 10#undef ULE_DEBUG#ifdef ULE_DEBUG#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 );	}}#endifstruct dvb_net_priv {	int in_use;	struct net_device_stats stats;	u16 pid;	struct dvb_net *host;	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];	int rx_mode;#define RX_MODE_UNI 0#define RX_MODE_MULTI 1#define RX_MODE_ALL_MULTI 2#define RX_MODE_PROMISC 3	struct work_struct set_multicast_list_wq;	struct work_struct restart_net_feed_wq;	unsigned char feedtype;			/* Either FEED_TYPE_ or FEED_TYPE_ULE */	int need_pusi;				/* Set to 1, if synchronization on PUSI required. */	unsigned char tscc;			/* TS continuity counter after sync on PUSI. */	struct sk_buff *ule_skb;		/* ULE SNDU decodes into this buffer. */	unsigned char *ule_next_hdr;		/* Pointer into skb to next ULE extension header. */	unsigned short ule_sndu_len;		/* ULE SNDU length in bytes, w/o D-Bit. */	unsigned short ule_sndu_type;		/* ULE SNDU type field, complete. */	unsigned char ule_sndu_type_1;		/* ULE SNDU type field, if split across 2 TS cells. */	unsigned char ule_dbit;			/* Whether the DestMAC address present						 * or not (bit is set). */	unsigned char ule_bridged;		/* Whether the ULE_BRIDGED extension header was found. */	int ule_sndu_remain;			/* Nr. of bytes still required for current ULE SNDU. */	unsigned long ts_count;			/* Current ts cell counter. */	struct semaphore mutex;};/** *	Determine the packet's protocol ID. The rule here is that we *	assume 802.3 if the type field is short enough to be a length. *	This is normal practice and works for any 'now in use' protocol. * *  stolen from eth.c out of the linux kernel, hacked for dvb-device *  by Michael Holzt <kju@debian.org> */static unsigned short dvb_net_eth_type_trans(struct sk_buff *skb,				      struct net_device *dev){	struct ethhdr *eth;	unsigned char *rawp;	skb->mac.raw=skb->data;	skb_pull(skb,dev->hard_header_len);	eth = eth_hdr(skb);	if (*eth->h_dest & 1) {		if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)			skb->pkt_type=PACKET_BROADCAST;		else			skb->pkt_type=PACKET_MULTICAST;	}	if (ntohs(eth->h_proto) >= 1536)		return eth->h_proto;	rawp = skb->data;	/**	 *	This is a magic hack to spot IPX packets. Older Novell breaks	 *	the protocol design and runs IPX over 802.3 without an 802.2 LLC	 *	layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This	 *	won't work for fault tolerant netware but does for the rest.	 */	if (*(unsigned short *)rawp == 0xFFFF)		return htons(ETH_P_802_3);	/**	 *	Real 802.2 LLC	 */	return htons(ETH_P_802_2);}#define TS_SZ	188#define TS_SYNC	0x47#define TS_TEI	0x80#define TS_SC	0xC0#define TS_PUSI	0x40#define TS_AF_A	0x20#define TS_AF_D	0x10/* ULE Extension Header handlers. */#define ULE_TEST	0#define ULE_BRIDGED	1static int ule_test_sndu( struct dvb_net_priv *p ){	return -1;}static int ule_bridged_sndu( struct dvb_net_priv *p ){	/* BRIDGE SNDU handling sucks in draft-ietf-ipdvb-ule-03.txt.	 * This has to be the last extension header, otherwise it won't work.	 * Blame the authors!	 */	p->ule_bridged = 1;	return 0;}/** Handle ULE extension headers. *  Function is called after a successful CRC32 verification of an ULE SNDU to complete its decoding. *  Returns: >= 0: nr. of bytes consumed by next extension header *	     -1:   Mandatory extension header that is not recognized or TEST SNDU; discard. */static int handle_one_ule_extension( struct dvb_net_priv *p ){	/* Table of mandatory extension header handlers.  The header type is the index. */	static int (*ule_mandatory_ext_handlers[255])( struct dvb_net_priv *p ) =		{ [0] = ule_test_sndu, [1] = ule_bridged_sndu, [2] = NULL,  };	/* Table of optional extension header handlers.  The header type is the index. */	static int (*ule_optional_ext_handlers[255])( struct dvb_net_priv *p ) = { NULL, };	int ext_len = 0;	unsigned char hlen = (p->ule_sndu_type & 0x0700) >> 8;	unsigned char htype = p->ule_sndu_type & 0x00FF;	/* Discriminate mandatory and optional extension headers. */	if (hlen == 0) {		/* Mandatory extension header */		if (ule_mandatory_ext_handlers[htype]) {			ext_len = ule_mandatory_ext_handlers[htype]( p );			p->ule_next_hdr += ext_len;			if (! p->ule_bridged) {				p->ule_sndu_type = ntohs( *(unsigned short *)p->ule_next_hdr );				p->ule_next_hdr += 2;			} else {				p->ule_sndu_type = ntohs( *(unsigned short *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN)) );				/* This assures the extension handling loop will terminate. */			}		} else			ext_len = -1;	/* SNDU has to be discarded. */	} else {		/* Optional extension header.  Calculate the length. */		ext_len = hlen << 2;		/* Process the optional extension header according to its type. */		if (ule_optional_ext_handlers[htype])			(void)ule_optional_ext_handlers[htype]( p );		p->ule_next_hdr += ext_len;		p->ule_sndu_type = ntohs( *(unsigned short *)p->ule_next_hdr );		p->ule_next_hdr += 2;	}	return ext_len;}static int handle_ule_extensions( struct dvb_net_priv *p ){	int total_ext_len = 0, l;	p->ule_next_hdr = p->ule_skb->data;	do {		l = handle_one_ule_extension( p );		if (l == -1) return -1;	/* Stop extension header processing and discard SNDU. */		total_ext_len += l;	} while (p->ule_sndu_type < 1536);	return total_ext_len;}/** Prepare for a new ULE SNDU: reset the decoder state. */static inline void reset_ule( struct dvb_net_priv *p ){	p->ule_skb = NULL;	p->ule_next_hdr = 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_bridged = 0;}/** * Decode ULE SNDUs according to draft-ietf-ipdvb-ule-03.txt from a sequence of * TS cells of a single PID. */static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ){	struct dvb_net_priv *priv = dev->priv;	unsigned long skipped = 0L;	u8 *ts, *ts_end, *from_where = NULL, ts_remain = 0, how_much = 0, new_ts = 1;	struct ethhdr *ethh = NULL;#ifdef ULE_DEBUG	/* The code inside ULE_DEBUG keeps a history of the last 100 TS cells processed. */	static unsigned char ule_hist[100*TS_SZ];	static unsigned char *ule_where = ule_hist, ule_dump = 0;#endif	if (dev == NULL) {		printk( KERN_ERR "NO netdev struct!\n" );		return;	}	/* For all TS cells in current buffer.	 * Appearently, we are called for every single TS cell.	 */	for (ts = (char *)buf, ts_end = (char *)buf + buf_len; ts < ts_end; /* no default incr. */ ) {		if (new_ts) {			/* We are about to process a new TS cell. */#ifdef ULE_DEBUG			if (ule_where >= &ule_hist[100*TS_SZ]) ule_where = ule_hist;			memcpy( ule_where, ts, TS_SZ );			if (ule_dump) {				hexdump( ule_where, TS_SZ );				ule_dump = 0;			}			ule_where += TS_SZ;#endif			/* Check TS error conditions: sync_byte, transport_error_indicator, scrambling_control . */			if ((ts[0] != TS_SYNC) || (ts[1] & TS_TEI) || ((ts[3] & TS_SC) != 0)) {				printk(KERN_WARNING "%lu: Invalid TS cell: SYNC %#x, TEI %u, SC %#x.\n",				       priv->ts_count, ts[0], ts[1] & TS_TEI >> 7, ts[3] & 0xC0 >> 6);				/* Drop partly decoded SNDU, reset state, resync on PUSI. */				if (priv->ule_skb) {					dev_kfree_skb( priv->ule_skb );					/* Prepare for next SNDU. */					((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;					((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++;				}				reset_ule(priv);				priv->need_pusi = 1;				/* Continue with next TS cell. */				ts += TS_SZ;				priv->ts_count++;				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. */				/* Synchronize continuity counter. */				priv->tscc = ts[3] & 0x0F;				/* There is a pointer field here. */				if (ts[4] > ts_remain) {					printk(KERN_ERR "%lu: Invalid ULE packet "					       "(pointer field %d)\n", priv->ts_count, ts[4]);					ts += TS_SZ;					priv->ts_count++;					continue;				}				/* Skip to destination of pointer field. */				from_where = &ts[5] + ts[4];				ts_remain -= 1 + ts[4];				skipped = 0;			} else {				skipped++;				ts += TS_SZ;				priv->ts_count++;				continue;			}		}		/* Check continuity counter. */		if (new_ts) {			if ((ts[3] & 0x0F) == priv->tscc)				priv->tscc = (priv->tscc + 1) & 0x0F;			else {				/* TS discontinuity handling: */				printk(KERN_WARNING "%lu: TS discontinuity: got %#x, "				       "exptected %#x.\n", priv->ts_count, ts[3] & 0x0F, priv->tscc);				/* Drop partly decoded SNDU, reset state, resync on PUSI. */				if (priv->ule_skb) {					dev_kfree_skb( priv->ule_skb );					/* Prepare for next SNDU. */					// reset_ule(priv);  moved to below.					((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;					((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++;				}				reset_ule(priv);				/* skip to next PUSI. */				priv->need_pusi = 1;				ts += TS_SZ;				priv->ts_count++;				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 wrap). */			if (ts[1] & TS_PUSI) {				if (! priv->need_pusi) {					if (*from_where > 181) {						/* Pointer field is invalid.  Drop this TS cell and any started ULE SNDU. */						printk(KERN_WARNING "%lu: Invalid pointer "						       "field: %u.\n", priv->ts_count, *from_where);						/* Drop partly decoded SNDU, reset state, resync on PUSI. */						if (priv->ule_skb) {							dev_kfree_skb( priv->ule_skb );							((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;							((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++;						}						reset_ule(priv);						priv->need_pusi = 1;						ts += TS_SZ;						priv->ts_count++;						continue;					}					/* 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) {					/* Current SNDU lacks more data than there could be available in the					 * current TS cell. */					((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;					((struct dvb_net_priv *) dev->priv)->stats.rx_length_errors++;					printk(KERN_WARNING "%lu: Expected %d more SNDU bytes, but "					       "got PUSI (pf %d, ts_remain %d).  Flushing incomplete payload.\n",					       priv->ts_count, priv->ule_sndu_remain, ts[4], ts_remain);					dev_kfree_skb(priv->ule_skb);					/* Prepare for next SNDU. */					reset_ule(priv);					/* Resync: go to where pointer field points to: start of next ULE SNDU. */					from_where += ts[4];					ts_remain -= ts[4];				}			}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -