#include "ipv4.h" #include #include "net.h" #include "parse_buffer.h" #include "debug_log.h" namespace ipv4 { namespace { constexpr ip4_addr IP_BROADCAST_ALL = {255, 255, 255, 255}; std::array addr_filters; size_t addr_filter_count = 0; struct protocol_entry { uint8_t protocol; protocol_handler fn; }; std::array protocol_handlers; size_t protocol_handler_count = 0; bool default_addr_filter(const ip4_addr& dst) { const auto& ns = net::get_state(); return dst == ns.ip || dst == IP_BROADCAST_ALL || dst == SUBNET_BROADCAST; } } // namespace uint16_t checksum(const void* data, size_t len) { auto p = static_cast(data); uint32_t sum = 0; for (size_t i = 0; i < len - 1; i += 2) { sum += (p[i] << 8) | p[i + 1]; } if (len & 1) { sum += p[len - 1] << 8; } while (sum >> 16) { sum = (sum & 0xFFFF) + (sum >> 16); } return __builtin_bswap16(~sum); } void register_addr_filter(addr_filter fn) { if (addr_filter_count >= addr_filters.size()) { dlog("ipv4::register_addr_filter overflow: filter dropped"); return; } addr_filters[addr_filter_count++] = fn; } bool addressed_to_us(ip4_addr dst) { for (size_t i = 0; i < addr_filter_count; i++) { if (addr_filters[i](dst)) { return true; } } return false; } void register_protocol(uint8_t protocol, protocol_handler fn) { if (protocol_handler_count >= protocol_handlers.size()) { dlogf("ipv4::register_protocol overflow: protocol=%u dropped", protocol); return; } protocol_handlers[protocol_handler_count++] = {protocol, fn}; } void handle(std::span frame, span_writer& tx) { parse_buffer pb(frame); pb.consume(); auto* ip = pb.consume
(); if (!ip) { return; } if ((ip->ver_ihl >> 4) != 4) { return; } size_t options_len = ip->header_len() - sizeof(header); if (options_len > 0 && !pb.skip(options_len)) { return; } for (size_t i = 0; i < protocol_handler_count; i++) { if (protocol_handlers[i].protocol == ip->protocol) { protocol_handlers[i].fn(frame, tx); break; } } } __attribute__((constructor)) static void register_self() { net::register_ethertype(eth::ETH_IPV4, handle); register_addr_filter(default_addr_filter); } } // namespace ipv4