summaryrefslogtreecommitdiff
path: root/src/iface/socket_meta.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/iface/socket_meta.rs')
-rw-r--r--src/iface/socket_meta.rs103
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,
+ };
+ }
+}