Kaynağa Gözat

Merge pull request #736 from smoltcp-rs/fixes

iface: make everything owned, remove lifetime, remove builder.
Dario Nieuwenhuis 2 yıl önce
ebeveyn
işleme
80b0756a34

+ 12 - 15
examples/benchmark.rs

@@ -9,7 +9,7 @@ use std::os::unix::io::AsRawFd;
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::thread;
 
-use smoltcp::iface::{InterfaceBuilder, NeighborCache, SocketSet};
+use smoltcp::iface::{Config, Interface, SocketSet};
 use smoltcp::phy::{wait as phy_wait, Device, Medium};
 use smoltcp::socket::tcp;
 use smoltcp::time::{Duration, Instant};
@@ -80,8 +80,6 @@ fn main() {
         _ => panic!("invalid mode"),
     };
 
-    let neighbor_cache = NeighborCache::new();
-
     let tcp1_rx_buffer = tcp::SocketBuffer::new(vec![0; 65535]);
     let tcp1_tx_buffer = tcp::SocketBuffer::new(vec![0; 65535]);
     let tcp1_socket = tcp::Socket::new(tcp1_rx_buffer, tcp1_tx_buffer);
@@ -90,19 +88,18 @@ fn main() {
     let tcp2_tx_buffer = tcp::SocketBuffer::new(vec![0; 65535]);
     let tcp2_socket = tcp::Socket::new(tcp2_rx_buffer, tcp2_tx_buffer);
 
-    let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]);
-    let mut ip_addrs = heapless::Vec::<IpCidr, 5>::new();
-    ip_addrs
-        .push(IpCidr::new(IpAddress::v4(192, 168, 69, 1), 24))
-        .unwrap();
-    let medium = device.capabilities().medium;
-    let mut builder = InterfaceBuilder::new().ip_addrs(ip_addrs);
-    if medium == Medium::Ethernet {
-        builder = builder
-            .hardware_addr(ethernet_addr.into())
-            .neighbor_cache(neighbor_cache);
+    let mut config = Config::new();
+    config.random_seed = rand::random();
+    if device.capabilities().medium == Medium::Ethernet {
+        config.hardware_addr = Some(EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]).into());
     }
-    let mut iface = builder.finalize(&mut device);
+
+    let mut iface = Interface::new(config, &mut device);
+    iface.update_ip_addrs(|ip_addrs| {
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v4(192, 168, 69, 1), 24))
+            .unwrap();
+    });
 
     let mut sockets = SocketSet::new(vec![]);
     let tcp1_handle = sockets.add(tcp1_socket);

+ 30 - 35
examples/client.rs

@@ -4,11 +4,11 @@ use log::debug;
 use std::os::unix::io::AsRawFd;
 use std::str::{self, FromStr};
 
-use smoltcp::iface::{InterfaceBuilder, NeighborCache, Routes, SocketSet};
+use smoltcp::iface::{Config, Interface, SocketSet};
 use smoltcp::phy::{wait as phy_wait, Device, Medium};
 use smoltcp::socket::tcp;
 use smoltcp::time::Instant;
-use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address};
+use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address, Ipv6Address};
 
 fn main() {
     utils::setup_logging("");
@@ -28,43 +28,38 @@ fn main() {
     let address = IpAddress::from_str(&matches.free[0]).expect("invalid address format");
     let port = u16::from_str(&matches.free[1]).expect("invalid port format");
 
-    let neighbor_cache = NeighborCache::new();
+    // Create interface
+    let mut config = Config::new();
+    config.random_seed = rand::random();
+    if device.capabilities().medium == Medium::Ethernet {
+        config.hardware_addr = Some(EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]).into());
+    }
+
+    let mut iface = Interface::new(config, &mut device);
+    iface.update_ip_addrs(|ip_addrs| {
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v4(192, 168, 69, 1), 24))
+            .unwrap();
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v6(0xfdaa, 0, 0, 0, 0, 0, 0, 1), 64))
+            .unwrap();
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64))
+            .unwrap();
+    });
+    iface
+        .routes_mut()
+        .add_default_ipv4_route(Ipv4Address::new(192, 168, 69, 100))
+        .unwrap();
+    iface
+        .routes_mut()
+        .add_default_ipv6_route(Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0x100))
+        .unwrap();
 
+    // Create sockets
     let tcp_rx_buffer = tcp::SocketBuffer::new(vec![0; 1500]);
     let tcp_tx_buffer = tcp::SocketBuffer::new(vec![0; 1500]);
     let tcp_socket = tcp::Socket::new(tcp_rx_buffer, tcp_tx_buffer);
-
-    let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
-    let mut ip_addrs = heapless::Vec::<IpCidr, 5>::new();
-    ip_addrs
-        .push(IpCidr::new(IpAddress::v4(192, 168, 69, 2), 24))
-        .unwrap();
-    let default_v4_gw = Ipv4Address::new(192, 168, 69, 100);
-    let mut routes = Routes::new();
-    routes.add_default_ipv4_route(default_v4_gw).unwrap();
-
-    let medium = device.capabilities().medium;
-    let builder = InterfaceBuilder::new().ip_addrs(ip_addrs).routes(routes);
-
-    #[cfg(feature = "proto-ipv4-fragmentation")]
-    let mut ipv4_out_packet_cache = [0u8; 1280];
-    #[cfg(feature = "proto-ipv4-fragmentation")]
-    let builder = builder.ipv4_fragmentation_buffer(&mut ipv4_out_packet_cache[..]);
-
-    #[cfg(feature = "proto-sixlowpan-fragmentation")]
-    let mut sixlowpan_out_packet_cache = [0u8; 1280];
-    #[cfg(feature = "proto-sixlowpan-fragmentation")]
-    let builder = builder.sixlowpan_fragmentation_buffer(&mut sixlowpan_out_packet_cache[..]);
-
-    let builder = if medium == Medium::Ethernet {
-        builder
-            .hardware_addr(ethernet_addr.into())
-            .neighbor_cache(neighbor_cache)
-    } else {
-        builder
-    };
-    let mut iface = builder.finalize(&mut device);
-
     let mut sockets = SocketSet::new(vec![]);
     let tcp_handle = sockets.add(tcp_socket);
 

+ 9 - 16
examples/dhcp_client.rs

@@ -4,7 +4,7 @@ mod utils;
 use log::*;
 use std::os::unix::io::AsRawFd;
 
-use smoltcp::iface::{Interface, InterfaceBuilder, NeighborCache, SocketSet};
+use smoltcp::iface::{Config, Interface, SocketSet};
 use smoltcp::socket::dhcpv4;
 use smoltcp::time::Instant;
 use smoltcp::wire::{EthernetAddress, IpCidr, Ipv4Address, Ipv4Cidr};
@@ -27,22 +27,15 @@ fn main() {
     let mut device =
         utils::parse_middleware_options(&mut matches, device, /*loopback=*/ false);
 
-    let neighbor_cache = NeighborCache::new();
-    let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]);
-    let mut ip_addrs = heapless::Vec::<IpCidr, 5>::new();
-    ip_addrs
-        .push(IpCidr::new(Ipv4Address::UNSPECIFIED.into(), 0))
-        .unwrap();
-
-    let medium = device.capabilities().medium;
-    let mut builder = InterfaceBuilder::new().ip_addrs(ip_addrs);
-    if medium == Medium::Ethernet {
-        builder = builder
-            .hardware_addr(ethernet_addr.into())
-            .neighbor_cache(neighbor_cache);
+    // Create interface
+    let mut config = Config::new();
+    config.random_seed = rand::random();
+    if device.capabilities().medium == Medium::Ethernet {
+        config.hardware_addr = Some(EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]).into());
     }
-    let mut iface = builder.finalize(&mut device);
+    let mut iface = Interface::new(config, &mut device);
 
+    // Create sockets
     let mut dhcp_socket = dhcpv4::Socket::new();
 
     // Set a ridiculously short max lease time to show DHCP renews work properly.
@@ -90,7 +83,7 @@ fn main() {
     }
 }
 
-fn set_ipv4_addr(iface: &mut Interface<'_>, cidr: Ipv4Cidr) {
+fn set_ipv4_addr(iface: &mut Interface, cidr: Ipv4Cidr) {
     iface.update_ip_addrs(|addrs| {
         let dest = addrs.iter_mut().next().unwrap();
         *dest = IpCidr::Ipv4(cidr);

+ 30 - 30
examples/dns.rs

@@ -7,14 +7,12 @@ extern crate smoltcp;
 
 mod utils;
 
-use smoltcp::iface::{InterfaceBuilder, NeighborCache, Routes, SocketSet};
+use smoltcp::iface::{Config, Interface, SocketSet};
 use smoltcp::phy::Device;
 use smoltcp::phy::{wait as phy_wait, Medium};
 use smoltcp::socket::dns::{self, GetQueryResultError};
 use smoltcp::time::Instant;
-use smoltcp::wire::{
-    DnsQueryType, EthernetAddress, HardwareAddress, IpAddress, IpCidr, Ipv4Address, Ipv6Address,
-};
+use smoltcp::wire::{DnsQueryType, EthernetAddress, IpAddress, IpCidr, Ipv4Address, Ipv6Address};
 use std::os::unix::io::AsRawFd;
 
 fn main() {
@@ -32,39 +30,41 @@ fn main() {
         utils::parse_middleware_options(&mut matches, device, /*loopback=*/ false);
     let name = &matches.free[0];
 
-    let neighbor_cache = NeighborCache::new();
+    // Create interface
+    let mut config = Config::new();
+    config.random_seed = rand::random();
+    if device.capabilities().medium == Medium::Ethernet {
+        config.hardware_addr = Some(EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]).into());
+    }
 
+    let mut iface = Interface::new(config, &mut device);
+    iface.update_ip_addrs(|ip_addrs| {
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v4(192, 168, 69, 1), 24))
+            .unwrap();
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v6(0xfdaa, 0, 0, 0, 0, 0, 0, 1), 64))
+            .unwrap();
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64))
+            .unwrap();
+    });
+    iface
+        .routes_mut()
+        .add_default_ipv4_route(Ipv4Address::new(192, 168, 69, 100))
+        .unwrap();
+    iface
+        .routes_mut()
+        .add_default_ipv6_route(Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0x100))
+        .unwrap();
+
+    // Create sockets
     let servers = &[
         Ipv4Address::new(8, 8, 4, 4).into(),
         Ipv4Address::new(8, 8, 8, 8).into(),
     ];
     let dns_socket = dns::Socket::new(servers, vec![]);
 
-    let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
-    let src_ipv6 = IpAddress::v6(0xfdaa, 0, 0, 0, 0, 0, 0, 1);
-    let mut ip_addrs = heapless::Vec::<IpCidr, 5>::new();
-    ip_addrs
-        .push(IpCidr::new(IpAddress::v4(192, 168, 69, 1), 24))
-        .unwrap();
-    ip_addrs.push(IpCidr::new(src_ipv6, 64)).unwrap();
-    ip_addrs
-        .push(IpCidr::new(IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64))
-        .unwrap();
-    let default_v4_gw = Ipv4Address::new(192, 168, 69, 100);
-    let default_v6_gw = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0x100);
-    let mut routes = Routes::new();
-    routes.add_default_ipv4_route(default_v4_gw).unwrap();
-    routes.add_default_ipv6_route(default_v6_gw).unwrap();
-
-    let medium = device.capabilities().medium;
-    let mut builder = InterfaceBuilder::new().ip_addrs(ip_addrs).routes(routes);
-    if medium == Medium::Ethernet {
-        builder = builder
-            .hardware_addr(HardwareAddress::Ethernet(ethernet_addr))
-            .neighbor_cache(neighbor_cache);
-    }
-    let mut iface = builder.finalize(&mut device);
-
     let mut sockets = SocketSet::new(vec![]);
     let dns_handle = sockets.add(dns_socket);
 

