diff options
Diffstat (limited to 'src/iface/socket_meta.rs')
-rw-r--r-- | src/iface/socket_meta.rs | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/src/iface/socket_meta.rs b/src/iface/socket_meta.rs new file mode 100644 index 0000000..82c9908 --- /dev/null +++ b/src/iface/socket_meta.rs @@ -0,0 +1,103 @@ +use super::SocketHandle; +use crate::{ + socket::PollAt, + time::{Duration, Instant}, + wire::IpAddress, +}; + +/// Neighbor dependency. +/// +/// This enum tracks whether the socket should be polled based on the neighbor +/// it is going to send packets to. +#[derive(Debug, Default)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +enum NeighborState { + /// Socket can be polled immediately. + #[default] + Active, + /// Socket should not be polled until either `silent_until` passes or + /// `neighbor` appears in the neighbor cache. + Waiting { + neighbor: IpAddress, + silent_until: Instant, + }, +} + +/// Network socket metadata. +/// +/// This includes things that only external (to the socket, that is) code +/// is interested in, but which are more conveniently stored inside the socket +/// itself. +#[derive(Debug, Default)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub(crate) struct Meta { + /// Handle of this socket within its enclosing `SocketSet`. + /// Mainly useful for debug output. + pub(crate) handle: SocketHandle, + /// See [NeighborState](struct.NeighborState.html). + neighbor_state: NeighborState, +} + +impl Meta { + /// Minimum delay between neighbor discovery requests for this particular + /// socket, in milliseconds. + /// + /// See also `iface::NeighborCache::SILENT_TIME`. + pub(crate) const DISCOVERY_SILENT_TIME: Duration = Duration::from_millis(1_000); + + pub(crate) fn poll_at<F>(&self, socket_poll_at: PollAt, has_neighbor: F) -> PollAt + where + F: Fn(IpAddress) -> bool, + { + match self.neighbor_state { + NeighborState::Active => socket_poll_at, + NeighborState::Waiting { neighbor, .. } if has_neighbor(neighbor) => socket_poll_at, + NeighborState::Waiting { silent_until, .. } => PollAt::Time(silent_until), + } + } + + pub(crate) fn egress_permitted<F>(&mut self, timestamp: Instant, has_neighbor: F) -> bool + where + F: Fn(IpAddress) -> bool, + { + match self.neighbor_state { + NeighborState::Active => true, + NeighborState::Waiting { + neighbor, + silent_until, + } => { + if has_neighbor(neighbor) { + net_trace!( + "{}: neighbor {} discovered, unsilencing", + self.handle, + neighbor + ); + self.neighbor_state = NeighborState::Active; + true + } else if timestamp >= silent_until { + net_trace!( + "{}: neighbor {} silence timer expired, rediscovering", + self.handle, + neighbor + ); + true + } else { + false + } + } + } + } + + pub(crate) fn neighbor_missing(&mut self, timestamp: Instant, neighbor: IpAddress) { + net_trace!( + "{}: neighbor {} missing, silencing until t+{}", + self.handle, + neighbor, + Self::DISCOVERY_SILENT_TIME + ); + self.neighbor_state = NeighborState::Waiting { + neighbor, + silent_until: timestamp + Self::DISCOVERY_SILENT_TIME, + }; + } +} |