use std::fmt::Debug;
use crate::{
core::{
layout::{BitRange, Layout},
read::unchecked_bit_range_be_read,
view::{
View, ViewConversionError,
macros::{gen_field_read, gen_field_write, gen_unsafe_field_write, gen_view_impl},
},
write::unchecked_bit_range_be_write,
},
header::layout::{AddressHeaderLayout, CommonHeaderLayout, ScionHeaderLayout},
path::{
standard::view::StandardPathView,
types::PathType,
view::{ScionPathView, ScionPathViewMut},
},
scion::{
address::host_addr::{HostAddressSizeError, WireHostAddr, WireHostAddrType},
identifier::{asn::Asn, isd::Isd, isd_asn::IsdAsn},
},
};
#[repr(transparent)]
pub struct ScionHeaderView([u8]);
gen_view_impl!(ScionHeaderView, ScionHeaderLayout);
impl ScionHeaderView {
gen_field_read!(version, CommonHeaderLayout::VERSION_RNG, u8);
gen_field_read!(traffic_class, CommonHeaderLayout::TRAFFIC_CLASS_RNG, u8);
gen_field_read!(flow_id, CommonHeaderLayout::FLOW_ID_RNG, u32);
gen_field_read!(next_header, CommonHeaderLayout::NEXT_HEADER_RNG, u8);
gen_field_read!(payload_len, CommonHeaderLayout::PAYLOAD_LEN_RNG, u16);
#[inline]
pub fn header_len(&self) -> u16 {
unsafe {
unchecked_bit_range_be_read::<u8>(&self.0, CommonHeaderLayout::HEADER_LEN_RNG) as u16
* 4
}
}
#[inline]
pub fn path_type_range(&self) -> BitRange {
CommonHeaderLayout::PATH_TYPE_RNG
}
#[inline]
pub fn path_type(&self) -> PathType {
unsafe { unchecked_bit_range_be_read::<u8>(&self.0, CommonHeaderLayout::PATH_TYPE_RNG) }
.into()
}
#[inline]
pub fn dst_addr_type(&self) -> WireHostAddrType {
unsafe { unchecked_bit_range_be_read::<u8>(&self.0, CommonHeaderLayout::DST_ADDR_INFO_RNG) }
.into()
}
#[inline]
pub fn src_addr_type(&self) -> WireHostAddrType {
unsafe { unchecked_bit_range_be_read::<u8>(&self.0, CommonHeaderLayout::SRC_ADDR_INFO_RNG) }
.into()
}
}
impl ScionHeaderView {
gen_field_write!(set_version, CommonHeaderLayout::VERSION_RNG, u8);
gen_field_write!(set_traffic_class, CommonHeaderLayout::TRAFFIC_CLASS_RNG, u8);
gen_field_write!(set_flow_id, CommonHeaderLayout::FLOW_ID_RNG, u32);
gen_field_write!(set_next_header, CommonHeaderLayout::NEXT_HEADER_RNG, u8);
gen_unsafe_field_write!(set_payload_len, CommonHeaderLayout::PAYLOAD_LEN_RNG, u16);
#[inline]
pub unsafe fn set_header_len(&mut self, len: u16) {
debug_assert!(
len.is_multiple_of(4),
"Header length must be a multiple of 4"
);
debug_assert!(
len <= ScionHeaderLayout::MAX_SIZE_BYTES as u16,
"Header length must be at most 1020 bytes"
);
let raw_len = (len / 4) as u8;
unsafe {
unchecked_bit_range_be_write::<u8>(
&mut self.0,
CommonHeaderLayout::HEADER_LEN_RNG,
raw_len,
)
}
}
#[inline]
pub unsafe fn set_path_type(&mut self, path_type: PathType) {
let raw_path_type: u8 = path_type.into();
unsafe {
unchecked_bit_range_be_write::<u8>(
&mut self.0,
CommonHeaderLayout::PATH_TYPE_RNG,
raw_path_type,
)
}
}
#[inline]
pub unsafe fn set_dst_addr_type(&mut self, addr_type: WireHostAddrType) {
let addr_info: u8 = addr_type.into();
unsafe {
unchecked_bit_range_be_write::<u8>(
&mut self.0,
CommonHeaderLayout::DST_ADDR_INFO_RNG,
addr_info,
)
}
}
#[inline]
pub unsafe fn set_src_addr_type(&mut self, addr_type: WireHostAddrType) {
let addr_info: u8 = addr_type.into();
unsafe {
unchecked_bit_range_be_write::<u8>(
&mut self.0,
CommonHeaderLayout::SRC_ADDR_INFO_RNG,
addr_info,
)
}
}
}
impl ScionHeaderView {
#[inline]
pub fn dst_ia(&self) -> IsdAsn {
let val = unsafe {
unchecked_bit_range_be_read::<u64>(
&self.0,
AddressHeaderLayout::DST_IA_RNG.shift(CommonHeaderLayout::SIZE_BYTES),
)
};
IsdAsn::from_u64(val)
}
pub fn dst_isd(&self) -> Isd {
let val = unsafe {
unchecked_bit_range_be_read::<u16>(
&self.0,
AddressHeaderLayout::DST_ISD_RNG.shift(CommonHeaderLayout::SIZE_BYTES),
)
};
Isd(val)
}
pub fn dst_as(&self) -> Asn {
let val = unsafe {
unchecked_bit_range_be_read::<u64>(
&self.0,
AddressHeaderLayout::DST_AS_RNG.shift(CommonHeaderLayout::SIZE_BYTES),
)
};
Asn(val)
}
#[inline]
pub fn src_ia(&self) -> IsdAsn {
let val = unsafe {
unchecked_bit_range_be_read::<u64>(
&self.0,
AddressHeaderLayout::SRC_IA_RNG.shift(CommonHeaderLayout::SIZE_BYTES),
)
};
IsdAsn::from_u64(val)
}
pub fn src_isd(&self) -> Isd {
let val = unsafe {
unchecked_bit_range_be_read::<u16>(
&self.0,
AddressHeaderLayout::SRC_ISD_RNG.shift(CommonHeaderLayout::SIZE_BYTES),
)
};
Isd(val)
}
pub fn src_as(&self) -> Asn {
let val = unsafe {
unchecked_bit_range_be_read::<u64>(
&self.0,
AddressHeaderLayout::SRC_AS_RNG.shift(CommonHeaderLayout::SIZE_BYTES),
)
};
Asn(val)
}
#[inline]
pub fn dst_host_addr(&self) -> Result<WireHostAddr, HostAddressSizeError> {
let src_len = self.src_addr_type().size();
let dst_len = self.dst_addr_type().size();
let range = AddressHeaderLayout::new(src_len, dst_len)
.dst_host_addr_range()
.shift(CommonHeaderLayout::SIZE_BYTES);
let raw = unsafe { self.0.get_unchecked(range.aligned_byte_range()) };
WireHostAddr::from_parts(self.dst_addr_type(), raw)
}
#[inline]
pub fn src_host_addr_range(&self) -> BitRange {
let src_len = self.src_addr_type().size();
let dst_len = self.dst_addr_type().size();
AddressHeaderLayout::new(src_len, dst_len)
.src_host_addr_range()
.shift(CommonHeaderLayout::SIZE_BYTES)
}
#[inline]
pub fn src_host_addr(&self) -> Result<WireHostAddr, HostAddressSizeError> {
let range = self.src_host_addr_range();
let raw = unsafe { self.0.get_unchecked(range.aligned_byte_range()) };
WireHostAddr::from_parts(self.src_addr_type(), raw)
}
}
impl ScionHeaderView {
pub fn set_src_isd(&mut self, isd: Isd) {
unsafe {
unchecked_bit_range_be_write(
&mut self.0,
AddressHeaderLayout::SRC_ISD_RNG.shift(CommonHeaderLayout::SIZE_BYTES),
isd.0,
)
}
}
pub fn set_src_as(&mut self, asn: Asn) {
unsafe {
unchecked_bit_range_be_write(
&mut self.0,
AddressHeaderLayout::SRC_AS_RNG.shift(CommonHeaderLayout::SIZE_BYTES),
asn.0,
)
}
}
pub fn set_dst_isd(&mut self, isd: Isd) {
unsafe {
unchecked_bit_range_be_write(
&mut self.0,
AddressHeaderLayout::DST_ISD_RNG.shift(CommonHeaderLayout::SIZE_BYTES),
isd.0,
)
}
}
pub fn set_dst_as(&mut self, asn: Asn) {
unsafe {
unchecked_bit_range_be_write(
&mut self.0,
AddressHeaderLayout::DST_AS_RNG.shift(CommonHeaderLayout::SIZE_BYTES),
asn.0,
)
}
}
}
impl ScionHeaderView {
#[inline]
pub fn path(&self) -> ScionPathView<'_> {
let path_offset = CommonHeaderLayout::SIZE_BYTES
+ AddressHeaderLayout::new(self.dst_addr_type().size(), self.src_addr_type().size())
.size_bytes();
let len = self.header_len() as usize;
match self.path_type() {
PathType::Empty => ScionPathView::Empty,
PathType::Scion => {
let path_buf = unsafe { self.0.get_unchecked(path_offset..len) };
let path = unsafe { StandardPathView::from_slice_unchecked(path_buf) };
ScionPathView::Standard(path)
}
PathType::OneHop => {
let path_size = crate::proto::path::onehop::layout::OneHopPathLayout::SIZE_BYTES;
let path_range = path_offset..path_offset + path_size;
let path_buf = unsafe { self.0.get_unchecked(path_range) };
let path = unsafe {
crate::proto::path::onehop::view::OneHopPathView::from_slice_unchecked(path_buf)
};
ScionPathView::OneHop(path)
}
pt => {
let path_buf = unsafe { self.0.get_unchecked(path_offset..len) };
ScionPathView::Unsupported {
path_type: pt,
data: path_buf,
}
}
}
}
#[inline]
pub fn path_mut(&mut self) -> ScionPathViewMut<'_> {
let path_offset = CommonHeaderLayout::SIZE_BYTES
+ AddressHeaderLayout::new(self.dst_addr_type().size(), self.src_addr_type().size())
.size_bytes();
let len = self.header_len() as usize;
match self.path_type() {
PathType::Empty => ScionPathViewMut::Empty,
PathType::Scion => {
let path_buf = unsafe { self.0.get_unchecked_mut(path_offset..len) };
let path = unsafe { StandardPathView::from_mut_slice_unchecked(path_buf) };
ScionPathViewMut::Standard(path)
}
PathType::OneHop => {
let header_size = crate::proto::path::onehop::layout::OneHopPathLayout::SIZE_BYTES;
let path_range = path_offset..path_offset + header_size;
let path_buf = unsafe { self.0.get_unchecked_mut(path_range) };
let path = unsafe {
crate::proto::path::onehop::view::OneHopPathView::from_mut_slice_unchecked(
path_buf,
)
};
ScionPathViewMut::OneHop(path)
}
pt => {
let path_buf = unsafe { self.0.get_unchecked_mut(path_offset..len) };
ScionPathViewMut::Unsupported {
path_type: pt,
buf: path_buf,
}
}
}
}
}
impl Debug for ScionHeaderView {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let path = self.path();
f.debug_struct("ScionHeaderView")
.field("version", &self.version())
.field("traffic_class", &self.traffic_class())
.field("flow_id", &self.flow_id())
.field("next_header", &self.next_header())
.field("payload_len", &self.payload_len())
.field("header_len", &self.header_len())
.field("path_type", &self.path_type())
.field("dst_addr_type", &self.dst_addr_type())
.field("src_addr_type", &self.src_addr_type())
.field("dst_isd", &self.dst_isd())
.field("dst_as", &self.dst_as())
.field("src_isd", &self.src_isd())
.field("src_as", &self.src_as())
.field("dst_host_addr", &self.dst_host_addr())
.field("src_host_addr", &self.src_host_addr())
.field("path", &path)
.finish()
}
}