65 lines
2.1 KiB
C
65 lines
2.1 KiB
C
|
|
#pragma once
|
||
|
|
#include <cstdint>
|
||
|
|
#include <functional>
|
||
|
|
#include <span>
|
||
|
|
#include "eth.h"
|
||
|
|
#include "ipv4.h"
|
||
|
|
#include "span_writer.h"
|
||
|
|
|
||
|
|
namespace igmp {
|
||
|
|
|
||
|
|
static constexpr ipv4::ip4_addr PICOMAP_DISCOVERY_GROUP = {239, 112, 77, 1};
|
||
|
|
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,
|
||
|
|
eth::mac_addr our_mac, ipv4::ip4_addr our_ip,
|
||
|
|
std::function<void(std::span<const uint8_t>)> send_raw);
|
||
|
|
|
||
|
|
void send_all_reports(eth::mac_addr our_mac, ipv4::ip4_addr our_ip,
|
||
|
|
std::function<void(std::span<const uint8_t>)> send_raw);
|
||
|
|
|
||
|
|
void handle(std::span<const uint8_t> frame, span_writer& tx,
|
||
|
|
eth::mac_addr our_mac, ipv4::ip4_addr our_ip,
|
||
|
|
std::function<void(std::span<const uint8_t>)> send_raw);
|
||
|
|
|
||
|
|
template <typename Buf>
|
||
|
|
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<message>();
|
||
|
|
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 <typename Buf>
|
||
|
|
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<message>();
|
||
|
|
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<const uint8_t> frame, ipv4::ip4_addr& group);
|
||
|
|
|
||
|
|
} // namespace igmp
|