+ 29 - 28
examples/httpclient.rs

@@ -5,7 +5,7 @@ use std::os::unix::io::AsRawFd;
 use std::str::{self, FromStr};
 use url::Url;
 
-use smoltcp::iface::{InterfaceBuilder, NeighborCache, Routes, SocketSet};
+use smoltcp::iface::{Config, Interface, SocketSet};
 use smoltcp::phy::{wait as phy_wait, Device, Medium};
 use smoltcp::socket::tcp;
 use smoltcp::time::Instant;
@@ -28,37 +28,38 @@ fn main() {
     let address = IpAddress::from_str(&matches.free[0]).expect("invalid address format");
     let url = Url::parse(&matches.free[1]).expect("invalid url format");
 
-    let neighbor_cache = NeighborCache::new();
-
-    let tcp_rx_buffer = tcp::SocketBuffer::new(vec![0; 1024]);
-    let tcp_tx_buffer = tcp::SocketBuffer::new(vec![0; 1024]);
-    let tcp_socket = tcp::Socket::new(tcp_rx_buffer, tcp_tx_buffer);
+    // Create interface
+    let mut config = Config::new();
+    config.random_seed = rand::random();
+    if device.capabilities().medium == Medium::Ethernet {
+        config.hardware_addr = Some(EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]).into());
+    }
 
-    let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
-    let mut ip_addrs = heapless::Vec::<IpCidr, 5>::new();
-    ip_addrs
-        .push(IpCidr::new(IpAddress::v4(192, 168, 69, 1), 24))
+    let mut iface = Interface::new(config, &mut device);
+    iface.update_ip_addrs(|ip_addrs| {
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v4(192, 168, 69, 1), 24))
+            .unwrap();
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v6(0xfdaa, 0, 0, 0, 0, 0, 0, 1), 64))
+            .unwrap();
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64))
+            .unwrap();
+    });
+    iface
+        .routes_mut()
+        .add_default_ipv4_route(Ipv4Address::new(192, 168, 69, 100))
         .unwrap();
-    ip_addrs
-        .push(IpCidr::new(IpAddress::v6(0xfdaa, 0, 0, 0, 0, 0, 0, 1), 64))
+    iface
+        .routes_mut()
+        .add_default_ipv6_route(Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0x100))
         .unwrap();
-    ip_addrs
-        .push(IpCidr::new(IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64))
-        .unwrap();
-    let default_v4_gw = Ipv4Address::new(192, 168, 69, 100);
-    let default_v6_gw = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0x100);
-    let mut routes = Routes::new();
-    routes.add_default_ipv4_route(default_v4_gw).unwrap();
-    routes.add_default_ipv6_route(default_v6_gw).unwrap();
 
-    let medium = device.capabilities().medium;
-    let mut builder = InterfaceBuilder::new().ip_addrs(ip_addrs).routes(routes);
-    if medium == Medium::Ethernet {
-        builder = builder
-            .hardware_addr(ethernet_addr.into())
-            .neighbor_cache(neighbor_cache);
-    }
-    let mut iface = builder.finalize(&mut device);
+    // Create sockets
+    let tcp_rx_buffer = tcp::SocketBuffer::new(vec![0; 1024]);
+    let tcp_tx_buffer = tcp::SocketBuffer::new(vec![0; 1024]);
+    let tcp_socket = tcp::Socket::new(tcp_rx_buffer, tcp_tx_buffer);
 
     let mut sockets = SocketSet::new(vec![]);
     let tcp_handle = sockets.add(tcp_socket);

+ 12 - 10
examples/loopback.rs

@@ -9,7 +9,7 @@ mod utils;
 use core::str;
 use log::{debug, error, info};
 
-use smoltcp::iface::{InterfaceBuilder, NeighborCache, SocketSet};
+use smoltcp::iface::{Config, Interface, SocketSet};
 use smoltcp::phy::{Loopback, Medium};
 use smoltcp::socket::tcp;
 use smoltcp::time::{Duration, Instant};
@@ -82,16 +82,18 @@ fn main() {
         utils::parse_middleware_options(&mut matches, device, /*loopback=*/ true)
     };
 
-    let mut ip_addrs = heapless::Vec::<IpCidr, 5>::new();
-    ip_addrs
-        .push(IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8))
-        .unwrap();
-    let mut iface = InterfaceBuilder::new()
-        .hardware_addr(EthernetAddress::default().into())
-        .neighbor_cache(NeighborCache::new())
-        .ip_addrs(ip_addrs)
-        .finalize(&mut device);
+    // Create interface
+    let mut config = Config::new();
+    config.hardware_addr = Some(EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]).into());
 
+    let mut iface = Interface::new(config, &mut device);
+    iface.update_ip_addrs(|ip_addrs| {
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8))
+            .unwrap();
+    });
+
+    // Create sockets
     let server_socket = {
         // It is not strictly necessary to use a `static mut` and unsafe code here, but
         // on embedded systems that smoltcp targets it is far better to allocate the data

+ 37 - 18
examples/multicast.rs

@@ -2,13 +2,13 @@ mod utils;
 
 use std::os::unix::io::AsRawFd;
 
-use smoltcp::iface::{InterfaceBuilder, NeighborCache, SocketSet};
-use smoltcp::phy::wait as phy_wait;
+use smoltcp::iface::{Config, Interface, SocketSet};
+use smoltcp::phy::{wait as phy_wait, Device, Medium};
 use smoltcp::socket::{raw, udp};
 use smoltcp::time::Instant;
 use smoltcp::wire::{
     EthernetAddress, IgmpPacket, IgmpRepr, IpAddress, IpCidr, IpProtocol, IpVersion, Ipv4Address,
-    Ipv4Packet,
+    Ipv4Packet, Ipv6Address,
 };
 
 const MDNS_PORT: u16 = 5353;
@@ -26,26 +26,36 @@ fn main() {
     let fd = device.as_raw_fd();
     let mut device =
         utils::parse_middleware_options(&mut matches, device, /*loopback=*/ false);
-    let neighbor_cache = NeighborCache::new();
 
-    let local_addr = Ipv4Address::new(192, 168, 69, 2);
-
-    let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
-    let ip_addr = IpCidr::new(IpAddress::from(local_addr), 24);
-    let mut ip_addrs = heapless::Vec::<IpCidr, 5>::new();
-    ip_addrs.push(ip_addr).unwrap();
-    let mut iface = InterfaceBuilder::new()
-        .hardware_addr(ethernet_addr.into())
-        .neighbor_cache(neighbor_cache)
-        .ip_addrs(ip_addrs)
-        .finalize(&mut device);
+    // Create interface
+    let mut config = Config::new();
+    config.random_seed = rand::random();
+    if device.capabilities().medium == Medium::Ethernet {
+        config.hardware_addr = Some(EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]).into());
+    }
 
-    let now = Instant::now();
-    // Join a multicast group to receive mDNS traffic
+    let mut iface = Interface::new(config, &mut device);
+    iface.update_ip_addrs(|ip_addrs| {
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v4(192, 168, 69, 1), 24))
+            .unwrap();
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v6(0xfdaa, 0, 0, 0, 0, 0, 0, 1), 64))
+            .unwrap();
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64))
+            .unwrap();
+    });
+    iface
+        .routes_mut()
+        .add_default_ipv4_route(Ipv4Address::new(192, 168, 69, 100))
+        .unwrap();
     iface
-        .join_multicast_group(&mut device, Ipv4Address::from_bytes(&MDNS_GROUP), now)
+        .routes_mut()
+        .add_default_ipv6_route(Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0x100))
         .unwrap();
 
+    // Create sockets
     let mut sockets = SocketSet::new(vec![]);
 
     // Must fit at least one IGMP packet
@@ -67,6 +77,15 @@ fn main() {
     let udp_socket = udp::Socket::new(udp_rx_buffer, udp_tx_buffer);
     let udp_handle = sockets.add(udp_socket);
 
+    // Join a multicast group to receive mDNS traffic
+    iface
+        .join_multicast_group(
+            &mut device,
+            Ipv4Address::from_bytes(&MDNS_GROUP),
+            Instant::now(),
+        )
+        .unwrap();
+
     loop {
         let timestamp = Instant::now();
         iface.poll(timestamp, &mut device, &mut sockets);

+ 32 - 33
examples/ping.rs

@@ -1,13 +1,13 @@
 mod utils;
 
 use byteorder::{ByteOrder, NetworkEndian};
-use smoltcp::iface::SocketSet;
+use smoltcp::iface::{Interface, SocketSet};
 use std::cmp;
 use std::collections::HashMap;
 use std::os::unix::io::AsRawFd;
 use std::str::FromStr;
 
-use smoltcp::iface::{InterfaceBuilder, NeighborCache, Routes};
+use smoltcp::iface::Config;
 use smoltcp::phy::wait as phy_wait;
 use smoltcp::phy::Device;
 use smoltcp::socket::icmp;
@@ -88,7 +88,7 @@ fn main() {
     let mut device =
         utils::parse_middleware_options(&mut matches, device, /*loopback=*/ false);
     let device_caps = device.capabilities();
-    let address = IpAddress::from_str(&matches.free[0]).expect("invalid address format");
+    let remote_addr = IpAddress::from_str(&matches.free[0]).expect("invalid address format");
     let count = matches
         .opt_str("count")
         .map(|s| usize::from_str(&s).unwrap())
@@ -104,39 +104,38 @@ fn main() {
             .unwrap_or(5),
     );
 
-    let neighbor_cache = NeighborCache::new();
+    // Create interface
+    let mut config = Config::new();
+    config.random_seed = rand::random();
+    if device.capabilities().medium == Medium::Ethernet {
+        config.hardware_addr = Some(EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]).into());
+    }
 
-    let remote_addr = address;
+    let mut iface = Interface::new(config, &mut device);
+    iface.update_ip_addrs(|ip_addrs| {
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v4(192, 168, 69, 1), 24))
+            .unwrap();
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v6(0xfdaa, 0, 0, 0, 0, 0, 0, 1), 64))
+            .unwrap();
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64))
+            .unwrap();
+    });
+    iface
+        .routes_mut()
+        .add_default_ipv4_route(Ipv4Address::new(192, 168, 69, 100))
+        .unwrap();
+    iface
+        .routes_mut()
+        .add_default_ipv6_route(Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0x100))
+        .unwrap();
 
+    // Create sockets
     let icmp_rx_buffer = icmp::PacketBuffer::new(vec![icmp::PacketMetadata::EMPTY], vec![0; 256]);
     let icmp_tx_buffer = icmp::PacketBuffer::new(vec![icmp::PacketMetadata::EMPTY], vec![0; 256]);
     let icmp_socket = icmp::Socket::new(icmp_rx_buffer, icmp_tx_buffer);
