2021-02-03 05:09:37 +01:00
#![ cfg_attr(not(feature = " std " ), no_std) ]
2023-05-14 23:44:53 +02:00
#![ cfg_attr(feature = " nightly " , feature(async_fn_in_trait, impl_trait_projections)) ]
2023-05-15 00:39:57 +02:00
#![ warn(missing_docs) ]
#![ doc = include_str!( " ../README.md " ) ]
2021-02-03 05:09:37 +01:00
2023-08-25 19:48:45 +02:00
#[ cfg(not(any(feature = " proto-ipv4 " , feature = " proto-ipv6 " ))) ]
compile_error! ( " You must enable at least one of the following features: proto-ipv4, proto-ipv6 " ) ;
2021-02-03 05:09:37 +01:00
// This mod MUST go first, so that the others see its macros.
pub ( crate ) mod fmt ;
2023-02-08 17:52:02 +01:00
mod device ;
2023-01-31 22:06:41 +01:00
#[ cfg(feature = " dns " ) ]
pub mod dns ;
2021-04-07 19:06:45 +02:00
#[ cfg(feature = " tcp " ) ]
2022-05-04 20:48:37 +02:00
pub mod tcp ;
2023-05-15 00:38:58 +02:00
mod time ;
2022-07-28 10:25:47 +02:00
#[ cfg(feature = " udp " ) ]
pub mod udp ;
2022-12-07 16:02:28 +01:00
use core ::cell ::RefCell ;
use core ::future ::{ poll_fn , Future } ;
use core ::task ::{ Context , Poll } ;
2023-05-15 00:39:57 +02:00
pub use embassy_net_driver as driver ;
2023-08-25 19:48:45 +02:00
use embassy_net_driver ::{ Driver , LinkState } ;
2022-12-07 16:02:28 +01:00
use embassy_sync ::waitqueue ::WakerRegistration ;
use embassy_time ::{ Instant , Timer } ;
use futures ::pin_mut ;
2023-07-16 02:02:04 +02:00
#[ allow(unused_imports) ]
2022-12-07 16:02:28 +01:00
use heapless ::Vec ;
2023-05-15 00:39:57 +02:00
#[ cfg(feature = " igmp " ) ]
pub use smoltcp ::iface ::MulticastError ;
2023-07-16 02:02:04 +02:00
#[ allow(unused_imports) ]
2023-04-18 22:11:15 +02:00
use smoltcp ::iface ::{ Interface , SocketHandle , SocketSet , SocketStorage } ;
2022-12-07 16:02:28 +01:00
#[ cfg(feature = " dhcpv4 " ) ]
2023-04-18 22:11:15 +02:00
use smoltcp ::socket ::dhcpv4 ::{ self , RetryConfig } ;
2023-07-28 14:52:03 +02:00
#[ cfg(feature = " medium-ethernet " ) ]
pub use smoltcp ::wire ::EthernetAddress ;
2023-07-31 12:20:13 +02:00
#[ cfg(any(feature = " medium-ethernet " , feature = " medium-ieee802154 " , feature = " medium-ip " )) ]
2023-07-28 14:52:03 +02:00
pub use smoltcp ::wire ::HardwareAddress ;
2023-05-15 00:55:34 +02:00
#[ cfg(feature = " udp " ) ]
pub use smoltcp ::wire ::IpListenEndpoint ;
2023-07-16 02:02:04 +02:00
#[ cfg(feature = " medium-ieee802154 " ) ]
2023-07-28 14:52:03 +02:00
pub use smoltcp ::wire ::{ Ieee802154Address , Ieee802154Frame } ;
2023-07-07 16:38:56 +02:00
pub use smoltcp ::wire ::{ IpAddress , IpCidr , IpEndpoint } ;
2023-06-05 16:00:53 +02:00
#[ cfg(feature = " proto-ipv4 " ) ]
pub use smoltcp ::wire ::{ Ipv4Address , Ipv4Cidr } ;
2022-06-01 13:48:09 +02:00
#[ cfg(feature = " proto-ipv6 " ) ]
pub use smoltcp ::wire ::{ Ipv6Address , Ipv6Cidr } ;
2022-12-07 16:02:28 +01:00
2022-12-26 03:33:49 +01:00
use crate ::device ::DriverAdapter ;
2023-05-15 00:38:58 +02:00
use crate ::time ::{ instant_from_smoltcp , instant_to_smoltcp } ;
2022-12-07 16:02:28 +01:00
const LOCAL_PORT_MIN : u16 = 1025 ;
const LOCAL_PORT_MAX : u16 = 65535 ;
2023-02-10 18:34:21 +01:00
#[ cfg(feature = " dns " ) ]
const MAX_QUERIES : usize = 4 ;
2022-12-07 16:02:28 +01:00
2023-05-15 00:39:57 +02:00
/// Memory resources needed for a network stack.
2023-01-18 10:10:33 +01:00
pub struct StackResources < const SOCK : usize > {
2022-12-07 16:02:28 +01:00
sockets : [ SocketStorage < 'static > ; SOCK ] ,
2023-02-10 17:43:23 +01:00
#[ cfg(feature = " dns " ) ]
2023-02-10 18:30:17 +01:00
queries : [ Option < dns ::DnsQuery > ; MAX_QUERIES ] ,
2022-12-07 16:02:28 +01:00
}
2023-01-18 10:10:33 +01:00
impl < const SOCK : usize > StackResources < SOCK > {
2023-05-15 00:39:57 +02:00
/// Create a new set of stack resources.
2023-06-28 15:03:57 +02:00
pub const fn new ( ) -> Self {
2023-02-10 17:43:23 +01:00
#[ cfg(feature = " dns " ) ]
const INIT : Option < dns ::DnsQuery > = None ;
2022-12-07 16:02:28 +01:00
Self {
sockets : [ SocketStorage ::EMPTY ; SOCK ] ,
2023-02-10 17:43:23 +01:00
#[ cfg(feature = " dns " ) ]
2023-02-10 18:30:17 +01:00
queries : [ INIT ; MAX_QUERIES ] ,
2022-12-07 16:02:28 +01:00
}
}
}
2023-05-15 00:39:57 +02:00
/// Static IP address configuration.
2023-06-05 16:00:53 +02:00
#[ cfg(feature = " proto-ipv4 " ) ]
2022-12-07 16:02:28 +01:00
#[ derive(Debug, Clone, PartialEq, Eq) ]
2023-06-05 14:57:17 +02:00
pub struct StaticConfigV4 {
2023-05-15 00:39:57 +02:00
/// IP address and subnet mask.
2022-12-07 16:02:28 +01:00
pub address : Ipv4Cidr ,
2023-05-15 00:39:57 +02:00
/// Default gateway.
2022-12-07 16:02:28 +01:00
pub gateway : Option < Ipv4Address > ,
2023-05-15 00:39:57 +02:00
/// DNS servers.
2022-12-07 16:02:28 +01:00
pub dns_servers : Vec < Ipv4Address , 3 > ,
}
2023-06-05 16:12:24 +02:00
/// Static IPv6 address configuration
#[ cfg(feature = " proto-ipv6 " ) ]
#[ derive(Debug, Clone, PartialEq, Eq) ]
pub struct StaticConfigV6 {
/// IP address and subnet mask.
pub address : Ipv6Cidr ,
/// Default gateway.
pub gateway : Option < Ipv6Address > ,
/// DNS servers.
pub dns_servers : Vec < Ipv6Address , 3 > ,
}
2023-05-15 00:39:57 +02:00
/// DHCP configuration.
2023-04-18 22:11:15 +02:00
#[ cfg(feature = " dhcpv4 " ) ]
2023-01-18 10:10:33 +01:00
#[ derive(Debug, Clone, PartialEq, Eq) ]
pub struct DhcpConfig {
2023-05-15 00:39:57 +02:00
/// Maximum lease duration.
///
/// If not set, the lease duration specified by the server will be used.
/// If set, the lease duration will be capped at this value.
2023-05-15 00:38:58 +02:00
pub max_lease_duration : Option < embassy_time ::Duration > ,
2023-05-15 00:39:57 +02:00
/// Retry configuration.
2023-01-18 10:10:33 +01:00
pub retry_config : RetryConfig ,
2023-05-15 00:39:57 +02:00
/// Ignore NAKs from DHCP servers.
///
/// This is not compliant with the DHCP RFCs, since theoretically we must stop using the assigned IP when receiving a NAK. This can increase reliability on broken networks with buggy routers or rogue DHCP servers, however.
2023-01-18 10:10:33 +01:00
pub ignore_naks : bool ,
2023-05-15 00:39:57 +02:00
/// Server port. This is almost always 67. Do not change unless you know what you're doing.
2023-01-18 10:10:33 +01:00
pub server_port : u16 ,
2023-05-15 00:39:57 +02:00
/// Client port. This is almost always 68. Do not change unless you know what you're doing.
2023-01-18 10:10:33 +01:00
pub client_port : u16 ,
}
2023-04-18 22:11:15 +02:00
#[ cfg(feature = " dhcpv4 " ) ]
2023-01-18 10:10:33 +01:00
impl Default for DhcpConfig {
fn default ( ) -> Self {
Self {
max_lease_duration : Default ::default ( ) ,
retry_config : Default ::default ( ) ,
ignore_naks : Default ::default ( ) ,
server_port : smoltcp ::wire ::DHCP_SERVER_PORT ,
client_port : smoltcp ::wire ::DHCP_CLIENT_PORT ,
}
}
}
2023-05-15 00:39:57 +02:00
/// Network stack configuration.
2023-08-25 19:48:45 +02:00
#[ derive(Debug, Clone, Default) ]
#[ non_exhaustive ]
2023-06-07 12:04:15 +02:00
pub struct Config {
2023-06-07 12:08:53 +02:00
/// IPv4 configuration
2023-06-05 16:00:53 +02:00
#[ cfg(feature = " proto-ipv4 " ) ]
2023-06-07 12:04:15 +02:00
pub ipv4 : ConfigV4 ,
2023-06-07 12:08:53 +02:00
/// IPv6 configuration
2023-06-07 12:04:15 +02:00
#[ cfg(feature = " proto-ipv6 " ) ]
pub ipv6 : ConfigV6 ,
}
impl Config {
2023-06-07 12:08:53 +02:00
/// IPv4 configuration with static addressing.
2023-06-07 12:04:15 +02:00
#[ cfg(feature = " proto-ipv4 " ) ]
pub fn ipv4_static ( config : StaticConfigV4 ) -> Self {
Self {
ipv4 : ConfigV4 ::Static ( config ) ,
#[ cfg(feature = " proto-ipv6 " ) ]
ipv6 : ConfigV6 ::None ,
}
}
2023-06-07 12:08:53 +02:00
/// IPv6 configuration with static addressing.
2023-06-05 16:12:24 +02:00
#[ cfg(feature = " proto-ipv6 " ) ]
2023-06-07 12:04:15 +02:00
pub fn ipv6_static ( config : StaticConfigV6 ) -> Self {
Self {
#[ cfg(feature = " proto-ipv4 " ) ]
ipv4 : ConfigV4 ::None ,
ipv6 : ConfigV6 ::Static ( config ) ,
}
}
2023-06-07 12:08:53 +02:00
/// IPv6 configuration with dynamic addressing.
///
/// # Example
/// ```rust
/// let _cfg = Config::dhcpv4(Default::default());
/// ```
2023-06-07 12:04:15 +02:00
#[ cfg(feature = " dhcpv4 " ) ]
pub fn dhcpv4 ( config : DhcpConfig ) -> Self {
Self {
ipv4 : ConfigV4 ::Dhcp ( config ) ,
#[ cfg(feature = " proto-ipv6 " ) ]
ipv6 : ConfigV6 ::None ,
}
}
}
/// Network stack IPv4 configuration.
#[ cfg(feature = " proto-ipv4 " ) ]
2023-08-25 19:48:45 +02:00
#[ derive(Debug, Clone, Default) ]
2023-06-07 12:04:15 +02:00
pub enum ConfigV4 {
2023-08-25 19:48:45 +02:00
/// Do not configure IPv4.
#[ default ]
None ,
2023-06-07 12:04:15 +02:00
/// Use a static IPv4 address configuration.
Static ( StaticConfigV4 ) ,
2023-05-15 00:39:57 +02:00
/// Use DHCP to obtain an IP address configuration.
2022-12-07 16:02:28 +01:00
#[ cfg(feature = " dhcpv4 " ) ]
2023-01-18 10:10:33 +01:00
Dhcp ( DhcpConfig ) ,
2023-06-07 12:04:15 +02:00
}
/// Network stack IPv6 configuration.
#[ cfg(feature = " proto-ipv6 " ) ]
2023-08-25 19:48:45 +02:00
#[ derive(Debug, Clone, Default) ]
2023-06-07 12:04:15 +02:00
pub enum ConfigV6 {
/// Do not configure IPv6.
2023-08-25 19:48:45 +02:00
#[ default ]
2023-06-07 12:04:15 +02:00
None ,
2023-08-25 19:48:45 +02:00
/// Use a static IPv6 address configuration.
Static ( StaticConfigV6 ) ,
2022-12-07 16:02:28 +01:00
}
2023-05-15 00:39:57 +02:00
/// A network stack.
///
/// This is the main entry point for the network stack.
2022-12-26 03:33:49 +01:00
pub struct Stack < D : Driver > {
2022-12-07 16:02:28 +01:00
pub ( crate ) socket : RefCell < SocketStack > ,
inner : RefCell < Inner < D > > ,
}
2022-12-26 03:33:49 +01:00
struct Inner < D : Driver > {
2022-12-07 16:02:28 +01:00
device : D ,
link_up : bool ,
2023-06-05 16:00:53 +02:00
#[ cfg(feature = " proto-ipv4 " ) ]
static_v4 : Option < StaticConfigV4 > ,
2023-06-05 16:12:24 +02:00
#[ cfg(feature = " proto-ipv6 " ) ]
static_v6 : Option < StaticConfigV6 > ,
2022-12-07 16:02:28 +01:00
#[ cfg(feature = " dhcpv4 " ) ]
dhcp_socket : Option < SocketHandle > ,
2023-02-10 17:43:23 +01:00
#[ cfg(feature = " dns " ) ]
2023-02-10 18:30:17 +01:00
dns_socket : SocketHandle ,
2023-02-10 18:44:51 +01:00
#[ cfg(feature = " dns " ) ]
dns_waker : WakerRegistration ,
2022-12-07 16:02:28 +01:00
}
pub ( crate ) struct SocketStack {
pub ( crate ) sockets : SocketSet < 'static > ,
2023-01-19 14:41:39 +01:00
pub ( crate ) iface : Interface ,
2022-12-07 16:02:28 +01:00
pub ( crate ) waker : WakerRegistration ,
next_local_port : u16 ,
}
2023-07-31 10:40:48 +02:00
fn to_smoltcp_hardware_address ( addr : driver ::HardwareAddress ) -> HardwareAddress {
match addr {
#[ cfg(feature = " medium-ethernet " ) ]
driver ::HardwareAddress ::Ethernet ( eth ) = > HardwareAddress ::Ethernet ( EthernetAddress ( eth ) ) ,
#[ cfg(feature = " medium-ieee802154 " ) ]
driver ::HardwareAddress ::Ieee802154 ( ieee ) = > HardwareAddress ::Ieee802154 ( Ieee802154Address ::Extended ( ieee ) ) ,
2023-07-31 12:19:04 +02:00
#[ cfg(feature = " medium-ip " ) ]
driver ::HardwareAddress ::Ip = > HardwareAddress ::Ip ,
2023-07-31 10:40:48 +02:00
#[ allow(unreachable_patterns) ]
2023-08-25 01:03:24 +02:00
_ = > panic! (
" Unsupported medium {:?}. Make sure to enable the right medium feature in embassy-net's Cargo features. " ,
addr
) ,
2023-07-31 10:40:48 +02:00
}
}
2022-12-26 03:33:49 +01:00
impl < D : Driver + 'static > Stack < D > {
2023-05-15 00:39:57 +02:00
/// Create a new network stack.
2023-01-18 10:10:33 +01:00
pub fn new < const SOCK : usize > (
2022-12-07 16:02:28 +01:00
mut device : D ,
2023-01-18 10:10:33 +01:00
config : Config ,
resources : & 'static mut StackResources < SOCK > ,
2022-12-07 16:02:28 +01:00
random_seed : u64 ,
) -> Self {
2023-07-31 12:20:13 +02:00
let mut iface_cfg = smoltcp ::iface ::Config ::new ( to_smoltcp_hardware_address ( device . hardware_address ( ) ) ) ;
2023-01-19 14:41:39 +01:00
iface_cfg . random_seed = random_seed ;
2022-12-07 16:02:28 +01:00
2023-01-19 14:41:39 +01:00
let iface = Interface ::new (
iface_cfg ,
& mut DriverAdapter {
inner : & mut device ,
cx : None ,
} ,
2023-06-26 01:59:25 +02:00
instant_to_smoltcp ( Instant ::now ( ) ) ,
2023-01-19 14:41:39 +01:00
) ;
2022-12-07 16:02:28 +01:00
let sockets = SocketSet ::new ( & mut resources . sockets [ .. ] ) ;
let next_local_port = ( random_seed % ( LOCAL_PORT_MAX - LOCAL_PORT_MIN ) as u64 ) as u16 + LOCAL_PORT_MIN ;
2023-07-16 02:02:04 +02:00
#[ cfg_attr(feature = " medium-ieee802154 " , allow(unused_mut)) ]
2023-02-10 18:30:17 +01:00
let mut socket = SocketStack {
sockets ,
iface ,
waker : WakerRegistration ::new ( ) ,
next_local_port ,
} ;
2022-12-07 16:02:28 +01:00
let mut inner = Inner {
device ,
link_up : false ,
2023-06-05 16:00:53 +02:00
#[ cfg(feature = " proto-ipv4 " ) ]
static_v4 : None ,
2023-06-05 16:12:24 +02:00
#[ cfg(feature = " proto-ipv6 " ) ]
static_v6 : None ,
2022-12-07 16:02:28 +01:00
#[ cfg(feature = " dhcpv4 " ) ]
dhcp_socket : None ,
2023-02-10 17:43:23 +01:00
#[ cfg(feature = " dns " ) ]
2023-02-10 18:44:51 +01:00
dns_socket : socket . sockets . add ( dns ::Socket ::new (
& [ ] ,
managed ::ManagedSlice ::Borrowed ( & mut resources . queries ) ,
) ) ,
#[ cfg(feature = " dns " ) ]
dns_waker : WakerRegistration ::new ( ) ,
2022-12-07 16:02:28 +01:00
} ;
2023-02-10 17:43:23 +01:00
2023-06-07 12:04:15 +02:00
#[ cfg(feature = " proto-ipv4 " ) ]
2023-08-25 19:48:45 +02:00
inner . set_config_v4 ( & mut socket , config . ipv4 ) ;
2023-06-07 12:04:15 +02:00
#[ cfg(feature = " proto-ipv6 " ) ]
2023-08-25 19:48:45 +02:00
inner . set_config_v6 ( & mut socket , config . ipv6 ) ;
inner . apply_static_config ( & mut socket ) ;
2022-12-07 16:02:28 +01:00
Self {
socket : RefCell ::new ( socket ) ,
inner : RefCell ::new ( inner ) ,
}
}
fn with < R > ( & self , f : impl FnOnce ( & SocketStack , & Inner < D > ) -> R ) -> R {
f ( & * self . socket . borrow ( ) , & * self . inner . borrow ( ) )
}
fn with_mut < R > ( & self , f : impl FnOnce ( & mut SocketStack , & mut Inner < D > ) -> R ) -> R {
f ( & mut * self . socket . borrow_mut ( ) , & mut * self . inner . borrow_mut ( ) )
}
2023-07-28 16:19:24 +02:00
/// Get the hardware address of the network interface.
pub fn hardware_address ( & self ) -> HardwareAddress {
2023-07-31 10:40:48 +02:00
self . with ( | _s , i | to_smoltcp_hardware_address ( i . device . hardware_address ( ) ) )
2022-12-07 16:02:28 +01:00
}
2023-05-15 00:39:57 +02:00
/// Get whether the link is up.
2022-12-07 16:02:28 +01:00
pub fn is_link_up ( & self ) -> bool {
self . with ( | _s , i | i . link_up )
}
2023-05-15 00:39:57 +02:00
/// Get whether the network stack has a valid IP configuration.
/// This is true if the network stack has a static IP configuration or if DHCP has completed
2022-12-07 16:02:28 +01:00
pub fn is_config_up ( & self ) -> bool {
2023-06-06 11:17:02 +02:00
let v4_up ;
let v6_up ;
2023-06-05 16:00:53 +02:00
#[ cfg(feature = " proto-ipv4 " ) ]
{
2023-06-06 11:17:02 +02:00
v4_up = self . config_v4 ( ) . is_some ( ) ;
}
#[ cfg(not(feature = " proto-ipv4 " )) ]
{
v4_up = false ;
2023-06-05 16:00:53 +02:00
}
2023-06-06 11:17:02 +02:00
#[ cfg(feature = " proto-ipv6 " ) ]
{
v6_up = self . config_v6 ( ) . is_some ( ) ;
}
#[ cfg(not(feature = " proto-ipv6 " )) ]
2023-06-05 16:00:53 +02:00
{
2023-06-06 11:17:02 +02:00
v6_up = false ;
2023-06-05 16:00:53 +02:00
}
2023-06-06 11:17:02 +02:00
v4_up | | v6_up
2022-12-07 16:02:28 +01:00
}
2023-06-06 11:17:02 +02:00
/// Get the current IPv4 configuration.
2023-08-25 19:48:45 +02:00
///
/// If using DHCP, this will be None if DHCP hasn't been able to
/// acquire an IP address, or Some if it has.
2023-06-05 16:00:53 +02:00
#[ cfg(feature = " proto-ipv4 " ) ]
pub fn config_v4 ( & self ) -> Option < StaticConfigV4 > {
2023-08-25 19:48:45 +02:00
self . with ( | _ , i | i . static_v4 . clone ( ) )
2022-12-07 16:02:28 +01:00
}
2023-06-06 11:17:02 +02:00
/// Get the current IPv6 configuration.
#[ cfg(feature = " proto-ipv6 " ) ]
pub fn config_v6 ( & self ) -> Option < StaticConfigV6 > {
2023-08-25 19:48:45 +02:00
self . with ( | _ , i | i . static_v6 . clone ( ) )
}
/// Set the IPv4 configuration.
#[ cfg(feature = " proto-ipv4 " ) ]
pub fn set_config_v4 ( & self , config : ConfigV4 ) {
self . with_mut ( | s , i | {
i . set_config_v4 ( s , config ) ;
i . apply_static_config ( s ) ;
} )
}
/// Set the IPv6 configuration.
#[ cfg(feature = " proto-ipv6 " ) ]
pub fn set_config_v6 ( & self , config : ConfigV6 ) {
self . with_mut ( | s , i | {
i . set_config_v6 ( s , config ) ;
i . apply_static_config ( s ) ;
} )
2023-06-06 11:17:02 +02:00
}
2023-05-15 00:39:57 +02:00
/// Run the network stack.
///
/// You must call this in a background task, to process network events.
2022-12-07 16:02:28 +01:00
pub async fn run ( & self ) -> ! {
poll_fn ( | cx | {
self . with_mut ( | s , i | i . poll ( cx , s ) ) ;
Poll ::< ( ) > ::Pending
} )
. await ;
unreachable! ( )
}
2023-02-10 17:43:23 +01:00
2023-02-10 18:20:50 +01:00
/// Make a query for a given name and return the corresponding IP addresses.
2023-02-10 17:43:23 +01:00
#[ cfg(feature = " dns " ) ]
2023-02-10 18:20:50 +01:00
pub async fn dns_query ( & self , name : & str , qtype : dns ::DnsQueryType ) -> Result < Vec < IpAddress , 1 > , dns ::Error > {
2023-02-25 20:58:28 +01:00
// For A and AAAA queries we try detect whether `name` is just an IP address
match qtype {
2023-06-05 16:00:53 +02:00
#[ cfg(feature = " proto-ipv4 " ) ]
2023-02-25 20:58:28 +01:00
dns ::DnsQueryType ::A = > {
if let Ok ( ip ) = name . parse ( ) . map ( IpAddress ::Ipv4 ) {
return Ok ( [ ip ] . into_iter ( ) . collect ( ) ) ;
}
}
#[ cfg(feature = " proto-ipv6 " ) ]
dns ::DnsQueryType ::Aaaa = > {
if let Ok ( ip ) = name . parse ( ) . map ( IpAddress ::Ipv6 ) {
return Ok ( [ ip ] . into_iter ( ) . collect ( ) ) ;
}
}
_ = > { }
}
2023-02-10 18:44:51 +01:00
let query = poll_fn ( | cx | {
self . with_mut ( | s , i | {
let socket = s . sockets . get_mut ::< dns ::Socket > ( i . dns_socket ) ;
match socket . start_query ( s . iface . context ( ) , name , qtype ) {
Ok ( handle ) = > Poll ::Ready ( Ok ( handle ) ) ,
Err ( dns ::StartQueryError ::NoFreeSlot ) = > {
i . dns_waker . register ( cx . waker ( ) ) ;
Poll ::Pending
}
Err ( e ) = > Poll ::Ready ( Err ( e ) ) ,
}
} )
} )
. await ? ;
2023-02-10 17:43:23 +01:00
2023-06-29 19:51:16 +02:00
#[ must_use = " to delay the drop handler invocation to the end of the scope " ]
struct OnDrop < F : FnOnce ( ) > {
f : core ::mem ::MaybeUninit < F > ,
}
impl < F : FnOnce ( ) > OnDrop < F > {
fn new ( f : F ) -> Self {
Self {
f : core ::mem ::MaybeUninit ::new ( f ) ,
}
}
fn defuse ( self ) {
core ::mem ::forget ( self )
}
}
impl < F : FnOnce ( ) > Drop for OnDrop < F > {
fn drop ( & mut self ) {
unsafe { self . f . as_ptr ( ) . read ( ) ( ) }
}
}
2023-02-10 17:43:23 +01:00
let drop = OnDrop ::new ( | | {
self . with_mut ( | s , i | {
2023-02-10 18:30:17 +01:00
let socket = s . sockets . get_mut ::< dns ::Socket > ( i . dns_socket ) ;
socket . cancel_query ( query ) ;
s . waker . wake ( ) ;
2023-02-10 18:44:51 +01:00
i . dns_waker . wake ( ) ;
2023-02-10 17:43:23 +01:00
} )
} ) ;
let res = poll_fn ( | cx | {
self . with_mut ( | s , i | {
2023-02-10 18:30:17 +01:00
let socket = s . sockets . get_mut ::< dns ::Socket > ( i . dns_socket ) ;
match socket . get_query_result ( query ) {
2023-02-10 18:44:51 +01:00
Ok ( addrs ) = > {
i . dns_waker . wake ( ) ;
Poll ::Ready ( Ok ( addrs ) )
}
2023-02-10 18:30:17 +01:00
Err ( dns ::GetQueryResultError ::Pending ) = > {
socket . register_query_waker ( query , cx . waker ( ) ) ;
Poll ::Pending
2023-02-10 17:43:23 +01:00
}
2023-02-10 18:44:51 +01:00
Err ( e ) = > {
i . dns_waker . wake ( ) ;
Poll ::Ready ( Err ( e . into ( ) ) )
}
2023-02-10 17:43:23 +01:00
}
} )
} )
. await ;
drop . defuse ( ) ;
res
}
2022-12-07 16:02:28 +01:00
}
2023-03-06 17:50:57 +01:00
#[ cfg(feature = " igmp " ) ]
2023-07-18 17:35:20 +02:00
impl < D : Driver + 'static > Stack < D > {
2023-05-15 00:39:57 +02:00
/// Join a multicast group.
2023-07-18 17:35:20 +02:00
pub async fn join_multicast_group < T > ( & self , addr : T ) -> Result < bool , MulticastError >
where
T : Into < IpAddress > ,
{
let addr = addr . into ( ) ;
poll_fn ( move | cx | self . poll_join_multicast_group ( addr , cx ) ) . await
}
2023-05-15 00:39:57 +02:00
/// Join a multicast group.
2023-07-18 17:35:20 +02:00
///
/// When the send queue is full, this method will return `Poll::Pending`
/// and register the current task to be notified when the queue has space available.
pub fn poll_join_multicast_group < T > ( & self , addr : T , cx : & mut Context < '_ > ) -> Poll < Result < bool , MulticastError > >
2023-03-07 23:40:20 +01:00
where
T : Into < IpAddress > ,
2023-03-06 17:50:57 +01:00
{
let addr = addr . into ( ) ;
self . with_mut ( | s , i | {
2023-07-18 17:35:20 +02:00
let mut smoldev = DriverAdapter {
cx : Some ( cx ) ,
inner : & mut i . device ,
} ;
match s
. iface
. join_multicast_group ( & mut smoldev , addr , instant_to_smoltcp ( Instant ::now ( ) ) )
{
Ok ( announce_sent ) = > Poll ::Ready ( Ok ( announce_sent ) ) ,
Err ( MulticastError ::Exhausted ) = > Poll ::Pending ,
Err ( other ) = > Poll ::Ready ( Err ( other ) ) ,
}
2023-03-06 17:50:57 +01:00
} )
}
2023-05-15 00:39:57 +02:00
/// Leave a multicast group.
2023-07-18 17:35:20 +02:00
pub async fn leave_multicast_group < T > ( & self , addr : T ) -> Result < bool , MulticastError >
where
T : Into < IpAddress > ,
{
let addr = addr . into ( ) ;
poll_fn ( move | cx | self . poll_leave_multicast_group ( addr , cx ) ) . await
}
/// Leave a multicast group.
///
/// When the send queue is full, this method will return `Poll::Pending`
/// and register the current task to be notified when the queue has space available.
pub fn poll_leave_multicast_group < T > ( & self , addr : T , cx : & mut Context < '_ > ) -> Poll < Result < bool , MulticastError > >
2023-03-07 23:40:20 +01:00
where
T : Into < IpAddress > ,
2023-03-06 17:50:57 +01:00
{
let addr = addr . into ( ) ;
self . with_mut ( | s , i | {
2023-07-18 17:35:20 +02:00
let mut smoldev = DriverAdapter {
cx : Some ( cx ) ,
inner : & mut i . device ,
} ;
match s
. iface
. leave_multicast_group ( & mut smoldev , addr , instant_to_smoltcp ( Instant ::now ( ) ) )
{
Ok ( leave_sent ) = > Poll ::Ready ( Ok ( leave_sent ) ) ,
Err ( MulticastError ::Exhausted ) = > Poll ::Pending ,
Err ( other ) = > Poll ::Ready ( Err ( other ) ) ,
}
2023-03-06 17:50:57 +01:00
} )
}
2023-05-15 00:39:57 +02:00
/// Get whether the network stack has joined the given multicast group.
2023-03-08 12:37:00 +01:00
pub fn has_multicast_group < T : Into < IpAddress > > ( & self , addr : T ) -> bool {
2023-03-06 17:50:57 +01:00
self . socket . borrow ( ) . iface . has_multicast_group ( addr )
}
}
2022-12-07 16:02:28 +01:00
impl SocketStack {
2023-01-18 10:10:33 +01:00
#[ allow(clippy::absurd_extreme_comparisons, dead_code) ]
2022-12-07 16:02:28 +01:00
pub fn get_local_port ( & mut self ) -> u16 {
let res = self . next_local_port ;
self . next_local_port = if res > = LOCAL_PORT_MAX { LOCAL_PORT_MIN } else { res + 1 } ;
res
}
}
2022-12-26 03:33:49 +01:00
impl < D : Driver + 'static > Inner < D > {
2023-06-05 16:00:53 +02:00
#[ cfg(feature = " proto-ipv4 " ) ]
2023-08-25 19:48:45 +02:00
pub fn set_config_v4 ( & mut self , _s : & mut SocketStack , config : ConfigV4 ) {
// Handle static config.
self . static_v4 = match config . clone ( ) {
ConfigV4 ::None = > None ,
#[ cfg(feature = " dhcpv4 " ) ]
ConfigV4 ::Dhcp ( _ ) = > None ,
ConfigV4 ::Static ( c ) = > Some ( c ) ,
} ;
2022-12-07 16:02:28 +01:00
2023-08-25 19:48:45 +02:00
// Handle DHCP config.
#[ cfg(feature = " dhcpv4 " ) ]
match config {
ConfigV4 ::Dhcp ( c ) = > {
// Create the socket if it doesn't exist.
if self . dhcp_socket . is_none ( ) {
let socket = smoltcp ::socket ::dhcpv4 ::Socket ::new ( ) ;
let handle = _s . sockets . add ( socket ) ;
self . dhcp_socket = Some ( handle ) ;
}
2023-06-05 16:35:31 +02:00
2023-08-25 19:48:45 +02:00
// Configure it
2023-09-02 07:44:10 +02:00
let socket = _s . sockets . get_mut ::< dhcpv4 ::Socket > ( unwrap! ( self . dhcp_socket ) ) ;
2023-08-25 19:48:45 +02:00
socket . set_ignore_naks ( c . ignore_naks ) ;
socket . set_max_lease_duration ( c . max_lease_duration . map ( crate ::time ::duration_to_smoltcp ) ) ;
socket . set_ports ( c . server_port , c . client_port ) ;
socket . set_retry_config ( c . retry_config ) ;
socket . reset ( ) ;
}
_ = > {
// Remove DHCP socket if any.
if let Some ( socket ) = self . dhcp_socket {
_s . sockets . remove ( socket ) ;
self . dhcp_socket = None ;
}
}
2023-02-10 19:00:00 +01:00
}
2022-12-07 16:02:28 +01:00
}
2023-06-05 16:12:24 +02:00
#[ cfg(feature = " proto-ipv6 " ) ]
2023-08-25 19:48:45 +02:00
pub fn set_config_v6 ( & mut self , _s : & mut SocketStack , config : ConfigV6 ) {
self . static_v6 = match config {
ConfigV6 ::None = > None ,
ConfigV6 ::Static ( c ) = > Some ( c ) ,
} ;
}
2023-06-05 16:12:24 +02:00
2023-08-25 19:48:45 +02:00
fn apply_static_config ( & mut self , s : & mut SocketStack ) {
let mut addrs = Vec ::new ( ) ;
#[ cfg(feature = " dns " ) ]
let mut dns_servers : Vec < _ , 6 > = Vec ::new ( ) ;
#[ cfg(feature = " proto-ipv4 " ) ]
let mut gateway_v4 = None ;
#[ cfg(feature = " proto-ipv6 " ) ]
let mut gateway_v6 = None ;
2023-06-05 16:12:24 +02:00
2023-08-25 19:48:45 +02:00
#[ cfg(feature = " proto-ipv4 " ) ]
if let Some ( config ) = & self . static_v4 {
debug! ( " IPv4: UP " ) ;
debug! ( " IP address: {:?} " , config . address ) ;
debug! ( " Default gateway: {:?} " , config . gateway ) ;
2023-06-05 16:12:24 +02:00
2023-09-02 07:44:10 +02:00
unwrap! ( addrs . push ( IpCidr ::Ipv4 ( config . address ) ) . ok ( ) ) ;
2023-08-25 19:48:45 +02:00
gateway_v4 = config . gateway . into ( ) ;
#[ cfg(feature = " dns " ) ]
for s in & config . dns_servers {
debug! ( " DNS server: {:?} " , s ) ;
2023-09-02 07:44:10 +02:00
unwrap! ( dns_servers . push ( s . clone ( ) . into ( ) ) . ok ( ) ) ;
2023-06-05 16:12:24 +02:00
}
2023-08-25 19:48:45 +02:00
} else {
info! ( " IPv4: DOWN " ) ;
2023-06-05 16:12:24 +02:00
}
2023-08-25 19:48:45 +02:00
#[ cfg(feature = " proto-ipv6 " ) ]
if let Some ( config ) = & self . static_v6 {
debug! ( " IPv6: UP " ) ;
debug! ( " IP address: {:?} " , config . address ) ;
debug! ( " Default gateway: {:?} " , config . gateway ) ;
2023-06-05 16:35:31 +02:00
2023-09-02 07:44:10 +02:00
unwrap! ( addrs . push ( IpCidr ::Ipv6 ( config . address ) ) . ok ( ) ) ;
2023-08-25 19:48:45 +02:00
gateway_v6 = config . gateway . into ( ) ;
#[ cfg(feature = " dns " ) ]
for s in & config . dns_servers {
debug! ( " DNS server: {:?} " , s ) ;
2023-09-02 07:44:10 +02:00
unwrap! ( dns_servers . push ( s . clone ( ) . into ( ) ) . ok ( ) ) ;
2023-08-25 19:48:45 +02:00
}
} else {
info! ( " IPv6: DOWN " ) ;
2023-06-05 16:35:31 +02:00
}
2023-08-25 19:48:45 +02:00
// Apply addresses
s . iface . update_ip_addrs ( | a | * a = addrs ) ;
2023-06-05 16:35:31 +02:00
2023-08-25 19:48:45 +02:00
// Apply gateways
2023-06-05 16:35:31 +02:00
#[ cfg(feature = " proto-ipv4 " ) ]
2023-08-25 19:48:45 +02:00
if let Some ( gateway ) = gateway_v4 {
2023-09-02 07:44:10 +02:00
unwrap! ( s . iface . routes_mut ( ) . add_default_ipv4_route ( gateway ) ) ;
2023-08-25 19:48:45 +02:00
} else {
s . iface . routes_mut ( ) . remove_default_ipv4_route ( ) ;
2023-06-05 16:35:31 +02:00
}
#[ cfg(feature = " proto-ipv6 " ) ]
2023-08-25 19:48:45 +02:00
if let Some ( gateway ) = gateway_v6 {
2023-09-02 07:44:10 +02:00
unwrap! ( s . iface . routes_mut ( ) . add_default_ipv6_route ( gateway ) ) ;
2023-08-25 19:48:45 +02:00
} else {
s . iface . routes_mut ( ) . remove_default_ipv6_route ( ) ;
2023-06-05 16:35:31 +02:00
}
2023-06-05 16:12:24 +02:00
2023-08-25 19:48:45 +02:00
// Apply DNS servers
#[ cfg(feature = " dns " ) ]
s . sockets
. get_mut ::< smoltcp ::socket ::dns ::Socket > ( self . dns_socket )
. update_servers ( & dns_servers [ .. ] ) ;
2022-12-07 16:02:28 +01:00
}
fn poll ( & mut self , cx : & mut Context < '_ > , s : & mut SocketStack ) {
s . waker . register ( cx . waker ( ) ) ;
2023-07-28 16:19:24 +02:00
#[ cfg(any(feature = " medium-ethernet " , feature = " medium-ieee802154 " )) ]
2023-08-25 19:48:45 +02:00
if self . device . capabilities ( ) . medium = = embassy_net_driver ::Medium ::Ethernet
| | self . device . capabilities ( ) . medium = = embassy_net_driver ::Medium ::Ieee802154
2023-07-28 16:19:24 +02:00
{
2023-07-31 10:40:48 +02:00
s . iface
. set_hardware_addr ( to_smoltcp_hardware_address ( self . device . hardware_address ( ) ) ) ;
2023-07-28 16:22:03 +02:00
}
2022-12-07 16:02:28 +01:00
let timestamp = instant_to_smoltcp ( Instant ::now ( ) ) ;
2022-12-26 03:33:49 +01:00
let mut smoldev = DriverAdapter {
2022-12-07 16:02:28 +01:00
cx : Some ( cx ) ,
inner : & mut self . device ,
} ;
2023-01-19 13:30:51 +01:00
s . iface . poll ( timestamp , & mut smoldev , & mut s . sockets ) ;
2022-12-07 16:02:28 +01:00
// Update link up
let old_link_up = self . link_up ;
self . link_up = self . device . link_state ( cx ) = = LinkState ::Up ;
// Print when changed
if old_link_up ! = self . link_up {
info! ( " link_up = {:?} " , self . link_up ) ;
}
2023-08-25 19:48:45 +02:00
#[ allow(unused_mut) ]
let mut apply_config = false ;
2022-12-07 16:02:28 +01:00
#[ cfg(feature = " dhcpv4 " ) ]
if let Some ( dhcp_handle ) = self . dhcp_socket {
let socket = s . sockets . get_mut ::< dhcpv4 ::Socket > ( dhcp_handle ) ;
if self . link_up {
match socket . poll ( ) {
None = > { }
2023-08-25 19:48:45 +02:00
Some ( dhcpv4 ::Event ::Deconfigured ) = > {
self . static_v4 = None ;
apply_config = true ;
}
2022-12-07 16:02:28 +01:00
Some ( dhcpv4 ::Event ::Configured ( config ) ) = > {
2023-08-25 19:48:45 +02:00
self . static_v4 = Some ( StaticConfigV4 {
2022-12-07 16:02:28 +01:00
address : config . address ,
gateway : config . router ,
dns_servers : config . dns_servers ,
2023-08-25 19:48:45 +02:00
} ) ;
apply_config = true ;
2022-12-07 16:02:28 +01:00
}
}
} else if old_link_up {
socket . reset ( ) ;
2023-08-25 19:48:45 +02:00
self . static_v4 = None ;
apply_config = true ;
2022-12-07 16:02:28 +01:00
}
}
2023-08-25 19:48:45 +02:00
if apply_config {
self . apply_static_config ( s ) ;
}
2022-12-07 16:02:28 +01:00
if let Some ( poll_at ) = s . iface . poll_at ( timestamp , & mut s . sockets ) {
let t = Timer ::at ( instant_from_smoltcp ( poll_at ) ) ;
pin_mut! ( t ) ;
if t . poll ( cx ) . is_ready ( ) {
cx . waker ( ) . wake_by_ref ( ) ;
}
}
}
}