Skip to content
Open
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
4 changes: 3 additions & 1 deletion embassy-net-wiznet/src/chip/w5500.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ impl super::SealedChip for W5500 {
const SOCKET_INTR: Self::Address = (RegisterBlock::Socket0, 0x02);
const SOCKET_INTR_CLR: Self::Address = (RegisterBlock::Socket0, 0x02);

const SOCKET_MODE_VALUE: u8 = (1 << 2) | (1 << 7);
// Disable filter on mac-address
const SOCKET_MODE_VALUE: u8 = (1 << 2);
// const SOCKET_MODE_VALUE: u8 = (1 << 2) | (1 << 7);

const BUF_SIZE: u16 = 0x4000;
const AUTO_WRAP: bool = true;
Expand Down
11 changes: 9 additions & 2 deletions embassy-net/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ features = ["defmt", "tcp", "udp", "raw", "dns", "icmp", "dhcpv4", "proto-ipv6",

[features]
## Enable defmt
defmt = ["dep:defmt", "smoltcp/defmt", "embassy-net-driver/defmt", "embassy-time/defmt", "heapless/defmt-03", "defmt?/ip_in_core"]
defmt = ["dep:defmt", "smoltcp/defmt", "embassy-net-driver/defmt", "embassy-time/defmt", "heapless/defmt", "defmt?/ip_in_core"]
## Enable log
log = ["dep:log"]

Expand All @@ -69,6 +69,10 @@ icmp = ["smoltcp/socket-icmp"]
udp = ["smoltcp/socket-udp"]
## Enable Raw support
raw = ["smoltcp/socket-raw"]
## Enable Raw Ethernet socket support
# Currently socket-raw is added for compile error in smoll-tcp
# See https://github.com/smoltcp-rs/smoltcp/pull/1013#issuecomment-3327778090
eth = ["smoltcp/socket-eth", "smoltcp/socket-raw"]
## Enable TCP support
tcp = ["smoltcp/socket-tcp"]
## Enable DNS support
Expand Down Expand Up @@ -112,6 +116,9 @@ embassy-sync = { version = "0.7.2", path = "../embassy-sync" }
embedded-io-async = { version = "0.6.1" }

managed = { version = "0.8.0", default-features = false, features = [ "map" ] }
heapless = { version = "0.8", default-features = false }
heapless = { version = "0.9", default-features = false }
embedded-nal-async = "0.8.0"
document-features = "0.2.7"

[patch.crates-io]
smoltcp = { git = "https://github.com/ususdei/smoltcp.git", rev = "c189a2e8832dc7951c7455465f61151b95bb1e21" }
188 changes: 188 additions & 0 deletions embassy-net/src/eth.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
//! Raw Ethernet sockets.

use core::future::{Future, poll_fn};
use core::mem;
use core::task::{Context, Poll};

use smoltcp::iface::{Interface, SocketHandle};
use smoltcp::socket::eth;
pub use smoltcp::socket::eth::EthMetadata;
pub use smoltcp::socket::eth::PacketMetadata;
pub use smoltcp::wire::{IpProtocol, IpVersion};

use crate::Stack;

/// Error returned by [`EthSocket::recv`] and [`EthSocket::send`].
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum RecvError {
/// Provided buffer was smaller than the received packet.
Truncated,
}

/// An Raw Ethernet socket.
pub struct EthSocket<'a> {
stack: Stack<'a>,
handle: SocketHandle,
}

impl<'a> EthSocket<'a> {
/// Create a new Raw Ethernet socket using the provided stack and buffers.
pub fn new(
stack: Stack<'a>,
eth_type: Option<u16>,
rx_meta: &'a mut [PacketMetadata],
rx_buffer: &'a mut [u8],
tx_meta: &'a mut [PacketMetadata],
tx_buffer: &'a mut [u8],
) -> Self {
let handle = stack.with_mut(|i| {
let rx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(rx_meta) };
let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) };
let tx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(tx_meta) };
let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) };
i.sockets.add(eth::Socket::new(
eth_type,
eth::PacketBuffer::new(rx_meta, rx_buffer),
eth::PacketBuffer::new(tx_meta, tx_buffer),
))
});

Self { stack, handle }
}

fn with_mut<R>(&self, f: impl FnOnce(&mut eth::Socket, &mut Interface) -> R) -> R {
self.stack.with_mut(|i| {
let socket = i.sockets.get_mut::<eth::Socket>(self.handle);
let res = f(socket, &mut i.iface);
i.waker.wake();
res
})
}

/// Wait until the socket becomes readable.
///
/// A socket is readable when a packet has been received, or when there are queued packets in
/// the buffer.
pub fn wait_recv_ready(&self) -> impl Future<Output = ()> + '_ {
poll_fn(move |cx| self.poll_recv_ready(cx))
}

