tools/testing/selftests/net/lib/csum.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/net/lib/csum.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/net/lib/csum.c
Extension
.c
Size
25434 bytes
Lines
1011
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

struct udp_encap_hdr {
	uint8_t nexthdr;
	uint8_t padding[3];
};

/* Ipaddrs, for pseudo csum. Global var is ugly, pass through funcs was worse */
static void *iph_addr_p;

static unsigned long gettimeofday_ms(void)
{
	struct timeval tv;

	gettimeofday(&tv, NULL);
	return (tv.tv_sec * 1000UL) + (tv.tv_usec / 1000UL);
}

static uint32_t checksum_nofold(char *data, size_t len, uint32_t sum)
{
	uint16_t *words = (uint16_t *)data;
	int i;

	for (i = 0; i < len / 2; i++)
		sum += words[i];

	if (len & 1)
		sum += ((unsigned char *)data)[len - 1];

	return sum;
}

static uint16_t checksum_fold(void *data, size_t len, uint32_t sum)
{
	sum = checksum_nofold(data, len, sum);

	while (sum > 0xFFFF)
		sum = (sum & 0xFFFF) + (sum >> 16);

	return ~sum;
}

static uint16_t checksum(void *th, uint16_t proto, size_t len)
{
	uint32_t sum;
	int alen;

	alen = cfg_family == PF_INET6 ? 32 : 8;

	sum = checksum_nofold(iph_addr_p, alen, 0);
	sum += htons(proto);
	sum += htons(len);

	/* With CHECKSUM_PARTIAL kernel expects non-inverted pseudo csum */
	if (cfg_do_tx && cfg_send_pfpacket)
		return ~checksum_fold(NULL, 0, sum);
	else
		return checksum_fold(th, len, sum);
}

static void *build_packet_ipv4(void *_iph, uint8_t proto, unsigned int len)
{
	struct iphdr *iph = _iph;

	memset(iph, 0, sizeof(*iph));

	iph->version = 4;
	iph->ihl = 5;
	iph->ttl = 8;
	iph->protocol = proto;
	iph->saddr = cfg_saddr4.sin_addr.s_addr;
	iph->daddr = cfg_daddr4.sin_addr.s_addr;
	iph->tot_len = htons(sizeof(*iph) + len);
	iph->check = checksum_fold(iph, sizeof(*iph), 0);

	iph_addr_p = &iph->saddr;

	return iph + 1;
}

static void *build_packet_ipv6(void *_ip6h, uint8_t proto, unsigned int len)
{
	struct ipv6hdr *ip6h = _ip6h;

	memset(ip6h, 0, sizeof(*ip6h));

	ip6h->version = 6;
	ip6h->payload_len = htons(len);
	ip6h->nexthdr = proto;
	ip6h->hop_limit = 64;
	ip6h->saddr = cfg_saddr6.sin6_addr;
	ip6h->daddr = cfg_daddr6.sin6_addr;

Annotation

Implementation Notes