use core::convert::Infallible as Never;
use core::fmt::Debug;
use core::num::NonZeroU32;
use const_unwrap::const_unwrap_option;
use net_types::ip::{GenericOverIp, Ip, Ipv4, Ipv4Addr, Ipv6, Ipv6SourceAddr, Mtu};
use packet_formats::icmp::{
Icmpv4DestUnreachableCode, Icmpv4ParameterProblemCode, Icmpv4RedirectCode,
Icmpv4TimeExceededCode, Icmpv6DestUnreachableCode, Icmpv6ParameterProblemCode,
Icmpv6TimeExceededCode,
};
use packet_formats::ip::IpProtoExt;
pub trait BroadcastIpExt: Ip {
type BroadcastMarker: Debug + Copy + Clone + PartialEq + Eq + Send + Sync + 'static;
}
impl BroadcastIpExt for Ipv4 {
type BroadcastMarker = ();
}
impl BroadcastIpExt for Ipv6 {
type BroadcastMarker = Never;
}
#[derive(GenericOverIp)]
#[generic_over_ip(I, Ip)]
pub struct WrapBroadcastMarker<I: BroadcastIpExt>(pub I::BroadcastMarker);
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Mms(NonZeroU32);
impl Mms {
pub fn from_mtu<I: IpExt>(mtu: Mtu, options_size: u32) -> Option<Self> {
NonZeroU32::new(mtu.get().saturating_sub(I::IP_HEADER_LENGTH.get() + options_size))
.map(|mms| Self(mms.min(I::IP_MAX_PAYLOAD_LENGTH)))
}
pub fn get(&self) -> NonZeroU32 {
let Self(mms) = *self;
mms
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[allow(missing_docs)]
pub enum Icmpv4ErrorCode {
DestUnreachable(Icmpv4DestUnreachableCode),
Redirect(Icmpv4RedirectCode),
TimeExceeded(Icmpv4TimeExceededCode),
ParameterProblem(Icmpv4ParameterProblemCode),
}
impl<I: IcmpIpExt> GenericOverIp<I> for Icmpv4ErrorCode {
type Type = I::ErrorCode;
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[allow(missing_docs)]
pub enum Icmpv6ErrorCode {
DestUnreachable(Icmpv6DestUnreachableCode),
PacketTooBig,
TimeExceeded(Icmpv6TimeExceededCode),
ParameterProblem(Icmpv6ParameterProblemCode),
}
impl<I: IcmpIpExt> GenericOverIp<I> for Icmpv6ErrorCode {
type Type = I::ErrorCode;
}
#[derive(Debug, Clone, Copy)]
pub enum IcmpErrorCode {
V4(Icmpv4ErrorCode),
V6(Icmpv6ErrorCode),
}
impl From<Icmpv4ErrorCode> for IcmpErrorCode {
fn from(v4_err: Icmpv4ErrorCode) -> Self {
IcmpErrorCode::V4(v4_err)
}
}
impl From<Icmpv6ErrorCode> for IcmpErrorCode {
fn from(v6_err: Icmpv6ErrorCode) -> Self {
IcmpErrorCode::V6(v6_err)
}
}
pub trait IcmpIpExt: packet_formats::ip::IpExt + packet_formats::icmp::IcmpIpExt {
type ErrorCode: Debug
+ Copy
+ PartialEq
+ GenericOverIp<Self, Type = Self::ErrorCode>
+ GenericOverIp<Ipv4, Type = Icmpv4ErrorCode>
+ GenericOverIp<Ipv6, Type = Icmpv6ErrorCode>
+ Into<IcmpErrorCode>;
}
impl IcmpIpExt for Ipv4 {
type ErrorCode = Icmpv4ErrorCode;
}
impl IcmpIpExt for Ipv6 {
type ErrorCode = Icmpv6ErrorCode;
}
pub trait IpTypesIpExt: packet_formats::ip::IpExt {
type BroadcastMarker: Debug + Copy + Clone + PartialEq + Eq;
}
impl IpTypesIpExt for Ipv4 {
type BroadcastMarker = ();
}
impl IpTypesIpExt for Ipv6 {
type BroadcastMarker = Never;
}
pub trait IpExt: packet_formats::ip::IpExt + IcmpIpExt + BroadcastIpExt + IpProtoExt {
type RecvSrcAddr: Into<Self::Addr> + TryFrom<Self::Addr, Error: Debug> + Copy + Clone;
const IP_HEADER_LENGTH: NonZeroU32;
const IP_MAX_PAYLOAD_LENGTH: NonZeroU32;
}
impl IpExt for Ipv4 {
type RecvSrcAddr = Ipv4Addr;
const IP_HEADER_LENGTH: NonZeroU32 =
const_unwrap_option(NonZeroU32::new(packet_formats::ipv4::HDR_PREFIX_LEN as u32));
const IP_MAX_PAYLOAD_LENGTH: NonZeroU32 =
const_unwrap_option(NonZeroU32::new(u16::MAX as u32 - Self::IP_HEADER_LENGTH.get()));
}
impl IpExt for Ipv6 {
type RecvSrcAddr = Ipv6SourceAddr;
const IP_HEADER_LENGTH: NonZeroU32 =
const_unwrap_option(NonZeroU32::new(packet_formats::ipv6::IPV6_FIXED_HDR_LEN as u32));
const IP_MAX_PAYLOAD_LENGTH: NonZeroU32 = const_unwrap_option(NonZeroU32::new(u16::MAX as u32));
}