use alloc::{boxed::Box, sync::Arc, vec::Vec};
pub use rd_net::{DmaBuffer, RxCompletion, TxChecksumCapabilities, TxNotify, TxSubmitOptions};
pub(crate) const ETH_ZLEN: usize = 60;
pub(crate) const ETHERNET_FRAME_CAPACITY: usize = 2048;
#[derive(Clone, Copy, Debug, Eq, PartialEq, thiserror::Error)]
pub enum NetDeviceError {
#[error("network frame port should be retried")]
Again,
#[error("network frame port is stopped")]
Stopped,
#[error("invalid network frame size")]
InvalidParam,
#[error("network frame port I/O failed")]
Io,
#[error("network frame port memory allocation failed")]
NoMemory,
}
pub type NetDeviceResult<T = ()> = Result<T, NetDeviceError>;
#[derive(Clone)]
pub struct ProtocolEthernetFrame {
bytes: [u8; ETHERNET_FRAME_CAPACITY],
len: usize,
}
impl ProtocolEthernetFrame {
pub fn new(len: usize) -> NetDeviceResult<Self> {
if len > ETHERNET_FRAME_CAPACITY {
return Err(NetDeviceError::InvalidParam);
}
Ok(Self {
bytes: [0; ETHERNET_FRAME_CAPACITY],
len,
})
}
pub fn packet(&self) -> &[u8] {
&self.bytes[..self.len]
}
pub fn packet_mut(&mut self) -> &mut [u8] {
&mut self.bytes[..self.len]
}
pub fn packet_len(&self) -> usize {
self.len
}
pub(crate) fn copy_from_slice(packet: &[u8]) -> NetDeviceResult<Self> {
let mut frame = Self::new(packet.len())?;
frame.packet_mut().copy_from_slice(packet);
Ok(frame)
}
}
pub(crate) trait RxBufferRecycler: Send + Sync {
fn recycle(&self, buffer: DmaBuffer);
}
pub struct ProtocolRxFrame {
completion: Option<RxCompletion>,
recycler: Arc<dyn RxBufferRecycler>,
}
impl ProtocolRxFrame {
pub(crate) fn new(completion: RxCompletion, recycler: Arc<dyn RxBufferRecycler>) -> Self {
debug_assert!(completion.packet_len <= completion.buffer.capacity());
Self {
completion: Some(completion),
recycler,
}
}
pub fn packet_len(&self) -> usize {
self.completion
.as_ref()
.expect("owned RX frame lost its DMA token")
.packet_len
}
pub fn read_with<R>(&self, consume: impl FnOnce(&[u8]) -> R) -> R {
let completion = self
.completion
.as_ref()
.expect("owned RX frame lost its DMA token");
completion
.buffer
.read_with_cpu(completion.packet_len, consume)
}
}
impl Drop for ProtocolRxFrame {
fn drop(&mut self) {
if let Some(completion) = self.completion.take() {
self.recycler.recycle(completion.buffer);
}
}
}
pub trait EthernetFramePort: Send + 'static {
fn device_name(&self) -> &str;
fn mac_address(&self) -> [u8; 6];
fn checksum_capabilities(&self) -> TxChecksumCapabilities {
TxChecksumCapabilities::NONE
}
fn transmit(&mut self, frame: &ProtocolEthernetFrame) -> NetDeviceResult;
fn transmit_frame_with_options(
&mut self,
frame_len: usize,
options: TxSubmitOptions,
fill: &mut dyn FnMut(&mut [u8]),
) -> NetDeviceResult {
if options.checksum.is_some() {
return Err(NetDeviceError::InvalidParam);
}
let mut frame = ProtocolEthernetFrame::new(frame_len)?;
fill(frame.packet_mut());
self.transmit(&frame)
}
fn receive(&mut self) -> NetDeviceResult<ProtocolEthernetFrame>;
fn drain_rx_drops(&mut self) -> u64 {
0
}
fn receive_owned(&mut self) -> NetDeviceResult<Option<ProtocolRxFrame>> {
Ok(None)
}
fn receive_with(&mut self, consume: &mut dyn FnMut(&[u8]) -> usize) -> NetDeviceResult<usize> {
let frame = self.receive()?;
Ok(consume(frame.packet()))
}
}
pub type EthernetFramePortList = Vec<Box<dyn EthernetFramePort>>;