diff --git a/CHANGELOG.md b/CHANGELOG.md index fe4c24a..0ee800e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ This document describes the changes to smoltcp-nal between releases. # [Unreleased] ## Added +* Implemented full UDP socket + ## Fixed # [0.2.1] diff --git a/src/lib.rs b/src/lib.rs index 981d69c..220bf23 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ pub use embedded_nal; use nanorand::Rng; pub use smoltcp; -use embedded_nal::{TcpClientStack, UdpClientStack}; +use embedded_nal::{TcpClientStack, UdpClientStack, UdpFullStack}; use embedded_time::duration::Milliseconds; use smoltcp::{ iface::SocketHandle, @@ -644,3 +644,65 @@ where Ok(()) } } + +impl<'a, DeviceT, Clock> UdpFullStack for NetworkStack<'a, DeviceT, Clock> +where + DeviceT: for<'x> smoltcp::phy::Device<'x>, + Clock: embedded_time::Clock, + u32: From, +{ + /// Bind a UDP socket to a specific port. + fn bind(&mut self, socket: &mut UdpSocket, local_port: u16) -> Result<(), NetworkError> { + if self.is_ip_unspecified() { + return Err(NetworkError::NoIpAddress); + } + + let local_address = self + .network_interface + .ip_addrs() + .iter() + .find(|item| matches!(item, smoltcp::wire::IpCidr::Ipv4(_))) + .unwrap() + .address(); + + let local_endpoint = IpEndpoint::new(local_address, local_port); + + let internal_socket: &mut smoltcp::socket::UdpSocket = + self.network_interface.get_socket(socket.handle); + internal_socket + .bind(local_endpoint) + .map_err(|_| NetworkError::ConnectionFailure)?; + + Ok(()) + } + + /// Send a packet to a remote host/port. + fn send_to( + &mut self, + socket: &mut Self::UdpSocket, + remote: embedded_nal::SocketAddr, + buffer: &[u8], + ) -> embedded_nal::nb::Result<(), NetworkError> { + if self.is_ip_unspecified() { + return Err(embedded_nal::nb::Error::Other(NetworkError::NoIpAddress)); + } + + let destination = match remote { + embedded_nal::SocketAddr::V4(addr) => { + let octets = addr.ip().octets(); + IpEndpoint::new( + IpAddress::v4(octets[0], octets[1], octets[2], octets[3]), + addr.port(), + ) + } + // We only support IPv4. + _ => return Err(embedded_nal::nb::Error::Other(NetworkError::Unsupported)), + }; + + let internal_socket: &mut smoltcp::socket::UdpSocket = + self.network_interface.get_socket(socket.handle); + internal_socket + .send_slice(buffer, destination) + .map_err(|_| embedded_nal::nb::Error::Other(NetworkError::WriteFailure)) + } +} diff --git a/src/shared.rs b/src/shared.rs index 109acf5..7584c60 100644 --- a/src/shared.rs +++ b/src/shared.rs @@ -86,6 +86,14 @@ where forward! {close(socket: S::UdpSocket) -> Result<(), S::Error>} } +impl<'a, S> embedded_nal::UdpFullStack for NetworkStackProxy<'a, S> +where + S: embedded_nal::UdpFullStack, +{ + forward! {send_to(socket: &mut S::UdpSocket, remote: embedded_nal::SocketAddr, buffer: &[u8]) -> embedded_nal::nb::Result<(), S::Error>} + forward! {bind(socket: &mut S::UdpSocket, local_port: u16) -> Result<(), S::Error>} +} + impl<'a, DeviceT, Clock> NetworkManager<'a, DeviceT, Clock> where DeviceT: for<'x> smoltcp::phy::Device<'x>,