#pragma once #include #include #include #include #include #include "eth.h" #include "span_writer.h" namespace ipv4 { using ip4_addr = std::array; inline std::string to_string(const ip4_addr& ip) { char buf[16]; snprintf(buf, sizeof(buf), "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); return buf; } struct __attribute__((packed)) header { uint8_t ver_ihl; uint8_t dscp_ecn; uint16_t total_len; uint16_t identification; uint16_t flags_frag; uint8_t ttl; uint8_t protocol; uint16_t checksum; ip4_addr src; ip4_addr dst; size_t header_len() const { return (ver_ihl & 0x0F) * 4; } size_t total() const { return __builtin_bswap16(total_len); } }; static_assert(sizeof(header) == 20); uint16_t checksum(const void* data, size_t len); template void prepend(Buf& buf, const eth::mac_addr& dst_mac, const eth::mac_addr& src_mac, ip4_addr src_ip, ip4_addr dst_ip, uint8_t protocol, size_t payload_len, uint8_t ttl = 64) { auto* h = buf.template prepend
(); h->ver_ihl = 0x45; h->dscp_ecn = 0; h->total_len = __builtin_bswap16(sizeof(header) + payload_len); h->identification = 0; h->flags_frag = 0; h->ttl = ttl; h->protocol = protocol; h->checksum = 0; h->src = src_ip; h->dst = dst_ip; h->checksum = checksum(h, sizeof(header)); eth::prepend(buf, dst_mac, src_mac, eth::ETH_IPV4); } void handle(std::span frame, span_writer& tx, eth::mac_addr our_mac, ip4_addr our_ip, ip4_addr subnet_broadcast); } // namespace ipv4