use crate::{
Buf, BufError, BufMut, BufResult, Codec, Cursor,
ip::{Protocol, Version},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Ipv6 {
pub traffic_class: TrafficClass,
pub flow_label: FlowLabel,
pub payload_length: PayloadLength,
pub next_header: Protocol,
pub hop_limit: HopLimit,
pub source_address: Address,
pub destination_address: Address,
}
impl Ipv6 {
pub const VERSION: Version = Version::Ipv6;
}
impl Codec for Ipv6 {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.payload_length.encode(writer, ())?;
self.next_header.encode(writer, ())?;
self.hop_limit.encode(writer, ())?;
self.source_address.encode(writer, ())?;
self.destination_address.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
let v_tc_fl = u32::decode(reader, ())?;
let version = v_tc_fl >> 28;
if version != 6 {
return Err(BufError::UnexpectedValue);
}
let traffic_class = TrafficClass::decode(reader, ())?;
let flow_label = FlowLabel(v_tc_fl & 0x000F_FFFF);
let payload_length = PayloadLength::decode(reader, ())?;
let next_header = Protocol::decode(reader, ())?;
let hop_limit = HopLimit::decode(reader, ())?;
let source_address = Address::decode(reader, ())?;
let destination_address = Address::decode(reader, ())?;
Ok(Self {
traffic_class,
flow_label,
payload_length,
next_header,
hop_limit,
source_address,
destination_address,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct TrafficClass(pub u8);
impl TrafficClass {}
impl From<u8> for TrafficClass {
fn from(value: u8) -> Self {
Self(value)
}
}
impl From<TrafficClass> for u8 {
fn from(value: TrafficClass) -> Self {
value.0
}
}
impl std::fmt::Display for TrafficClass {
fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
todo!()
}
}
impl Codec for TrafficClass {
fn encode<W: BufMut>(&self, _writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
todo!()
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
let _version_traffic_class = reader.read_u8()?;
let _traffic_class_flow_label = reader.peek_u8()?;
let traffic_class = 0;
Ok(Self(traffic_class))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct FlowLabel(pub u32);
impl FlowLabel {}
impl From<u32> for FlowLabel {
fn from(value: u32) -> Self {
Self(value)
}
}
impl From<FlowLabel> for u32 {
fn from(value: FlowLabel) -> Self {
value.0
}
}
impl Codec for FlowLabel {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.0.encode(writer, ())
}
fn decode<R: Buf>(_reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
todo!()
}
}
impl std::fmt::Display for FlowLabel {
fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
todo!()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct PayloadLength(pub u16);
impl PayloadLength {}
impl From<u16> for PayloadLength {
fn from(value: u16) -> Self {
Self(value)
}
}
impl From<PayloadLength> for u16 {
fn from(value: PayloadLength) -> Self {
value.0
}
}
impl Codec for PayloadLength {
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, ())?))
}
}
impl std::fmt::Display for PayloadLength {
fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
todo!()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct HopLimit(pub u8);
impl HopLimit {}
impl From<u8> for HopLimit {
fn from(value: u8) -> Self {
Self(value)
}
}
impl From<HopLimit> for u8 {
fn from(value: HopLimit) -> Self {
value.0
}
}
impl Codec for HopLimit {
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, ())?))
}
}
impl std::fmt::Display for HopLimit {
fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
todo!()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct Address(pub [u8; 16]);
impl Address {
pub const UNSPECIFIED: Self = Self([0; 16]);
pub const LOOPBACK: Self = Self([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
pub const fn from_octets(octets: [u8; 16]) -> Self {
Self(octets)
}
pub const fn octets(self) -> [u8; 16] {
self.0
}
pub const fn is_multicast(self) -> bool {
self.0[0] == 0xFF
}
pub const fn is_link_local(self) -> bool {
self.0[0] == 0xFE && (self.0[1] & 0xC0) == 0x80
}
pub const fn is_unique_local(self) -> bool {
(self.0[0] & 0xFE) == 0xFC
}
pub const fn is_global_unicast(self) -> bool {
!self.is_multicast() && !self.is_link_local() && !self.is_unique_local()
}
}
impl From<[u8; 16]> for Address {
fn from(octets: [u8; 16]) -> Self {
Self(octets)
}
}
impl From<Address> for [u8; 16] {
fn from(addr: Address) -> Self {
addr.0
}
}
impl Codec for Address {
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(reader.read_array::<16>()?))
}
}
impl std::fmt::Display for Address {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for (i, &byte) in self.0.iter().enumerate() {
if i % 2 == 0 && i != 0 {
write!(f, ":")?;
}
write!(f, "{:02x}", byte)?;
}
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct HopByHopOptionsHeader {
pub next_header: Protocol,
pub hdr_ext_len: u8,
}
impl Codec for HopByHopOptionsHeader {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.next_header.encode(writer, ())?;
self.hdr_ext_len.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
let next_header = Protocol::decode(reader, ())?;
let hdr_ext_len = u8::decode(reader, ())?;
Ok(Self {
next_header,
hdr_ext_len,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RoutingHeader {
pub next_header: u8,
pub reserved: u8,
pub fragment_offset: u16,
pub res: u8,
pub m: bool,
pub identification: u32,
}
impl Codec for RoutingHeader {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.next_header.encode(writer, ())?;
self.reserved.encode(writer, ())?;
let frag_off_res_m: u16 = ((self.fragment_offset & 0x1FFF) << 3)
| ((self.res as u16 & 0x03) << 1)
| (self.m as u16);
frag_off_res_m.encode(writer, ())?;
self.identification.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
let next_header = u8::decode(reader, ())?;
let reserved = u8::decode(reader, ())?;
let frag_off_res_m = u16::decode(reader, ())?;
let fragment_offset = frag_off_res_m >> 3;
let res = ((frag_off_res_m >> 1) & 0x03) as u8;
let m = (frag_off_res_m & 0x01) != 0;
let identification = u32::decode(reader, ())?;
Ok(Self {
next_header,
reserved,
fragment_offset,
res,
m,
identification,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FragmentHeader {
pub next_header: Protocol,
pub reserved: u8,
pub fragment_offset: u16,
pub res: u8,
pub m: bool,
pub identification: u32,
}
impl Codec for FragmentHeader {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.next_header.encode(writer, ())?;
self.reserved.encode(writer, ())?;
let frag_off_res_m: u16 = ((self.fragment_offset & 0x1FFF) << 3)
| ((self.res as u16 & 0x03) << 1)
| (self.m as u16);
frag_off_res_m.encode(writer, ())?;
self.identification.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
let next_header = Protocol::decode(reader, ())?;
let reserved = u8::decode(reader, ())?;
let frag_off_res_m = u16::decode(reader, ())?;
let fragment_offset = frag_off_res_m >> 3;
let res = ((frag_off_res_m >> 1) & 0x03) as u8;
let m = (frag_off_res_m & 0x01) != 0;
let identification = u32::decode(reader, ())?;
Ok(Self {
next_header,
reserved,
fragment_offset,
res,
m,
identification,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DestinationOptionsHeader {
pub next_header: u8,
pub reserved: u8,
pub fragment_offset: u16,
pub res: u8,
pub m: bool,
pub identification: u32,
}
impl Codec for DestinationOptionsHeader {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.next_header.encode(writer, ())?;
self.reserved.encode(writer, ())?;
let frag_off_res_m: u16 = ((self.fragment_offset & 0x1FFF) << 3)
| ((self.res as u16 & 0x03) << 1)
| (self.m as u16);
frag_off_res_m.encode(writer, ())?;
self.identification.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
let next_header = u8::decode(reader, ())?;
let reserved = u8::decode(reader, ())?;
let frag_off_res_m = u16::decode(reader, ())?;
let fragment_offset = frag_off_res_m >> 3;
let res = ((frag_off_res_m >> 1) & 0x03) as u8;
let m = (frag_off_res_m & 0x01) != 0;
let identification = u32::decode(reader, ())?;
Ok(Self {
next_header,
reserved,
fragment_offset,
res,
m,
identification,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EncapsulatingSecurityPayloadHeader {
pub next_header: u8,
pub reserved: u8,
pub fragment_offset: u16,
pub res: u8,
pub m: bool,
pub identification: u32,
}
impl Codec for EncapsulatingSecurityPayloadHeader {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.next_header.encode(writer, ())?;
self.reserved.encode(writer, ())?;
let frag_off_res_m: u16 = ((self.fragment_offset & 0x1FFF) << 3)
| ((self.res as u16 & 0x03) << 1)
| (self.m as u16);
frag_off_res_m.encode(writer, ())?;
self.identification.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
let next_header = u8::decode(reader, ())?;
let reserved = u8::decode(reader, ())?;
let frag_off_res_m = u16::decode(reader, ())?;
let fragment_offset = frag_off_res_m >> 3;
let res = ((frag_off_res_m >> 1) & 0x03) as u8;
let m = (frag_off_res_m & 0x01) != 0;
let identification = u32::decode(reader, ())?;
Ok(Self {
next_header,
reserved,
fragment_offset,
res,
m,
identification,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AuthenticationHeader {
pub next_header: u8,
pub reserved: u8,
pub fragment_offset: u16,
pub res: u8,
pub m: bool,
pub identification: u32,
}
impl Codec for AuthenticationHeader {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.next_header.encode(writer, ())?;
self.reserved.encode(writer, ())?;
let frag_off_res_m: u16 = ((self.fragment_offset & 0x1FFF) << 3)
| ((self.res as u16 & 0x03) << 1)
| (self.m as u16);
frag_off_res_m.encode(writer, ())?;
self.identification.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
let next_header = u8::decode(reader, ())?;
let reserved = u8::decode(reader, ())?;
let frag_off_res_m = u16::decode(reader, ())?;
let fragment_offset = frag_off_res_m >> 3;
let res = ((frag_off_res_m >> 1) & 0x03) as u8;
let m = (frag_off_res_m & 0x01) != 0;
let identification = u32::decode(reader, ())?;
Ok(Self {
next_header,
reserved,
fragment_offset,
res,
m,
identification,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MobilityHeader {
pub next_header: u8,
pub reserved: u8,
pub fragment_offset: u16,
pub res: u8,
pub m: bool,
pub identification: u32,
}
impl Codec for MobilityHeader {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.next_header.encode(writer, ())?;
self.reserved.encode(writer, ())?;
let frag_off_res_m: u16 = ((self.fragment_offset & 0x1FFF) << 3)
| ((self.res as u16 & 0x03) << 1)
| (self.m as u16);
frag_off_res_m.encode(writer, ())?;
self.identification.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
let next_header = u8::decode(reader, ())?;
let reserved = u8::decode(reader, ())?;
let frag_off_res_m = u16::decode(reader, ())?;
let fragment_offset = frag_off_res_m >> 3;
let res = ((frag_off_res_m >> 1) & 0x03) as u8;
let m = (frag_off_res_m & 0x01) != 0;
let identification = u32::decode(reader, ())?;
Ok(Self {
next_header,
reserved,
fragment_offset,
res,
m,
identification,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct HostIdentityProtocolHeader {
pub next_header: u8,
pub reserved: u8,
pub fragment_offset: u16,
pub res: u8,
pub m: bool,
pub identification: u32,
}
impl Codec for HostIdentityProtocolHeader {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.next_header.encode(writer, ())?;
self.reserved.encode(writer, ())?;
let frag_off_res_m: u16 = ((self.fragment_offset & 0x1FFF) << 3)
| ((self.res as u16 & 0x03) << 1)
| (self.m as u16);
frag_off_res_m.encode(writer, ())?;
self.identification.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
let next_header = u8::decode(reader, ())?;
let reserved = u8::decode(reader, ())?;
let frag_off_res_m = u16::decode(reader, ())?;
let fragment_offset = frag_off_res_m >> 3;
let res = ((frag_off_res_m >> 1) & 0x03) as u8;
let m = (frag_off_res_m & 0x01) != 0;
let identification = u32::decode(reader, ())?;
Ok(Self {
next_header,
reserved,
fragment_offset,
res,
m,
identification,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Shim6Header {
pub next_header: u8,
pub reserved: u8,
pub fragment_offset: u16,
pub res: u8,
pub m: bool,
pub identification: u32,
}
impl Codec for Shim6Header {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.next_header.encode(writer, ())?;
self.reserved.encode(writer, ())?;
let frag_off_res_m: u16 = ((self.fragment_offset & 0x1FFF) << 3)
| ((self.res as u16 & 0x03) << 1)
| (self.m as u16);
frag_off_res_m.encode(writer, ())?;
self.identification.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
let next_header = u8::decode(reader, ())?;
let reserved = u8::decode(reader, ())?;
let frag_off_res_m = u16::decode(reader, ())?;
let fragment_offset = frag_off_res_m >> 3;
let res = ((frag_off_res_m >> 1) & 0x03) as u8;
let m = (frag_off_res_m & 0x01) != 0;
let identification = u32::decode(reader, ())?;
Ok(Self {
next_header,
reserved,
fragment_offset,
res,
m,
identification,
})
}
}