#![no_std]
use core::marker::PhantomData;
use macro_bits::{bit, check_bit};
use scroll::{
ctx::{MeasureWith, TryFromCtx, TryIntoCtx},
Endian, Pread, Pwrite,
};
pub use ether_type::EtherType;
const SNAP_CODE: u8 = 0xaa;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct SnapLlcFrame<'a, Payload = &'a [u8]> {
pub oui: [u8; 3],
pub ether_type: EtherType,
pub payload: Payload,
pub _phantom: PhantomData<&'a ()>,
}
impl<'a> TryFromCtx<'a> for SnapLlcFrame<'a> {
type Error = scroll::Error;
fn try_from_ctx(from: &'a [u8], _ctx: ()) -> Result<(Self, usize), Self::Error> {
let mut offset = 0;
let dsap = from.gread::<u8>(&mut offset)?;
let ssap = from.gread::<u8>(&mut offset)?;
if dsap != SNAP_CODE || ssap != SNAP_CODE {
return Err(scroll::Error::BadInput {
size: offset,
msg: "DSAP/SSAP wasn't set to 0xaa (SNAP).",
});
}
let control = from.gread::<u8>(&mut offset)?;
if !check_bit!(control, bit!(0, 1)) {
return Err(scroll::Error::BadInput {
size: offset,
msg: "LLC control field wasn't set to unnumbered.",
});
}
let oui = from.gread(&mut offset)?;
let ether_type = EtherType::from_bits(from.gread_with(&mut offset, Endian::Big)?);
let payload = &from[offset..];
Ok((
Self {
oui,
ether_type,
payload,
_phantom: PhantomData,
},
offset,
))
}
}
impl<Payload: MeasureWith<()>> MeasureWith<()> for SnapLlcFrame<'_, Payload> {
fn measure_with(&self, ctx: &()) -> usize {
7 + self.payload.measure_with(ctx)
}
}
impl<Payload: TryIntoCtx<Error = scroll::Error>> TryIntoCtx for SnapLlcFrame<'_, Payload> {
type Error = scroll::Error;
fn try_into_ctx(self, buf: &mut [u8], _ctx: ()) -> Result<usize, Self::Error> {
let mut offset = 0;
buf.gwrite(SNAP_CODE, &mut offset)?;
buf.gwrite(SNAP_CODE, &mut offset)?;
buf.gwrite(0b11u8, &mut offset)?;
buf.gwrite(self.oui.as_slice(), &mut offset)?;
buf.gwrite_with(self.ether_type.into_bits(), &mut offset, Endian::Big)?;
buf.gwrite(self.payload, &mut offset)?;
Ok(offset)
}
}