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 */
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); }