use core::sync::atomic::{AtomicBool, Ordering}; use smoltcp::iface::{Config, Interface, SocketHandle, SocketSet, SocketStorage}; use smoltcp::socket::{dhcpv4, dns, icmp, tcp, udp}; use smoltcp::time::{Duration, Instant}; use smoltcp::wire::{ EthernetAddress, HardwareAddress, IpAddress, IpCidr, Ipv4Address, Ipv6Address, Ipv6Cidr, }; use crate::device::PacketDevice; static CREATED: AtomicBool = AtomicBool::new(false); pub static MDNS_JOIN_FAILED: AtomicBool = AtomicBool::new(false); const TCP_RX_BUF_SIZE: usize = 8192; const TCP_TX_BUF_SIZE: usize = 8192; const SHELL_TCP_RX_SIZE: usize = 8192; const SHELL_TCP_TX_SIZE: usize = 8192; pub const MAX_SHELL_SOCKETS: usize = 4; pub const MAX_UDP_SOCKETS: usize = 4; const DNS_QUERY_SLOTS: usize = 2; const MAX_SOCKETS: usize = 2 + MAX_SHELL_SOCKETS + 2 + 1 + MAX_UDP_SOCKETS + 1; static mut TCP_RX_DATA: [u8; TCP_RX_BUF_SIZE] = [0u8; TCP_RX_BUF_SIZE]; static mut TCP_TX_DATA: [u8; TCP_TX_BUF_SIZE] = [0u8; TCP_TX_BUF_SIZE]; static mut SHELL_TCP_RX_POOL: [[u8; SHELL_TCP_RX_SIZE]; MAX_SHELL_SOCKETS] = [[0u8; SHELL_TCP_RX_SIZE]; MAX_SHELL_SOCKETS]; static mut SHELL_TCP_TX_POOL: [[u8; SHELL_TCP_TX_SIZE]; MAX_SHELL_SOCKETS] = [[0u8; SHELL_TCP_TX_SIZE]; MAX_SHELL_SOCKETS]; static mut SOCKET_STORAGE: [SocketStorage<'static>; MAX_SOCKETS] = [SocketStorage::EMPTY; MAX_SOCKETS]; static mut DNS_QUERIES: [Option; DNS_QUERY_SLOTS] = [const { None }; DNS_QUERY_SLOTS]; const ICMP_META_SLOTS: usize = 4; const ICMP_PAYLOAD_SIZE: usize = 512; static mut ICMP_RX_META: [icmp::PacketMetadata; ICMP_META_SLOTS] = [icmp::PacketMetadata::EMPTY; ICMP_META_SLOTS]; static mut ICMP_RX_DATA: [u8; ICMP_PAYLOAD_SIZE] = [0u8; ICMP_PAYLOAD_SIZE]; static mut ICMP_TX_META: [icmp::PacketMetadata; ICMP_META_SLOTS] = [icmp::PacketMetadata::EMPTY; ICMP_META_SLOTS]; static mut ICMP_TX_DATA: [u8; ICMP_PAYLOAD_SIZE] = [0u8; ICMP_PAYLOAD_SIZE]; const UDP_BUF_SIZE: usize = 2048; const UDP_META_SLOTS: usize = 4; static mut UDP_RX_META_POOL: [[udp::PacketMetadata; UDP_META_SLOTS]; MAX_UDP_SOCKETS] = [[udp::PacketMetadata::EMPTY; UDP_META_SLOTS]; MAX_UDP_SOCKETS]; static mut UDP_RX_DATA_POOL: [[u8; UDP_BUF_SIZE]; MAX_UDP_SOCKETS] = [[0u8; UDP_BUF_SIZE]; MAX_UDP_SOCKETS]; static mut UDP_TX_META_POOL: [[udp::PacketMetadata; UDP_META_SLOTS]; MAX_UDP_SOCKETS] = [[udp::PacketMetadata::EMPTY; UDP_META_SLOTS]; MAX_UDP_SOCKETS]; static mut UDP_TX_DATA_POOL: [[u8; UDP_BUF_SIZE]; MAX_UDP_SOCKETS] = [[0u8; UDP_BUF_SIZE]; MAX_UDP_SOCKETS]; const MDNS_META_SLOTS: usize = 4; const MDNS_BUF_SIZE: usize = 1500; static mut MDNS_RX_META: [udp::PacketMetadata; MDNS_META_SLOTS] = [udp::PacketMetadata::EMPTY; MDNS_META_SLOTS]; static mut MDNS_RX_DATA: [u8; MDNS_BUF_SIZE] = [0u8; MDNS_BUF_SIZE]; static mut MDNS_TX_META: [udp::PacketMetadata; MDNS_META_SLOTS] = [udp::PacketMetadata::EMPTY; MDNS_META_SLOTS]; static mut MDNS_TX_DATA: [u8; MDNS_BUF_SIZE] = [0u8; MDNS_BUF_SIZE]; pub struct NetStack { pub iface: Interface, pub sockets: SocketSet<'static>, pub tcp_handle: SocketHandle, pub shell_handles: [SocketHandle; MAX_SHELL_SOCKETS], pub dhcp_handle: SocketHandle, pub dns_handle: SocketHandle, pub icmp_handle: SocketHandle, pub udp_handles: [SocketHandle; MAX_UDP_SOCKETS], pub mdns_handle: SocketHandle, } #[allow(clippy::deref_addrof)] pub fn create(device: &mut PacketDevice, mac: [u8; 6], now: Instant) -> NetStack { assert!( !CREATED.swap(true, Ordering::Relaxed), "stack::create() called twice" ); let hw_addr = HardwareAddress::Ethernet(EthernetAddress(mac)); let config = Config::new(hw_addr); let mut iface = Interface::new(config, device, now); let socket_storage: &'static mut [SocketStorage<'static>; MAX_SOCKETS] = unsafe { &mut *(&raw mut SOCKET_STORAGE) }; let mut sockets = SocketSet::new(&mut socket_storage[..]); let tcp_rx_data: &'static mut [u8] = unsafe { &mut *(&raw mut TCP_RX_DATA) }; let tcp_rx_buf = tcp::SocketBuffer::new(tcp_rx_data); let tcp_tx_data: &'static mut [u8] = unsafe { &mut *(&raw mut TCP_TX_DATA) }; let tcp_tx_buf = tcp::SocketBuffer::new(tcp_tx_data); let tcp_socket = tcp::Socket::new(tcp_rx_buf, tcp_tx_buf); let tcp_handle = sockets.add(tcp_socket); let rx_pool: &'static mut [[u8; SHELL_TCP_RX_SIZE]; MAX_SHELL_SOCKETS] = unsafe { &mut *(&raw mut SHELL_TCP_RX_POOL) }; let tx_pool: &'static mut [[u8; SHELL_TCP_TX_SIZE]; MAX_SHELL_SOCKETS] = unsafe { &mut *(&raw mut SHELL_TCP_TX_POOL) }; let mut shell_handles_tmp: [Option; MAX_SHELL_SOCKETS] = [None; MAX_SHELL_SOCKETS]; rx_pool .iter_mut() .zip(tx_pool.iter_mut()) .zip(shell_handles_tmp.iter_mut()) .for_each(|((rx_data, tx_data), slot)| { let mut sock = tcp::Socket::new( tcp::SocketBuffer::new(&mut rx_data[..]), tcp::SocketBuffer::new(&mut tx_data[..]), ); sock.set_nagle_enabled(false); sock.set_ack_delay(None); sock.set_keep_alive(Some(Duration::from_secs(30))); *slot = Some(sockets.add(sock)); }); let shell_handles = shell_handles_tmp.map(|opt| opt.unwrap()); let dhcp_socket = dhcpv4::Socket::new(); let dhcp_handle = sockets.add(dhcp_socket); let dns_queries: &'static mut [Option; DNS_QUERY_SLOTS] = unsafe { &mut *(&raw mut DNS_QUERIES) }; let dns_socket = dns::Socket::new(&[] as &[IpAddress], &mut dns_queries[..]); let dns_handle = sockets.add(dns_socket); let icmp_rx_meta: &'static mut [icmp::PacketMetadata; ICMP_META_SLOTS] = unsafe { &mut *(&raw mut ICMP_RX_META) }; let icmp_rx_data: &'static mut [u8; ICMP_PAYLOAD_SIZE] = unsafe { &mut *(&raw mut ICMP_RX_DATA) }; let icmp_tx_meta: &'static mut [icmp::PacketMetadata; ICMP_META_SLOTS] = unsafe { &mut *(&raw mut ICMP_TX_META) }; let icmp_tx_data: &'static mut [u8; ICMP_PAYLOAD_SIZE] = unsafe { &mut *(&raw mut ICMP_TX_DATA) }; let icmp_rx_buf = icmp::PacketBuffer::new(&mut icmp_rx_meta[..], &mut icmp_rx_data[..]); let icmp_tx_buf = icmp::PacketBuffer::new(&mut icmp_tx_meta[..], &mut icmp_tx_data[..]); let mut icmp_socket = icmp::Socket::new(icmp_rx_buf, icmp_tx_buf); icmp_socket.bind(icmp::Endpoint::Ident(0x4C41)).unwrap(); let icmp_handle = sockets.add(icmp_socket); let udp_rx_meta_pool: &'static mut [[udp::PacketMetadata; UDP_META_SLOTS]; MAX_UDP_SOCKETS] = unsafe { &mut *(&raw mut UDP_RX_META_POOL) }; let udp_rx_data_pool: &'static mut [[u8; UDP_BUF_SIZE]; MAX_UDP_SOCKETS] = unsafe { &mut *(&raw mut UDP_RX_DATA_POOL) }; let udp_tx_meta_pool: &'static mut [[udp::PacketMetadata; UDP_META_SLOTS]; MAX_UDP_SOCKETS] = unsafe { &mut *(&raw mut UDP_TX_META_POOL) }; let udp_tx_data_pool: &'static mut [[u8; UDP_BUF_SIZE]; MAX_UDP_SOCKETS] = unsafe { &mut *(&raw mut UDP_TX_DATA_POOL) }; let mut udp_handles_tmp: [Option; MAX_UDP_SOCKETS] = [None; MAX_UDP_SOCKETS]; udp_rx_meta_pool .iter_mut() .zip(udp_rx_data_pool.iter_mut()) .zip(udp_tx_meta_pool.iter_mut()) .zip(udp_tx_data_pool.iter_mut()) .zip(udp_handles_tmp.iter_mut()) .for_each(|((((rx_meta, rx_data), tx_meta), tx_data), slot)| { let sock = udp::Socket::new( udp::PacketBuffer::new(&mut rx_meta[..], &mut rx_data[..]), udp::PacketBuffer::new(&mut tx_meta[..], &mut tx_data[..]), ); *slot = Some(sockets.add(sock)); }); let udp_handles = udp_handles_tmp.map(|opt| opt.unwrap()); let mdns_rx_meta: &'static mut [udp::PacketMetadata; MDNS_META_SLOTS] = unsafe { &mut *(&raw mut MDNS_RX_META) }; let mdns_rx_data: &'static mut [u8; MDNS_BUF_SIZE] = unsafe { &mut *(&raw mut MDNS_RX_DATA) }; let mdns_tx_meta: &'static mut [udp::PacketMetadata; MDNS_META_SLOTS] = unsafe { &mut *(&raw mut MDNS_TX_META) }; let mdns_tx_data: &'static mut [u8; MDNS_BUF_SIZE] = unsafe { &mut *(&raw mut MDNS_TX_DATA) }; let mdns_rx_buf = udp::PacketBuffer::new(&mut mdns_rx_meta[..], &mut mdns_rx_data[..]); let mdns_tx_buf = udp::PacketBuffer::new(&mut mdns_tx_meta[..], &mut mdns_tx_data[..]); let mut mdns_socket = udp::Socket::new(mdns_rx_buf, mdns_tx_buf); mdns_socket .bind(smoltcp::wire::IpListenEndpoint { addr: None, port: 5353, }) .unwrap(); let mdns_handle = sockets.add(mdns_socket); let link_local = eui64_link_local(&mac); iface.update_ip_addrs(|addrs| { let _ = addrs.push(IpCidr::Ipv6(Ipv6Cidr::new(link_local, 64))); }); if iface .join_multicast_group(Ipv4Address::new(224, 0, 0, 251)) .is_err() { MDNS_JOIN_FAILED.store(true, Ordering::Relaxed); } NetStack { iface, sockets, tcp_handle, shell_handles, dhcp_handle, dns_handle, icmp_handle, udp_handles, mdns_handle, } } pub fn eui64_link_local_bytes(mac: &[u8; 6]) -> [u8; 16] { let addr = eui64_link_local(mac); addr.octets() } fn eui64_link_local(mac: &[u8; 6]) -> Ipv6Address { Ipv6Address::new( 0xfe80, 0, 0, 0, ((mac[0] ^ 0x02) as u16) << 8 | mac[1] as u16, (mac[2] as u16) << 8 | 0x00ff, 0xfe00 | mac[3] as u16, (mac[4] as u16) << 8 | mac[5] as u16, ) }