9 #include <satcat5/ip_dispatch.h>
15 using satcat5::ip::ADDR_NONE;
19 static constexpr
unsigned TIMER_INTERVAL_MSEC = 10;
22 constexpr u8 FLAG_QUERIER = (1u << 0);
24 void Group::reset(
const Addr& addr) {
39 void Group::refresh() {
43 mask_active = mask_rcvd1 | mask_rcvd2;
44 mask_rcvd1 = mask_rcvd2;
47 if (!mask_active) reset(ADDR_NONE);
53 Group* groups,
unsigned gcount)
58 , m_status(iface ? FLAG_QUERIER : 0)
63 , m_query_timer(iface ? 1000 : 0)
69 #if SATCAT5_ALLOW_DELETION
76 for (u16 a = 0 ; a < m_gcount ; ++a)
77 m_groups[a].reset(ADDR_NONE);
78 if (m_iface) send_query(
nullptr,
true);
83 if (addr == DST_ALL_SYSTEMS)
return satcat5::eth::PMASK_ALL;
87 auto group = find_match(addr);
88 return group ? group->mask_active : 0;
92 return m_status & FLAG_QUERIER;
96 if (pkt.
is_ip() && pkt.
ip.
proto() == satcat5::ip::PROTO_IGMP) {
104 return satcat5::util::min_u8(m_vmin, m_vmax);
110 if (countdown<u32>(m_window_timer, TIMER_INTERVAL_MSEC)) {
111 for (u16 a = 0 ; a < m_gcount ; ++a)
112 m_groups[a].refresh();
118 if (countdown<u32>(m_query_timer, TIMER_INTERVAL_MSEC)) {
119 if (m_iface) send_query(
nullptr,
true);
124 for (u16 a = 0 ; a < m_gcount ; ++a) {
125 if (countdown<u16>(m_groups[a].query_timer, TIMER_INTERVAL_MSEC)) {
126 m_groups[a].refresh();
127 if (m_iface && ++m_groups[a].query_count < 3) {
128 send_query(m_groups + a,
false);
134 Group* Server::find_or_create(
const Addr& group) {
136 if (!valid)
return nullptr;
137 Group* match = find_match(group);
138 if (match)
return match;
139 Group* empty = find_match(ADDR_NONE);
140 if (empty) empty->reset(group);
145 Group* Server::find_match(
const Addr& group)
const {
146 Group* match =
nullptr;
147 for (u16 a = 0 ; a < m_gcount && !match ; ++a) {
148 if (m_groups[a].group == group) match = m_groups + a;
158 if (pkt.
ip.
src() == m_iface->ipaddr())
return;
166 if (len > MAX_LEN_BYTES || len < MIN_LEN_BYTES)
return;
167 if (pkt.
ip.
frg())
return;
172 raw.read_consume(pkt.
hlen);
178 while (msg.get_read_ready())
179 rcvd[wcount++] = msg.read_u16();
180 u16 chk = satcat5::ip::checksum(wcount, rcvd);
186 Addr addr(rcvd[2], rcvd[3]);
189 if (type == TYPE_REPORT_V1 && m_vmin > 1) m_vmin = 1;
190 if (type == TYPE_REPORT_V2 && m_vmin > 2) m_vmin = 2;
193 if (type == TYPE_QUERY) {
203 if (m_iface) m_query_timer = 2*max_dly;
204 m_window_timer = max_dly;
206 }
else if (type == TYPE_REPORT_V1 || type == TYPE_REPORT_V2) {
208 auto group = find_or_create(addr);
209 if (group) group->rcvd(pkt.
src_mask());
210 }
else if (type == TYPE_REPORT_V3) {
212 unsigned rcount = rcvd[3];
214 for (
unsigned a = 0 ; a < rcount && rdpos + 4 <= wcount ; ++a) {
217 u16 rec = rcvd[rdpos+1];
218 Addr dst(rcvd[rdpos+2], rcvd[rdpos+3]);
219 rdpos += 4 + 2*aux + 2*rec;
221 auto group = find_or_create(dst);
222 if (group) group->rcvd(pkt.
src_mask());
224 }
else if (type == TYPE_LEAVE_V2 && m_iface) {
227 auto group = find_match(addr);
228 if (group) send_query(group,
true);
241 void Server::send_query(
Group* group,
bool first) {
243 u16 mdly = group ? m_mdly_fast : m_mdly_slow;
254 const Addr addr = group ? group->group : ADDR_NONE;
257 if (first) group->query_count = 0;
258 group->query_timer = msec;
261 m_query_timer = msec;
262 m_window_timer = msec;
270 msg[wcount++] = u16(addr.
value >> 16);
271 msg[wcount++] = u16(addr.
value >> 0);
273 msg[wcount++] = mdly;
276 igmp_send(m_iface, DST_ALL_SYSTEMS, wcount, msg);
A shared-memory Ethernet switch based on the MultiBuffer class.
Router/Server for the Internet Group Management Protocol (IGMP).
bool is_querier() const
Are we the current querier?
Server(satcat5::eth::SwitchCore *sw, satcat5::ip::Dispatch *iface, satcat5::igmp::Group *groups, unsigned gcount)
Link this plugin to the network switch or router.
void query(satcat5::eth::PluginPacket &pkt) override
Packet-processing callback from PluginCore.
u8 version() const
Current IGMP version for this network.
void flush()
Flush all existing routes and reset status.
SATCAT5_PMASK_TYPE get_mask(const satcat5::ip::Addr &addr) const
Get the port-mask for a given multicast IP address.
void timer_event() override
Child class MUST override this method.
Limited read of next N bytes.
Barebones class for reading data from a MultiPacket.
Protocol handler and dispatch unit for Internet Protocol v4 (IPv4).
void timer_every(unsigned msec)
Configure a repeating notification every X milliseconds.
Diagnostic logging system for the Ethernet switch.
#define SATCAT5_PMASK_TYPE
Set the integer type used to identify source and destination ports.
Client-side implementation of the Internet Group Management Protocol (IGMP)
constexpr unsigned MAX_LEN_SHORTS
Set upper and lower bounds for the length of an IGMP message.
constexpr satcat5::ip::Addr DST_ALL_ROUTERS(224, 0, 0, 2)
< All endpoints on subnet.
constexpr u16 MASK_MAXLEN
Bit-mask "length" from first header word.
u32 decode_maxdly(u16 hdr, bool v3)
Given the first word of the IGMP query header, decode max delay.
bool igmp_send(satcat5::ip::Dispatch *iface, const satcat5::ip::Addr &dst, const unsigned wcount, u16 *data)
Given IGMP message contents, write Eth/IP headers and send packet.
constexpr u16 TYPE_QUERY
IGMP query (all versions)
constexpr u16 MASK_TYPE
Bit-mask "type" from first header word.
Router-side implementation of the Internet Group Management Protocol (IGMP)
Ephemeral data structure provided to plugin callbacks.
satcat5::io::MultiPacket * pkt
Complete packet contents.
satcat5::ip::Header ip
Copy of additional header fields, if present.
bool is_ip() const
Accessors and shortcuts for packet metadata.
u16 hlen
Original header length.
u16 flags
Additional status flags indicating packet status.
SATCAT5_PMASK_TYPE dst_mask
Destination mask for which port(s) receive this packet.
SATCAT5_PMASK_TYPE src_mask() const
Accessors and shortcuts for packet metadata.
static constexpr u8 DROP_MCTRL
Link-local control packet.
Router state for monitoring IGMP multicast subscriptions.
IPv4 address is a 32-bit unsigned integer.
u32 value
Raw access to the underlying representation.
bool is_multicast() const
IP multicast (224.*.*.*)
bool is_broadcast() const
Limited broadcast (255.255.255.255)
Miscellaneous mathematical utility functions.
void clr_mask_u8(volatile u8 &val, u8 mask)
Set or clear bit masks.
void set_mask_u8(volatile u8 &val, u8 mask)
Set or clear bit masks.
bool countdown(T &timer, const T &decr)
Decrement a countdown timer, returning true if it reaches zero.
void set_mask(T &val, T mask)
Set or clear bit masks.