aboutsummaryrefslogtreecommitdiff
path: root/embassy-net-examples/src
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-net-examples/src')
-rw-r--r--embassy-net-examples/src/main.rs79
-rw-r--r--embassy-net-examples/src/tuntap.rs200
2 files changed, 279 insertions, 0 deletions
diff --git a/embassy-net-examples/src/main.rs b/embassy-net-examples/src/main.rs
new file mode 100644
index 000000000..bc413f1a2
--- /dev/null
+++ b/embassy-net-examples/src/main.rs
@@ -0,0 +1,79 @@
1#![feature(type_alias_impl_trait)]
2
3use embassy::executor::{Spawner, task};
4use embassy::io::{AsyncBufReadExt, AsyncWriteExt};
5use embassy::time::{Duration, Timer};
6use embassy::util::Forever;
7use embassy_net::*;
8use embassy_std::Executor;
9use heapless::Vec;
10use log::*;
11
12mod tuntap;
13
14use crate::tuntap::TunTapDevice;
15
16static DEVICE: Forever<TunTapDevice> = Forever::new();
17static CONFIG: Forever<StaticConfigurator> = Forever::new();
18
19#[task]
20async fn net_task() {
21 embassy_net::run().await
22}
23
24#[task]
25async fn main_task(spawner: Spawner) {
26 // Init network device
27 let device = TunTapDevice::new("tap0").unwrap();
28
29 // Static IP configuration
30 let config = StaticConfigurator::new(UpConfig {
31 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 1), 24),
32 dns_servers: Vec::new(),
33 gateway: Ipv4Address::new(192, 168, 69, 100),
34 });
35
36 // Init network stack
37 embassy_net::init(DEVICE.put(device), CONFIG.put(config));
38
39 // Launch network task
40 spawner.spawn(net_task()).unwrap();
41
42 // Then we can use it!
43 let mut rx_buffer = [0; 4096];
44 let mut tx_buffer = [0; 4096];
45 let mut socket = TcpSocket::new(&mut rx_buffer, &mut tx_buffer);
46
47 socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10)));
48
49 let remote_endpoint = (Ipv4Address::new(192, 168, 69, 100), 8000);
50 info!("connecting to {:?}...", remote_endpoint);
51 let r = socket.connect(remote_endpoint).await;
52 if let Err(e) = r {
53 warn!("connect error: {:?}", e);
54 return;
55 }
56 info!("connected!");
57 loop {
58 let r = socket.write_all(b"Hello!\n").await;
59 if let Err(e) = r {
60 warn!("write error: {:?}", e);
61 return;
62 }
63 }
64}
65
66static EXECUTOR: Forever<Executor> = Forever::new();
67
68fn main() {
69 env_logger::builder()
70 .filter_level(log::LevelFilter::Debug)
71 .filter_module("async_io", log::LevelFilter::Info)
72 .format_timestamp_nanos()
73 .init();
74
75 let executor = EXECUTOR.put(Executor::new());
76 executor.run(|spawner| {
77 spawner.spawn(main_task(spawner)).unwrap();
78 });
79}
diff --git a/embassy-net-examples/src/tuntap.rs b/embassy-net-examples/src/tuntap.rs
new file mode 100644
index 000000000..5c138c069
--- /dev/null
+++ b/embassy-net-examples/src/tuntap.rs
@@ -0,0 +1,200 @@
1use async_io::Async;
2use embassy::util::WakerRegistration;
3use libc;
4use smoltcp::wire::EthernetFrame;
5use std::io;
6use std::io::{Read, Write};
7use std::os::unix::io::{AsRawFd, RawFd};
8use log::*;
9
10pub const SIOCGIFMTU: libc::c_ulong = 0x8921;
11pub const SIOCGIFINDEX: libc::c_ulong = 0x8933;
12pub const ETH_P_ALL: libc::c_short = 0x0003;
13pub const TUNSETIFF: libc::c_ulong = 0x400454CA;
14pub const IFF_TUN: libc::c_int = 0x0001;
15pub const IFF_TAP: libc::c_int = 0x0002;
16pub const IFF_NO_PI: libc::c_int = 0x1000;
17
18#[repr(C)]
19#[derive(Debug)]
20struct ifreq {
21 ifr_name: [libc::c_char; libc::IF_NAMESIZE],
22 ifr_data: libc::c_int, /* ifr_ifindex or ifr_mtu */
23}
24
25fn ifreq_for(name: &str) -> ifreq {
26 let mut ifreq = ifreq {
27 ifr_name: [0; libc::IF_NAMESIZE],
28 ifr_data: 0,
29 };
30 for (i, byte) in name.as_bytes().iter().enumerate() {
31 ifreq.ifr_name[i] = *byte as libc::c_char
32 }
33 ifreq
34}
35
36fn ifreq_ioctl(
37 lower: libc::c_int,
38 ifreq: &mut ifreq,
39 cmd: libc::c_ulong,
40) -> io::Result<libc::c_int> {
41 unsafe {
42 let res = libc::ioctl(lower, cmd as _, ifreq as *mut ifreq);
43 if res == -1 {
44 return Err(io::Error::last_os_error());
45 }
46 }
47
48 Ok(ifreq.ifr_data)
49}
50
51#[derive(Debug)]
52pub struct TunTap {
53 fd: libc::c_int,
54 ifreq: ifreq,
55 mtu: usize,
56}
57
58impl AsRawFd for TunTap {
59 fn as_raw_fd(&self) -> RawFd {
60 self.fd
61 }
62}
63
64impl TunTap {
65 pub fn new(name: &str) -> io::Result<TunTap> {
66 unsafe {
67 let fd = libc::open(
68 "/dev/net/tun\0".as_ptr() as *const libc::c_char,
69 libc::O_RDWR | libc::O_NONBLOCK,
70 );
71 if fd == -1 {
72 return Err(io::Error::last_os_error());
73 }
74
75 let mut ifreq = ifreq_for(name);
76 ifreq.ifr_data = IFF_TAP | IFF_NO_PI;
77 ifreq_ioctl(fd, &mut ifreq, TUNSETIFF)?;
78
79 let socket = libc::socket(libc::AF_INET, libc::SOCK_DGRAM, libc::IPPROTO_IP);
80 if socket == -1 {
81 return Err(io::Error::last_os_error());
82 }
83
84 let ip_mtu = ifreq_ioctl(socket, &mut ifreq, SIOCGIFMTU);
85 libc::close(socket);
86 let ip_mtu = ip_mtu? as usize;
87
88 // SIOCGIFMTU returns the IP MTU (typically 1500 bytes.)
89 // smoltcp counts the entire Ethernet packet in the MTU, so add the Ethernet header size to it.
90 let mtu = ip_mtu + EthernetFrame::<&[u8]>::header_len();
91
92 Ok(TunTap { fd, mtu, ifreq })
93 }
94 }
95}
96
97impl Drop for TunTap {
98 fn drop(&mut self) {
99 unsafe {
100 libc::close(self.fd);
101 }
102 }
103}
104
105impl io::Read for TunTap {
106 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
107 let len = unsafe { libc::read(self.fd, buf.as_mut_ptr() as *mut libc::c_void, buf.len()) };
108 if len == -1 {
109 Err(io::Error::last_os_error())
110 } else {
111 Ok(len as usize)
112 }
113 }
114}
115
116impl io::Write for TunTap {
117 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
118 let len = unsafe { libc::write(self.fd, buf.as_ptr() as *mut libc::c_void, buf.len()) };
119 if len == -1 {
120 Err(io::Error::last_os_error())
121 } else {
122 Ok(len as usize)
123 }
124 }
125
126 fn flush(&mut self) -> io::Result<()> {
127 Ok(())
128 }
129}
130
131pub struct TunTapDevice {
132 device: Async<TunTap>,
133 waker: WakerRegistration,
134}
135
136impl TunTapDevice {
137 pub fn new(name: &str) -> io::Result<TunTapDevice> {
138 Ok(Self {
139 device: Async::new(TunTap::new(name)?)?,
140 waker: WakerRegistration::new(),
141 })
142 }
143}
144
145use embassy_net::{LinkState, DeviceCapabilities, Packet, PacketBox, PacketBuf};
146use core::task::Waker;
147
148impl crate::Device for TunTapDevice {
149 fn is_transmit_ready(&mut self) -> bool {
150 true
151 }
152
153 fn transmit(&mut self, pkt: PacketBuf) {
154 // todo handle WouldBlock
155 match self.device.get_mut().write(&pkt) {
156 Ok(_) => {}
157 Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
158 info!("transmit WouldBlock");
159 }
160 Err(e) => panic!("transmit error: {:?}", e),
161 }
162 }
163
164 fn receive(&mut self) -> Option<PacketBuf> {
165 let mut pkt = PacketBox::new(Packet::new()).unwrap();
166 loop {
167 match self.device.get_mut().read(&mut pkt[..]) {
168 Ok(n) => {
169 return Some(pkt.slice(0..n));
170 }
171 Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
172 let ready = if let Some(mut cx) = self.waker.context() {
173 let ready = self.device.poll_readable(&mut cx).is_ready();
174 ready
175 } else {
176 false
177 };
178 if !ready {
179 return None;
180 }
181 }
182 Err(e) => panic!("read error: {:?}", e),
183 }
184 }
185 }
186
187 fn register_waker(&mut self, waker: &Waker) {
188 self.waker.register(waker)
189 }
190
191 fn capabilities(&mut self) -> DeviceCapabilities {
192 let mut caps = DeviceCapabilities::default();
193 caps.max_transmission_unit = self.device.get_ref().mtu;
194 caps
195 }
196
197 fn link_state(&mut self) -> LinkState {
198 LinkState::Up
199 }
200}