/* XXX De-pend the interfaces */
/* Disable all offloads */
- nc->net_device->features &= ~NETIF_F_IP_CSUM;
+ nc->net_device->features &= ~NETIF_F_HW_CSUM;
nc->allow_tx_csum_offload = 0;
}
nc2_copy_from_ring(&nc->rings.cons_ring, &msg, hdr->size);
if (msg.csum != nc->allow_tx_csum_offload) {
nc->allow_tx_csum_offload = msg.csum;
+ if (msg.csum)
+ nc->net_device->features |= NETIF_F_HW_CSUM;
+ else
+ nc->net_device->features &= ~NETIF_F_HW_CSUM;
nc2_set_tx_csum(nc->net_device, msg.csum);
/* Linux doesn't support scatter-gather mode without
TX csum offload. We therefore need to disable SG
is_bad = 0;
if (msg->prefix_size < SKB_MIN_PAYLOAD_SIZE)
prefix_len = SKB_MIN_PAYLOAD_SIZE;
+ else if (msg->prefix_size < msg->csum_offset + 2)
+ prefix_len = msg->csum_offset + 2;
else
prefix_len = msg->prefix_size;
/* We don't enforce the MAX_PACKET_BYTES limit here. That's
head_skb->len = cur_skb->len + acc_len;
head_skb->data_len = cur_skb->data_len + acc_len;
head_skb->truesize = cur_skb->truesize + acc_len;
- if (skb_headlen(head_skb) < SKB_MIN_PAYLOAD_SIZE)
+ if (skb_headlen(head_skb) < prefix_len)
pull_through(head_skb,
- SKB_MIN_PAYLOAD_SIZE - skb_headlen(head_skb));
+ prefix_len - skb_headlen(head_skb));
}
return head_skb;
if (msg->prefix_size < SKB_MIN_PAYLOAD_SIZE)
prefix_size = SKB_MIN_PAYLOAD_SIZE;
+ else if (msg->prefix_size < msg->csum_offset + 2)
+ prefix_size = msg->csum_offset + 2;
else
prefix_size = msg->prefix_size;
/* As in posted_buffers.c, we don't limit the total size of
}
spin_unlock(&receive_mapper->rm_lock);
- if (skb_headlen(head_skb) < SKB_MIN_PAYLOAD_SIZE)
- pull_through(head_skb,
- SKB_MIN_PAYLOAD_SIZE - skb_headlen(head_skb));
+ if (skb_headlen(head_skb) < prefix_size)
+ pull_through(head_skb, prefix_size - skb_headlen(head_skb));
return head_skb;
break;
default:
skb->ip_summed = CHECKSUM_PARTIAL;
+ if (msg.csum_offset + 2 > skb_headlen(skb)) {
+ /* Whoops. Assuming no bugs in our
+ receive methods, the other end just
+ requested checksum calculation
+ beyond the end of the packet. */
+ if (net_ratelimit())
+ dev_warn(&nc->net_device->dev,
+ "csum field too far through packet (%d, skb len %d, headlen %d)\n",
+ msg.csum_offset, skb->len,
+ skb_headlen(skb));
+ goto err;
+ }
+ skb->csum_start = msg.csum_start + skb_headroom(skb);
+ skb->csum_offset = msg.csum_offset - msg.csum_start;
break;
}
#endif
skb_headsize = nr_bytes + NET_IP_ALIGN;
if (skb_headsize >
((PAGE_SIZE - sizeof(struct skb_shared_info) - NET_SKB_PAD) & ~(SMP_CACHE_BYTES))) {
- skb_headsize = msg->prefix_size + NET_IP_ALIGN;
+ if (msg->prefix_size < msg->csum_offset + 2)
+ skb_headsize = msg->csum_offset + 2;
+ else
+ skb_headsize = msg->prefix_size + NET_IP_ALIGN;
}
skb = dev_alloc_skb(skb_headsize);
volatile struct netchannel2_msg_packet *msg)
{
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20)
- if (skb->ip_summed == CHECKSUM_PARTIAL)
- msg->flags |=
- NC2_PACKET_FLAG_csum_blank |
- NC2_PACKET_FLAG_data_validated;
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ msg->flags |= NC2_PACKET_FLAG_data_validated |
+ NC2_PACKET_FLAG_csum_blank;
+ msg->csum_start = skb->csum_start - skb_headroom(skb);
+ msg->csum_offset = skb->csum_offset + msg->csum_start;
+ }
+ if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+ msg->flags |= NC2_PACKET_FLAG_data_validated;
#else
if (skb->ip_summed == CHECKSUM_HW)
msg->flags |=
uint8_t pad;
uint16_t prefix_size;
uint16_t mss;
+ uint16_t csum_start;
+ uint16_t csum_offset;
/* Variable-size array. The number of elements is determined
by the size of the message. */
struct netchannel2_fragment frags[0];
};
+
+/* TX csum offload. The transmitting domain has skipped a checksum
+ * calculation. Before forwarding the packet on, the receiving domain
+ * must first perform a 16 bit IP checksum on everything from
+ * csum_start to the end of the packet, and then write the result to
+ * an offset csum_offset in the packet.
+ */
#define NC2_PACKET_FLAG_csum_blank 1
+/* RX csum offload. The transmitting domain has already validated the
+ * protocol-level checksum on this packet (i.e. TCP or UDP), so the
+ * receiving domain shouldn't bother. This does not tell you anything
+ * about the IP-level checksum. */
#define NC2_PACKET_FLAG_data_validated 2
+/* If set, this flag indicates that this packet could have used a
+ * bypass if one had been available, and so it should be sent to the
+ * autobypass state machine.
+ */
#define NC2_PACKET_FLAG_bypass_candidate 4
+/* If set, the transmitting domain requires an event urgently when
+ * this packet's finish message is sent. Otherwise, the event can be
+ * delayed. */
#define NC2_PACKET_FLAG_need_event 8
/* The mechanism which should be used to receive the data part of