diff options
| -rw-r--r-- | embassy-net/Cargo.toml | 6 | ||||
| -rw-r--r-- | embassy-net/src/lib.rs | 2 | ||||
| -rw-r--r-- | embassy-net/src/raw.rs | 178 | ||||
| -rw-r--r-- | examples/rp/Cargo.toml | 2 |
4 files changed, 185 insertions, 3 deletions
diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index be9f1d784..47faaa205 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml | |||
| @@ -16,11 +16,11 @@ categories = [ | |||
| 16 | [package.metadata.embassy_docs] | 16 | [package.metadata.embassy_docs] |
| 17 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/" | 17 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/" |
| 18 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net/src/" | 18 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net/src/" |
| 19 | features = ["defmt", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] | 19 | features = ["defmt", "tcp", "udp","raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] |
| 20 | target = "thumbv7em-none-eabi" | 20 | target = "thumbv7em-none-eabi" |
| 21 | 21 | ||
| 22 | [package.metadata.docs.rs] | 22 | [package.metadata.docs.rs] |
| 23 | features = ["defmt", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] | 23 | features = ["defmt", "tcp", "udp", "raw","dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] |
| 24 | 24 | ||
| 25 | [features] | 25 | [features] |
| 26 | default = [] | 26 | default = [] |
| @@ -38,6 +38,8 @@ packet-trace = [] | |||
| 38 | 38 | ||
| 39 | ## Enable UDP support | 39 | ## Enable UDP support |
| 40 | udp = ["smoltcp/socket-udp"] | 40 | udp = ["smoltcp/socket-udp"] |
| 41 | ## Enable Raw support | ||
| 42 | raw = ["smoltcp/socket-raw"] | ||
| 41 | ## Enable TCP support | 43 | ## Enable TCP support |
| 42 | tcp = ["smoltcp/socket-tcp"] | 44 | tcp = ["smoltcp/socket-tcp"] |
| 43 | ## Enable DNS support | 45 | ## Enable DNS support |
diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 1c0cf1a12..05c8aec7b 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs | |||
| @@ -20,6 +20,8 @@ pub mod tcp; | |||
| 20 | mod time; | 20 | mod time; |
| 21 | #[cfg(feature = "udp")] | 21 | #[cfg(feature = "udp")] |
| 22 | pub mod udp; | 22 | pub mod udp; |
| 23 | #[cfg(feature = "raw")] | ||
| 24 | pub mod raw; | ||
| 23 | 25 | ||
| 24 | use core::cell::RefCell; | 26 | use core::cell::RefCell; |
| 25 | use core::future::{poll_fn, Future}; | 27 | use core::future::{poll_fn, Future}; |
diff --git a/embassy-net/src/raw.rs b/embassy-net/src/raw.rs new file mode 100644 index 000000000..a0e458fff --- /dev/null +++ b/embassy-net/src/raw.rs | |||
| @@ -0,0 +1,178 @@ | |||
| 1 | //! Raw sockets. | ||
| 2 | |||
| 3 | use core::cell::RefCell; | ||
| 4 | use core::future::poll_fn; | ||
| 5 | use core::mem; | ||
| 6 | use core::task::{Context, Poll}; | ||
| 7 | |||
| 8 | use embassy_net_driver::Driver; | ||
| 9 | use smoltcp::iface::{Interface, SocketHandle}; | ||
| 10 | use smoltcp::socket::raw; | ||
| 11 | pub use smoltcp::socket::raw::PacketMetadata; | ||
| 12 | use smoltcp::wire::{IpProtocol, IpVersion}; | ||
| 13 | |||
| 14 | use crate::{SocketStack, Stack}; | ||
| 15 | |||
| 16 | |||
| 17 | /// Unrelavent for RawSocket? | ||
| 18 | /* /// Error returned by [`RawSocket::bind`]. | ||
| 19 | #[derive(PartialEq, Eq, Clone, Copy, Debug)] | ||
| 20 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 21 | pub enum BindError { | ||
| 22 | /// The socket was already open. | ||
| 23 | InvalidState, | ||
| 24 | /// No route to host. | ||
| 25 | NoRoute, | ||
| 26 | } */ | ||
| 27 | |||
| 28 | /// Error returned by [`RawSocket::recv_from`] and [`RawSocket::send_to`]. | ||
| 29 | #[derive(PartialEq, Eq, Clone, Copy, Debug)] | ||
| 30 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 31 | pub enum SendError { | ||
| 32 | /// No route to host. | ||
| 33 | NoRoute, | ||
| 34 | /// Socket not bound to an outgoing port. | ||
| 35 | SocketNotBound, | ||
| 36 | } | ||
| 37 | |||
| 38 | /// Error returned by [`RawSocket::recv`] and [`RawSocket::send`]. | ||
| 39 | #[derive(PartialEq, Eq, Clone, Copy, Debug)] | ||
| 40 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 41 | pub enum RecvError { | ||
| 42 | /// Provided buffer was smaller than the received packet. | ||
| 43 | Truncated, | ||
| 44 | } | ||
| 45 | |||
| 46 | /// An Raw socket. | ||
| 47 | pub struct RawSocket<'a> { | ||
| 48 | stack: &'a RefCell<SocketStack>, | ||
| 49 | handle: SocketHandle, | ||
| 50 | } | ||
| 51 | |||
| 52 | impl<'a> RawSocket<'a> { | ||
| 53 | /// Create a new Raw socket using the provided stack and buffers. | ||
| 54 | pub fn new<D: Driver>( | ||
| 55 | stack: &'a Stack<D>, | ||
| 56 | ip_version: IpVersion, | ||
| 57 | ip_protocol: IpProtocol, | ||
| 58 | rx_meta: &'a mut [PacketMetadata], | ||
| 59 | rx_buffer: &'a mut [u8], | ||
| 60 | tx_meta: &'a mut [PacketMetadata], | ||
| 61 | tx_buffer: &'a mut [u8], | ||
| 62 | ) -> Self { | ||
| 63 | let s = &mut *stack.socket.borrow_mut(); | ||
| 64 | |||
| 65 | let rx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(rx_meta) }; | ||
| 66 | let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) }; | ||
| 67 | let tx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(tx_meta) }; | ||
| 68 | let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) }; | ||
| 69 | let handle = s.sockets.add(raw::Socket::new( | ||
| 70 | ip_version, | ||
| 71 | ip_protocol, | ||
| 72 | raw::PacketBuffer::new(rx_meta, rx_buffer), | ||
| 73 | raw::PacketBuffer::new(tx_meta, tx_buffer), | ||
| 74 | )); | ||
| 75 | |||
| 76 | Self { | ||
| 77 | stack: &stack.socket, | ||
| 78 | handle, | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | fn with_mut<R>(&self, f: impl FnOnce(&mut raw::Socket, &mut Interface) -> R) -> R { | ||
| 83 | let s = &mut *self.stack.borrow_mut(); | ||
| 84 | let socket = s.sockets.get_mut::<raw::Socket>(self.handle); | ||
| 85 | let res = f(socket, &mut s.iface); | ||
| 86 | s.waker.wake(); | ||
| 87 | res | ||
| 88 | } | ||
| 89 | |||
| 90 | /// Bind the socket to a local endpoint. | ||
| 91 | /// | ||
| 92 | /// How to handle this in RawSocket? no need for bind? | ||
| 93 | /// | ||
| 94 | /* pub fn bind<T>(&mut self, endpoint: T) -> Result<(), BindError> | ||
| 95 | where | ||
| 96 | T: Into<IpListenEndpoint>, | ||
| 97 | { | ||
| 98 | let mut endpoint = endpoint.into(); | ||
| 99 | |||
| 100 | if endpoint.port == 0 { | ||
| 101 | // If user didn't specify port allocate a dynamic port. | ||
| 102 | endpoint.port = self.stack.borrow_mut().get_local_port(); | ||
| 103 | } | ||
| 104 | |||
| 105 | match self.with_mut(|s, _| s.bind(endpoint)) { | ||
| 106 | Ok(()) => Ok(()), | ||
| 107 | Err(raw::BindError::InvalidState) => Err(BindError::InvalidState), | ||
| 108 | Err(raw::BindError::Unaddressable) => Err(BindError::NoRoute), | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | fn with<R>(&self, f: impl FnOnce(&raw::Socket, &Interface) -> R) -> R { | ||
| 113 | let s = &*self.stack.borrow(); | ||
| 114 | let socket = s.sockets.get::<raw::Socket>(self.handle); | ||
| 115 | f(socket, &s.iface) | ||
| 116 | } | ||
| 117 | |||
| 118 | fn with_mut<R>(&self, f: impl FnOnce(&mut raw::Socket, &mut Interface) -> R) -> R { | ||
| 119 | let s = &mut *self.stack.borrow_mut(); | ||
| 120 | let socket = s.sockets.get_mut::<raw::Socket>(self.handle); | ||
| 121 | let res = f(socket, &mut s.iface); | ||
| 122 | s.waker.wake(); | ||
| 123 | res | ||
| 124 | } */ | ||
| 125 | |||
| 126 | /// Receive a datagram. | ||
| 127 | /// | ||
| 128 | /// This method will wait until a datagram is received. | ||
| 129 | pub async fn recv(&self, buf: &mut [u8]) -> Result<usize, RecvError> { | ||
| 130 | poll_fn(move |cx| self.poll_recv(buf, cx)).await | ||
| 131 | } | ||
| 132 | |||
| 133 | /// Receive a datagram. | ||
| 134 | /// | ||
| 135 | /// When no datagram is available, this method will return `Poll::Pending` and | ||
| 136 | /// register the current task to be notified when a datagram is received. | ||
| 137 | pub fn poll_recv(&self, buf: &mut [u8], cx: &mut Context<'_>) -> Poll<Result<usize, RecvError>> { | ||
| 138 | self.with_mut(|s, _| match s.recv_slice(buf) { | ||
| 139 | Ok(n) => Poll::Ready(Ok(n)), | ||
| 140 | // No data ready | ||
| 141 | Err(raw::RecvError::Truncated) => Poll::Ready(Err(RecvError::Truncated)), | ||
| 142 | Err(raw::RecvError::Exhausted) => { | ||
| 143 | s.register_recv_waker(cx.waker()); | ||
| 144 | Poll::Pending | ||
| 145 | } | ||
| 146 | }) | ||
| 147 | } | ||
| 148 | |||
| 149 | /// Send a datagram. | ||
| 150 | /// | ||
| 151 | /// This method will wait until the datagram has been sent.` | ||
| 152 | pub async fn send<T>(&self, buf: &[u8]) -> Result<(), SendError> { | ||
| 153 | poll_fn(move |cx| self.poll_send(buf, cx)).await | ||
| 154 | } | ||
| 155 | |||
| 156 | /// Send a datagram. | ||
| 157 | /// | ||
| 158 | /// When the datagram has been sent, this method will return `Poll::Ready(Ok())`. | ||
| 159 | /// | ||
| 160 | /// When the socket's send buffer is full, this method will return `Poll::Pending` | ||
| 161 | /// and register the current task to be notified when the buffer has space available. | ||
| 162 | pub fn poll_send(&self, buf: &[u8], cx: &mut Context<'_>) -> Poll<Result<(), SendError>>{ | ||
| 163 | self.with_mut(|s, _| match s.send_slice(buf) { | ||
| 164 | // Entire datagram has been sent | ||
| 165 | Ok(()) => Poll::Ready(Ok(())), | ||
| 166 | Err(raw::SendError::BufferFull) => { | ||
| 167 | s.register_send_waker(cx.waker()); | ||
| 168 | Poll::Pending | ||
| 169 | } | ||
| 170 | }) | ||
| 171 | } | ||
| 172 | } | ||
| 173 | |||
| 174 | impl Drop for RawSocket<'_> { | ||
| 175 | fn drop(&mut self) { | ||
| 176 | self.stack.borrow_mut().sockets.remove(self.handle); | ||
| 177 | } | ||
| 178 | } | ||
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 585349506..0f58f143c 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml | |||
| @@ -12,7 +12,7 @@ embassy-executor = { version = "0.5.0", path = "../../embassy-executor", feature | |||
| 12 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 12 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 13 | embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl"] } | 13 | embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl"] } |
| 14 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 14 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } |
| 15 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } | 15 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet"] } |
| 16 | embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } | 16 | embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } |
| 17 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 17 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 18 | embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger" } | 18 | embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger" } |
