Skip to content

Commit 7ec98e4

Browse files
committed
Make ethernet work with async/await and add dhcp support
1 parent 9794418 commit 7ec98e4

File tree

4 files changed

+109
-58
lines changed

4 files changed

+109
-58
lines changed

Cargo.lock

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@ version = "1.0"
3333
default-features = false
3434

3535
[dependencies.smoltcp]
36-
version = "0.5.0"
36+
#version = "0.5.0"
37+
git = "https://github.com/astro/smoltcp.git"
38+
branch = "dhcp"
3739
default-features = false
38-
features = ["alloc", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp", "proto-ipv4"]
40+
features = ["alloc", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp", "proto-ipv4", "proto-dhcpv4"]
3941

4042
[dependencies.font8x8]
4143
version = "0.2.4"
@@ -52,3 +54,7 @@ features = ["alloc"]
5254
codegen-units = 1 # better optimizations
5355
debug = true
5456
lto = true # better optimizations
57+
58+
[patch.crates-io.cortex-m-rt]
59+
git = "https://github.com/phil-opp/cortex-m-rt.git"
60+
branch = "phil-opp-patch-1"

src/bin/async-await.rs

Lines changed: 82 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use sh::hio::{self, HStdout};
3636
use smoltcp::{
3737
socket::{
3838
Socket, SocketSet, TcpSocket, TcpSocketBuffer, UdpPacketMetadata, UdpSocket,
39-
UdpSocketBuffer,
39+
UdpSocketBuffer, IcmpSocket, IcmpEndpoint,
4040
},
4141
time::Instant,
4242
wire::{EthernetAddress, IpAddress, IpEndpoint, Ipv4Address},
@@ -63,7 +63,6 @@ static ALLOCATOR: CortexMHeap = CortexMHeap::empty();
6363

6464
const HEAP_SIZE: usize = 50 * 1024; // in bytes
6565
const ETH_ADDR: EthernetAddress = EthernetAddress([0x00, 0x08, 0xdc, 0xab, 0xcd, 0xef]);
66-
const IP_ADDR: Ipv4Address = Ipv4Address([141, 52, 46, 198]);
6766

6867
#[entry]
6968
fn main() -> ! {
@@ -293,7 +292,7 @@ fn run() -> ! {
293292

294293
// FIXME: Causes link error: no memory region specified for section '.ARM.extab'
295294
// see https://github.com/rust-embedded/cortex-m-rt/issues/157
296-
//executor.spawn_local(_ethernet_task.run()).unwrap();
295+
executor.spawn_local(ethernet_task.run()).unwrap();
297296

298297
// FIXME: Does not work currently due to borrowing errors
299298
// executor.spawn_local(sd_card_task(sd, idle_stream.clone())).unwrap();
@@ -493,6 +492,10 @@ where
493492
}
494493

495494
async fn run(mut self) {
495+
use smoltcp::wire::{EthernetAddress, Ipv4Address, IpCidr};
496+
use smoltcp::socket::{SocketSet, RawSocketBuffer, RawPacketMetadata, IcmpSocketBuffer, IcmpPacketMetadata};
497+
use smoltcp::dhcp::Dhcpv4Client;
498+
496499
let mut ethernet_interface = ethernet::EthernetDevice::new(
497500
Default::default(),
498501
Default::default(),
@@ -502,54 +505,93 @@ where
502505
&mut self.ethernet_dma,
503506
ETH_ADDR,
504507
)
505-
.map(|device| device.into_interface(IP_ADDR));
506-
if let Err(e) = ethernet_interface {
507-
println!("ethernet init failed: {:?}", e);
508+
.map(|device| device.into_interface());
509+
let mut iface = match ethernet_interface {
510+
Ok(iface) => iface,
511+
Err(e) => {
512+
println!("ethernet init failed: {:?}", e);
513+
return;
514+
}
508515
};
509516

510517
let idle_stream = self.idle_stream;
511518
pin_mut!(idle_stream);
512519

513520
let mut sockets = SocketSet::new(Vec::new());
514521

515-
if ethernet_interface.is_ok() {
516-
let endpoint = IpEndpoint::new(IpAddress::Ipv4(IP_ADDR), 15);
517-
let udp_rx_buffer =
518-
UdpSocketBuffer::new(vec![UdpPacketMetadata::EMPTY; 3], vec![0u8; 256]);
519-
let udp_tx_buffer =
520-
UdpSocketBuffer::new(vec![UdpPacketMetadata::EMPTY; 1], vec![0u8; 128]);
521-
let mut example_udp_socket = UdpSocket::new(udp_rx_buffer, udp_tx_buffer);
522-
example_udp_socket.bind(endpoint).unwrap();
523-
sockets.add(example_udp_socket);
524-
525-
let tcp_rx_buffer = TcpSocketBuffer::new(vec![0; ethernet::MTU]);
526-
let tcp_tx_buffer = TcpSocketBuffer::new(vec![0; ethernet::MTU]);
527-
let mut example_tcp_socket = TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer);
528-
example_tcp_socket.listen(endpoint).unwrap();
529-
sockets.add(example_tcp_socket);
530-
}
522+
let dhcp_rx_buffer = RawSocketBuffer::new(
523+
[RawPacketMetadata::EMPTY; 2],
524+
vec![0; 1500]
525+
);
526+
let dhcp_tx_buffer = RawSocketBuffer::new(
527+
[RawPacketMetadata::EMPTY; 1],
528+
vec![0; 3000]
529+
);
530+
let mut dhcp = Dhcpv4Client::new(&mut sockets, dhcp_rx_buffer, dhcp_tx_buffer, Instant::from_millis(system_clock::ms() as i64));
531+
let mut prev_ip_addr = iface.ipv4_addr().unwrap();
531532

532533
// handle new ethernet packets
533-
if let Ok(ref mut eth) = ethernet_interface {
534-
loop {
535-
match eth.poll(
536-
&mut sockets,
537-
Instant::from_millis(system_clock::ms() as i64),
538-
) {
539-
Err(::smoltcp::Error::Exhausted) => {
540-
await!(idle_stream.next()).expect("idle stream closed");
541-
}
542-
Err(::smoltcp::Error::Unrecognized) => {}
543-
Err(e) => println!("Network error: {:?}", e),
544-
Ok(socket_changed) => {
545-
if socket_changed {
546-
for mut socket in sockets.iter_mut() {
547-
Self::poll_socket(&mut socket).expect("socket poll failed");
548-
}
534+
loop {
535+
await!(idle_stream.next());
536+
let timestamp = Instant::from_millis(system_clock::ms() as i64);
537+
match iface.poll(
538+
&mut sockets,
539+
timestamp,
540+
) {
541+
Err(::smoltcp::Error::Exhausted) => {
542+
continue;
543+
}
544+
Err(::smoltcp::Error::Unrecognized) => {print!("U")}
545+
Err(e) => println!("Network error: {:?}", e),
546+
Ok(socket_changed) => {
547+
if socket_changed {
548+
for mut socket in sockets.iter_mut() {
549+
Self::poll_socket(&mut socket).expect("socket poll failed");
549550
}
550551
}
551552
}
552553
}
554+
555+
dhcp.poll(&mut iface, &mut sockets, timestamp)
556+
.unwrap_or_else(|e| println!("DHCP: {:?}", e));
557+
let ip_addr = iface.ipv4_addr().unwrap();
558+
if ip_addr != prev_ip_addr {
559+
println!("Assigned a new IPv4 address: {}", ip_addr);
560+
iface.routes_mut()
561+
.update(|routes_map| {
562+
routes_map.get(&IpCidr::new(Ipv4Address::UNSPECIFIED.into(), 0))
563+
.map(|default_route| {
564+
println!("Default gateway: {}", default_route.via_router);
565+
});
566+
});
567+
for dns_server in dhcp.dns_servers() {
568+
println!("DNS servers: {}", dns_server);
569+
}
570+
571+
// TODO delete old sockets
572+
573+
// add new sockets
574+
let endpoint = IpEndpoint::new(ip_addr.into(), 15);
575+
576+
let udp_rx_buffer =
577+
UdpSocketBuffer::new(vec![UdpPacketMetadata::EMPTY; 3], vec![0u8; 256]);
578+
let udp_tx_buffer =
579+
UdpSocketBuffer::new(vec![UdpPacketMetadata::EMPTY; 1], vec![0u8; 128]);
580+
let mut example_udp_socket = UdpSocket::new(udp_rx_buffer, udp_tx_buffer);
581+
example_udp_socket.bind(endpoint).unwrap();
582+
sockets.add(example_udp_socket);
583+
584+
let tcp_rx_buffer = TcpSocketBuffer::new(vec![0; ethernet::MTU]);
585+
let tcp_tx_buffer = TcpSocketBuffer::new(vec![0; ethernet::MTU]);
586+
let mut example_tcp_socket = TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer);
587+
example_tcp_socket.listen(endpoint).unwrap();
588+
sockets.add(example_tcp_socket);
589+
590+
prev_ip_addr = ip_addr;
591+
}
592+
let mut timeout = dhcp.next_poll(timestamp);
593+
iface.poll_delay(&sockets, timestamp).map(|sockets_timeout| timeout = sockets_timeout);
594+
// TODO await next interrupt
553595
}
554596
}
555597

@@ -570,7 +612,7 @@ where
570612
}
571613
socket.send_slice(&reply.0, reply.1)?;
572614
},
573-
_ => {}
615+
_ => unreachable!()
574616
},
575617
&mut Socket::Tcp(ref mut socket) => match socket.local_endpoint().port {
576618
15 => {
@@ -592,7 +634,7 @@ where
592634
assert_eq!(socket.send_slice(&reply)?, reply.len());
593635
}
594636
}
595-
_ => {}
637+
_ => unreachable!()
596638
},
597639
_ => {}
598640
}

src/ethernet/mod.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ use core::fmt;
55
use stm32f7::stm32f7x6::{ETHERNET_DMA, ETHERNET_MAC, RCC, SYSCFG};
66
use volatile::Volatile;
77

8-
use smoltcp::iface::{EthernetInterface, EthernetInterfaceBuilder};
8+
use smoltcp::iface::{EthernetInterface, EthernetInterfaceBuilder, Routes};
99
use smoltcp::phy::{Device, DeviceCapabilities};
1010
use smoltcp::time::Instant;
11-
use smoltcp::wire::{EthernetAddress, IpCidr, Ipv4Address, Ipv4Cidr};
11+
use smoltcp::wire::{EthernetAddress, IpCidr, Ipv4Address};
1212

1313
mod init;
1414
mod phy;
@@ -90,18 +90,21 @@ impl<'d> EthernetDevice<'d> {
9090
}
9191

9292
pub fn into_interface<'a>(
93-
self,
94-
ip_address: Ipv4Address,
93+
self
9594
) -> EthernetInterface<'a, 'a, 'a, Self> {
9695
use alloc::collections::BTreeMap;
9796
use smoltcp::iface::NeighborCache;
9897

98+
let ip_addrs = [IpCidr::new(Ipv4Address::UNSPECIFIED.into(), 0)];
99+
let routes_storage = Box::leak(Box::new([None; 1]));
100+
let routes = Routes::new(&mut routes_storage[..]);
101+
99102
let neighbor_cache = NeighborCache::new(BTreeMap::new());
100103
let ethernet_address = self.ethernet_address;
101104
let interface_builder = EthernetInterfaceBuilder::new(self);
102105
let interface_builder = interface_builder.ethernet_addr(ethernet_address);
103-
let ip_cidr = IpCidr::Ipv4(Ipv4Cidr::new(ip_address, 0));
104-
let interface_builder = interface_builder.ip_addrs(vec![ip_cidr]);
106+
let interface_builder = interface_builder.ip_addrs(ip_addrs);
107+
let interface_builder = interface_builder.routes(routes);
105108
let interface_builder = interface_builder.neighbor_cache(neighbor_cache);
106109
interface_builder.finalize()
107110
}

0 commit comments

Comments
 (0)