#pragma once #include #include #include "eth.h" #include "ipv4.h" #include "span_writer.h" namespace igmp { static constexpr ipv4::ip4_addr ALL_HOSTS = {224, 0, 0, 1}; struct __attribute__((packed)) message { uint8_t type; uint8_t max_resp_time; uint16_t checksum; ipv4::ip4_addr group; }; static_assert(sizeof(message) == 8); eth::mac_addr mac_for_ip(const ipv4::ip4_addr& group); bool is_member(const ipv4::ip4_addr& ip); bool is_member_mac(const eth::mac_addr& mac); void join(const ipv4::ip4_addr& group); void send_all_reports(); void handle(std::span frame, span_writer& tx); template void prepend_report(Buf& buf, const eth::mac_addr& src_mac, ipv4::ip4_addr src_ip, const ipv4::ip4_addr& group) { auto* m = buf.template prepend(); m->type = 0x16; m->max_resp_time = 0; m->checksum = 0; m->group = group; m->checksum = ipv4::checksum(m, sizeof(message)); ipv4::prepend(buf, mac_for_ip(group), src_mac, src_ip, group, 2, sizeof(message), 1); } template void prepend_query(Buf& buf, const eth::mac_addr& src_mac, ipv4::ip4_addr src_ip, const ipv4::ip4_addr& group) { ipv4::ip4_addr dst_ip = (group == ipv4::ip4_addr{0, 0, 0, 0}) ? ALL_HOSTS : group; auto* m = buf.template prepend(); m->type = 0x11; m->max_resp_time = 100; m->checksum = 0; m->group = group; m->checksum = ipv4::checksum(m, sizeof(message)); ipv4::prepend(buf, mac_for_ip(dst_ip), src_mac, src_ip, dst_ip, 2, sizeof(message), 1); } bool parse_report(std::span frame, ipv4::ip4_addr& group); } // namespace igmp