Ejemplo n.º 1
0
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
			/* this includes the CRC32 _and_ dest mac, if !dbit! */
			priv->ule_sndu_remain = priv->ule_sndu_len;
			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);
					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);
				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 kvec 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) {
				/* Set D-bit for CRC32 verification,
				 * if it was set originally. */
				ulen |= 0x0080;
			} 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 */
Ejemplo n.º 2
0
static void dvb_net_sec(struct net_device *dev, u8 *pkt, int pkt_len)
{
        u8 *eth;
        struct sk_buff *skb;

	/* note: pkt_len includes a 32bit checksum */
	if (pkt_len < 16) {
		printk("%s: IP/MPE packet length = %d too small.\n",
			dev->name, pkt_len);
		((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
		((struct dvb_net_priv *) dev->priv)->stats.rx_length_errors++;
		return;
	}
	if ((pkt[5] & 0xfd) != 0xc1) {
		/* drop scrambled or broken packets */
		((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
		((struct dvb_net_priv *) dev->priv)->stats.rx_crc_errors++;
		return;
	}
	if (pkt[5] & 0x02) {
		//FIXME: handle LLC/SNAP
                ((struct dvb_net_priv *)dev->priv)->stats.rx_dropped++;
                return;
        }
	if (pkt[7]) {
		/* FIXME: assemble datagram from multiple sections */
		((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
		((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++;
		return;
	}

	/* we have 14 byte ethernet header (ip header follows);
	 * 12 byte MPE header; 4 byte checksum; + 2 byte alignment
	 */
	if (!(skb = dev_alloc_skb(pkt_len - 4 - 12 + 14 + 2))) {
		//printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
		((struct dvb_net_priv *) dev->priv)->stats.rx_dropped++;
		return;
	}
	skb_reserve(skb, 2);    /* longword align L3 header */
	skb->dev = dev;

	/* copy L3 payload */
	eth = (u8 *) skb_put(skb, pkt_len - 12 - 4 + 14);
	memcpy(eth + 14, pkt + 12, pkt_len - 12 - 4);

	/* create ethernet header: */
        eth[0]=pkt[0x0b];
        eth[1]=pkt[0x0a];
        eth[2]=pkt[0x09];
        eth[3]=pkt[0x08];
        eth[4]=pkt[0x04];
        eth[5]=pkt[0x03];

        eth[6]=eth[7]=eth[8]=eth[9]=eth[10]=eth[11]=0;

	eth[12] = 0x08;	/* ETH_P_IP */
	eth[13] = 0x00;

	skb->protocol = dvb_net_eth_type_trans(skb, dev);
        
        ((struct dvb_net_priv *)dev->priv)->stats.rx_packets++;
        ((struct dvb_net_priv *)dev->priv)->stats.rx_bytes+=skb->len;
        netif_rx(skb);
}