mirror of
				https://github.com/xdp-project/bpf-examples.git
				synced 2024-05-06 15:54:53 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			182 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			182 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0
 | 
						|
// Code taken from kernel samples/bpf/xdpsock_user.c
 | 
						|
 | 
						|
#ifndef __LIB_CHECKSUM_H
 | 
						|
#define __LIB_CHECKSUM_H
 | 
						|
 | 
						|
static void *memset32_htonl(void *dest, __u32 val, __u32 size)
 | 
						|
{
 | 
						|
	__u32 *ptr = (__u32 *)dest;
 | 
						|
	int i;
 | 
						|
 | 
						|
	val = htonl(val);
 | 
						|
 | 
						|
	for (i = 0; i < (size & (~0x3)); i += 4)
 | 
						|
		ptr[i >> 2] = val;
 | 
						|
 | 
						|
	for (; i < size; i++)
 | 
						|
		((char *)dest)[i] = ((char *)&val)[i & 3];
 | 
						|
 | 
						|
	return dest;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * This function code has been taken from
 | 
						|
 * Linux kernel lib/checksum.c
 | 
						|
 */
 | 
						|
static inline unsigned short from32to16(unsigned int x)
 | 
						|
{
 | 
						|
	/* add up 16-bit and 16-bit for 16+c bit */
 | 
						|
	x = (x & 0xffff) + (x >> 16);
 | 
						|
	/* add up carry.. */
 | 
						|
	x = (x & 0xffff) + (x >> 16);
 | 
						|
	return x;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * This function code has been taken from
 | 
						|
 * Linux kernel lib/checksum.c
 | 
						|
 */
 | 
						|
static unsigned int do_csum(const unsigned char *buff, int len)
 | 
						|
{
 | 
						|
	unsigned int result = 0;
 | 
						|
	int odd;
 | 
						|
 | 
						|
	if (len <= 0)
 | 
						|
		goto out;
 | 
						|
	odd = 1 & (unsigned long)buff;
 | 
						|
	if (odd) {
 | 
						|
#ifdef __LITTLE_ENDIAN
 | 
						|
		result += (*buff << 8);
 | 
						|
#else
 | 
						|
		result = *buff;
 | 
						|
#endif
 | 
						|
		len--;
 | 
						|
		buff++;
 | 
						|
	}
 | 
						|
	if (len >= 2) {
 | 
						|
		if (2 & (unsigned long)buff) {
 | 
						|
			result += *(unsigned short *)buff;
 | 
						|
			len -= 2;
 | 
						|
			buff += 2;
 | 
						|
		}
 | 
						|
		if (len >= 4) {
 | 
						|
			const unsigned char *end = buff +
 | 
						|
						   ((unsigned int)len & ~3);
 | 
						|
			unsigned int carry = 0;
 | 
						|
 | 
						|
			do {
 | 
						|
				unsigned int w = *(unsigned int *)buff;
 | 
						|
 | 
						|
				buff += 4;
 | 
						|
				result += carry;
 | 
						|
				result += w;
 | 
						|
				carry = (w > result);
 | 
						|
			} while (buff < end);
 | 
						|
			result += carry;
 | 
						|
			result = (result & 0xffff) + (result >> 16);
 | 
						|
		}
 | 
						|
		if (len & 2) {
 | 
						|
			result += *(unsigned short *)buff;
 | 
						|
			buff += 2;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (len & 1)
 | 
						|
#ifdef __LITTLE_ENDIAN
 | 
						|
		result += *buff;
 | 
						|
#else
 | 
						|
		result += (*buff << 8);
 | 
						|
#endif
 | 
						|
	result = from32to16(result);
 | 
						|
	if (odd)
 | 
						|
		result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
 | 
						|
out:
 | 
						|
	return result;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 *	This is a version of ip_compute_csum() optimized for IP headers,
 | 
						|
 *	which always checksum on 4 octet boundaries.
 | 
						|
 *	This function code has been taken from
 | 
						|
 *	Linux kernel lib/checksum.c
 | 
						|
 */
 | 
						|
static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
 | 
						|
{
 | 
						|
	return (__sum16)~do_csum(iph, ihl * 4);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Fold a partial checksum
 | 
						|
 * This function code has been taken from
 | 
						|
 * Linux kernel include/asm-generic/checksum.h
 | 
						|
 */
 | 
						|
static inline __sum16 csum_fold(__wsum csum)
 | 
						|
{
 | 
						|
	__u32 sum = (__u32)csum;
 | 
						|
 | 
						|
	sum = (sum & 0xffff) + (sum >> 16);
 | 
						|
	sum = (sum & 0xffff) + (sum >> 16);
 | 
						|
	return (__sum16)~sum;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * This function code has been taken from
 | 
						|
 * Linux kernel lib/checksum.c
 | 
						|
 */
 | 
						|
static inline __u32 from64to32(__u64 x)
 | 
						|
{
 | 
						|
	/* add up 32-bit and 32-bit for 32+c bit */
 | 
						|
	x = (x & 0xffffffff) + (x >> 32);
 | 
						|
	/* add up carry.. */
 | 
						|
	x = (x & 0xffffffff) + (x >> 32);
 | 
						|
	return (__u32)x;
 | 
						|
}
 | 
						|
 | 
						|
__wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
 | 
						|
			  __u32 len, __u8 proto, __wsum sum);
 | 
						|
 | 
						|
/*
 | 
						|
 * This function code has been taken from
 | 
						|
 * Linux kernel lib/checksum.c
 | 
						|
 */
 | 
						|
__wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
 | 
						|
			  __u32 len, __u8 proto, __wsum sum)
 | 
						|
{
 | 
						|
	unsigned long long s = (__u32)sum;
 | 
						|
 | 
						|
	s += (__u32)saddr;
 | 
						|
	s += (__u32)daddr;
 | 
						|
#ifdef __BIG_ENDIAN__
 | 
						|
	s += proto + len;
 | 
						|
#else
 | 
						|
	s += (proto + len) << 8;
 | 
						|
#endif
 | 
						|
	return (__wsum)from64to32(s);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * This function has been taken from
 | 
						|
 * Linux kernel include/asm-generic/checksum.h
 | 
						|
 */
 | 
						|
static inline __sum16
 | 
						|
csum_tcpudp_magic(__be32 saddr, __be32 daddr, __u32 len,
 | 
						|
		  __u8 proto, __wsum sum)
 | 
						|
{
 | 
						|
	return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
 | 
						|
}
 | 
						|
 | 
						|
static inline __u16 udp_csum(__u32 saddr, __u32 daddr, __u32 len,
 | 
						|
			   __u8 proto, __u16 *udp_pkt)
 | 
						|
{
 | 
						|
	__u32 csum = 0;
 | 
						|
	__u32 cnt = 0;
 | 
						|
 | 
						|
	/* udp hdr and data */
 | 
						|
	for (; cnt < len; cnt += 2)
 | 
						|
		csum += udp_pkt[cnt >> 1];
 | 
						|
 | 
						|
	return csum_tcpudp_magic(saddr, daddr, len, proto, csum);
 | 
						|
}
 | 
						|
 | 
						|
#endif /* __LIB_CHECKSUM_H */
 |