Improved EoE state machine.

This commit is contained in:
Florian Pose 2006-08-01 18:37:55 +00:00
parent 973af4179d
commit e662e98464
1 changed files with 105 additions and 103 deletions

View File

@ -384,114 +384,116 @@ void ec_eoe_state_rx_fetch(ec_eoe_t *eoe /**< EoE handler */)
frame_type = EC_READ_U16(data) & 0x000F;
if (frame_type == 0x00) { // EoE Fragment Request
last_fragment = (EC_READ_U16(data) >> 8) & 0x0001;
time_appended = (EC_READ_U16(data) >> 9) & 0x0001;
fragment_number = EC_READ_U16(data + 2) & 0x003F;
fragment_offset = (EC_READ_U16(data + 2) >> 6) & 0x003F;
frame_number = (EC_READ_U16(data + 2) >> 12) & 0x000F;
#if EOE_DEBUG_LEVEL > 0
EC_DBG("EoE RX fragment %i, offset %i, frame %i%s%s,"
" %i octets\n", fragment_number, fragment_offset,
frame_number,
last_fragment ? ", last fragment" : "",
time_appended ? ", + timestamp" : "",
time_appended ? rec_size - 8 : rec_size - 4);
#endif
#if EOE_DEBUG_LEVEL > 1
EC_DBG("");
for (i = 0; i < rec_size - 4; i++) {
printk("%02X ", data[i + 4]);
if ((i + 1) % 16 == 0) {
printk("\n");
EC_DBG("");
}
}
printk("\n");
#endif
data_size = time_appended ? rec_size - 8 : rec_size - 4;
if (!fragment_number) {
if (eoe->rx_skb) {
EC_WARN("EoE RX freeing old socket buffer...\n");
dev_kfree_skb(eoe->rx_skb);
}
// new socket buffer
if (!(eoe->rx_skb = dev_alloc_skb(fragment_offset * 32))) {
if (printk_ratelimit())
EC_WARN("EoE RX low on mem. frame dropped.\n");
eoe->stats.rx_dropped++;
eoe->state = ec_eoe_state_tx_start;
return;
}
eoe->rx_skb_offset = 0;
eoe->rx_skb_size = fragment_offset * 32;
eoe->rx_expected_fragment = 0;
}
else {
if (!eoe->rx_skb) {
eoe->stats.rx_dropped++;
eoe->state = ec_eoe_state_tx_start;
return;
}
offset = fragment_offset * 32;
if (offset != eoe->rx_skb_offset ||
offset + data_size > eoe->rx_skb_size ||
fragment_number != eoe->rx_expected_fragment) {
eoe->stats.rx_errors++;
eoe->state = ec_eoe_state_tx_start;
dev_kfree_skb(eoe->rx_skb);
eoe->rx_skb = NULL;
return;
}
}
// copy fragment into socket buffer
memcpy(skb_put(eoe->rx_skb, data_size), data + 4, data_size);
eoe->rx_skb_offset += data_size;
if (last_fragment) {
// update statistics
eoe->stats.rx_packets++;
eoe->stats.rx_bytes += eoe->rx_skb->len;
#if EOE_DEBUG_LEVEL > 0
EC_DBG("EoE RX frame completed with %u octets.\n",
eoe->rx_skb->len);
#endif
// pass socket buffer to network stack
eoe->rx_skb->dev = eoe->dev;
eoe->rx_skb->protocol = eth_type_trans(eoe->rx_skb, eoe->dev);
eoe->rx_skb->ip_summed = CHECKSUM_UNNECESSARY;
if (netif_rx(eoe->rx_skb)) {
EC_WARN("EoE RX netif_rx failed.\n");
}
eoe->rx_skb = NULL;
eoe->state = ec_eoe_state_tx_start;
}
else {
eoe->rx_expected_fragment++;
#if EOE_DEBUG_LEVEL > 0
EC_DBG("EoE RX expecting fragment %i\n",
eoe->rx_expected_fragment);
#endif
eoe->state = ec_eoe_state_rx_start;
}
}
else {
if (frame_type != 0x00) {
#if EOE_DEBUG_LEVEL > 0
EC_DBG("other frame received.\n");
#endif
eoe->stats.rx_dropped++;
eoe->state = ec_eoe_state_tx_start;
return;
}
// EoE Fragment Request received
last_fragment = (EC_READ_U16(data) >> 8) & 0x0001;
time_appended = (EC_READ_U16(data) >> 9) & 0x0001;
fragment_number = EC_READ_U16(data + 2) & 0x003F;
fragment_offset = (EC_READ_U16(data + 2) >> 6) & 0x003F;
frame_number = (EC_READ_U16(data + 2) >> 12) & 0x000F;
#if EOE_DEBUG_LEVEL > 0
EC_DBG("EoE RX fragment %i, offset %i, frame %i%s%s,"
" %i octets\n", fragment_number, fragment_offset,
frame_number,
last_fragment ? ", last fragment" : "",
time_appended ? ", + timestamp" : "",
time_appended ? rec_size - 8 : rec_size - 4);
#endif
#if EOE_DEBUG_LEVEL > 1
EC_DBG("");
for (i = 0; i < rec_size - 4; i++) {
printk("%02X ", data[i + 4]);
if ((i + 1) % 16 == 0) {
printk("\n");
EC_DBG("");
}
}
printk("\n");
#endif
data_size = time_appended ? rec_size - 8 : rec_size - 4;
if (!fragment_number) {
if (eoe->rx_skb) {
EC_WARN("EoE RX freeing old socket buffer...\n");
dev_kfree_skb(eoe->rx_skb);
}
// new socket buffer
if (!(eoe->rx_skb = dev_alloc_skb(fragment_offset * 32))) {
if (printk_ratelimit())
EC_WARN("EoE RX low on mem. frame dropped.\n");
eoe->stats.rx_dropped++;
eoe->state = ec_eoe_state_tx_start;
return;
}
eoe->rx_skb_offset = 0;
eoe->rx_skb_size = fragment_offset * 32;
eoe->rx_expected_fragment = 0;
}
else {
if (!eoe->rx_skb) {
eoe->stats.rx_dropped++;
eoe->state = ec_eoe_state_tx_start;
return;
}
offset = fragment_offset * 32;
if (offset != eoe->rx_skb_offset ||
offset + data_size > eoe->rx_skb_size ||
fragment_number != eoe->rx_expected_fragment) {
dev_kfree_skb(eoe->rx_skb);
eoe->rx_skb = NULL;
eoe->stats.rx_errors++;
eoe->state = ec_eoe_state_tx_start;
return;
}
}
// copy fragment into socket buffer
memcpy(skb_put(eoe->rx_skb, data_size), data + 4, data_size);
eoe->rx_skb_offset += data_size;
if (last_fragment) {
// update statistics
eoe->stats.rx_packets++;
eoe->stats.rx_bytes += eoe->rx_skb->len;
#if EOE_DEBUG_LEVEL > 0
EC_DBG("EoE RX frame completed with %u octets.\n",
eoe->rx_skb->len);
#endif
// pass socket buffer to network stack
eoe->rx_skb->dev = eoe->dev;
eoe->rx_skb->protocol = eth_type_trans(eoe->rx_skb, eoe->dev);
eoe->rx_skb->ip_summed = CHECKSUM_UNNECESSARY;
if (netif_rx(eoe->rx_skb)) {
EC_WARN("EoE RX netif_rx failed.\n");
}
eoe->rx_skb = NULL;
eoe->state = ec_eoe_state_tx_start;
}
else {
eoe->rx_expected_fragment++;
#if EOE_DEBUG_LEVEL > 0
EC_DBG("EoE RX expecting fragment %i\n",
eoe->rx_expected_fragment);
#endif
eoe->state = ec_eoe_state_rx_start;
}
}