summaryrefslogtreecommitdiffstats
path: root/ring.c
diff options
context:
space:
mode:
Diffstat (limited to 'ring.c')
-rw-r--r--ring.c14
1 files changed, 13 insertions, 1 deletions
diff --git a/ring.c b/ring.c
index 5e99fd5..6929ab4 100644
--- a/ring.c
+++ b/ring.c
@@ -29,6 +29,8 @@
#include "translate.h"
#include "tun.h"
+#define TP_STATUS_CSUM_UNNECESSARY (1 << 7)
+
int ring_create(struct tun_data *tunnel) {
int packetsock = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6));
if (packetsock < 0) {
@@ -117,9 +119,19 @@ static struct tpacket2_hdr* ring_advance(struct packet_ring *ring) {
*/
void ring_read(struct packet_ring *ring, int write_fd, int to_ipv6) {
struct tpacket2_hdr *tp = ring->next;
+ uint16_t val = TP_CSUM_NONE;
if (tp->tp_status & TP_STATUS_USER) {
+ //We expect only GRO coalesced packets to have TP_STATUS_CSUMNOTREADY
+ //(ip_summed = CHECKSUM_PARTIAL) in this path. Note that these packets have already gone
+ //through checksum validation in GRO engine. CHECKSUM_PARTIAL is defined to be 3 while
+ //CHECKSUM_UNNECESSARY is defined to be 1.
+ //Kernel only checks for CHECKSUM_UNNECESSARY (TP_CSUM_UNNECESSARY) bit while processing a
+ //packet, so its ok to pass only this bit rather than the full ip_summed field.
+ if ((tp->tp_status & TP_STATUS_CSUMNOTREADY) || (tp->tp_status & TP_STATUS_CSUM_UNNECESSARY)) {
+ val = TP_CSUM_UNNECESSARY;
+ }
uint8_t *packet = ((uint8_t *) tp) + tp->tp_net;
- translate_packet(write_fd, to_ipv6, packet, tp->tp_len);
+ translate_packet(write_fd, to_ipv6, packet, tp->tp_len, val);
tp->tp_status = TP_STATUS_KERNEL;
tp = ring_advance(ring);
}