use crate::{IpV4Addr, Protocol, DSCP};
use byte_struct::*;
use modular_bitfield::prelude::*;
use static_assertions::const_assert;
use ufmt::derive::uDebug;
const_assert!(IpV4Header::BYTE_LEN == 20);
#[derive(ByteStruct, Clone, Copy, uDebug, Debug, PartialEq, Eq)]
#[byte_struct_be]
pub struct IpV4Header {
pub version_and_header_length: VersionAndHeaderLength,
pub dscp: DSCP,
pub total_length: u16,
pub identification: u16,
pub fragmentation: Fragmentation,
pub time_to_live: u8,
pub protocol: Protocol,
pub checksum: u16,
pub src_ipaddr: IpV4Addr,
pub dst_ipaddr: IpV4Addr,
}
impl IpV4Header {
pub fn to_be_bytes(&self) -> [u8; Self::BYTE_LEN] {
let mut bytes = [0_u8; Self::BYTE_LEN];
self.write_bytes(&mut bytes);
bytes
}
}
#[derive(Clone, Copy, uDebug, Debug, PartialEq, Eq)]
pub struct IpV4Frame<T>
where
T: ByteStruct,
{
pub header: IpV4Header,
pub data: T,
}
impl<T> ByteStructLen for IpV4Frame<T>
where
T: ByteStruct,
{
const BYTE_LEN: usize = IpV4Header::BYTE_LEN + T::BYTE_LEN;
}
impl<T> ByteStruct for IpV4Frame<T>
where
T: ByteStruct,
{
fn read_bytes(bytes: &[u8]) -> Self {
IpV4Frame::<T> {
header: IpV4Header::read_bytes(&bytes[0..IpV4Header::BYTE_LEN]),
data: T::read_bytes(&bytes[IpV4Header::BYTE_LEN..]),
}
}
fn write_bytes(&self, bytes: &mut [u8]) {
self.header.write_bytes(&mut bytes[0..IpV4Header::BYTE_LEN]);
self.data.write_bytes(&mut bytes[IpV4Header::BYTE_LEN..]);
}
}
impl<T> IpV4Frame<T>
where
T: ByteStruct,
{
pub fn to_be_bytes(&self) -> [u8; Self::BYTE_LEN] {
let mut bytes = [0_u8; Self::BYTE_LEN];
self.write_bytes(&mut bytes);
bytes
}
}
#[bitfield(bits = 16)]
#[derive(Clone, Copy, uDebug, Debug, Default, PartialEq, Eq)]
pub struct Fragmentation {
unused: B1,
pub do_not_fragment: B1,
pub more_fragments: B1,
pub offset: B13,
}
impl ByteStructLen for Fragmentation {
const BYTE_LEN: usize = 2;
}
impl ByteStruct for Fragmentation {
fn read_bytes(bytes: &[u8]) -> Self {
let mut bytes_to_read = [0_u8; Fragmentation::BYTE_LEN];
bytes_to_read.copy_from_slice(&bytes[0..=1]);
Fragmentation::from_bytes(bytes_to_read)
}
fn write_bytes(&self, bytes: &mut [u8]) {
let bytes_to_write = self.into_bytes();
bytes[0] = bytes_to_write[0];
bytes[1] = bytes_to_write[1];
}
}
#[bitfield(bits = 8)]
#[derive(Clone, Copy, uDebug, Debug, Default, PartialEq, Eq)]
pub struct VersionAndHeaderLength {
pub header_length: B4,
pub version: B4,
}
impl ByteStructLen for VersionAndHeaderLength {
const BYTE_LEN: usize = 1;
}
impl ByteStruct for VersionAndHeaderLength {
fn read_bytes(bytes: &[u8]) -> Self {
VersionAndHeaderLength::from_bytes([bytes[0]])
}
fn write_bytes(&self, bytes: &mut [u8]) {
bytes[0] = self.into_bytes()[0];
}
}