use alloc::vec::Vec;
use core::convert::Infallible as Never;
use net_types::ip::{Ip, IpVersion, Mtu};
use packet::{Buf, BufferMut, Serializer};
use tracing::warn;
use crate::{
context::{CoreTimerContext, ResourceCounterContext, TimerContext},
device::{
self,
queue::{
tx::{BufVecU8Allocator, TransmitQueue, TransmitQueueHandler},
TransmitQueueFrameError,
},
state::DeviceStateSpec,
BaseDeviceId, BasePrimaryDeviceId, BaseWeakDeviceId, Device, DeviceCounters,
DeviceIdContext, DeviceLayerTypes, DeviceReceiveFrameSpec, DeviceSendFrameError,
PureIpDeviceCounters,
},
sync::RwLock,
};
mod integration;
pub type PureIpWeakDeviceId<BT> = BaseWeakDeviceId<PureIpDevice, BT>;
pub type PureIpDeviceId<BT> = BaseDeviceId<PureIpDevice, BT>;
pub(crate) type PureIpPrimaryDeviceId<BT> = BasePrimaryDeviceId<PureIpDevice, BT>;
#[derive(Copy, Clone)]
pub enum PureIpDevice {}
#[derive(Debug)]
pub struct PureIpDeviceCreationProperties {
pub mtu: Mtu,
}
pub struct PureIpDeviceTxQueueFrameMetadata {
ip_version: IpVersion,
}
#[derive(Debug, PartialEq)]
pub struct PureIpHeaderParams {
pub ip_version: IpVersion,
}
pub struct PureIpDeviceState {
dynamic_state: RwLock<DynamicPureIpDeviceState>,
tx_queue: TransmitQueue<PureIpDeviceTxQueueFrameMetadata, Buf<Vec<u8>>, BufVecU8Allocator>,
counters: PureIpDeviceCounters,
}
pub(crate) struct DynamicPureIpDeviceState {
pub(crate) mtu: Mtu,
}
impl Device for PureIpDevice {}
impl DeviceStateSpec for PureIpDevice {
type Link<BT: DeviceLayerTypes> = PureIpDeviceState;
type External<BT: DeviceLayerTypes> = BT::PureIpDeviceState;
type CreationProperties = PureIpDeviceCreationProperties;
type Counters = PureIpDeviceCounters;
const IS_LOOPBACK: bool = false;
const DEBUG_TYPE: &'static str = "PureIP";
type TimerId<D: device::WeakId> = Never;
fn new_link_state<
CC: CoreTimerContext<Self::TimerId<CC::WeakDeviceId>, BC> + DeviceIdContext<Self>,
BC: DeviceLayerTypes + TimerContext,
>(
_bindings_ctx: &mut BC,
_self_id: CC::WeakDeviceId,
PureIpDeviceCreationProperties { mtu }: Self::CreationProperties,
) -> Self::Link<BC> {
PureIpDeviceState {
dynamic_state: RwLock::new(DynamicPureIpDeviceState { mtu }),
tx_queue: Default::default(),
counters: PureIpDeviceCounters::default(),
}
}
}
pub struct PureIpDeviceReceiveFrameMetadata<D> {
pub device_id: D,
pub ip_version: IpVersion,
}
impl DeviceReceiveFrameSpec for PureIpDevice {
type FrameMetadata<D> = PureIpDeviceReceiveFrameMetadata<D>;
}
pub(crate) trait PureIpDeviceStateContext: DeviceIdContext<PureIpDevice> {
fn with_pure_ip_state<O, F: FnOnce(&DynamicPureIpDeviceState) -> O>(
&mut self,
device_id: &Self::DeviceId,
cb: F,
) -> O;
fn with_pure_ip_state_mut<O, F: FnOnce(&mut DynamicPureIpDeviceState) -> O>(
&mut self,
device_id: &Self::DeviceId,
cb: F,
) -> O;
}
pub(super) fn send_ip_frame<CC, BC, I, S>(
core_ctx: &mut CC,
bindings_ctx: &mut BC,
device_id: &CC::DeviceId,
packet: S,
) -> Result<(), S>
where
CC: TransmitQueueHandler<PureIpDevice, BC, Meta = PureIpDeviceTxQueueFrameMetadata>
+ ResourceCounterContext<CC::DeviceId, DeviceCounters>,
I: Ip,
S: Serializer,
S::Buffer: BufferMut,
{
core_ctx.increment(device_id, |counters| &counters.send_total_frames);
match I::VERSION {
IpVersion::V4 => core_ctx.increment(device_id, |counters| &counters.send_ipv4_frame),
IpVersion::V6 => core_ctx.increment(device_id, |counters| &counters.send_ipv6_frame),
}
let result = TransmitQueueHandler::<PureIpDevice, _>::queue_tx_frame(
core_ctx,
bindings_ctx,
device_id,
PureIpDeviceTxQueueFrameMetadata { ip_version: I::VERSION },
packet,
);
match result {
Ok(()) => {
core_ctx.increment(device_id, |counters| &counters.send_frame);
Ok(())
}
Err(TransmitQueueFrameError::NoQueue(DeviceSendFrameError::DeviceNotReady(()))) => {
core_ctx.increment(device_id, |counters| &counters.send_dropped_no_queue);
warn!("device {device_id:?} not ready to send frame.");
Ok(())
}
Err(TransmitQueueFrameError::QueueFull(s)) => {
core_ctx.increment(device_id, |counters| &counters.send_queue_full);
Err(s)
}
Err(TransmitQueueFrameError::SerializeError(s)) => {
core_ctx.increment(device_id, |counters| &counters.send_serialize_error);
Err(s)
}
}
}
pub(super) fn get_mtu<CC: PureIpDeviceStateContext>(
core_ctx: &mut CC,
device_id: &CC::DeviceId,
) -> Mtu {
core_ctx.with_pure_ip_state(device_id, |DynamicPureIpDeviceState { mtu }| *mtu)
}
pub(super) fn set_mtu<CC: PureIpDeviceStateContext>(
core_ctx: &mut CC,
device_id: &CC::DeviceId,
new_mtu: Mtu,
) {
core_ctx.with_pure_ip_state_mut(device_id, |DynamicPureIpDeviceState { mtu }| *mtu = new_mtu)
}