pub const IPPROTO_IGMP: u8 = 2;
pub const IGMP_FIXED_HEADER_LEN: usize = 8;
pub const IGMP_HEADER_LEN: usize = IGMP_FIXED_HEADER_LEN;
pub const IGMP_MRD_ADVERTISEMENT_LEN: usize = 8;
pub const IGMP_MRD_SOLICITATION_LEN: usize = 4;
pub const IGMP_MRD_TERMINATION_LEN: usize = 4;
pub const IGMP_V3_QUERY_MIN_LEN: usize = 12;
pub const IGMP_V3_REPORT_HEADER_LEN: usize = 8;
pub const IGMP_V3_GROUP_RECORD_HEADER_LEN: usize = 8;
pub const IGMP_EXTENSION_HEADER_LEN: usize = 4;
pub const IGMP_TYPE_RESERVED: u8 = 0x00;
pub const IGMP_TYPE_OBSOLETE_RESERVED_FIRST: u8 = 0x01;
pub const IGMP_TYPE_OBSOLETE_RESERVED_LAST: u8 = 0x08;
pub const IGMP_TYPE_UNASSIGNED_FIRST: u8 = 0x09;
pub const IGMP_TYPE_UNASSIGNED_LAST: u8 = 0x10;
pub const IGMP_TYPE_MEMBERSHIP_QUERY: u8 = 0x11;
pub const IGMP_TYPE_V1_MEMBERSHIP_REPORT: u8 = 0x12;
pub const IGMP_TYPE_DVMRP: u8 = 0x13;
pub const IGMP_TYPE_PIM_V1: u8 = 0x14;
pub const IGMP_TYPE_CISCO_TRACE_MESSAGES: u8 = 0x15;
pub const IGMP_TYPE_V2_MEMBERSHIP_REPORT: u8 = 0x16;
pub const IGMP_TYPE_V2_LEAVE_GROUP: u8 = 0x17;
pub const IGMP_TYPE_MULTICAST_TRACEROUTE_RESPONSE: u8 = 0x1e;
pub const IGMP_TYPE_MULTICAST_TRACEROUTE: u8 = 0x1f;
pub const IGMP_TYPE_V3_MEMBERSHIP_REPORT: u8 = 0x22;
pub const IGMP_TYPE_MULTICAST_ROUTER_ADVERTISEMENT: u8 = 0x30;
pub const IGMP_TYPE_MULTICAST_ROUTER_SOLICITATION: u8 = 0x31;
pub const IGMP_TYPE_MULTICAST_ROUTER_TERMINATION: u8 = 0x32;
pub const IGMP_TYPE_EXPERIMENTAL_FIRST: u8 = 0xf0;
pub const IGMP_TYPE_EXPERIMENTAL_LAST: u8 = 0xff;
pub const IGMP_QUERY_CODE_V1: u8 = 0;
pub const IGMP_QUERY_CODE_MAX_RESPONSE_FIRST: u8 = 1;
pub const IGMP_QUERY_CODE_MAX_RESPONSE_LAST: u8 = u8::MAX;
pub const IGMP_DEFAULT_CODE: u8 = 0;
pub const IGMP_DEFAULT_CHECKSUM: u16 = 0;
pub const IGMP_DEFAULT_RESERVED_U8: u8 = 0;
pub const IGMP_DEFAULT_RESERVED_U16: u16 = 0;
pub const IGMP_DEFAULT_SOURCE_COUNT: u16 = 0;
pub const IGMP_DEFAULT_GROUP_RECORD_COUNT: u16 = 0;
pub const IGMP_DEFAULT_AUX_DATA_LEN: u8 = 0;
pub const IGMP_DEFAULT_QUERY_FLAGS: u8 = 0;
pub const IGMP_DEFAULT_REPORT_FLAGS: u16 = 0;
pub const IGMP_DEFAULT_EXTENSION_LENGTH: u16 = 0;
pub const IGMP_MRD_DEFAULT_RESERVED: u8 = 0;
pub const IGMP_RECORD_TYPE_MODE_IS_INCLUDE: u8 = 1;
pub const IGMP_RECORD_TYPE_MODE_IS_EXCLUDE: u8 = 2;
pub const IGMP_RECORD_TYPE_CHANGE_TO_INCLUDE_MODE: u8 = 3;
pub const IGMP_RECORD_TYPE_CHANGE_TO_EXCLUDE_MODE: u8 = 4;
pub const IGMP_RECORD_TYPE_ALLOW_NEW_SOURCES: u8 = 5;
pub const IGMP_RECORD_TYPE_BLOCK_OLD_SOURCES: u8 = 6;
pub const IGMP_EXTENSION_TYPE_NOOP: u16 = 0;
pub const IGMP_EXTENSION_TYPE_UNASSIGNED_FIRST: u16 = 1;
pub const IGMP_EXTENSION_TYPE_UNASSIGNED_LAST: u16 = 65_533;
pub const IGMP_EXTENSION_TYPE_EXPERIMENTAL_FIRST: u16 = 65_534;
pub const IGMP_EXTENSION_TYPE_EXPERIMENTAL_LAST: u16 = u16::MAX;
pub const IGMP_V3_QUERY_FLAG_EXTENSION: u8 = 0x80;
pub const IGMP_V3_QUERY_FLAGS_MASK: u8 = 0xf0;
pub const IGMP_V3_QUERY_FLAGS_UNASSIGNED_MASK: u8 = 0x70;
pub const IGMP_V3_REPORT_FLAG_EXTENSION: u16 = 0x8000;
pub const IGMP_V3_REPORT_FLAGS_MASK: u16 = u16::MAX;
pub const IGMP_V3_REPORT_FLAGS_UNASSIGNED_MASK: u16 = 0x7fff;
const IGMP_V3_TIMER_CODE_FLOATING_BIT: u8 = 0x80;
const IGMP_V3_TIMER_CODE_EXP_MASK: u8 = 0x70;
const IGMP_V3_TIMER_CODE_MANT_MASK: u8 = 0x0f;
const IGMP_V3_TIMER_CODE_LINEAR_LIMIT: u32 = 128;
pub(crate) const IGMP_V3_TIMER_CODE_MAX_UNITS: u32 = 31_744;
pub(crate) fn igmp_v3_timer_code_units(code: u8) -> u32 {
if code < IGMP_V3_TIMER_CODE_FLOATING_BIT {
return u32::from(code);
}
let exp = (code & IGMP_V3_TIMER_CODE_EXP_MASK) >> 4;
let mant = code & IGMP_V3_TIMER_CODE_MANT_MASK;
u32::from(mant | 0x10) << (u32::from(exp) + 3)
}
pub(crate) fn igmp_v3_timer_code_from_units_floor(units: u32) -> u8 {
if units < IGMP_V3_TIMER_CODE_LINEAR_LIMIT {
return units as u8;
}
let target = units.min(IGMP_V3_TIMER_CODE_MAX_UNITS);
let mut encoded = IGMP_V3_TIMER_CODE_FLOATING_BIT;
for code in IGMP_V3_TIMER_CODE_FLOATING_BIT..=u8::MAX {
let value = igmp_v3_timer_code_units(code);
if value > target {
break;
}
encoded = code;
}
encoded
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn igmp_constants_match_reviewed_codepoints() {
assert_eq!(IPPROTO_IGMP, 2);
assert_eq!(IGMP_FIXED_HEADER_LEN, 8);
assert_eq!(IGMP_HEADER_LEN, IGMP_FIXED_HEADER_LEN);
assert_eq!(IGMP_MRD_ADVERTISEMENT_LEN, 8);
assert_eq!(IGMP_MRD_SOLICITATION_LEN, 4);
assert_eq!(IGMP_MRD_TERMINATION_LEN, 4);
assert_eq!(IGMP_V3_QUERY_MIN_LEN, 12);
assert_eq!(IGMP_V3_REPORT_HEADER_LEN, 8);
assert_eq!(IGMP_V3_GROUP_RECORD_HEADER_LEN, 8);
assert_eq!(IGMP_EXTENSION_HEADER_LEN, 4);
assert_eq!(IGMP_TYPE_RESERVED, 0x00);
assert_eq!(IGMP_TYPE_OBSOLETE_RESERVED_FIRST, 0x01);
assert_eq!(IGMP_TYPE_OBSOLETE_RESERVED_LAST, 0x08);
assert_eq!(IGMP_TYPE_UNASSIGNED_FIRST, 0x09);
assert_eq!(IGMP_TYPE_UNASSIGNED_LAST, 0x10);
assert_eq!(IGMP_TYPE_MEMBERSHIP_QUERY, 0x11);
assert_eq!(IGMP_TYPE_V1_MEMBERSHIP_REPORT, 0x12);
assert_eq!(IGMP_TYPE_DVMRP, 0x13);
assert_eq!(IGMP_TYPE_PIM_V1, 0x14);
assert_eq!(IGMP_TYPE_CISCO_TRACE_MESSAGES, 0x15);
assert_eq!(IGMP_TYPE_V2_MEMBERSHIP_REPORT, 0x16);
assert_eq!(IGMP_TYPE_V2_LEAVE_GROUP, 0x17);
assert_eq!(IGMP_TYPE_MULTICAST_TRACEROUTE_RESPONSE, 0x1e);
assert_eq!(IGMP_TYPE_MULTICAST_TRACEROUTE, 0x1f);
assert_eq!(IGMP_TYPE_V3_MEMBERSHIP_REPORT, 0x22);
assert_eq!(IGMP_TYPE_MULTICAST_ROUTER_ADVERTISEMENT, 0x30);
assert_eq!(IGMP_TYPE_MULTICAST_ROUTER_SOLICITATION, 0x31);
assert_eq!(IGMP_TYPE_MULTICAST_ROUTER_TERMINATION, 0x32);
assert_eq!(IGMP_TYPE_EXPERIMENTAL_FIRST, 0xf0);
assert_eq!(IGMP_TYPE_EXPERIMENTAL_LAST, 0xff);
assert_eq!(IGMP_QUERY_CODE_V1, 0);
assert_eq!(IGMP_QUERY_CODE_MAX_RESPONSE_FIRST, 1);
assert_eq!(IGMP_QUERY_CODE_MAX_RESPONSE_LAST, 255);
assert_eq!(IGMP_DEFAULT_CODE, 0);
assert_eq!(IGMP_DEFAULT_CHECKSUM, 0);
assert_eq!(IGMP_DEFAULT_RESERVED_U8, 0);
assert_eq!(IGMP_DEFAULT_RESERVED_U16, 0);
assert_eq!(IGMP_DEFAULT_SOURCE_COUNT, 0);
assert_eq!(IGMP_DEFAULT_GROUP_RECORD_COUNT, 0);
assert_eq!(IGMP_DEFAULT_AUX_DATA_LEN, 0);
assert_eq!(IGMP_DEFAULT_QUERY_FLAGS, 0);
assert_eq!(IGMP_DEFAULT_REPORT_FLAGS, 0);
assert_eq!(IGMP_DEFAULT_EXTENSION_LENGTH, 0);
assert_eq!(IGMP_MRD_DEFAULT_RESERVED, 0);
assert_eq!(IGMP_RECORD_TYPE_MODE_IS_INCLUDE, 1);
assert_eq!(IGMP_RECORD_TYPE_MODE_IS_EXCLUDE, 2);
assert_eq!(IGMP_RECORD_TYPE_CHANGE_TO_INCLUDE_MODE, 3);
assert_eq!(IGMP_RECORD_TYPE_CHANGE_TO_EXCLUDE_MODE, 4);
assert_eq!(IGMP_RECORD_TYPE_ALLOW_NEW_SOURCES, 5);
assert_eq!(IGMP_RECORD_TYPE_BLOCK_OLD_SOURCES, 6);
assert_eq!(IGMP_EXTENSION_TYPE_NOOP, 0);
assert_eq!(IGMP_EXTENSION_TYPE_UNASSIGNED_FIRST, 1);
assert_eq!(IGMP_EXTENSION_TYPE_UNASSIGNED_LAST, 65_533);
assert_eq!(IGMP_EXTENSION_TYPE_EXPERIMENTAL_FIRST, 65_534);
assert_eq!(IGMP_EXTENSION_TYPE_EXPERIMENTAL_LAST, 65_535);
assert_eq!(IGMP_V3_QUERY_FLAG_EXTENSION, 0x80);
assert_eq!(IGMP_V3_QUERY_FLAGS_MASK, 0xf0);
assert_eq!(IGMP_V3_QUERY_FLAGS_UNASSIGNED_MASK, 0x70);
assert_eq!(IGMP_V3_REPORT_FLAG_EXTENSION, 0x8000);
assert_eq!(IGMP_V3_REPORT_FLAGS_MASK, 0xffff);
assert_eq!(IGMP_V3_REPORT_FLAGS_UNASSIGNED_MASK, 0x7fff);
}
}