tools/testing/selftests/net/ip_defrag.c

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

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/net/ip_defrag.c
Extension
.c
Size
12900 bytes
Lines
473
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

if (!cfg_permissive) {
			if (ret != -1)
				error(1, 0, "recv: expected timeout; got %d",
					(int)ret);
			error(1, errno, "recv: expected timeout: %d", errno);
		}
	}

	if (ret == -1)
		error(1, errno, "recv: payload_len = %d max_frag_len = %d",
			payload_len, max_frag_len);
	if (ret != payload_len)
		error(1, 0, "recv: wrong size: %d vs %d", (int)ret, payload_len);
	if (memcmp(udp_payload, recv_buff, payload_len))
		error(1, 0, "recv: wrong data");
}

static uint32_t raw_checksum(uint8_t *buf, int len, uint32_t sum)
{
	int i;

	for (i = 0; i < (len & ~1U); i += 2) {
		sum += (u_int16_t)ntohs(*((u_int16_t *)(buf + i)));
		if (sum > 0xffff)
			sum -= 0xffff;
	}

	if (i < len) {
		sum += buf[i] << 8;
		if (sum > 0xffff)
			sum -= 0xffff;
	}

	return sum;
}

static uint16_t udp_checksum(struct ip *iphdr, struct udphdr *udphdr)
{
	uint32_t sum = 0;
	uint16_t res;

	sum = raw_checksum((uint8_t *)&iphdr->ip_src, 2 * sizeof(iphdr->ip_src),
				IPPROTO_UDP + (uint32_t)(UDP_HLEN + payload_len));
	sum = raw_checksum((uint8_t *)udphdr, UDP_HLEN, sum);
	sum = raw_checksum((uint8_t *)udp_payload, payload_len, sum);
	res = 0xffff & ~sum;
	if (res)
		return htons(res);
	else
		return CSUM_MANGLED_0;
}

static uint16_t udp6_checksum(struct ip6_hdr *iphdr, struct udphdr *udphdr)
{
	uint32_t sum = 0;
	uint16_t res;

	sum = raw_checksum((uint8_t *)&iphdr->ip6_src, 2 * sizeof(iphdr->ip6_src),
				IPPROTO_UDP);
	sum = raw_checksum((uint8_t *)&udphdr->len, sizeof(udphdr->len), sum);
	sum = raw_checksum((uint8_t *)udphdr, UDP_HLEN, sum);
	sum = raw_checksum((uint8_t *)udp_payload, payload_len, sum);
	res = 0xffff & ~sum;
	if (res)
		return htons(res);
	else
		return CSUM_MANGLED_0;
}

static void send_fragment(int fd_raw, struct sockaddr *addr, socklen_t alen,
				int offset, bool ipv6)
{
	int frag_len;
	int res;
	int payload_offset = offset > 0 ? offset - UDP_HLEN : 0;
	uint8_t *frag_start = ipv6 ? ip_frame + IP6_HLEN + FRAG_HLEN :
					ip_frame + IP4_HLEN;

	if (offset == 0) {
		struct udphdr udphdr;
		udphdr.source = htons(cfg_port + 1);
		udphdr.dest = htons(cfg_port);
		udphdr.len = htons(UDP_HLEN + payload_len);
		udphdr.check = 0;
		if (ipv6)
			udphdr.check = udp6_checksum((struct ip6_hdr *)ip_frame, &udphdr);
		else
			udphdr.check = udp_checksum((struct ip *)ip_frame, &udphdr);
		memcpy(frag_start, &udphdr, UDP_HLEN);
	}

Annotation

Implementation Notes