use crate::logging::{debug, trace, warn};
use serde::Serialize;
#[cfg(feature = "embedded-io-async-v0_6")]
pub mod eio_0_6;
#[cfg(feature = "embassy-usb-v0_5")]
pub mod eusb_0_5;
#[cfg(feature = "tokio-std")]
pub mod tokio_tcp;
#[cfg(feature = "tokio-std")]
pub mod tokio_udp;
#[cfg(feature = "embassy-net-v0_7")]
pub mod embassy_net_udp_0_7;
use crate::{
Header, HeaderSeq, ProtocolError,
interface_manager::{
Interface, InterfaceSendError, InterfaceSink, InterfaceState, Profile, SetStateError,
},
net_stack::NetStackHandle,
wire_frames::de_frame,
};
pub const CENTRAL_NODE_ID: u8 = 1;
pub const EDGE_NODE_ID: u8 = 2;
pub enum SetNetIdError {
CantSetZero,
NoActiveSink,
}
pub struct DirectEdge<I: Interface> {
sink: I::Sink,
seq_no: u16,
state: InterfaceState,
own_node_id: u8,
other_node_id: u8,
}
impl<I: Interface> DirectEdge<I> {
pub const fn new_target(sink: I::Sink) -> Self {
Self {
sink,
seq_no: 0,
state: InterfaceState::Down,
own_node_id: EDGE_NODE_ID,
other_node_id: CENTRAL_NODE_ID,
}
}
pub const fn new_controller(sink: I::Sink, state: InterfaceState) -> Self {
Self {
sink,
seq_no: 0,
state,
own_node_id: CENTRAL_NODE_ID,
other_node_id: EDGE_NODE_ID,
}
}
}
impl<I: Interface> DirectEdge<I> {
fn common_send<'b>(
&'b mut self,
hdr: &Header,
) -> Result<(&'b mut I::Sink, HeaderSeq), InterfaceSendError> {
let net_id = match &self.state {
InterfaceState::Down => {
trace!("{}: ignoring send, interface down", hdr);
return Err(InterfaceSendError::NoRouteToDest);
}
InterfaceState::Inactive => {
trace!("{}: ignoring send, interface inactive", hdr);
return Err(InterfaceSendError::NoRouteToDest);
}
InterfaceState::ActiveLocal { .. } => {
trace!("{}: ignoring send, interface local only", hdr);
return Err(InterfaceSendError::NoRouteToDest);
}
InterfaceState::Active { net_id, node_id: _ } => *net_id,
};
trace!("{}: common_send", hdr);
if net_id == 0 {
debug!("Attempted to send via interface before we have been assigned a net ID");
return Err(InterfaceSendError::NoRouteToDest);
}
if hdr.dst.network_id == net_id && hdr.dst.node_id == self.own_node_id {
return Err(InterfaceSendError::DestinationLocal);
}
let mut hdr = hdr.clone();
hdr.decrement_ttl()?;
if hdr.src.net_node_any() {
hdr.src.network_id = net_id;
hdr.src.node_id = self.own_node_id;
}
if hdr.dst.port_id == 255 {
hdr.dst.network_id = net_id;
hdr.dst.node_id = self.other_node_id;
}
let header = hdr.to_headerseq_or_with_seq(|| {
let seq_no = self.seq_no;
self.seq_no = self.seq_no.wrapping_add(1);
seq_no
});
if [0, 255].contains(&hdr.dst.port_id) && hdr.any_all.is_none() {
return Err(InterfaceSendError::AnyPortMissingKey);
}
Ok((&mut self.sink, header))
}
}
impl<I: Interface> Profile for DirectEdge<I> {
type InterfaceIdent = ();
fn send<T: Serialize>(&mut self, hdr: &Header, data: &T) -> Result<(), InterfaceSendError> {
let (intfc, header) = self.common_send(hdr)?;
let res = intfc.send_ty(&header, data);
match res {
Ok(()) => Ok(()),
Err(()) => Err(InterfaceSendError::InterfaceFull),
}
}
fn send_err(
&mut self,
hdr: &Header,
err: ProtocolError,
source: Option<Self::InterfaceIdent>,
) -> Result<(), InterfaceSendError> {
if source.is_some() {
return Err(InterfaceSendError::RoutingLoop);
}
let (intfc, header) = self.common_send(hdr)?;
let res = intfc.send_err(&header, err);
match res {
Ok(()) => Ok(()),
Err(()) => Err(InterfaceSendError::InterfaceFull),
}
}
fn send_raw(
&mut self,
_hdr: &HeaderSeq,
_data: &[u8],
_source: Self::InterfaceIdent,
) -> Result<(), InterfaceSendError> {
Err(InterfaceSendError::RoutingLoop)
}
fn interface_state(&mut self, _ident: ()) -> Option<InterfaceState> {
Some(self.state)
}
fn set_interface_state(
&mut self,
_ident: (),
state: InterfaceState,
) -> Result<(), SetStateError> {
match state {
InterfaceState::Down => {
self.state = InterfaceState::Down;
}
InterfaceState::Inactive => {
self.state = InterfaceState::Inactive;
}
InterfaceState::ActiveLocal { node_id } => {
if node_id != self.own_node_id {
return Err(SetStateError::InvalidNodeId);
}
self.state = InterfaceState::ActiveLocal { node_id };
}
InterfaceState::Active { net_id, node_id } => {
if node_id != self.own_node_id {
return Err(SetStateError::InvalidNodeId);
}
self.state = InterfaceState::Active { net_id, node_id };
}
}
Ok(())
}
}
pub fn process_frame<N>(
net_id: &mut Option<u16>,
data: &[u8],
nsh: &N,
ident: <<N as NetStackHandle>::Profile as Profile>::InterfaceIdent,
) where
N: NetStackHandle,
{
let Some(mut frame) = de_frame(data) else {
warn!(
"Decode error! Ignoring frame on net_id {}",
net_id.unwrap_or(0)
);
return;
};
debug!("{}: Got Frame!", frame.hdr);
let take_net = net_id.is_none()
|| net_id.is_some_and(|n| frame.hdr.dst.network_id != 0 && n != frame.hdr.dst.network_id);
if take_net {
nsh.stack().manage_profile(|im| {
im.set_interface_state(
ident.clone(),
InterfaceState::Active {
net_id: frame.hdr.dst.network_id,
node_id: EDGE_NODE_ID,
},
)
.unwrap();
});
*net_id = Some(frame.hdr.dst.network_id);
}
if let Some(net) = net_id.as_ref()
&& frame.hdr.src.network_id == 0
{
assert_ne!(frame.hdr.src.node_id, 0, "we got a local packet remotely?");
assert_ne!(frame.hdr.src.node_id, 2, "someone is pretending to be us?");
frame.hdr.src.network_id = *net;
}
let res = match frame.body {
Ok(body) => nsh.stack().send_raw(&frame.hdr, body, ident),
Err(e) => {
let nshdr: Header = frame.hdr.clone().into();
nsh.stack().send_err(&nshdr, e, Some(ident))
}
};
match res {
Ok(()) => {}
Err(e) => {
warn!("send error: {:?}", e);
}
}
}