#ifndef XDP_UTIL_H
#define XDP_UTIL_H
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/types.h>
#include <linux/udp.h>
int ethtool_channels_get(char const *ifname);
void set_caps(int unset_setid_caps);
static inline __sum16 csum16_add(__sum16 csum, __be16 addend) {
uint16_t res = (uint16_t)csum;
res += (__u16)addend;
return (__sum16)(res + (res < (__u16)addend));
}
static inline __sum16 csum16_sub(__sum16 csum, __be16 addend) {
return csum16_add(csum, ~addend);
}
static inline void csum16_replace(__sum16 *sum, __be16 old, __be16 new) {
*sum = ~csum16_add(csum16_sub(~(*sum), old), new);
}
static inline void csum_add_data(uint32_t *result,
const void *_data,
uint32_t len) {
const uint16_t *data = _data;
while (len > 1) {
*result += *data++;
len -= 2;
}
if (len)
*result += *data & 0xff;
}
static inline void csum_add_u16(uint32_t *result, uint16_t x) { *result += x; }
static inline void csum_reduce(uint32_t *result) {
while (*result >> 16)
*result = (*result & 0xffff) + (*result >> 16);
}
static inline uint16_t calc_csum_udp6(struct udphdr *udp, struct ipv6hdr *ipv6) {
uint32_t sum = 0;
sum += udp->len;
sum += htons(IPPROTO_UDP);
csum_add_data(&sum, &ipv6->saddr, sizeof(ipv6->saddr));
csum_add_data(&sum, &ipv6->daddr, sizeof(ipv6->daddr));
udp->check = 0;
csum_add_data(&sum, udp, ntohs(udp->len));
csum_reduce(&sum);
if (sum != 0xffff)
return (uint16_t) ~sum;
else
return (uint16_t) sum;
}
static inline uint16_t calc_csum_udp4(struct udphdr *udp, struct iphdr *ipv4) {
uint32_t sum = 0;
sum += udp->len;
sum += htons(IPPROTO_UDP);
csum_add_data(&sum, &ipv4->saddr, sizeof(ipv4->saddr));
csum_add_data(&sum, &ipv4->daddr, sizeof(ipv4->daddr));
udp->check = 0;
csum_add_data(&sum, udp, ntohs(udp->len));
csum_reduce(&sum);
if (sum != 0xffff)
return (uint16_t) ~sum;
else
return (uint16_t) sum;
}
#endif