From 2fe299cc538c28711fd838b5f2c3da6143a7335e Mon Sep 17 00:00:00 2001 From: Easyoakland <97992568+Easyoakland@users.noreply.github.com> Date: Fri, 24 Jan 2025 18:45:43 -0700 Subject: [PATCH 1/2] don't infinite loop if udp::send methods receive a buffer too large to ever be sent --- embassy-net/src/udp.rs | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index 64a22d45b9..7baa89ea0b 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs @@ -21,7 +21,7 @@ pub enum BindError { NoRoute, } -/// Error returned by [`UdpSocket::recv_from`] and [`UdpSocket::send_to`]. +/// Error returned by [`UdpSocket::send_to`]. #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum SendError { @@ -29,9 +29,11 @@ pub enum SendError { NoRoute, /// Socket not bound to an outgoing port. SocketNotBound, + /// There is not enough transmit buffer capacity to ever send this packet. + Truncated, } -/// Error returned by [`UdpSocket::recv_from`] and [`UdpSocket::send_to`]. +/// Error returned by [`UdpSocket::recv_from`]. #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum RecvError { @@ -224,6 +226,8 @@ impl<'a> UdpSocket<'a> { /// /// This method will wait until the datagram has been sent. /// + /// If the socket's send buffer is too small to fit `buf`, this method will return `Poll::Ready(Err(SendError::Truncated))` + /// /// When the remote endpoint is not reachable, this method will return `Err(SendError::NoRoute)` pub async fn send_to(&self, buf: &[u8], remote_endpoint: T) -> Result<(), SendError> where @@ -240,11 +244,21 @@ impl<'a> UdpSocket<'a> { /// When the socket's send buffer is full, this method will return `Poll::Pending` /// and register the current task to be notified when the buffer has space available. /// + /// If the socket's send buffer is too small to fit `buf`, this method will return `Poll::Ready(Err(SendError::Truncated))` + /// /// When the remote endpoint is not reachable, this method will return `Poll::Ready(Err(Error::NoRoute))`. pub fn poll_send_to(&self, buf: &[u8], remote_endpoint: T, cx: &mut Context<'_>) -> Poll> where T: Into, { + // Don't need to wake waker in `with_mut` if the buffer will never fit the udp tx_buffer. + let send_capacity_too_small = self + .stack + .with(|i| i.sockets.get::(self.handle).payload_send_capacity() < buf.len()); + if send_capacity_too_small { + return Poll::Ready(Err(SendError::Truncated)); + } + self.with_mut(|s, _| match s.send_slice(buf, remote_endpoint) { // Entire datagram has been sent Ok(()) => Poll::Ready(Ok(())), @@ -268,12 +282,22 @@ impl<'a> UdpSocket<'a> { /// This method will wait until the buffer can fit the requested size before /// calling the function to fill its contents. /// + /// If the socket's send buffer is too small to fit `size`, this method will return `Poll::Ready(Err(SendError::Truncated))` + /// /// When the remote endpoint is not reachable, this method will return `Err(SendError::NoRoute)` pub async fn send_to_with(&mut self, size: usize, remote_endpoint: T, f: F) -> Result where T: Into + Copy, F: FnOnce(&mut [u8]) -> R, { + // Don't need to wake waker in `with_mut` if the buffer will never fit the udp tx_buffer. + let send_capacity_too_small = self + .stack + .with(|i| i.sockets.get::(self.handle).payload_send_capacity() < size); + if send_capacity_too_small { + return Err(SendError::Truncated); + } + let mut f = Some(f); poll_fn(move |cx| { self.with_mut(|s, _| { From c0d14a145c901126a548a77026ef2ef0d6e79738 Mon Sep 17 00:00:00 2001 From: Easyoakland <97992568+Easyoakland@users.noreply.github.com> Date: Sun, 26 Jan 2025 15:51:31 -0700 Subject: [PATCH 2/2] - use `with` - rename to Truncated to `PacketTooLarge` --- embassy-net/src/udp.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index 7baa89ea0b..eca3980b9f 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs @@ -30,7 +30,7 @@ pub enum SendError { /// Socket not bound to an outgoing port. SocketNotBound, /// There is not enough transmit buffer capacity to ever send this packet. - Truncated, + PacketTooLarge, } /// Error returned by [`UdpSocket::recv_from`]. @@ -252,11 +252,9 @@ impl<'a> UdpSocket<'a> { T: Into, { // Don't need to wake waker in `with_mut` if the buffer will never fit the udp tx_buffer. - let send_capacity_too_small = self - .stack - .with(|i| i.sockets.get::(self.handle).payload_send_capacity() < buf.len()); + let send_capacity_too_small = self.with(|s, _| s.payload_send_capacity() < buf.len()); if send_capacity_too_small { - return Poll::Ready(Err(SendError::Truncated)); + return Poll::Ready(Err(SendError::PacketTooLarge)); } self.with_mut(|s, _| match s.send_slice(buf, remote_endpoint) { @@ -291,11 +289,9 @@ impl<'a> UdpSocket<'a> { F: FnOnce(&mut [u8]) -> R, { // Don't need to wake waker in `with_mut` if the buffer will never fit the udp tx_buffer. - let send_capacity_too_small = self - .stack - .with(|i| i.sockets.get::(self.handle).payload_send_capacity() < size); + let send_capacity_too_small = self.with(|s, _| s.payload_send_capacity() < size); if send_capacity_too_small { - return Err(SendError::Truncated); + return Err(SendError::PacketTooLarge); } let mut f = Some(f);