/// Receive a datagram.
///
/// This method will wait until a datagram is received.
pub async fn recv(&self, buf: &mut [u8]) -> Result<(usize, EthMetadata), RecvError> {
poll_fn(move |cx| self.poll_recv(buf, cx)).await
}

/// Wait until a datagram can be read.
///
/// When no datagram is readable, this method will return `Poll::Pending` and
/// register the current task to be notified when a datagram is received.
///
/// When a datagram is received, this method will return `Poll::Ready`.
pub fn poll_recv_ready(&self, cx: &mut Context<'_>) -> Poll<()> {
self.with_mut(|s, _| {
if s.can_recv() {
Poll::Ready(())
} else {
// socket buffer is empty wait until at least one byte has arrived
s.register_recv_waker(cx.waker());
Poll::Pending
}
})
}

/// Receive a datagram.
///
/// When no datagram is available, this method will return `Poll::Pending` and
/// register the current task to be notified when a datagram is received.
pub fn poll_recv(&self, buf: &mut [u8], cx: &mut Context<'_>) -> Poll<Result<(usize, EthMetadata), RecvError>> {
self.with_mut(|s, _| match s.recv_slice(buf) {
Ok(n) => Poll::Ready(Ok(n)),
// No data ready
Err(eth::RecvError::Truncated) => Poll::Ready(Err(RecvError::Truncated)),
Err(eth::RecvError::Exhausted) => {
s.register_recv_waker(cx.waker());
Poll::Pending
}
})
}

/// Wait until the socket becomes writable.
///
/// A socket becomes writable when there is space in the buffer, from initial memory or after
/// dispatching datagrams on a full buffer.
pub fn wait_send_ready(&self) -> impl Future<Output = ()> + '_ {
poll_fn(move |cx| self.poll_send_ready(cx))
}

/// Wait until a datagram can be sent.
///
/// When no datagram can be sent (i.e. the buffer is full), this method will return
/// `Poll::Pending` and register the current task to be notified when
/// space is freed in the buffer after a datagram has been dispatched.
///
/// When a datagram can be sent, this method will return `Poll::Ready`.
pub fn poll_send_ready(&self, cx: &mut Context<'_>) -> Poll<()> {
self.with_mut(|s, _| {
if s.can_send() {
Poll::Ready(())
} else {
// socket buffer is full wait until a datagram has been dispatched
s.register_send_waker(cx.waker());
Poll::Pending
}
})
}

/// Send a datagram.
///
/// This method will wait until the datagram has been sent.`
pub fn send<'s>(&'s self, buf: &'s [u8], meta: EthMetadata) -> impl Future<Output = ()> + 's {
poll_fn(move |cx| self.poll_send(buf, cx, meta))
}

/// Send a datagram.
///
/// When the datagram has been sent, this method will return `Poll::Ready(Ok())`.
///
/// 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.
pub fn poll_send(&self, buf: &[u8], cx: &mut Context<'_>, meta: EthMetadata) -> Poll<()> {
self.with_mut(|s, _| match s.send_slice(buf, meta) {
// Entire datagram has been sent
Ok(()) => Poll::Ready(()),
Err(eth::SendError::BufferFull) => {
s.register_send_waker(cx.waker());
Poll::Pending
}
})
}

/// Flush the socket.
///
/// This method will wait until the socket is flushed.
pub fn flush(&mut self) -> impl Future<Output = ()> + '_ {
poll_fn(|cx| {
self.with_mut(|s, _| {
if s.send_queue() == 0 {
Poll::Ready(())
} else {
s.register_send_waker(cx.waker());
Poll::Pending
}
})
})
}
}

impl Drop for EthSocket<'_> {
fn drop(&mut self) {
self.stack.with_mut(|i| i.sockets.remove(self.handle));
}
}

fn _assert_covariant<'a, 'b: 'a>(x: EthSocket<'b>) -> EthSocket<'a> {
x
}
2 changes: 2 additions & 0 deletions embassy-net/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ pub(crate) mod fmt;
#[cfg(feature = "dns")]
pub mod dns;
mod driver_util;
#[cfg(feature = "eth")]
pub mod eth;
#[cfg(feature = "icmp")]
pub mod icmp;
#[cfg(feature = "raw")]
Expand Down
4 changes: 2 additions & 2 deletions embassy-net/src/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ impl<'a> RawSocket<'a> {
/// Create a new Raw socket using the provided stack and buffers.
pub fn new<D: Driver>(
stack: Stack<'a>,
ip_version: IpVersion,
ip_protocol: IpProtocol,
ip_version: Option<IpVersion>,
ip_protocol: Option<IpProtocol>,
rx_meta: &'a mut [PacketMetadata],
rx_buffer: &'a mut [u8],
tx_meta: &'a mut [PacketMetadata],
Expand Down
Loading