-
-    let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
-    let src_ipv6 = IpAddress::v6(0xfdaa, 0, 0, 0, 0, 0, 0, 1);
-    let mut ip_addrs = heapless::Vec::<IpCidr, 5>::new();
-    ip_addrs
-        .push(IpCidr::new(IpAddress::v4(192, 168, 69, 1), 24))
-        .unwrap();
-    ip_addrs.push(IpCidr::new(src_ipv6, 64)).unwrap();
-    ip_addrs
-        .push(IpCidr::new(IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64))
-        .unwrap();
-    let default_v4_gw = Ipv4Address::new(192, 168, 69, 100);
-    let default_v6_gw = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0x100);
-    let mut routes = Routes::new();
-    routes.add_default_ipv4_route(default_v4_gw).unwrap();
-    routes.add_default_ipv6_route(default_v6_gw).unwrap();
-
-    let medium = device.capabilities().medium;
-    let mut builder = InterfaceBuilder::new().ip_addrs(ip_addrs).routes(routes);
-    if medium == Medium::Ethernet {
-        builder = builder
-            .hardware_addr(ethernet_addr.into())
-            .neighbor_cache(neighbor_cache);
-    }
-    let mut iface = builder.finalize(&mut device);
-
     let mut sockets = SocketSet::new(vec![]);
     let icmp_handle = sockets.add(icmp_socket);
 
@@ -185,7 +184,7 @@ fn main() {
                         remote_addr
                     );
                     icmp_repr.emit(
-                        &src_ipv6,
+                        &iface.ipv6_addr().unwrap().into_address(),
                         &remote_addr,
                         &mut icmp_packet,
                         &device_caps.checksum,
@@ -219,7 +218,7 @@ fn main() {
                     let icmp_packet = Icmpv6Packet::new_checked(&payload).unwrap();
                     let icmp_repr = Icmpv6Repr::parse(
                         &remote_addr,
-                        &src_ipv6,
+                        &iface.ipv6_addr().unwrap().into_address(),
                         &icmp_packet,
                         &device_caps.checksum,
                     )

+ 30 - 42
examples/server.rs

@@ -4,11 +4,11 @@ use log::debug;
 use std::fmt::Write;
 use std::os::unix::io::AsRawFd;
 
-use smoltcp::iface::{InterfaceBuilder, NeighborCache, SocketSet};
+use smoltcp::iface::{Config, Interface, SocketSet};
 use smoltcp::phy::{wait as phy_wait, Device, Medium};
 use smoltcp::socket::{tcp, udp};
 use smoltcp::time::{Duration, Instant};
-use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr};
+use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address, Ipv6Address};
 
 fn main() {
     utils::setup_logging("");
@@ -23,8 +23,35 @@ fn main() {
     let mut device =
         utils::parse_middleware_options(&mut matches, device, /*loopback=*/ false);
 
-    let neighbor_cache = NeighborCache::new();
+    // Create interface
+    let mut config = Config::new();
+    config.random_seed = rand::random();
+    if device.capabilities().medium == Medium::Ethernet {
+        config.hardware_addr = Some(EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]).into());
+    }
+
+    let mut iface = Interface::new(config, &mut device);
+    iface.update_ip_addrs(|ip_addrs| {
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v4(192, 168, 69, 1), 24))
+            .unwrap();
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v6(0xfdaa, 0, 0, 0, 0, 0, 0, 1), 64))
+            .unwrap();
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64))
+            .unwrap();
+    });
+    iface
+        .routes_mut()
+        .add_default_ipv4_route(Ipv4Address::new(192, 168, 69, 100))
+        .unwrap();
+    iface
+        .routes_mut()
+        .add_default_ipv6_route(Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0x100))
+        .unwrap();
 
+    // Create sockets
     let udp_rx_buffer = udp::PacketBuffer::new(
         vec![udp::PacketMetadata::EMPTY, udp::PacketMetadata::EMPTY],
         vec![0; 65535],
@@ -51,45 +78,6 @@ fn main() {
     let tcp4_tx_buffer = tcp::SocketBuffer::new(vec![0; 65535]);
     let tcp4_socket = tcp::Socket::new(tcp4_rx_buffer, tcp4_tx_buffer);
 
-    let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]);
-    let mut ip_addrs = heapless::Vec::<IpCidr, 5>::new();
-    ip_addrs
-        .push(IpCidr::new(IpAddress::v4(192, 168, 69, 1), 24))
-        .unwrap();
-    ip_addrs
-        .push(IpCidr::new(IpAddress::v6(0xfdaa, 0, 0, 0, 0, 0, 0, 1), 64))
-        .unwrap();
-    ip_addrs
-        .push(IpCidr::new(IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64))
-        .unwrap();
-
-    let medium = device.capabilities().medium;
-    let mut builder = InterfaceBuilder::new().ip_addrs(ip_addrs);
-
-    builder = builder.random_seed(
-        std::time::SystemTime::now()
-            .duration_since(std::time::UNIX_EPOCH)
-            .unwrap()
-            .as_secs(),
-    );
-
-    #[cfg(feature = "proto-ipv4-fragmentation")]
-    let mut ipv4_out_packet_cache = [0u8; 10_000];
-    #[cfg(feature = "proto-ipv4-fragmentation")]
-    let builder = builder.ipv4_fragmentation_buffer(&mut ipv4_out_packet_cache[..]);
-
-    #[cfg(feature = "proto-sixlowpan-fragmentation")]
-    let mut sixlowpan_out_packet_cache = [0u8; 1280];
-    #[cfg(feature = "proto-sixlowpan-fragmentation")]
-    let mut builder = builder.sixlowpan_fragmentation_buffer(&mut sixlowpan_out_packet_cache[..]);
-
-    if medium == Medium::Ethernet {
-        builder = builder
-            .hardware_addr(ethernet_addr.into())
-            .neighbor_cache(neighbor_cache);
-    }
-    let mut iface = builder.finalize(&mut device);
-
     let mut sockets = SocketSet::new(vec![]);
     let udp_handle = sockets.add(udp_socket);
     let tcp1_handle = sockets.add(tcp1_socket);

+ 20 - 32
examples/sixlowpan.rs

@@ -46,12 +46,12 @@ use log::debug;
 use std::os::unix::io::AsRawFd;
 use std::str;
 
-use smoltcp::iface::{InterfaceBuilder, NeighborCache, SocketSet};
+use smoltcp::iface::{Config, Interface, SocketSet};
 use smoltcp::phy::{wait as phy_wait, Medium, RawSocket};
 use smoltcp::socket::tcp;
 use smoltcp::socket::udp;
 use smoltcp::time::Instant;
-use smoltcp::wire::{Ieee802154Pan, IpAddress, IpCidr};
+use smoltcp::wire::{Ieee802154Address, Ieee802154Pan, IpAddress, IpCidr};
 
 fn main() {
     utils::setup_logging("");
@@ -62,13 +62,28 @@ fn main() {
     let mut matches = utils::parse_options(&opts, free);
 
     let device = RawSocket::new("wpan1", Medium::Ieee802154).unwrap();
-
     let fd = device.as_raw_fd();
     let mut device =
         utils::parse_middleware_options(&mut matches, device, /*loopback=*/ false);
 
-    let neighbor_cache = NeighborCache::new();
-
+    // Create interface
+    let mut config = Config::new();
+    config.random_seed = rand::random();
+    config.hardware_addr =
+        Some(Ieee802154Address::Extended([0x1a, 0x0b, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42]).into());
+    config.pan_id = Some(Ieee802154Pan(0xbeef));
+
+    let mut iface = Interface::new(config, &mut device);
+    iface.update_ip_addrs(|ip_addrs| {
+        ip_addrs
+            .push(IpCidr::new(
+                IpAddress::v6(0xfe80, 0, 0, 0, 0x180b, 0x4242, 0x4242, 0x4242),
+                64,
+            ))
+            .unwrap();
+    });
+
+    // Create sockets
     let udp_rx_buffer = udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY], vec![0; 1280]);
     let udp_tx_buffer = udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY], vec![0; 1280]);
     let udp_socket = udp::Socket::new(udp_rx_buffer, udp_tx_buffer);
@@ -77,33 +92,6 @@ fn main() {
     let tcp_tx_buffer = tcp::SocketBuffer::new(vec![0; 4096]);
     let tcp_socket = tcp::Socket::new(tcp_rx_buffer, tcp_tx_buffer);
 
-    let ieee802154_addr = smoltcp::wire::Ieee802154Address::Extended([
-        0x1a, 0x0b, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
-    ]);
-    let mut ip_addrs = heapless::Vec::<IpCidr, 5>::new();
-    ip_addrs
-        .push(IpCidr::new(
-            IpAddress::v6(0xfe80, 0, 0, 0, 0x180b, 0x4242, 0x4242, 0x4242),
-            64,
-        ))
-        .unwrap();
-
-    let mut builder = InterfaceBuilder::new()
-        .ip_addrs(ip_addrs)
-        .pan_id(Ieee802154Pan(0xbeef));
-    builder = builder
-        .hardware_addr(ieee802154_addr.into())
-        .neighbor_cache(neighbor_cache);
-
-    #[cfg(feature = "proto-sixlowpan-fragmentation")]
-    let mut out_packet_buffer = [0u8; 1280];
-    #[cfg(feature = "proto-sixlowpan-fragmentation")]
-    {
-        builder = builder.sixlowpan_fragmentation_buffer(&mut out_packet_buffer[..]);
-    }
-
-    let mut iface = builder.finalize(&mut device);
-
     let mut sockets = SocketSet::new(vec![]);
     let udp_handle = sockets.add(udp_socket);
     let tcp_handle = sockets.add(tcp_socket);

+ 18 - 23
examples/sixlowpan_benchmark.rs

@@ -46,10 +46,10 @@ mod utils;
 use std::os::unix::io::AsRawFd;
 use std::str;
 
-use smoltcp::iface::{InterfaceBuilder, NeighborCache, SocketSet};
+use smoltcp::iface::{Config, Interface, SocketSet};
 use smoltcp::phy::{wait as phy_wait, Medium, RawSocket};
 use smoltcp::socket::tcp;
-use smoltcp::wire::{Ieee802154Pan, IpAddress, IpCidr};
+use smoltcp::wire::{Ieee802154Address, Ieee802154Pan, IpAddress, IpCidr};
 
 //For benchmark
 use smoltcp::time::{Duration, Instant};
@@ -146,7 +146,22 @@ fn main() {
         _ => panic!("invalid mode"),
     };
 
-    let neighbor_cache = NeighborCache::new();
+    // Create interface
+    let mut config = Config::new();
+    config.random_seed = rand::random();
+    config.hardware_addr =
+        Some(Ieee802154Address::Extended([0x1a, 0x0b, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42]).into());
+    config.pan_id = Some(Ieee802154Pan(0xbeef));
+
+    let mut iface = Interface::new(config, &mut device);
+    iface.update_ip_addrs(|ip_addrs| {
+        ip_addrs
+            .push(IpCidr::new(
+                IpAddress::v6(0xfe80, 0, 0, 0, 0x180b, 0x4242, 0x4242, 0x4242),
+                64,
+            ))
+            .unwrap();
+    });
 
     let tcp1_rx_buffer = tcp::SocketBuffer::new(vec![0; 4096]);
     let tcp1_tx_buffer = tcp::SocketBuffer::new(vec![0; 4096]);
@@ -156,26 +171,6 @@ fn main() {
     let tcp2_tx_buffer = tcp::SocketBuffer::new(vec![0; 4096]);
     let tcp2_socket = tcp::Socket::new(tcp2_rx_buffer, tcp2_tx_buffer);
 
-    let ieee802154_addr = smoltcp::wire::Ieee802154Address::Extended([
-        0x1a, 0x0b, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
-    ]);
-    let mut ip_addrs = heapless::Vec::<IpCidr, 5>::new();
-    ip_addrs
-        .push(IpCidr::new(
-            IpAddress::v6(0xfe80, 0, 0, 0, 0x180b, 0x4242, 0x4242, 0x4242),
-            64,
-        ))
-        .unwrap();
-
-    let mut builder = InterfaceBuilder::new()
-        .ip_addrs(ip_addrs)
-        .pan_id(Ieee802154Pan(0xbeef));
-    builder = builder
-        .hardware_addr(ieee802154_addr.into())
-        .neighbor_cache(neighbor_cache)
-        .sixlowpan_fragmentation_buffer(vec![]);
-    let mut iface = builder.finalize(&mut device);
-
     let mut sockets = SocketSet::new(vec![]);
     let tcp1_handle = sockets.add(tcp1_socket);
     let tcp2_handle = sockets.add(tcp2_socket);

+ 4 - 20
src/iface/fragmentation.rs

@@ -111,16 +111,8 @@ impl<K> PacketAssembler<K> {
             offset
         );
 
-        match self.assembler.add(offset, len) {
-            Ok(()) => {
-                net_debug!("assembler: {}", self.assembler);
-                Ok(())
-            }
-            Err(_) => {
-                net_debug!("packet assembler: too many holes, dropping.");
-                Err(AssemblerError)
-            }
-        }
+        self.assembler.add(offset, len);
+        Ok(())
     }
 
     /// Add a fragment into the packet that is being reassembled.
@@ -149,16 +141,8 @@ impl<K> PacketAssembler<K> {
             offset
         );
 
-        match self.assembler.add(offset, data.len()) {
-            Ok(()) => {
-                net_debug!("assembler: {}", self.assembler);
-                Ok(())
-            }
-            Err(_) => {
-                net_debug!("packet assembler: too many holes, dropping.");
-                Err(AssemblerError)
-            }
-        }
+        self.assembler.add(offset, data.len());
+        Ok(())
     }
 
     /// Get an immutable slice of the underlying packet data, if reassembly complete.

