#![allow(clippy::doc_markdown)]
#![allow(unused)]
use core::fmt;
use ana_gotatun::packet::IpNextProtocol;
use bitfield_struct::bitfield;
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned, big_endian};
#[repr(C)]
#[derive(Debug, FromBytes, IntoBytes, KnownLayout, Unaligned, Immutable)]
pub struct Scion<Payload: ?Sized = [u8]> {
pub header: ScionHeader,
pub payload: Payload,
}
#[repr(C, packed)]
#[derive(Clone, Copy, FromBytes, IntoBytes, KnownLayout, Unaligned, Immutable, PartialEq, Eq)]
pub struct ScionHeader {
pub version_traffic_flow: ScionVersionTrafficFlow,
pub payload_length: big_endian::U16,
pub next_header: IpNextProtocol,
pub hop_count: u8,
pub source_id: big_endian::U64,
pub destination_id: big_endian::U64,
}
impl fmt::Debug for ScionHeader {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let vtf = self.version_traffic_flow;
f.debug_struct("ScionHeader")
.field("version", &vtf.version())
.field("traffic_class", &vtf.traffic_class())
.field("flow_id", &vtf.flow_id())
.field("payload_length", &self.payload_length.get())
.field("next_header", &self.next_header)
.field("hop_count", &self.hop_count)
.field("source_id", &format_args!("{:#018x}", self.source_id.get()))
.field(
"destination_id",
&format_args!("{:#018x}", self.destination_id.get()),
)
.finish()
}
}
#[bitfield(
u32,
repr = big_endian::U32,
from = big_endian::U32::new,
into = big_endian::U32::get
)]
#[derive(FromBytes, IntoBytes, KnownLayout, Unaligned, Immutable, PartialEq, Eq)]
pub struct ScionVersionTrafficFlow {
#[bits(20)]
pub flow_id: u32,
#[bits(8)]
pub traffic_class: u8,
#[bits(4)]
pub version: u8,
}
impl ScionHeader {
pub fn new(
version: u8,
traffic_class: u8,
flow_id: u32,
payload_len: u16,
next_header: IpNextProtocol,
hop_count: u8,
source_id: u64,
destination_id: u64,
) -> Self {
let vtf = ScionVersionTrafficFlow::new()
.with_version(version)
.with_traffic_class(traffic_class)
.with_flow_id(flow_id & 0x000F_FFFF);
ScionHeader {
version_traffic_flow: vtf, payload_length: big_endian::U16::new(payload_len),
next_header,
hop_count,
source_id: big_endian::U64::new(source_id),
destination_id: big_endian::U64::new(destination_id),
}
}
pub fn version(&self) -> u8 {
self.version_traffic_flow.version()
}
pub fn traffic_class(&self) -> u8 {
self.version_traffic_flow.traffic_class()
}
pub fn flow_id(&self) -> u32 {
self.version_traffic_flow.flow_id()
}
pub fn payload_length(&self) -> u16 {
self.payload_length.get()
}
}
#[cfg(test)]
mod tests {
use std::mem::size_of;
use super::*;
#[test]
fn scion_header_layout() {
assert_eq!(size_of::<ScionHeader>(), 4 + 2 + 1 + 1 + 8 + 8);
let hdr = ScionHeader::new(
1, 0xAA, 0xABCDE, 1200, IpNextProtocol::Udp,
7, 0x0123_4567_89AB_CDEF,
0xFEDC_BA98_7654_3210,
);
assert_eq!(hdr.version(), 1);
assert_eq!(hdr.traffic_class(), 0xAA);
assert_eq!(hdr.flow_id(), 0xABCDE & 0x000F_FFFF);
assert_eq!(hdr.payload_length(), 1200);
assert_eq!(hdr.next_header, IpNextProtocol::Udp);
assert_eq!(hdr.hop_count, 7);
}
}