Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions embassy-net/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## 0.9.0 - 2026-03-10

- raw: Removed unnecessary Driver type parameter from `RawSocket::new`
- `{UdpSocket, IcmpSocket}::send_to_with` support writing less than `max_size` into the buffer by returning the number of bytes written from the closure
- Update embassy-sync 0.8.0

## 0.8.0 - 2026-01-04
Expand Down
33 changes: 21 additions & 12 deletions embassy-net/src/icmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,28 +275,37 @@ impl<'a> IcmpSocket<'a> {
/// Enqueue a packet to be sent to a given remote address with a zero-copy function.
///
/// This method will wait until the buffer can fit the requested size before
/// calling the function to fill its contents.
pub async fn send_to_with<T, F, R>(&mut self, size: usize, remote_endpoint: T, f: F) -> Result<R, SendError>
/// passing it to the closure. The closure returns the number of bytes
/// written into the buffer.
pub async fn send_to_with<T, F, R>(&mut self, max_size: usize, remote_endpoint: T, f: F) -> Result<R, SendError>
where
T: Into<IpAddress>,
F: FnOnce(&mut [u8]) -> R,
F: FnOnce(&mut [u8]) -> (usize, R),
{
// Don't need to wake waker in `with_mut` if the buffer will never fit the icmp tx_buffer.
let send_capacity_too_small = self.with(|s, _| s.payload_send_capacity() < size);
let send_capacity_too_small = self.with(|s, _| s.payload_send_capacity() < max_size);
if send_capacity_too_small {
return Err(SendError::PacketTooLarge);
}

let mut f = Some(f);
let remote_endpoint = remote_endpoint.into();
poll_fn(move |cx| {
self.with_mut(|s, _| match s.send(size, remote_endpoint) {
Ok(buf) => Poll::Ready(Ok({ unwrap!(f.take())(buf) })),
Err(icmp::SendError::BufferFull) => {
s.register_send_waker(cx.waker());
Poll::Pending
self.with_mut(|s, _| {
let mut ret = None;

match s.send_with(max_size, remote_endpoint, |buf| {
let (size, r) = unwrap!(f.take())(buf);
ret = Some(r);
size
}) {
Ok(_n) => Poll::Ready(Ok(unwrap!(ret))),
Err(icmp::SendError::BufferFull) => {
s.register_send_waker(cx.waker());
Poll::Pending
}
Err(icmp::SendError::Unaddressable) => Poll::Ready(Err(SendError::NoRoute)),
}
Err(icmp::SendError::Unaddressable) => Poll::Ready(Err(SendError::NoRoute)),
})
})
.await
Expand Down Expand Up @@ -580,7 +589,7 @@ pub mod ping {
// Send with timeout the ICMP packet filling it with the helper function
let send_result = socket
.send_to_with(ping_repr.buffer_len(), params.target.unwrap(), |buf| {
fill_packet_buffer(buf, ping_repr)
(buf.len(), fill_packet_buffer(buf, ping_repr))
})
.with_timeout(Duration::from_millis(100))
.await;
Expand Down Expand Up @@ -651,7 +660,7 @@ pub mod ping {
// Send with timeout the ICMP packet filling it with the helper function
let send_result = socket
.send_to_with(ping_repr.buffer_len(), params.target.unwrap(), |buf| {
fill_packet_buffer(buf, ping_repr, params)
(buf.len(), fill_packet_buffer(buf, ping_repr, params))
})
.with_timeout(Duration::from_millis(100))
.await;
Expand Down
21 changes: 14 additions & 7 deletions embassy-net/src/udp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,27 +278,34 @@ impl<'a> UdpSocket<'a> {
/// Send a datagram to the specified remote endpoint with a zero-copy function.
///
/// This method will wait until the buffer can fit the requested size before
/// calling the function to fill its contents.
/// passing it to the closure. The closure returns the number of bytes
/// written into the buffer.
///
/// If the socket's send buffer is too small to fit `size`, this method will return `Err(SendError::PacketTooLarge)`
/// If the socket's send buffer is too small to fit `max_size`, this method will return `Err(SendError::PacketTooLarge)`
///
/// When the remote endpoint is not reachable, this method will return `Err(SendError::NoRoute)`
pub async fn send_to_with<T, F, R>(&mut self, size: usize, remote_endpoint: T, f: F) -> Result<R, SendError>
pub async fn send_to_with<T, F, R>(&mut self, max_size: usize, remote_endpoint: T, f: F) -> Result<R, SendError>
where
T: Into<UdpMetadata> + Copy,
F: FnOnce(&mut [u8]) -> R,
F: FnOnce(&mut [u8]) -> (usize, 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.with(|s, _| s.payload_send_capacity() < size);
let send_capacity_too_small = self.with(|s, _| s.payload_send_capacity() < max_size);
if send_capacity_too_small {
return Err(SendError::PacketTooLarge);
}

let mut f = Some(f);
poll_fn(move |cx| {
self.with_mut(|s, _| {
match s.send(size, remote_endpoint) {
Ok(buffer) => Poll::Ready(Ok(unwrap!(f.take())(buffer))),
let mut ret = None;

match s.send_with(max_size, remote_endpoint, |buf| {
let (size, r) = unwrap!(f.take())(buf);
ret = Some(r);
size
}) {
Ok(_n) => Poll::Ready(Ok(unwrap!(ret))),
Err(udp::SendError::BufferFull) => {
s.register_send_waker(cx.waker());
Poll::Pending
Expand Down
2 changes: 1 addition & 1 deletion examples/rp/src/bin/ethernet_w5500_icmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ async fn main(spawner: Spawner) {
// Create and populate the packet buffer allocated by `send_to_with`
let mut icmp_packet = Icmpv4Packet::new_unchecked(buf);
icmp_repr.emit(&mut icmp_packet, &ChecksumCapabilities::default());
Instant::now() // Return the instant where the packet was sent
(icmp_repr.buffer_len(), Instant::now()) // Return the instant where the packet was sent
})
.await
.unwrap();
Expand Down
2 changes: 1 addition & 1 deletion examples/rp235x/src/bin/ethernet_w5500_icmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ async fn main(spawner: Spawner) {
// Create and populate the packet buffer allocated by `send_to_with`
let mut icmp_packet = Icmpv4Packet::new_unchecked(buf);
icmp_repr.emit(&mut icmp_packet, &ChecksumCapabilities::default());
Instant::now() // Return the instant where the packet was sent
(icmp_repr.buffer_len(), Instant::now()) // Return the instant where the packet was sent
})
.await
.unwrap();
Expand Down