Browse Source

iface: remove builder.

Dario Nieuwenhuis 2 years ago
parent
commit
5740b76574

+ 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 - 25
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,33 +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);
-
-    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);
 

+ 8 - 15
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.

+ 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 - 32
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,35 +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(),
-    );
-
-    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 - 25
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,26 +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);
-
-    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 - 22
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,25 +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);
-    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);

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

@@ -324,7 +324,7 @@ impl InterfaceInner {
         } 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 InterfaceInner {
         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 InterfaceInner {
         &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 {

+ 227 - 347
src/iface/interface/mod.rs

@@ -24,10 +24,10 @@ use heapless::{LinearMap, Vec};
 
 #[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")]
@@ -284,353 +284,46 @@ pub struct InterfaceInner {
     igmp_report_state: IgmpReportState,
 }
 
-/// A builder structure used for creating a network interface.
-pub struct InterfaceBuilder {
-    #[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-sixlowpan-fragmentation")]
-    sixlowpan_reassembly_buffer_timeout: Duration,
-
-    #[cfg(feature = "proto-sixlowpan")]
-    sixlowpan_address_context: Vec<SixlowpanAddressContext, SIXLOWPAN_ADDRESS_CONTEXT_COUNT>,
-}
-
-impl InterfaceBuilder {
-    /// 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 {
-            #[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-sixlowpan-fragmentation")]
-            sixlowpan_reassembly_buffer_timeout: Duration::from_secs(60),
-
-            #[cfg(feature = "proto-sixlowpan")]
-            sixlowpan_address_context: Vec::new(),
-        }
-    }
-
-    /// 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) -> Self
-    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 address contexts the interface will use.
-    #[cfg(feature = "proto-sixlowpan")]
-    pub fn sixlowpan_address_context(
-        mut self,
-        sixlowpan_address_context: Vec<SixlowpanAddressContext, SIXLOWPAN_ADDRESS_CONTEXT_COUNT>,
-    ) -> Self {
-        self.sixlowpan_address_context = sixlowpan_address_context;
-        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
-    }
-
-    /// 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
-    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: PacketAssemblerSet::new(),
-                #[cfg(feature = "proto-sixlowpan-fragmentation")]
-                sixlowpan_fragments: PacketAssemblerSet::new(),
-                #[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(),
-                #[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: 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: Vec::new(),
-                rand,
-            },
-        }
+impl Default for Config {
+    fn default() -> Self {
+        Self::new()
     }
 }
 
@@ -785,6 +478,129 @@ enum IgmpReportState {
 }
 
 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.
@@ -842,13 +658,13 @@ impl Interface {
     /// 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.
@@ -866,12 +682,6 @@ impl Interface {
         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
     }
@@ -880,6 +690,66 @@ impl Interface {
         &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.
     ///
@@ -1441,11 +1311,21 @@ impl InterfaceInner {
 
     /// 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,
         })
     }
 

+ 50 - 55
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;
@@ -40,23 +38,23 @@ fn create<'a>(medium: Medium) -> (Interface, 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);
-
-    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)
 }
@@ -65,26 +63,24 @@ fn create_ip<'a>() -> (Interface, 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);
 
-    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)
 }
@@ -93,22 +89,20 @@ fn create_ethernet<'a>() -> (Interface, 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);
 
-    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)
 }
@@ -141,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]
@@ -527,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

+ 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};

+ 4 - 14
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(),