use crate::{Buf, BufError, BufMut, BufResult, Codec, Cursor};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Message<'a> {
DestinationUnreachable(DestinationUnreachable<'a>),
PacketTooBig(PacketTooBig<'a>),
TimeExceeded(TimeExceeded<'a>),
ParameterProblem(ParameterProblem<'a>),
EchoRequest(EchoRequest<'a>),
EchoReply(EchoReply<'a>),
}
impl<'a> Codec for Message<'a> {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
match self {
Message::DestinationUnreachable(message) => message.encode(writer, ()),
Message::PacketTooBig(message) => message.encode(writer, ()),
Message::TimeExceeded(message) => message.encode(writer, ()),
Message::ParameterProblem(message) => message.encode(writer, ()),
Message::EchoRequest(message) => message.encode(writer, ()),
Message::EchoReply(message) => message.encode(writer, ()),
}
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
let typ = Type::decode(&mut Cursor::new(&[(reader.peek_u8()?)]), ())?;
Ok(match typ {
Type::DestinationUnreachable => {
Self::DestinationUnreachable(DestinationUnreachable::decode(reader, ())?)
}
Type::PacketTooBig => Self::PacketTooBig(PacketTooBig::decode(reader, ())?),
Type::TimeExceeded => Self::TimeExceeded(TimeExceeded::decode(reader, ())?),
Type::ParameterProblem => Self::ParameterProblem(ParameterProblem::decode(reader, ())?),
Type::EchoRequest => Self::EchoRequest(EchoRequest::decode(reader, ())?),
Type::EchoReply => Self::EchoReply(EchoReply::decode(reader, ())?),
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
pub enum Type {
DestinationUnreachable = 1,
PacketTooBig = 2,
TimeExceeded = 3,
ParameterProblem = 4,
EchoRequest = 128,
EchoReply = 129,
}
impl Codec for Type {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
(*self as u8).encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
match u8::decode(reader, ())? {
x if x == (Self::DestinationUnreachable as u8) => Ok(Self::DestinationUnreachable),
x if x == (Self::PacketTooBig as u8) => Ok(Self::PacketTooBig),
x if x == (Self::TimeExceeded as u8) => Ok(Self::TimeExceeded),
x if x == (Self::ParameterProblem as u8) => Ok(Self::ParameterProblem),
x if x == (Self::EchoRequest as u8) => Ok(Self::EchoRequest),
x if x == (Self::EchoReply as u8) => Ok(Self::EchoReply),
_ => Err(BufError::UnexpectedValue),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Code(pub u8);
impl Codec for Code {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.0.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
Ok(Self(u8::decode(reader, ())?))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Checksum(pub u16);
impl Checksum {
pub fn calculate() -> Self {
todo!()
}
}
impl Codec for Checksum {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.0.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
Ok(Self(u16::decode(reader, ())?))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
pub enum ZeroCode {
Zero = 0,
}
impl Codec for ZeroCode {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
(*self as u8).encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
match u8::decode(reader, ())? {
x if x == Self::Zero as u8 => Ok(Self::Zero),
_ => Err(BufError::UnexpectedValue),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DestinationUnreachable<'a> {
pub code: DestinationUnreachableCode,
pub checksum: Checksum,
pub data: &'a [u8],
}
impl<'a> DestinationUnreachable<'a> {
pub const TYPE: Type = Type::DestinationUnreachable;
pub const UNUSED: [u8; 4] = [0u8; 4];
}
impl<'a> Codec for DestinationUnreachable<'a> {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
Self::TYPE.encode(writer, ())?;
self.code.encode(writer, ())?;
self.checksum.encode(writer, ())?;
Self::UNUSED.encode(writer, ())?;
Ok(())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
match Type::decode(reader, ())? {
Type::DestinationUnreachable => (),
_ => return Err(BufError::UnexpectedValue),
}
let code = DestinationUnreachableCode::decode(reader, ())?;
let checksum = Checksum::decode(reader, ())?;
let data = &[0u8];
Ok(Self {
code,
checksum,
data,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
pub enum DestinationUnreachableCode {
NoRouteToDestination = 0,
CommunicationWithDestinationAdministrativelyProhibited = 1,
BeyondScopeOfSourceAddress = 2,
AddressUnreachable = 3,
PortUnreachable = 4,
SourceAddressFailedIngressEgressPolicy = 5,
RejectRouteToDestination = 6,
}
impl Codec for DestinationUnreachableCode {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
(*self as u8).encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
match u8::decode(reader, ())? {
x if x == (Self::NoRouteToDestination as u8) => Ok(Self::NoRouteToDestination),
x if x == (Self::CommunicationWithDestinationAdministrativelyProhibited as u8) => {
Ok(Self::CommunicationWithDestinationAdministrativelyProhibited)
}
x if x == (Self::BeyondScopeOfSourceAddress as u8) => Ok(Self::BeyondScopeOfSourceAddress),
x if x == (Self::AddressUnreachable as u8) => Ok(Self::AddressUnreachable),
x if x == (Self::PortUnreachable as u8) => Ok(Self::PortUnreachable),
x if x == (Self::SourceAddressFailedIngressEgressPolicy as u8) => {
Ok(Self::SourceAddressFailedIngressEgressPolicy)
}
x if x == (Self::RejectRouteToDestination as u8) => Ok(Self::RejectRouteToDestination),
_ => Err(BufError::UnexpectedValue),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PacketTooBig<'a> {
pub code: PacketTooBigCode,
pub checksum: Checksum,
pub mtu: u32,
pub data: &'a [u8],
}
impl<'a> PacketTooBig<'a> {
pub const TYPE: Type = Type::PacketTooBig;
}
impl<'a> Codec for PacketTooBig<'a> {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
Self::TYPE.encode(writer, ())?;
self.code.encode(writer, ())?;
self.checksum.encode(writer, ())?;
self.mtu.encode(writer, ())?;
Ok(())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
if Type::decode(reader, ())? != Self::TYPE {
return Err(BufError::UnexpectedValue);
}
let code = PacketTooBigCode::decode(reader, ())?;
let checksum = Checksum::decode(reader, ())?;
let mtu = u32::decode(reader, ())?;
let data = &[0u8];
Ok(Self {
code,
checksum,
mtu,
data,
})
}
}
pub type PacketTooBigCode = ZeroCode;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TimeExceeded<'a> {
pub code: TimeExceededCode,
pub checksum: Checksum,
pub data: &'a [u8],
}
impl<'a> TimeExceeded<'a> {
pub const TYPE: Type = Type::TimeExceeded;
pub const UNUSED: [u8; 4] = [0u8; 4];
}
impl<'a> Codec for TimeExceeded<'a> {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
Self::TYPE.encode(writer, ())?;
self.code.encode(writer, ())?;
self.checksum.encode(writer, ())?;
Self::UNUSED.encode(writer, ())?;
Ok(())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
match Type::decode(reader, ())? {
Type::TimeExceeded => (),
_ => return Err(BufError::UnexpectedValue),
}
let code = TimeExceededCode::decode(reader, ())?;
let checksum = Checksum::decode(reader, ())?;
let data = &[0u8];
Ok(Self {
code,
checksum,
data,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
pub enum TimeExceededCode {
HopLimitExceededInTransit = 0,
FragmentReassemblyTimeExceeded = 1,
}
impl Codec for TimeExceededCode {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
(*self as u8).encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
match u8::decode(reader, ())? {
x if x == (Self::HopLimitExceededInTransit as u8) => Ok(Self::HopLimitExceededInTransit),
x if x == (Self::FragmentReassemblyTimeExceeded as u8) => {
Ok(Self::FragmentReassemblyTimeExceeded)
}
_ => Err(BufError::UnexpectedValue),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ParameterProblem<'a> {
pub code: ParameterProblemCode,
pub checksum: Checksum,
pub pointer: u32,
pub data: &'a [u8],
}
impl<'a> ParameterProblem<'a> {
pub const TYPE: Type = Type::ParameterProblem;
}
impl<'a> Codec for ParameterProblem<'a> {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
Self::TYPE.encode(writer, ())?;
self.code.encode(writer, ())?;
self.checksum.encode(writer, ())?;
self.pointer.encode(writer, ())?;
Ok(())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
match Type::decode(reader, ())? {
Type::ParameterProblem => (),
_ => return Err(BufError::UnexpectedValue),
}
let code = ParameterProblemCode::decode(reader, ())?;
let checksum = Checksum::decode(reader, ())?;
let pointer = u32::decode(reader, ())?;
let data = &[0u8];
Ok(Self {
code,
checksum,
pointer,
data,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
pub enum ParameterProblemCode {
ErroneousHeaderFieldEncountered = 0,
UnrecognizedNextHeaderTypeEncountered = 1,
UnrecognizedIpv6OptionEncountered = 2,
}
impl Codec for ParameterProblemCode {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
(*self as u8).encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
match u8::decode(reader, ())? {
x if x == (Self::ErroneousHeaderFieldEncountered as u8) => {
Ok(Self::ErroneousHeaderFieldEncountered)
}
x if x == (Self::UnrecognizedNextHeaderTypeEncountered as u8) => {
Ok(Self::UnrecognizedNextHeaderTypeEncountered)
}
x if x == (Self::UnrecognizedIpv6OptionEncountered as u8) => {
Ok(Self::UnrecognizedIpv6OptionEncountered)
}
_ => Err(BufError::UnexpectedValue),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct EchoRequest<'a> {
pub code: EchoRequestCode,
pub checksum: Checksum,
pub identifier: u16,
pub sequence_number: u16,
pub data: &'a [u8],
}
impl<'a> EchoRequest<'a> {
pub const TYPE: Type = Type::EchoRequest;
}
impl<'a> Codec for EchoRequest<'a> {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
Self::TYPE.encode(writer, ())?;
self.code.encode(writer, ())?;
self.checksum.encode(writer, ())?;
self.identifier.encode(writer, ())?;
self.sequence_number.encode(writer, ())?;
Ok(())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
match Type::decode(reader, ())? {
Self::TYPE => (),
_ => return Err(BufError::UnexpectedValue),
}
let code = EchoReplyCode::decode(reader, ())?;
let checksum = Checksum::decode(reader, ())?;
let identifier = u16::decode(reader, ())?;
let sequence_number = u16::decode(reader, ())?;
let data = &[0u8];
Ok(Self {
code,
checksum,
identifier,
sequence_number,
data,
})
}
}
pub type EchoRequestCode = ZeroCode;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct EchoReply<'a> {
pub code: EchoRequestCode,
pub checksum: Checksum,
pub identifier: u16,
pub sequence_number: u16,
pub data: &'a [u8],
}
impl<'a> EchoReply<'a> {
pub const TYPE: Type = Type::EchoReply;
}
impl<'a> Codec for EchoReply<'a> {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
Self::TYPE.encode(writer, ())?;
self.code.encode(writer, ())?;
self.checksum.encode(writer, ())?;
self.identifier.encode(writer, ())?;
self.sequence_number.encode(writer, ())?;
Ok(())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
match Type::decode(reader, ())? {
Self::TYPE => (),
_ => return Err(BufError::UnexpectedValue),
}
let code = EchoReplyCode::decode(reader, ())?;
let checksum = Checksum::decode(reader, ())?;
let identifier = u16::decode(reader, ())?;
let sequence_number = u16::decode(reader, ())?;
let data = &[0u8];
Ok(Self {
code,
checksum,
identifier,
sequence_number,
data,
})
}
}
pub type EchoReplyCode = ZeroCode;