aboutsummaryrefslogtreecommitdiff
path: root/embassy-net
diff options
context:
space:
mode:
authorGustav Toft <[email protected]>2024-04-04 15:51:25 +0200
committerGustav Toft <[email protected]>2024-04-04 15:51:25 +0200
commit0427c442ea531673e18da304c7402927589b8d0b (patch)
tree05c6d5f158059dd3bbdca8232a6ef966b55030ad /embassy-net
parent23740abdca24fb65d7c47f4fb17323290bc4a33b (diff)
Implement raw sockets in embassy-net
Diffstat (limited to 'embassy-net')
-rw-r--r--embassy-net/Cargo.toml6
-rw-r--r--embassy-net/src/lib.rs2
-rw-r--r--embassy-net/src/raw.rs178
3 files changed, 184 insertions, 2 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]
17src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/" 17src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/"
18src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net/src/" 18src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net/src/"
19features = ["defmt", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] 19features = ["defmt", "tcp", "udp","raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"]
20target = "thumbv7em-none-eabi" 20target = "thumbv7em-none-eabi"
21 21
22[package.metadata.docs.rs] 22[package.metadata.docs.rs]
23features = ["defmt", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] 23features = ["defmt", "tcp", "udp", "raw","dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"]
24 24
25[features] 25[features]
26default = [] 26default = []
@@ -38,6 +38,8 @@ packet-trace = []
38 38
39## Enable UDP support 39## Enable UDP support
40udp = ["smoltcp/socket-udp"] 40udp = ["smoltcp/socket-udp"]
41## Enable Raw support
42raw = ["smoltcp/socket-raw"]
41## Enable TCP support 43## Enable TCP support
42tcp = ["smoltcp/socket-tcp"] 44tcp = ["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;
20mod time; 20mod time;
21#[cfg(feature = "udp")] 21#[cfg(feature = "udp")]
22pub mod udp; 22pub mod udp;
23#[cfg(feature = "raw")]
24pub mod raw;
23 25
24use core::cell::RefCell; 26use core::cell::RefCell;
25use core::future::{poll_fn, Future}; 27use 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
3use core::cell::RefCell;
4use core::future::poll_fn;
5use core::mem;
6use core::task::{Context, Poll};
7
8use embassy_net_driver::Driver;
9use smoltcp::iface::{Interface, SocketHandle};
10use smoltcp::socket::raw;
11pub use smoltcp::socket::raw::PacketMetadata;
12use smoltcp::wire::{IpProtocol, IpVersion};
13
14use 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))]
21pub 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))]
31pub 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))]
41pub enum RecvError {
42 /// Provided buffer was smaller than the received packet.
43 Truncated,
44}
45
46/// An Raw socket.
47pub struct RawSocket<'a> {
48 stack: &'a RefCell<SocketStack>,
49 handle: SocketHandle,
50}
51
52impl<'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
174impl Drop for RawSocket<'_> {
175 fn drop(&mut self) {
176 self.stack.borrow_mut().sockets.remove(self.handle);
177 }
178}