|
@@ -54,6 +54,132 @@ struct InterfaceInner<'b, 'c> {
|
|
device_capabilities: DeviceCapabilities,
|
|
device_capabilities: DeviceCapabilities,
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/// A builder structure used for creating a Ethernet network
|
|
|
|
+/// interface.
|
|
|
|
+pub struct InterfaceBuilder <'b, 'c, DeviceT: for<'d> Device<'d>> {
|
|
|
|
+ device: DeviceT,
|
|
|
|
+ ethernet_addr: Option<EthernetAddress>,
|
|
|
|
+ neighbor_cache: Option<NeighborCache<'b>>,
|
|
|
|
+ ip_addrs: Option<ManagedSlice<'c, IpCidr>>,
|
|
|
|
+ ipv4_gateway: Option<Ipv4Address>,
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<'b, 'c, DeviceT> InterfaceBuilder<'b, 'c, DeviceT>
|
|
|
|
+ where DeviceT: for<'d> Device<'d> {
|
|
|
|
+ /// Create a builder used for creating a network interface using the
|
|
|
|
+ /// given device and address.
|
|
|
|
+ ///
|
|
|
|
+ /// # Examples
|
|
|
|
+ ///
|
|
|
|
+ /// ```
|
|
|
|
+ /// # use std::collections::BTreeMap;
|
|
|
|
+ /// use smoltcp::iface::{EthernetInterfaceBuilder, NeighborCache};
|
|
|
|
+ /// # use smoltcp::phy::Loopback;
|
|
|
|
+ /// use smoltcp::wire::{EthernetAddress, IpCidr, IpAddress};
|
|
|
|
+ ///
|
|
|
|
+ /// let device = // ...
|
|
|
|
+ /// # Loopback::new();
|
|
|
|
+ /// let hw_addr = // ...
|
|
|
|
+ /// # EthernetAddress::default();
|
|
|
|
+ /// let neighbor_cache = // ...
|
|
|
|
+ /// # NeighborCache::new(BTreeMap::new());
|
|
|
|
+ /// let ip_addrs = // ...
|
|
|
|
+ /// # [];
|
|
|
|
+ /// let iface = EthernetInterfaceBuilder::new(device)
|
|
|
|
+ /// .ethernet_addr(hw_addr)
|
|
|
|
+ /// .neighbor_cache(neighbor_cache)
|
|
|
|
+ /// .ip_addrs(ip_addrs)
|
|
|
|
+ /// .finalize();
|
|
|
|
+ /// ```
|
|
|
|
+ pub fn new(device: DeviceT) -> InterfaceBuilder<'b, 'c, DeviceT> {
|
|
|
|
+ InterfaceBuilder {
|
|
|
|
+ device: device,
|
|
|
|
+ ethernet_addr: None,
|
|
|
|
+ neighbor_cache: None,
|
|
|
|
+ ip_addrs: None,
|
|
|
|
+ ipv4_gateway: None
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// Set the Ethernet address the interface will use. See also
|
|
|
|
+ /// [ethernet_addr].
|
|
|
|
+ ///
|
|
|
|
+ /// # Panics
|
|
|
|
+ /// This function panics if the address is not unicast.
|
|
|
|
+ ///
|
|
|
|
+ /// [ethernet_addr]: struct.EthernetInterface.html#method.ethernet_addr
|
|
|
|
+ pub fn ethernet_addr(mut self, addr: EthernetAddress) -> InterfaceBuilder<'b, 'c, DeviceT> {
|
|
|
|
+ InterfaceInner::check_ethernet_addr(&addr);
|
|
|
|
+ self.ethernet_addr = Some(addr);
|
|
|
|
+ self
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// Set the IP addresses the interface will use. See also
|
|
|
|
+ /// [ip_addrs].
|
|
|
|
+ ///
|
|
|
|
+ /// # Panics
|
|
|
|
+ /// This function panics if any of the addresses is not unicast.
|
|
|
|
+ ///
|
|
|
|
+ /// [ip_addrs]: struct.EthernetInterface.html#method.ip_addrs
|
|
|
|
+ pub fn ip_addrs<T: Into<ManagedSlice<'c, IpCidr>>>(mut self, ips: T) -> InterfaceBuilder<'b, 'c, DeviceT> {
|
|
|
|
+ let ips = ips.into();
|
|
|
|
+ InterfaceInner::check_ip_addrs(&ips);
|
|
|
|
+ self.ip_addrs = Some(ips);
|
|
|
|
+ self
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// Set the IPv4 gateway the interface will use. See also
|
|
|
|
+ /// [ipv4_gateway].
|
|
|
|
+ ///
|
|
|
|
+ /// # Panics
|
|
|
|
+ /// This function panics if the given address is not unicast.
|
|
|
|
+ ///
|
|
|
|
+ /// [ipv4_gateway]: struct.EthernetInterface.html#method.ipv4_gateway
|
|
|
|
+ pub fn ipv4_gateway<T>(mut self, gateway: T) -> InterfaceBuilder<'b, 'c, DeviceT>
|
|
|
|
+ where T: Into<Ipv4Address> {
|
|
|
|
+ let addr = gateway.into();
|
|
|
|
+ InterfaceInner::check_gateway_addr(&addr);
|
|
|
|
+ self.ipv4_gateway = Some(addr);
|
|
|
|
+ self
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// Set the Neighbor Cache the interface will use.
|
|
|
|
+ pub fn neighbor_cache(mut self, neighbor_cache: NeighborCache<'b>) -> InterfaceBuilder<'b, 'c, DeviceT> {
|
|
|
|
+ self.neighbor_cache = Some(neighbor_cache);
|
|
|
|
+ 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]
|
|
|
|
+ /// - [ip_addrs]
|
|
|
|
+ ///
|
|
|
|
+ /// [ethernet_addr]: #method.ethernet_addr
|
|
|
|
+ /// [neighbor_cache]: #method.neighbor_cache
|
|
|
|
+ /// [ip_addrs]: #method.ip_addrs
|
|
|
|
+ pub fn finalize(self) -> Interface<'b, 'c, DeviceT> {
|
|
|
|
+ // TODO: Limit the number of required options.
|
|
|
|
+ match (self.ethernet_addr, self.neighbor_cache, self.ip_addrs) {
|
|
|
|
+ (Some(ethernet_addr), Some(neighbor_cache), Some(ip_addrs)) => {
|
|
|
|
+ let device_capabilities = self.device.capabilities();
|
|
|
|
+ Interface {
|
|
|
|
+ device: self.device,
|
|
|
|
+ inner: InterfaceInner {
|
|
|
|
+ ethernet_addr, device_capabilities, neighbor_cache,
|
|
|
|
+ ip_addrs, ipv4_gateway: self.ipv4_gateway,
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ _ => panic!("a required option was not set"),
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
#[derive(Debug, PartialEq)]
|
|
#[derive(Debug, PartialEq)]
|
|
enum Packet<'a> {
|
|
enum Packet<'a> {
|
|
None,
|
|
None,
|
|
@@ -84,33 +210,6 @@ impl<'a> Packet<'a> {
|
|
|
|
|
|
impl<'b, 'c, DeviceT> Interface<'b, 'c, DeviceT>
|
|
impl<'b, 'c, DeviceT> Interface<'b, 'c, DeviceT>
|
|
where DeviceT: for<'d> Device<'d> {
|
|
where DeviceT: for<'d> Device<'d> {
|
|
- /// Create a network interface using the provided network device.
|
|
|
|
- ///
|
|
|
|
- /// # Panics
|
|
|
|
- /// See the restrictions on [set_hardware_addr](#method.set_hardware_addr)
|
|
|
|
- /// and [set_protocol_addrs](#method.set_protocol_addrs) functions.
|
|
|
|
- pub fn new<ProtocolAddrsMT, Ipv4GatewayAddrT>
|
|
|
|
- (device: DeviceT,
|
|
|
|
- neighbor_cache: NeighborCache<'b>,
|
|
|
|
- ethernet_addr: EthernetAddress,
|
|
|
|
- ip_addrs: ProtocolAddrsMT,
|
|
|
|
- ipv4_gateway: Ipv4GatewayAddrT) ->
|
|
|
|
- Interface<'b, 'c, DeviceT>
|
|
|
|
- where ProtocolAddrsMT: Into<ManagedSlice<'c, IpCidr>>,
|
|
|
|
- Ipv4GatewayAddrT: Into<Option<Ipv4Address>>, {
|
|
|
|
- let ip_addrs = ip_addrs.into();
|
|
|
|
- InterfaceInner::check_ethernet_addr(ðernet_addr);
|
|
|
|
- InterfaceInner::check_ip_addrs(&ip_addrs);
|
|
|
|
-
|
|
|
|
- let inner = InterfaceInner {
|
|
|
|
- ethernet_addr, ip_addrs, neighbor_cache,
|
|
|
|
- ipv4_gateway: ipv4_gateway.into(),
|
|
|
|
- device_capabilities: device.capabilities(),
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- Interface { device, inner }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
/// Get the Ethernet address of the interface.
|
|
/// Get the Ethernet address of the interface.
|
|
pub fn ethernet_addr(&self) -> EthernetAddress {
|
|
pub fn ethernet_addr(&self) -> EthernetAddress {
|
|
self.inner.ethernet_addr
|
|
self.inner.ethernet_addr
|
|
@@ -314,6 +413,12 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ fn check_gateway_addr(addr: &Ipv4Address) {
|
|
|
|
+ if !addr.is_unicast() {
|
|
|
|
+ panic!("gateway IP address {} is not unicast", addr);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
/// Check whether the interface has the given IP address assigned.
|
|
/// Check whether the interface has the given IP address assigned.
|
|
fn has_ip_addr<T: Into<IpAddress>>(&self, addr: T) -> bool {
|
|
fn has_ip_addr<T: Into<IpAddress>>(&self, addr: T) -> bool {
|
|
let addr = addr.into();
|
|
let addr = addr.into();
|
|
@@ -795,6 +900,7 @@ mod test {
|
|
use std::collections::BTreeMap;
|
|
use std::collections::BTreeMap;
|
|
use {Result, Error};
|
|
use {Result, Error};
|
|
|
|
|
|
|
|
+ use super::InterfaceBuilder;
|
|
use iface::{NeighborCache, EthernetInterface};
|
|
use iface::{NeighborCache, EthernetInterface};
|
|
use phy::{self, Loopback, ChecksumCapabilities};
|
|
use phy::{self, Loopback, ChecksumCapabilities};
|
|
use socket::SocketSet;
|
|
use socket::SocketSet;
|
|
@@ -812,12 +918,13 @@ mod test {
|
|
// Create a basic device
|
|
// Create a basic device
|
|
let device = Loopback::new();
|
|
let device = Loopback::new();
|
|
|
|
|
|
- let neighbor_cache = NeighborCache::new(BTreeMap::new());
|
|
|
|
|
|
+ let iface = InterfaceBuilder::new(device)
|
|
|
|
+ .ethernet_addr(EthernetAddress::default())
|
|
|
|
+ .neighbor_cache(NeighborCache::new(BTreeMap::new()))
|
|
|
|
+ .ip_addrs([IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8)])
|
|
|
|
+ .finalize();
|
|
|
|
|
|
- let ip_addr = IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8);
|
|
|
|
- (EthernetInterface::new(device, neighbor_cache,
|
|
|
|
- EthernetAddress::default(), [ip_addr], None),
|
|
|
|
- SocketSet::new(vec![]))
|
|
|
|
|
|
+ (iface, SocketSet::new(vec![]))
|
|
}
|
|
}
|
|
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
#[derive(Debug, PartialEq)]
|
|
@@ -830,6 +937,12 @@ mod test {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ #[test]
|
|
|
|
+ #[should_panic(expected = "a required option was not set")]
|
|
|
|
+ fn test_builder_initialization_panic() {
|
|
|
|
+ InterfaceBuilder::new(Loopback::new()).finalize();
|
|
|
|
+ }
|
|
|
|
+
|
|
#[test]
|
|
#[test]
|
|
fn test_no_icmp_to_broadcast() {
|
|
fn test_no_icmp_to_broadcast() {
|
|
let (mut iface, mut socket_set) = create_loopback();
|
|
let (mut iface, mut socket_set) = create_loopback();
|