ergot_base/interface_manager/profiles/direct_edge/
mod.rs

1//! "Edge" device profile
2//!
3//! Edge devices are the second simplest device profile, and are intended for devices
4//! that are on the "edge" of a network, e.g. they have a single upstream connection
5//! to a bridge or seed router.
6//!
7//! These devices use as many tricks as possible to be as simple as possible. They
8//! initially start not knowing their network ID, and if a packet is sent to them,
9//! they assume the destination net ID is their net ID. They will also blindly send
10//! any outgoing packets, rather than trying to determine whether that packet is
11//! actually routable to a node on the network.
12
13use log::{debug, trace};
14use serde::Serialize;
15
16#[cfg(feature = "embassy-usb-v0_4")]
17pub mod eusb_0_4;
18
19#[cfg(feature = "embassy-usb-v0_5")]
20pub mod eusb_0_5;
21
22#[cfg(feature = "std")]
23pub mod std_tcp;
24
25use crate::{
26    Header, ProtocolError,
27    interface_manager::{
28        Interface, InterfaceSendError, InterfaceSink, InterfaceState, Profile, SetStateError,
29    },
30    wire_frames::CommonHeader,
31};
32
33pub const CENTRAL_NODE_ID: u8 = 1;
34pub const EDGE_NODE_ID: u8 = 2;
35
36pub enum SetNetIdError {
37    CantSetZero,
38    NoActiveSink,
39}
40
41// TODO: call this something like "point to point edge"
42pub struct DirectEdge<I: Interface> {
43    sink: I::Sink,
44    seq_no: u16,
45    state: InterfaceState,
46    own_node_id: u8,
47    other_node_id: u8,
48}
49
50impl<I: Interface> DirectEdge<I> {
51    pub const fn new_target(sink: I::Sink) -> Self {
52        Self {
53            sink,
54            seq_no: 0,
55            state: InterfaceState::Down,
56            own_node_id: EDGE_NODE_ID,
57            other_node_id: CENTRAL_NODE_ID,
58        }
59    }
60
61    pub const fn new_controller(sink: I::Sink, state: InterfaceState) -> Self {
62        Self {
63            sink,
64            seq_no: 0,
65            state,
66            own_node_id: CENTRAL_NODE_ID,
67            other_node_id: EDGE_NODE_ID,
68        }
69    }
70}
71
72impl<I: Interface> DirectEdge<I> {
73    fn common_send<'b>(
74        &'b mut self,
75        ihdr: &Header,
76    ) -> Result<(&'b mut I::Sink, CommonHeader), InterfaceSendError> {
77        let net_id = match &self.state {
78            InterfaceState::Down | InterfaceState::Inactive => {
79                return Err(InterfaceSendError::NoRouteToDest);
80            }
81            InterfaceState::ActiveLocal { .. } => {
82                // TODO: maybe also handle this?
83                return Err(InterfaceSendError::NoRouteToDest);
84            }
85            InterfaceState::Active { net_id, node_id: _ } => *net_id,
86        };
87
88        trace!("common_send header: {:?}", ihdr);
89
90        if net_id == 0 {
91            debug!("Attempted to send via interface before we have been assigned a net ID");
92            // No net_id yet, don't allow routing (todo: maybe broadcast?)
93            return Err(InterfaceSendError::NoRouteToDest);
94        }
95        // todo: we could probably keep a routing table of some kind, but for
96        // now, we treat this as a "default" route, all packets go
97
98        // TODO: a LOT of this is copy/pasted from the router, can we make this
99        // shared logic, or handled by the stack somehow?
100        if ihdr.dst.network_id == net_id && ihdr.dst.node_id == self.own_node_id {
101            return Err(InterfaceSendError::DestinationLocal);
102        }
103
104        // Now that we've filtered out "dest local" checks, see if there is
105        // any TTL left before we send to the next hop
106        let mut hdr = ihdr.clone();
107        hdr.decrement_ttl()?;
108
109        // If the source is local, rewrite the source using this interface's
110        // information so responses can find their way back here
111        if hdr.src.net_node_any() {
112            // todo: if we know the destination is EXACTLY this network,
113            // we could leave the network_id local to allow for shorter
114            // addresses
115            hdr.src.network_id = net_id;
116            hdr.src.node_id = self.own_node_id;
117        }
118
119        // If this is a broadcast message, update the destination, ignoring
120        // whatever was there before
121        if hdr.dst.port_id == 255 {
122            hdr.dst.network_id = net_id;
123            hdr.dst.node_id = self.other_node_id;
124        }
125
126        let seq_no = self.seq_no;
127        self.seq_no = self.seq_no.wrapping_add(1);
128
129        let header = CommonHeader {
130            src: hdr.src,
131            dst: hdr.dst,
132            seq_no,
133            kind: hdr.kind,
134            ttl: hdr.ttl,
135        };
136        if [0, 255].contains(&hdr.dst.port_id) && ihdr.any_all.is_none() {
137            return Err(InterfaceSendError::AnyPortMissingKey);
138        }
139
140        Ok((&mut self.sink, header))
141    }
142}
143
144impl<I: Interface> Profile for DirectEdge<I> {
145    type InterfaceIdent = ();
146
147    fn send<T: Serialize>(&mut self, hdr: &Header, data: &T) -> Result<(), InterfaceSendError> {
148        let (intfc, header) = self.common_send(hdr)?;
149
150        let res = intfc.send_ty(&header, hdr.any_all.as_ref(), data);
151
152        match res {
153            Ok(()) => Ok(()),
154            Err(()) => Err(InterfaceSendError::InterfaceFull),
155        }
156    }
157
158    fn send_err(&mut self, hdr: &Header, err: ProtocolError) -> Result<(), InterfaceSendError> {
159        let (intfc, header) = self.common_send(hdr)?;
160
161        let res = intfc.send_err(&header, err);
162
163        match res {
164            Ok(()) => Ok(()),
165            Err(()) => Err(InterfaceSendError::InterfaceFull),
166        }
167    }
168
169    fn send_raw(
170        &mut self,
171        hdr: &Header,
172        hdr_raw: &[u8],
173        data: &[u8],
174    ) -> Result<(), InterfaceSendError> {
175        let (intfc, header) = self.common_send(hdr)?;
176
177        let res = intfc.send_raw(&header, hdr_raw, data);
178
179        match res {
180            Ok(()) => Ok(()),
181            Err(()) => Err(InterfaceSendError::InterfaceFull),
182        }
183    }
184
185    fn interface_state(&mut self, _ident: ()) -> Option<InterfaceState> {
186        Some(self.state)
187    }
188
189    fn set_interface_state(
190        &mut self,
191        _ident: (),
192        state: InterfaceState,
193    ) -> Result<(), SetStateError> {
194        match state {
195            InterfaceState::Down => {
196                self.state = InterfaceState::Down;
197            }
198            InterfaceState::Inactive => {
199                self.state = InterfaceState::Inactive;
200            }
201            InterfaceState::ActiveLocal { node_id } => {
202                if node_id != self.own_node_id {
203                    return Err(SetStateError::InvalidNodeId);
204                }
205                self.state = InterfaceState::ActiveLocal { node_id };
206            }
207            InterfaceState::Active { net_id, node_id } => {
208                if node_id != self.own_node_id {
209                    return Err(SetStateError::InvalidNodeId);
210                }
211                self.state = InterfaceState::Active { net_id, node_id };
212            }
213        }
214        Ok(())
215    }
216}