+ 1 - 1
src/iface/interface/ethernet.rs

@@ -9,7 +9,7 @@ use core::result::Result;
 use crate::phy::TxToken;
 use crate::wire::*;
 
-impl<'i> InterfaceInner<'i> {
+impl InterfaceInner {
     #[cfg(feature = "medium-ethernet")]
     pub(super) fn process_ethernet<'frame, T: AsRef<[u8]>>(
         &mut self,

+ 2 - 2
src/iface/interface/igmp.rs

@@ -17,7 +17,7 @@ pub enum MulticastError {
     Ipv6NotSupported,
 }
 
-impl<'a> Interface<'a> {
+impl Interface {
     /// Add an address to a list of subscribed multicast IP addresses.
     ///
     /// Returns `Ok(announce_sent)` if the address was added successfully, where `annouce_sent`
@@ -180,7 +180,7 @@ impl<'a> Interface<'a> {
     }
 }
 
-impl<'a> InterfaceInner<'a> {
+impl InterfaceInner {
     /// Check whether the interface listens to given destination multicast IP address.
     ///
     /// If built without feature `proto-igmp` this function will

+ 4 - 4
src/iface/interface/ipv4.rs

@@ -21,7 +21,7 @@ use crate::phy::{Medium, TxToken};
 use crate::time::{Duration, Instant};
 use crate::wire::*;
 
-impl<'a> InterfaceInner<'a> {
+impl InterfaceInner {
     pub(super) fn process_ipv4<'output, 'payload: 'output, T: AsRef<[u8]> + ?Sized>(
         &mut self,
         sockets: &mut SocketSet,
@@ -324,7 +324,7 @@ impl<'a> InterfaceInner<'a> {
         } else if self.is_broadcast_v4(ipv4_repr.dst_addr) {
             // Only reply to broadcasts for echo replies and not other ICMP messages
             match icmp_repr {
-                Icmpv4Repr::EchoReply { .. } => match self.ipv4_address() {
+                Icmpv4Repr::EchoReply { .. } => match self.ipv4_addr() {
                     Some(src_addr) => {
                         let ipv4_reply_repr = Ipv4Repr {
                             src_addr,
@@ -427,7 +427,7 @@ impl<'a> InterfaceInner<'a> {
         version: IgmpVersion,
         group_addr: Ipv4Address,
     ) -> Option<IpPacket<'any>> {
-        let iface_addr = self.ipv4_address()?;
+        let iface_addr = self.ipv4_addr()?;
         let igmp_repr = IgmpRepr::MembershipReport {
             group_addr,
             version,
@@ -452,7 +452,7 @@ impl<'a> InterfaceInner<'a> {
         &self,
         group_addr: Ipv4Address,
     ) -> Option<IpPacket<'any>> {
-        self.ipv4_address().map(|iface_addr| {
+        self.ipv4_addr().map(|iface_addr| {
             let igmp_repr = IgmpRepr::LeaveGroup { group_addr };
             IpPacket::Igmp((
                 Ipv4Repr {

+ 1 - 1
src/iface/interface/ipv6.rs

@@ -10,7 +10,7 @@ use crate::socket::AnySocket;
 
 use crate::wire::*;
 
-impl<'a> InterfaceInner<'a> {
+impl InterfaceInner {
     #[cfg(feature = "proto-ipv6")]
     pub(super) fn process_ipv6<'frame, T: AsRef<[u8]> + ?Sized>(
         &mut self,

+ 255 - 443
src/iface/interface/mod.rs

@@ -19,17 +19,15 @@ mod ipv6;
 mod igmp;
 
 use core::cmp;
-use core::marker::PhantomData;
 use core::result::Result;
 use heapless::{LinearMap, Vec};
-use managed::ManagedSlice;
 
 #[cfg(any(feature = "proto-ipv4", feature = "proto-sixlowpan"))]
 use super::fragmentation::PacketAssemblerSet;
+#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
+use super::neighbor::{Answer as NeighborAnswer, Cache as NeighborCache};
 use super::socket_set::SocketSet;
 use crate::iface::Routes;
-#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
-use crate::iface::{NeighborAnswer, NeighborCache};
 use crate::phy::{ChecksumCapabilities, Device, DeviceCapabilities, Medium, RxToken, TxToken};
 use crate::rand::Rand;
 #[cfg(feature = "socket-dns")]
@@ -41,6 +39,9 @@ use crate::wire::*;
 const MAX_IP_ADDR_COUNT: usize = 5;
 #[cfg(feature = "proto-igmp")]
 const MAX_IPV4_MULTICAST_GROUPS: usize = 4;
+const FRAGMENTATION_BUFFER_SIZE: usize = 1500;
+#[cfg(feature = "proto-sixlowpan")]
+const SIXLOWPAN_ADDRESS_CONTEXT_COUNT: usize = 4;
 
 pub(crate) struct FragmentsBuffer {
     #[cfg(feature = "proto-sixlowpan")]
@@ -53,17 +54,14 @@ pub(crate) struct FragmentsBuffer {
     sixlowpan_fragments_cache_timeout: Duration,
 }
 
-pub(crate) struct OutPackets<'a> {
+pub(crate) struct OutPackets {
     #[cfg(feature = "proto-ipv4-fragmentation")]
-    ipv4_out_packet: Ipv4OutPacket<'a>,
+    ipv4_out_packet: Ipv4OutPacket,
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
-    sixlowpan_out_packet: SixlowpanOutPacket<'a>,
-
-    #[cfg(not(feature = "proto-sixlowpan-fragmentation"))]
-    _lifetime: core::marker::PhantomData<&'a ()>,
+    sixlowpan_out_packet: SixlowpanOutPacket,
 }
 
-impl<'a> OutPackets<'a> {
+impl OutPackets {
     #[cfg(any(
         feature = "proto-ipv4-fragmentation",
         feature = "proto-sixlowpan-fragmentation"
@@ -86,9 +84,9 @@ impl<'a> OutPackets<'a> {
 
 #[allow(unused)]
 #[cfg(feature = "proto-ipv4-fragmentation")]
-pub(crate) struct Ipv4OutPacket<'a> {
+pub(crate) struct Ipv4OutPacket {
     /// The buffer that holds the unfragmented 6LoWPAN packet.
-    buffer: ManagedSlice<'a, u8>,
+    buffer: [u8; FRAGMENTATION_BUFFER_SIZE],
     /// The size of the packet without the IEEE802.15.4 header and the fragmentation headers.
     packet_len: usize,
     /// The amount of bytes that already have been transmitted.
@@ -106,10 +104,10 @@ pub(crate) struct Ipv4OutPacket<'a> {
 }
 
 #[cfg(feature = "proto-ipv4-fragmentation")]
-impl<'a> Ipv4OutPacket<'a> {
-    pub(crate) fn new(buffer: ManagedSlice<'a, u8>) -> Self {
+impl Ipv4OutPacket {
+    pub(crate) fn new() -> Self {
         Self {
-            buffer,
+            buffer: [0u8; FRAGMENTATION_BUFFER_SIZE],
             packet_len: 0,
             sent_bytes: 0,
             repr: Ipv4Repr {
@@ -158,9 +156,9 @@ impl<'a> Ipv4OutPacket<'a> {
 
 #[allow(unused)]
 #[cfg(feature = "proto-sixlowpan")]
-pub(crate) struct SixlowpanOutPacket<'a> {
+pub(crate) struct SixlowpanOutPacket {
     /// The buffer that holds the unfragmented 6LoWPAN packet.
-    buffer: ManagedSlice<'a, u8>,
+    buffer: [u8; FRAGMENTATION_BUFFER_SIZE],
     /// The size of the packet without the IEEE802.15.4 header and the fragmentation headers.
     packet_len: usize,
     /// The amount of bytes that already have been transmitted.
@@ -182,10 +180,10 @@ pub(crate) struct SixlowpanOutPacket<'a> {
 }
 
 #[cfg(feature = "proto-sixlowpan-fragmentation")]
-impl<'a> SixlowpanOutPacket<'a> {
-    pub(crate) fn new(buffer: ManagedSlice<'a, u8>) -> Self {
+impl SixlowpanOutPacket {
+    pub(crate) fn new() -> Self {
         Self {
-            buffer,
+            buffer: [0u8; FRAGMENTATION_BUFFER_SIZE],
             packet_len: 0,
             datagram_size: 0,
             datagram_tag: 0,
@@ -243,10 +241,10 @@ use check;
 /// The network interface logically owns a number of other data structures; to avoid
 /// a dependency on heap allocation, it instead owns a `BorrowMut<[T]>`, which can be
 /// a `&mut [T]`, or `Vec<T>` if a heap is available.
-pub struct Interface<'a> {
-    inner: InterfaceInner<'a>,
+pub struct Interface {
+    inner: InterfaceInner,
     fragments: FragmentsBuffer,
-    out_packets: OutPackets<'a>,
+    out_packets: OutPackets,
 }
 
 /// The device independent part of an Ethernet network interface.
@@ -256,13 +254,11 @@ pub struct Interface<'a> {
 /// the `device` mutably until they're used, which makes it impossible to call other
 /// methods on the `Interface` in this time (since its `device` field is borrowed
 /// exclusively). However, it is still possible to call methods on its `inner` field.
-pub struct InterfaceInner<'a> {
+pub struct InterfaceInner {
     caps: DeviceCapabilities,
     now: Instant,
     rand: Rand,
 
-    phantom: PhantomData<&'a mut ()>,
-
     #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
     neighbor_cache: Option<NeighborCache>,
     #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
@@ -274,7 +270,7 @@ pub struct InterfaceInner<'a> {
     #[cfg(feature = "proto-ipv4-fragmentation")]
     ipv4_id: u16,
     #[cfg(feature = "proto-sixlowpan")]
-    sixlowpan_address_context: &'a [SixlowpanAddressContext<'a>],
+    sixlowpan_address_context: Vec<SixlowpanAddressContext, SIXLOWPAN_ADDRESS_CONTEXT_COUNT>,
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
     tag: u16,
     ip_addrs: Vec<IpCidr, MAX_IP_ADDR_COUNT>,
@@ -288,416 +284,46 @@ pub struct InterfaceInner<'a> {
     igmp_report_state: IgmpReportState,
 }
 
-/// A builder structure used for creating a network interface.
-pub struct InterfaceBuilder<'a> {
-    phantom: PhantomData<&'a mut ()>,
-
-    #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
-    hardware_addr: Option<HardwareAddress>,
-    #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
-    neighbor_cache: Option<NeighborCache>,
-    #[cfg(feature = "medium-ieee802154")]
-    pan_id: Option<Ieee802154Pan>,
-    ip_addrs: Vec<IpCidr, MAX_IP_ADDR_COUNT>,
-    #[cfg(feature = "proto-ipv4")]
-    any_ip: bool,
-    routes: Routes,
-    /// Does not share storage with `ipv6_multicast_groups` to avoid IPv6 size overhead.
-    #[cfg(feature = "proto-igmp")]
-    ipv4_multicast_groups: LinearMap<Ipv4Address, (), MAX_IPV4_MULTICAST_GROUPS>,
-    random_seed: u64,
-
-    #[cfg(feature = "proto-ipv4-fragmentation")]
-    ipv4_fragments: PacketAssemblerSet<Ipv4FragKey>,
-    #[cfg(feature = "proto-ipv4-fragmentation")]
-    ipv4_out_buffer: ManagedSlice<'a, u8>,
-
-    #[cfg(feature = "proto-sixlowpan-fragmentation")]
-    sixlowpan_fragments: PacketAssemblerSet<SixlowpanFragKey>,
-    #[cfg(feature = "proto-sixlowpan-fragmentation")]
-    sixlowpan_reassembly_buffer_timeout: Duration,
-    #[cfg(feature = "proto-sixlowpan-fragmentation")]
-    sixlowpan_out_buffer: ManagedSlice<'a, u8>,
-
-    #[cfg(feature = "proto-sixlowpan")]
-    sixlowpan_address_context: &'a [SixlowpanAddressContext<'a>],
-}
-
-impl<'a> InterfaceBuilder<'a> {
-    /// Create a builder used for creating a network interface using the
-    /// given device and address.
-    #[cfg_attr(
-        all(feature = "medium-ethernet", not(feature = "proto-sixlowpan")),
-        doc = r##"
-# Examples
-
-```
-# use std::collections::BTreeMap;
-#[cfg(feature = "proto-ipv4-fragmentation")]
-use smoltcp::iface::ReassemblyBuffer;
-use smoltcp::iface::{InterfaceBuilder, NeighborCache};
-# use smoltcp::phy::{Loopback, Medium};
-use smoltcp::wire::{EthernetAddress, IpCidr, IpAddress};
-
-let mut device = // ...
-# Loopback::new(Medium::Ethernet);
-let hw_addr = // ...
-# EthernetAddress::default();
-let neighbor_cache = // ...
-# NeighborCache::new();
-let ip_addrs = // ...
-# heapless::Vec::<IpCidr, 5>::new();
-let builder = InterfaceBuilder::new()
-        .hardware_addr(hw_addr.into())
-        .neighbor_cache(neighbor_cache)
-        .ip_addrs(ip_addrs);
-
-let iface = builder.finalize(&mut device);
-```
-    "##
-    )]
-    #[allow(clippy::new_without_default)]
-    pub fn new() -> Self {
-        InterfaceBuilder {
-            phantom: PhantomData,
-
-            #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
-            hardware_addr: None,
-            #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
-            neighbor_cache: None,
-
-            #[cfg(feature = "medium-ieee802154")]
-            pan_id: None,
-
-            ip_addrs: Vec::new(),
-            #[cfg(feature = "proto-ipv4")]
-            any_ip: false,
-            routes: Routes::new(),
-            #[cfg(feature = "proto-igmp")]
-            ipv4_multicast_groups: LinearMap::new(),
-            random_seed: 0,
-
-            #[cfg(feature = "proto-ipv4-fragmentation")]
-            ipv4_fragments: PacketAssemblerSet::new(),
-            #[cfg(feature = "proto-ipv4-fragmentation")]
-            ipv4_out_buffer: ManagedSlice::Borrowed(&mut [][..]),
-
-            #[cfg(feature = "proto-sixlowpan-fragmentation")]
-            sixlowpan_fragments: PacketAssemblerSet::new(),
-            #[cfg(feature = "proto-sixlowpan-fragmentation")]
-            sixlowpan_reassembly_buffer_timeout: Duration::from_secs(60),
-            #[cfg(feature = "proto-sixlowpan-fragmentation")]
-            sixlowpan_out_buffer: ManagedSlice::Borrowed(&mut [][..]),
-
-            #[cfg(feature = "proto-sixlowpan")]
-            sixlowpan_address_context: &[],
-        }
-    }
-
-    /// Set the random seed for this interface.
+/// Configuration structure used for creating a network interface.
+#[non_exhaustive]
+pub struct Config {
+    /// Random seed.
     ///
     /// It is strongly recommended that the random seed is different on each boot,
     /// to avoid problems with TCP port/sequence collisions.
     ///
     /// The seed doesn't have to be cryptographically secure.
-    pub fn random_seed(mut self, random_seed: u64) -> Self {
-        self.random_seed = random_seed;
-        self
-    }
+    pub random_seed: u64,
 
-    /// Set the Hardware address the interface will use. See also
-    /// [hardware_addr].
+    /// Set the Hardware address the interface will use.
     ///
     /// # Panics
-    /// This function panics if the address is not unicast.
-    ///
-    /// [hardware_addr]: struct.Interface.html#method.hardware_addr
+    /// Creating the interface panics if the address is not unicast.
     #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
-    pub fn hardware_addr(mut self, addr: HardwareAddress) -> Self {
-        InterfaceInner::check_hardware_addr(&addr);
-        self.hardware_addr = Some(addr);
-        self
-    }
+    pub hardware_addr: Option<HardwareAddress>,
 
     /// Set the IEEE802.15.4 PAN ID the interface will use.
     ///
     /// **NOTE**: we use the same PAN ID for destination and source.
     #[cfg(feature = "medium-ieee802154")]
-    pub fn pan_id(mut self, pan_id: Ieee802154Pan) -> Self {
-        self.pan_id = Some(pan_id);
-        self
-    }
-
-    /// Set the IP addresses the interface will use. See also
-    /// [ip_addrs].
-    ///
-    /// # Panics
-    /// This function panics if any of the addresses are not unicast.
-    ///
-    /// [ip_addrs]: struct.Interface.html#method.ip_addrs
-    pub fn ip_addrs<T>(mut self, ip_addrs: T) -> Self
-    where
-        T: Into<Vec<IpCidr, MAX_IP_ADDR_COUNT>>,
-    {
-        let ip_addrs = ip_addrs.into();
-        InterfaceInner::check_ip_addrs(&ip_addrs);
-        self.ip_addrs = ip_addrs;
-        self
-    }
-
-    /// Enable or disable the AnyIP capability, allowing packets to be received
-    /// locally on IPv4 addresses other than the interface's configured [ip_addrs].
-    /// When AnyIP is enabled and a route prefix in [routes] specifies one of
-    /// the interface's [ip_addrs] as its gateway, the interface will accept
-    /// packets addressed to that prefix.
-    ///
-    /// # IPv6
-    ///
-    /// This option is not available or required for IPv6 as packets sent to
-    /// the interface are not filtered by IPv6 address.
-    ///
-    /// [routes]: struct.Interface.html#method.routes
-    /// [ip_addrs]: struct.Interface.html#method.ip_addrs
-    #[cfg(feature = "proto-ipv4")]
-    pub fn any_ip(mut self, enabled: bool) -> Self {
-        self.any_ip = enabled;
-        self
-    }
-
-    /// Set the IP routes the interface will use. See also
-    /// [routes].
-    ///
-    /// [routes]: struct.Interface.html#method.routes
-    pub fn routes<T>(mut self, routes: T) -> InterfaceBuilder<'a>
-    where
-        T: Into<Routes>,
-    {
-        self.routes = routes.into();
-        self
-    }
-
-    /// Provide storage for multicast groups.
-    ///
-    /// Join multicast groups by calling [`join_multicast_group()`] on an `Interface`.
-    /// Using [`join_multicast_group()`] will send initial membership reports.
-    ///
-    /// A previously destroyed interface can be recreated by reusing the multicast group
-    /// storage, i.e. providing a non-empty storage to `ipv4_multicast_groups()`.
-    /// Note that this way initial membership reports are **not** sent.
-    ///
-    /// [`join_multicast_group()`]: struct.Interface.html#method.join_multicast_group
-    #[cfg(feature = "proto-igmp")]
-    pub fn ipv4_multicast_groups<T>(mut self, ipv4_multicast_groups: T) -> Self
-    where
-        T: Into<LinearMap<Ipv4Address, (), MAX_IPV4_MULTICAST_GROUPS>>,
-    {
-        self.ipv4_multicast_groups = ipv4_multicast_groups.into();
-        self
-    }
-
-    /// Set the Neighbor Cache the interface will use.
-    #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
-    pub fn neighbor_cache(mut self, neighbor_cache: NeighborCache) -> Self {
-        self.neighbor_cache = Some(neighbor_cache);
-        self
-    }
-
-    /// Set the IPv4 reassembly buffer the interface will use.
-    #[cfg(feature = "proto-ipv4-fragmentation")]
-    pub fn ipv4_reassembly_buffer(mut self, storage: PacketAssemblerSet<Ipv4FragKey>) -> Self {
-        self.ipv4_fragments = storage;
-        self
-    }
-
-    /// Set the IPv4 fragments buffer the interface will use.
-    #[cfg(feature = "proto-ipv4-fragmentation")]
-    pub fn ipv4_fragmentation_buffer<T>(mut self, storage: T) -> Self
-    where
-        T: Into<ManagedSlice<'a, u8>>,
-    {
-        self.ipv4_out_buffer = storage.into();
-        self
-    }
-
-    /// Set the address contexts the interface will use.
-    #[cfg(feature = "proto-sixlowpan")]
-    pub fn sixlowpan_address_context(
-        mut self,
-        sixlowpan_address_context: &'a [SixlowpanAddressContext<'a>],
-    ) -> Self {
-        self.sixlowpan_address_context = sixlowpan_address_context;
-        self
-    }
-
-    /// Set the 6LoWPAN reassembly buffer the interface will use.
-    #[cfg(feature = "proto-sixlowpan-fragmentation")]
-    pub fn sixlowpan_reassembly_buffer(
-        mut self,
-        storage: PacketAssemblerSet<SixlowpanFragKey>,
-    ) -> Self {
-        self.sixlowpan_fragments = storage;
-        self
-    }
-
-    /// Set the timeout value the 6LoWPAN reassembly buffer will use.
-    #[cfg(feature = "proto-sixlowpan-fragmentation")]
-    pub fn sixlowpan_reassembly_buffer_timeout(mut self, timeout: Duration) -> Self {
-        if timeout > Duration::from_secs(60) {
-            net_debug!("RFC 4944 specifies that the reassembly timeout MUST be set to a maximum of 60 seconds");
-        }
-        self.sixlowpan_reassembly_buffer_timeout = timeout;
-        self
-    }
-
-    /// Set the 6LoWPAN fragments buffer the interface will use.
-    #[cfg(feature = "proto-sixlowpan-fragmentation")]
-    pub fn sixlowpan_fragmentation_buffer<T>(mut self, storage: T) -> Self
-    where
-        T: Into<ManagedSlice<'a, u8>>,
-    {
-        self.sixlowpan_out_buffer = storage.into();
-        self
-    }
-
-    /// Create a network interface using the previously provided configuration.
-    ///
-    /// # Panics
-    /// If a required option is not provided, this function will panic. Required
-    /// options are:
-    ///
-    /// - [ethernet_addr]
-    /// - [neighbor_cache]
-    ///
-    /// [ethernet_addr]: #method.ethernet_addr
-    /// [neighbor_cache]: #method.neighbor_cache
-    pub fn finalize<D>(self, device: &mut D) -> Interface<'a>
-    where
-        D: Device + ?Sized,
-    {
-        let caps = device.capabilities();
+    pub pan_id: Option<Ieee802154Pan>,
+}
 
-        #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
-        let (hardware_addr, neighbor_cache) = match caps.medium {
-            #[cfg(feature = "medium-ethernet")]
-            Medium::Ethernet => (
-                Some(
-                    self.hardware_addr
-                        .expect("hardware_addr required option was not set"),
-                ),
-                Some(
-                    self.neighbor_cache
-                        .expect("neighbor_cache required option was not set"),
-                ),
-            ),
-            #[cfg(feature = "medium-ip")]
-            Medium::Ip => {
-                assert!(
-                    self.hardware_addr.is_none(),
-                    "hardware_addr is set, but device medium is IP"
-                );
-                assert!(
-                    self.neighbor_cache.is_none(),
-                    "neighbor_cache is set, but device medium is IP"
-                );
-                (None, None)
-            }
+impl Config {
+    pub fn new() -> Self {
+        Config {
+            random_seed: 0,
+            #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
+            hardware_addr: None,
             #[cfg(feature = "medium-ieee802154")]
-            Medium::Ieee802154 => (
-                Some(
-                    self.hardware_addr
-                        .expect("hardware_addr required option was not set"),
-                ),
-                Some(
-                    self.neighbor_cache
-                        .expect("neighbor_cache required option was not set"),
-                ),
-            ),
-        };
-
-        let mut rand = Rand::new(self.random_seed);
-
-        #[cfg(feature = "medium-ieee802154")]
-        let mut sequence_no;
-        #[cfg(feature = "medium-ieee802154")]
-        loop {
-            sequence_no = (rand.rand_u32() & 0xff) as u8;
-            if sequence_no != 0 {
-                break;
-            }
-        }
-
-        #[cfg(feature = "proto-sixlowpan")]
-        let mut tag;
-
-        #[cfg(feature = "proto-sixlowpan")]
-        loop {
-            tag = rand.rand_u16();
-            if tag != 0 {
-                break;
-            }
-        }
-
-        #[cfg(feature = "proto-ipv4")]
-        let mut ipv4_id;
-
-        #[cfg(feature = "proto-ipv4")]
-        loop {
-            ipv4_id = rand.rand_u16();
-            if ipv4_id != 0 {
-                break;
-            }
+            pan_id: None,
         }
+    }
+}
 
-        Interface {
-            fragments: FragmentsBuffer {
-                #[cfg(feature = "proto-sixlowpan")]
-                decompress_buf: [0u8; sixlowpan::MAX_DECOMPRESSED_LEN],
-
-                #[cfg(feature = "proto-ipv4-fragmentation")]
-                ipv4_fragments: self.ipv4_fragments,
-                #[cfg(feature = "proto-sixlowpan-fragmentation")]
-                sixlowpan_fragments: self.sixlowpan_fragments,
-                #[cfg(feature = "proto-sixlowpan-fragmentation")]
-                sixlowpan_fragments_cache_timeout: self.sixlowpan_reassembly_buffer_timeout,
-            },
-            out_packets: OutPackets {
-                #[cfg(feature = "proto-ipv4-fragmentation")]
-                ipv4_out_packet: Ipv4OutPacket::new(self.ipv4_out_buffer),
-                #[cfg(feature = "proto-sixlowpan-fragmentation")]
-                sixlowpan_out_packet: SixlowpanOutPacket::new(self.sixlowpan_out_buffer),
-
-                #[cfg(not(feature = "proto-sixlowpan-fragmentation"))]
-                _lifetime: core::marker::PhantomData,
-            },
-            inner: InterfaceInner {
-                phantom: PhantomData,
-                now: Instant::from_secs(0),
-                caps,
-                #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
-                hardware_addr,
-                ip_addrs: self.ip_addrs,
-                #[cfg(feature = "proto-ipv4")]
-                any_ip: self.any_ip,
-                routes: self.routes,
-                #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
-                neighbor_cache,
-                #[cfg(feature = "proto-igmp")]
-                ipv4_multicast_groups: self.ipv4_multicast_groups,
-                #[cfg(feature = "proto-igmp")]
-                igmp_report_state: IgmpReportState::Inactive,
-                #[cfg(feature = "medium-ieee802154")]
-                sequence_no,
-                #[cfg(feature = "medium-ieee802154")]
-                pan_id: self.pan_id,
-                #[cfg(feature = "proto-sixlowpan-fragmentation")]
-                tag,
-                #[cfg(feature = "proto-ipv4-fragmentation")]
-                ipv4_id,
-                #[cfg(feature = "proto-sixlowpan")]
-                sixlowpan_address_context: &[],
-                rand,
-            },
-        }
+impl Default for Config {
+    fn default() -> Self {
+        Self::new()
     }
 }
 
@@ -851,11 +477,134 @@ enum IgmpReportState {
     },
 }
 
-impl<'a> Interface<'a> {
+impl Interface {
+    /// Create a network interface using the previously provided configuration.
+    ///
+    /// # Panics
+    /// If a required option is not provided, this function will panic. Required
+    /// options are:
+    ///
+    /// - [ethernet_addr]
+    /// - [neighbor_cache]
+    ///
+    /// [ethernet_addr]: #method.ethernet_addr
+    /// [neighbor_cache]: #method.neighbor_cache
+    pub fn new<D>(config: Config, device: &mut D) -> Self
+    where
+        D: Device + ?Sized,
+    {
+        let caps = device.capabilities();
+
+        #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
+        let hardware_addr = match caps.medium {
+            #[cfg(feature = "medium-ethernet")]
+            Medium::Ethernet => Some(
+                config
+                    .hardware_addr
+                    .expect("hardware_addr required option was not set"),
+            ),
+            #[cfg(feature = "medium-ip")]
+            Medium::Ip => {
+                assert!(
+                    config.hardware_addr.is_none(),
+                    "hardware_addr is set, but device medium is IP"
+                );
+                None
+            }
+            #[cfg(feature = "medium-ieee802154")]
+            Medium::Ieee802154 => Some(
+                config
+                    .hardware_addr
+                    .expect("hardware_addr required option was not set"),
+            ),
+        };
+
+        let mut rand = Rand::new(config.random_seed);
+
+        #[cfg(feature = "medium-ieee802154")]
+        let mut sequence_no;
+        #[cfg(feature = "medium-ieee802154")]
+        loop {
+            sequence_no = (rand.rand_u32() & 0xff) as u8;
+            if sequence_no != 0 {
+                break;
+            }
+        }
+
+        #[cfg(feature = "proto-sixlowpan")]
+        let mut tag;
+
+        #[cfg(feature = "proto-sixlowpan")]
+        loop {
+            tag = rand.rand_u16();
+            if tag != 0 {
+                break;
+            }
+        }
+
+        #[cfg(feature = "proto-ipv4")]
+        let mut ipv4_id;
+
+        #[cfg(feature = "proto-ipv4")]
+        loop {
+            ipv4_id = rand.rand_u16();
+            if ipv4_id != 0 {
+                break;
+            }
+        }
+
+        Interface {
+            fragments: FragmentsBuffer {
+                #[cfg(feature = "proto-sixlowpan")]
+                decompress_buf: [0u8; sixlowpan::MAX_DECOMPRESSED_LEN],
+
+                #[cfg(feature = "proto-ipv4-fragmentation")]
+                ipv4_fragments: PacketAssemblerSet::new(),
+                #[cfg(feature = "proto-sixlowpan-fragmentation")]
+                sixlowpan_fragments: PacketAssemblerSet::new(),
+                #[cfg(feature = "proto-sixlowpan-fragmentation")]
+                sixlowpan_fragments_cache_timeout: Duration::from_secs(60),
+            },
+            out_packets: OutPackets {
+                #[cfg(feature = "proto-ipv4-fragmentation")]
+                ipv4_out_packet: Ipv4OutPacket::new(),
+                #[cfg(feature = "proto-sixlowpan-fragmentation")]
+                sixlowpan_out_packet: SixlowpanOutPacket::new(),
+            },
+            inner: InterfaceInner {
+                now: Instant::from_secs(0),
+                caps,
+                #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
+                hardware_addr,
+                ip_addrs: Vec::new(),
+                #[cfg(feature = "proto-ipv4")]
+                any_ip: false,
+                routes: Routes::new(),
+                #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
+                neighbor_cache: Some(NeighborCache::new()),
+                #[cfg(feature = "proto-igmp")]
+                ipv4_multicast_groups: LinearMap::new(),
+                #[cfg(feature = "proto-igmp")]
+                igmp_report_state: IgmpReportState::Inactive,
+                #[cfg(feature = "medium-ieee802154")]
+                sequence_no,
+                #[cfg(feature = "medium-ieee802154")]
+                pan_id: config.pan_id,
+                #[cfg(feature = "proto-sixlowpan-fragmentation")]
+                tag,
+                #[cfg(feature = "proto-ipv4-fragmentation")]
+                ipv4_id,
+                #[cfg(feature = "proto-sixlowpan")]
+                sixlowpan_address_context: Vec::new(),
+                rand,
+            },
+        }
+    }
+
     /// Get the socket context.
     ///
     /// The context is needed for some socket methods.
-    pub fn context(&mut self) -> &mut InterfaceInner<'a> {
+    pub fn context(&mut self) -> &mut InterfaceInner {
         &mut self.inner
     }
 
@@ -909,13 +658,13 @@ impl<'a> Interface<'a> {
     /// Get the first IPv4 address if present.
     #[cfg(feature = "proto-ipv4")]
     pub fn ipv4_addr(&self) -> Option<Ipv4Address> {
-        self.ip_addrs()
-            .iter()
-            .find_map(|cidr| match cidr.address() {
-                IpAddress::Ipv4(addr) => Some(addr),
-                #[allow(unreachable_patterns)]
-                _ => None,
-            })
+        self.inner.ipv4_addr()
+    }
+
+    /// Get the first IPv6 address if present.
+    #[cfg(feature = "proto-ipv6")]
+    pub fn ipv6_addr(&self) -> Option<Ipv6Address> {
+        self.inner.ipv6_addr()
     }
 
     /// Update the IP addresses of the interface.
@@ -933,12 +682,6 @@ impl<'a> Interface<'a> {
         self.inner.has_ip_addr(addr)
     }
 
-    /// Get the first IPv4 address of the interface.
-    #[cfg(feature = "proto-ipv4")]
-    pub fn ipv4_address(&self) -> Option<Ipv4Address> {
-        self.inner.ipv4_address()
-    }
-
     pub fn routes(&self) -> &Routes {
         &self.inner.routes
     }
@@ -947,6 +690,66 @@ impl<'a> Interface<'a> {
         &mut self.inner.routes
     }
 
+    /// Enable or disable the AnyIP capability.
+    ///
+    /// AnyIP allowins packets to be received
+    /// locally on IPv4 addresses other than the interface's configured [ip_addrs].
+    /// When AnyIP is enabled and a route prefix in [`routes`](Self::routes) specifies one of
+    /// the interface's [`ip_addrs`](Self::ip_addrs) as its gateway, the interface will accept
+    /// packets addressed to that prefix.
+    ///
+    /// # IPv6
+    ///
+    /// This option is not available or required for IPv6 as packets sent to
+    /// the interface are not filtered by IPv6 address.
+    #[cfg(feature = "proto-ipv4")]
+    pub fn set_any_ip(&mut self, any_ip: bool) {
+        self.inner.any_ip = any_ip;
+    }
+
+    /// Get whether AnyIP is enabled.
+    ///
+    /// See [`set_any_ip`](Self::set_any_ip) for details on AnyIP
+    #[cfg(feature = "proto-ipv4")]
+    pub fn any_ip(&self) -> bool {
+        self.inner.any_ip
+    }
+
+    /// Get the 6LoWPAN address contexts.
+    #[cfg(feature = "proto-sixlowpan")]
+    pub fn sixlowpan_address_context(
+        &self,
+    ) -> &Vec<SixlowpanAddressContext, SIXLOWPAN_ADDRESS_CONTEXT_COUNT> {
+        &self.inner.sixlowpan_address_context
+    }
+
+    /// Get a mutable reference to the 6LoWPAN address contexts.
+    #[cfg(feature = "proto-sixlowpan")]
+    pub fn sixlowpan_address_context_mut(
+        &mut self,
+    ) -> &mut Vec<SixlowpanAddressContext, SIXLOWPAN_ADDRESS_CONTEXT_COUNT> {
+        &mut self.inner.sixlowpan_address_context
+    }
+
+    /// Get the packet reassembly timeout.
+    ///
+    /// Currently used only for 6LoWPAN, will be used for IPv4 in the future as well.
+    #[cfg(feature = "proto-sixlowpan-fragmentation")]
+    pub fn reassembly_timeout(&self) -> Duration {
+        self.fragments.sixlowpan_fragments_cache_timeout
+    }
+
+    /// Set the packet reassembly timeout.
+    ///
+    /// Currently used only for 6LoWPAN, will be used for IPv4 in the future as well.
+    #[cfg(feature = "proto-sixlowpan-fragmentation")]
+    pub fn set_reassembly_timeout(&mut self, timeout: Duration) {
+        if timeout > Duration::from_secs(60) {
+            net_debug!("RFC 4944 specifies that the reassembly timeout MUST be set to a maximum of 60 seconds");
+        }
+        self.fragments.sixlowpan_fragments_cache_timeout = timeout;
+    }
+
     /// Transmit packets queued in the given sockets, and receive packets queued
     /// in the device.
     ///
@@ -1291,7 +1094,7 @@ impl<'a> Interface<'a> {
     }
 }
 
-impl<'a> InterfaceInner<'a> {
+impl InterfaceInner {
     #[allow(unused)] // unused depending on which sockets are enabled
     pub(crate) fn now(&self) -> Instant {
         self.now
@@ -1363,7 +1166,6 @@ impl<'a> InterfaceInner<'a> {
     #[cfg(test)]
     pub(crate) fn mock() -> Self {
         Self {
-            phantom: PhantomData,
             caps: DeviceCapabilities {
                 #[cfg(feature = "medium-ethernet")]
                 medium: crate::phy::Medium::Ethernet,
@@ -1414,7 +1216,7 @@ impl<'a> InterfaceInner<'a> {
             tag: 1,
 
             #[cfg(feature = "proto-sixlowpan")]
-            sixlowpan_address_context: &[],
+            sixlowpan_address_context: Vec::new(),
 
             #[cfg(feature = "proto-ipv4-fragmentation")]
             ipv4_id: 1,
@@ -1509,11 +1311,21 @@ impl<'a> InterfaceInner<'a> {
 
     /// Get the first IPv4 address of the interface.
     #[cfg(feature = "proto-ipv4")]
-    pub fn ipv4_address(&self) -> Option<Ipv4Address> {
+    pub fn ipv4_addr(&self) -> Option<Ipv4Address> {
         self.ip_addrs.iter().find_map(|addr| match *addr {
             IpCidr::Ipv4(cidr) => Some(cidr.address()),
-            #[cfg(feature = "proto-ipv6")]
-            IpCidr::Ipv6(_) => None,
+            #[allow(unreachable_patterns)]
+            _ => None,
+        })
+    }
+
+    /// Get the first IPv6 address if present.
+    #[cfg(feature = "proto-ipv6")]
+    pub fn ipv6_addr(&self) -> Option<Ipv6Address> {
+        self.ip_addrs.iter().find_map(|addr| match *addr {
+            IpCidr::Ipv6(cidr) => Some(cidr.address()),
+            #[allow(unreachable_patterns)]
+            _ => None,
         })
     }
 
@@ -1706,7 +1518,7 @@ impl<'a> InterfaceInner<'a> {
         &mut self,
         tx_token: Tx,
         packet: EthernetPacket,
-        _out_packet: Option<&mut OutPackets<'_>>,
+        _out_packet: Option<&mut OutPackets>,
     ) -> Result<(), DispatchError>
     where
         Tx: TxToken,
@@ -1921,7 +1733,7 @@ impl<'a> InterfaceInner<'a> {
         &mut self,
         tx_token: Tx,
         packet: IpPacket,
-        _out_packet: Option<&mut OutPackets<'_>>,
+        _out_packet: Option<&mut OutPackets>,
     ) -> Result<(), DispatchError> {
         let mut ip_repr = packet.ip_repr();
         assert!(!ip_repr.dst_addr().is_unspecified());

+ 5 - 11
src/iface/interface/sixlowpan.rs

@@ -16,7 +16,7 @@ use crate::wire::*;
 // TODO: lower. Should be (6lowpan mtu) - (min 6lowpan header size) + (max ipv6 header size)
 pub(crate) const MAX_DECOMPRESSED_LEN: usize = 1500;
 
-impl<'a> InterfaceInner<'a> {
+impl InterfaceInner {
     #[cfg(feature = "medium-ieee802154")]
     pub(super) fn process_ieee802154<'output, 'payload: 'output, T: AsRef<[u8]> + ?Sized>(
         &mut self,
@@ -178,7 +178,7 @@ impl<'a> InterfaceInner<'a> {
             &iphc,
             ieee802154_repr.src_addr,
             ieee802154_repr.dst_addr,
-            self.sixlowpan_address_context,
+            &self.sixlowpan_address_context,
         )?;
 
         let mut decompressed_size = 40 + iphc.payload().len();
@@ -384,18 +384,12 @@ impl<'a> InterfaceInner<'a> {
                     ..
                 } = &mut _out_packet.unwrap().sixlowpan_out_packet;
 
-                match buffer {
-                    managed::ManagedSlice::Borrowed(buffer) => {
-                        if buffer.len() < total_size {
-                            net_debug!(
+                if buffer.len() < total_size {
+                    net_debug!(
                                 "dispatch_ieee802154: dropping, fragmentation buffer is too small, at least {} needed",
                                 total_size
                             );
-                            return;
-                        }
-                    }
-                    #[cfg(feature = "alloc")]
-                    managed::ManagedSlice::Owned(buffer) => buffer.resize(total_size, 0),
+                    return;
                 }
 
                 *ll_dst_addr = ll_dst_a;

+ 55 - 72
src/iface/interface/tests.rs

@@ -4,8 +4,6 @@ use std::vec::Vec;
 use super::*;
 
 use crate::iface::Interface;
-#[cfg(feature = "medium-ethernet")]
-use crate::iface::NeighborCache;
 use crate::phy::{ChecksumCapabilities, Loopback};
 #[cfg(feature = "proto-igmp")]
 use crate::time::Instant;
@@ -24,7 +22,7 @@ const MEDIUM: Medium = Medium::Ip;
 #[cfg(all(not(feature = "medium-ethernet"), feature = "medium-ieee802154"))]
 const MEDIUM: Medium = Medium::Ieee802154;
 
-fn create<'a>(medium: Medium) -> (Interface<'a>, SocketSet<'a>, Loopback) {
+fn create<'a>(medium: Medium) -> (Interface, SocketSet<'a>, Loopback) {
     match medium {
         #[cfg(feature = "medium-ethernet")]
         Medium::Ethernet => create_ethernet(),
@@ -37,90 +35,74 @@ fn create<'a>(medium: Medium) -> (Interface<'a>, SocketSet<'a>, Loopback) {
 
 #[cfg(feature = "medium-ip")]
 #[allow(unused)]
-fn create_ip<'a>() -> (Interface<'a>, SocketSet<'a>, Loopback) {
+fn create_ip<'a>() -> (Interface, SocketSet<'a>, Loopback) {
     // Create a basic device
     let mut device = Loopback::new(Medium::Ip);
-    let mut ip_addrs = heapless::Vec::<IpCidr, MAX_IP_ADDR_COUNT>::new();
-    #[cfg(feature = "proto-ipv4")]
-    ip_addrs
-        .push(IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8))
-        .unwrap();
-    #[cfg(feature = "proto-ipv6")]
-    ip_addrs
-        .push(IpCidr::new(IpAddress::v6(0, 0, 0, 0, 0, 0, 0, 1), 128))
-        .unwrap();
-    #[cfg(feature = "proto-ipv6")]
-    ip_addrs
-        .push(IpCidr::new(IpAddress::v6(0xfdbe, 0, 0, 0, 0, 0, 0, 1), 64))
-        .unwrap();
-
-    let iface_builder = InterfaceBuilder::new().ip_addrs(ip_addrs);
-
-    #[cfg(feature = "proto-ipv4-fragmentation")]
-    let iface_builder = iface_builder.ipv4_fragmentation_buffer(vec![]);
 
-    let iface = iface_builder.finalize(&mut device);
+    let mut config = Config::new();
+    let mut iface = Interface::new(config, &mut device);
+    iface.update_ip_addrs(|ip_addrs| {
+        #[cfg(feature = "proto-ipv4")]
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8))
+            .unwrap();
+        #[cfg(feature = "proto-ipv6")]
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v6(0, 0, 0, 0, 0, 0, 0, 1), 128))
+            .unwrap();
+        #[cfg(feature = "proto-ipv6")]
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v6(0xfdbe, 0, 0, 0, 0, 0, 0, 1), 64))
+            .unwrap();
+    });
 
     (iface, SocketSet::new(vec![]), device)
 }
 
 #[cfg(feature = "medium-ethernet")]
-fn create_ethernet<'a>() -> (Interface<'a>, SocketSet<'a>, Loopback) {
+fn create_ethernet<'a>() -> (Interface, SocketSet<'a>, Loopback) {
     // Create a basic device
     let mut device = Loopback::new(Medium::Ethernet);
-    let mut ip_addrs = heapless::Vec::<IpCidr, MAX_IP_ADDR_COUNT>::new();
-    #[cfg(feature = "proto-ipv4")]
-    ip_addrs
-        .push(IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8))
-        .unwrap();
-    #[cfg(feature = "proto-ipv6")]
-    ip_addrs
-        .push(IpCidr::new(IpAddress::v6(0, 0, 0, 0, 0, 0, 0, 1), 128))
-        .unwrap();
-    #[cfg(feature = "proto-ipv6")]
-    ip_addrs
-        .push(IpCidr::new(IpAddress::v6(0xfdbe, 0, 0, 0, 0, 0, 0, 1), 64))
-        .unwrap();
 
-    let iface_builder = InterfaceBuilder::new()
-        .hardware_addr(EthernetAddress::default().into())
-        .neighbor_cache(NeighborCache::new())
-        .ip_addrs(ip_addrs);
-
-    #[cfg(feature = "proto-sixlowpan-fragmentation")]
-    let iface_builder = iface_builder.sixlowpan_fragmentation_buffer(vec![]);
-
-    #[cfg(feature = "proto-ipv4-fragmentation")]
-    let iface_builder = iface_builder.ipv4_fragmentation_buffer(vec![]);
-
-    let iface = iface_builder.finalize(&mut device);
+    let mut config = Config::new();
+    config.hardware_addr = Some(EthernetAddress::default().into());
+    let mut iface = Interface::new(config, &mut device);
+    iface.update_ip_addrs(|ip_addrs| {
+        #[cfg(feature = "proto-ipv4")]
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8))
+            .unwrap();
+        #[cfg(feature = "proto-ipv6")]
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v6(0, 0, 0, 0, 0, 0, 0, 1), 128))
+            .unwrap();
+        #[cfg(feature = "proto-ipv6")]
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v6(0xfdbe, 0, 0, 0, 0, 0, 0, 1), 64))
+            .unwrap();
+    });
 
     (iface, SocketSet::new(vec![]), device)
 }
 
 #[cfg(feature = "medium-ieee802154")]
-fn create_ieee802154<'a>() -> (Interface<'a>, SocketSet<'a>, Loopback) {
+fn create_ieee802154<'a>() -> (Interface, SocketSet<'a>, Loopback) {
     // Create a basic device
     let mut device = Loopback::new(Medium::Ieee802154);
-    let mut ip_addrs = heapless::Vec::<IpCidr, MAX_IP_ADDR_COUNT>::new();
-    #[cfg(feature = "proto-ipv6")]
-    ip_addrs
-        .push(IpCidr::new(IpAddress::v6(0, 0, 0, 0, 0, 0, 0, 1), 128))
-        .unwrap();
-    #[cfg(feature = "proto-ipv6")]
-    ip_addrs
-        .push(IpCidr::new(IpAddress::v6(0xfdbe, 0, 0, 0, 0, 0, 0, 1), 64))
-        .unwrap();
-
-    let iface_builder = InterfaceBuilder::new()
-        .hardware_addr(Ieee802154Address::default().into())
-        .neighbor_cache(NeighborCache::new())
-        .ip_addrs(ip_addrs);
 
-    #[cfg(feature = "proto-sixlowpan-fragmentation")]
-    let iface_builder = iface_builder.sixlowpan_fragmentation_buffer(vec![]);
-
-    let iface = iface_builder.finalize(&mut device);
+    let mut config = Config::new();
+    config.hardware_addr = Some(Ieee802154Address::default().into());
+    let mut iface = Interface::new(config, &mut device);
+    iface.update_ip_addrs(|ip_addrs| {
+        #[cfg(feature = "proto-ipv6")]
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v6(0, 0, 0, 0, 0, 0, 0, 1), 128))
+            .unwrap();
+        #[cfg(feature = "proto-ipv6")]
+        ip_addrs
+            .push(IpCidr::new(IpAddress::v6(0xfdbe, 0, 0, 0, 0, 0, 0, 1), 64))
+            .unwrap();
+    });
 
     (iface, SocketSet::new(vec![]), device)
 }
@@ -153,9 +135,10 @@ impl TxToken for MockTxToken {
 #[test]
 #[should_panic(expected = "hardware_addr required option was not set")]
 #[cfg(all(feature = "medium-ethernet"))]
-fn test_builder_initialization_panic() {
+fn test_new_panic() {
     let mut device = Loopback::new(Medium::Ethernet);
-    InterfaceBuilder::new().finalize(&mut device);
+    let config = Config::new();
+    Interface::new(config, &mut device);
 }
 
 #[test]
@@ -539,7 +522,7 @@ fn test_handle_ipv4_broadcast() {
 
     let (mut iface, mut sockets, _device) = create(MEDIUM);
 
-    let our_ipv4_addr = iface.ipv4_address().unwrap();
+    let our_ipv4_addr = iface.ipv4_addr().unwrap();
     let src_ipv4_addr = Ipv4Address([127, 0, 0, 2]);
 
     // ICMPv4 echo request
@@ -1467,7 +1450,7 @@ fn test_echo_request_sixlowpan_128_bytes() {
         &request_first_part_iphc_packet,
         ieee802154_repr.src_addr,
         ieee802154_repr.dst_addr,
-        iface.inner.sixlowpan_address_context,
+        &iface.inner.sixlowpan_address_context,
     )
     .unwrap();
 

+ 1 - 11
src/iface/mod.rs

@@ -13,16 +13,6 @@ mod route;
 mod socket_meta;
 mod socket_set;
 
-#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
-pub(crate) use self::neighbor::Answer as NeighborAnswer;
-#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
-pub use self::neighbor::Cache as NeighborCache;
-#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
-pub use self::neighbor::Neighbor;
+pub use self::interface::{Config, Interface, InterfaceInner as Context};
 pub use self::route::{Route, RouteTableFull, Routes};
 pub use socket_set::{SocketHandle, SocketSet, SocketStorage};
-
-#[cfg(any(feature = "proto-ipv4", feature = "proto-sixlowpan"))]
-pub use self::fragmentation::{PacketAssembler, PacketAssemblerSet as ReassemblyBuffer};
-
-pub use self::interface::{Interface, InterfaceBuilder, InterfaceInner as Context};

+ 6 - 8
src/socket/dhcpv4.rs

@@ -299,12 +299,12 @@ impl<'a> Socket<'a> {
                 return;
             }
         };
-        let hardware_addr = match cx.hardware_addr() {
-            Some(HardwareAddress::Ethernet(addr)) => addr,
-            _ => return,
+
+        let Some(HardwareAddress::Ethernet(ethernet_addr)) = cx.hardware_addr() else {
+            panic!("using DHCPv4 socket with a non-ethernet hardware address.");
         };
 
-        if dhcp_repr.client_hardware_address != hardware_addr {
+        if dhcp_repr.client_hardware_address != ethernet_addr {
             return;
         }
         if dhcp_repr.transaction_id != self.transaction_id {
@@ -503,9 +503,7 @@ impl<'a> Socket<'a> {
     {
         // note: Dhcpv4Socket is only usable in ethernet mediums, so the
         // unwrap can never fail.
-        let ethernet_addr = if let Some(HardwareAddress::Ethernet(addr)) = cx.hardware_addr() {
-            addr
-        } else {
+        let Some(HardwareAddress::Ethernet(ethernet_addr)) = cx.hardware_addr() else {
             panic!("using DHCPv4 socket with a non-ethernet hardware address.");
         };
 
@@ -724,7 +722,7 @@ mod test {
 
     struct TestSocket {
         socket: Socket<'static>,
-        cx: Context<'static>,
+        cx: Context,
     }
 
     impl Deref for TestSocket {

+ 5 - 15
src/socket/tcp.rs

@@ -731,15 +731,15 @@ impl<'a> Socket<'a> {
     /// The local port must be provided explicitly. Assuming `fn get_ephemeral_port() -> u16`
     /// allocates a port between 49152 and 65535, a connection may be established as follows:
     ///
-    /// ```rust
+    /// ```no_run
     /// # #[cfg(all(
     /// #     feature = "medium-ethernet",
     /// #     feature = "proto-ipv4",
     /// # ))]
     /// # {
     /// # use smoltcp::socket::tcp::{Socket, SocketBuffer};
-    /// # use smoltcp::iface::{InterfaceBuilder, NeighborCache};
-    /// # use smoltcp::wire::{HardwareAddress, EthernetAddress, IpAddress, IpCidr};
+    /// # use smoltcp::iface::Interface;
+    /// # use smoltcp::wire::IpAddress;
     /// #
     /// # fn get_ephemeral_port() -> u16 {
     /// #     49152
@@ -750,17 +750,7 @@ impl<'a> Socket<'a> {
     /// #     SocketBuffer::new(vec![0; 1200])
     /// # );
     /// #
-    /// # let mut ip_addrs = heapless::Vec::<IpCidr, 5>::new();
-    /// # ip_addrs
-    /// #     .push(IpCidr::new(IpAddress::v4(192, 168, 69, 1), 24))
-    /// #     .unwrap();
-    /// #
-    /// # let mut device =smoltcp::phy::Loopback::new(smoltcp::phy::Medium::Ethernet);
-    /// # let mut iface = InterfaceBuilder::new()
-    /// #     .hardware_addr(HardwareAddress::Ethernet(EthernetAddress::default()))
-    /// #     .neighbor_cache(NeighborCache::new())
-    /// #     .ip_addrs(ip_addrs)
-    /// #     .finalize(&mut device);
+    /// # let mut iface: Interface = todo!();
     /// #
     /// socket.connect(
     ///     iface.context(),
@@ -2415,7 +2405,7 @@ mod test {
 
     struct TestSocket {
         socket: Socket<'static>,
-        cx: Context<'static>,
+        cx: Context,
     }
 
     impl Deref for TestSocket {

+ 6 - 19
src/wire/sixlowpan.rs

@@ -2,24 +2,17 @@
 //! IEEE802.154-based networks.
 //!
 //! [RFC 6282]: https://datatracker.ietf.org/doc/html/rfc6282
-use core::ops::Deref;
 
 use super::{Error, Result};
 use crate::wire::ieee802154::Address as LlAddress;
 use crate::wire::ipv6;
 use crate::wire::IpProtocol;
 
+const ADDRESS_CONTEXT_LENGTH: usize = 8;
+
 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct AddressContext<'a>(pub &'a [u8]);
-
-impl<'a> Deref for AddressContext<'a> {
-    type Target = [u8];
-
-    fn deref(&self) -> &Self::Target {
-        self.0
-    }
-}
+pub struct AddressContext(pub [u8; ADDRESS_CONTEXT_LENGTH]);
 
 /// The representation of an unresolved address. 6LoWPAN compression of IPv6 addresses can be with
 /// and without context information. The decompression with context information is not yet
@@ -68,7 +61,7 @@ impl<'a> UnresolvedAddress<'a> {
     pub fn resolve(
         self,
         ll_address: Option<LlAddress>,
-        addr_context: &[AddressContext<'_>],
+        addr_context: &[AddressContext],
     ) -> Result<ipv6::Address> {
         let mut bytes = [0; 16];
 
@@ -78,13 +71,7 @@ impl<'a> UnresolvedAddress<'a> {
             }
 
             let context = addr_context[index];
-            let len = context.len();
-
-            if len > 8 {
-                return Err(Error);
-            }
-
-            bytes[..len].copy_from_slice(&context);
+            bytes[..ADDRESS_CONTEXT_LENGTH].copy_from_slice(&context.0);
 
             Ok(())
         };
@@ -1181,7 +1168,7 @@ pub mod iphc {
             packet: &Packet<&T>,
             ll_src_addr: Option<LlAddress>,
             ll_dst_addr: Option<LlAddress>,
-            addr_context: &[AddressContext<'_>],
+            addr_context: &[AddressContext],
         ) -> Result<Self> {
             // Ensure basic accessors will work.
             packet.check_len()?;