Browse Source

Add support for IP mediums.

- Add `medium` in `DeviceCapabilities`.
- Rename EthernetInterface to Interface.
- Add support to Interface for both Ethernet and IP mediums. The medium to use is detected from `device.capabilities().medium`.
- Ethernet-only features are gated behind the "ethernet" feature, as before.
- IP features are always enabled for now.
Dario Nieuwenhuis 4 years ago
parent
commit
d352e151f6

+ 2 - 2
examples/benchmark.rs

@@ -13,7 +13,7 @@ use log::debug;
 
 use smoltcp::phy::wait as phy_wait;
 use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr};
-use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder};
+use smoltcp::iface::{NeighborCache, InterfaceBuilder};
 use smoltcp::socket::SocketSet;
 use smoltcp::socket::{TcpSocket, TcpSocketBuffer};
 use smoltcp::time::{Duration, Instant};
@@ -90,7 +90,7 @@ fn main() {
 
     let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]);
     let ip_addrs = [IpCidr::new(IpAddress::v4(192, 168, 69, 1), 24)];
-    let mut iface = EthernetInterfaceBuilder::new(device)
+    let mut iface = InterfaceBuilder::new(device)
             .ethernet_addr(ethernet_addr)
             .neighbor_cache(neighbor_cache)
             .ip_addrs(ip_addrs)

+ 2 - 2
examples/client.rs

@@ -7,7 +7,7 @@ use log::debug;
 
 use smoltcp::phy::wait as phy_wait;
 use smoltcp::wire::{EthernetAddress, Ipv4Address, IpAddress, IpCidr};
-use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder, Routes};
+use smoltcp::iface::{NeighborCache, InterfaceBuilder, Routes};
 use smoltcp::socket::{SocketSet, TcpSocket, TcpSocketBuffer};
 use smoltcp::time::Instant;
 
@@ -39,7 +39,7 @@ fn main() {
     let mut routes_storage = [None; 1];
     let mut routes = Routes::new(&mut routes_storage[..]);
     routes.add_default_ipv4_route(default_v4_gw).unwrap();
-    let mut iface = EthernetInterfaceBuilder::new(device)
+    let mut iface = InterfaceBuilder::new(device)
             .ethernet_addr(ethernet_addr)
             .neighbor_cache(neighbor_cache)
             .ip_addrs(ip_addrs)

+ 2 - 2
examples/dhcp_client.rs

@@ -5,7 +5,7 @@ use std::collections::BTreeMap;
 use std::os::unix::io::AsRawFd;
 use smoltcp::phy::wait as phy_wait;
 use smoltcp::wire::{EthernetAddress, Ipv4Address, IpCidr, Ipv4Cidr};
-use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder, Routes};
+use smoltcp::iface::{NeighborCache, InterfaceBuilder, Routes};
 use smoltcp::socket::{SocketSet, RawSocketBuffer, RawPacketMetadata};
 use smoltcp::time::Instant;
 use smoltcp::dhcp::Dhcpv4Client;
@@ -28,7 +28,7 @@ fn main() {
     let ip_addrs = [IpCidr::new(Ipv4Address::UNSPECIFIED.into(), 0)];
     let mut routes_storage = [None; 1];
     let routes = Routes::new(&mut routes_storage[..]);
-    let mut iface = EthernetInterfaceBuilder::new(device)
+    let mut iface = InterfaceBuilder::new(device)
             .ethernet_addr(ethernet_addr)
             .neighbor_cache(neighbor_cache)
             .ip_addrs(ip_addrs)

+ 2 - 2
examples/httpclient.rs

@@ -8,7 +8,7 @@ use log::debug;
 
 use smoltcp::phy::wait as phy_wait;
 use smoltcp::wire::{EthernetAddress, Ipv4Address, Ipv6Address, IpAddress, IpCidr};
-use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder, Routes};
+use smoltcp::iface::{NeighborCache, InterfaceBuilder, Routes};
 use smoltcp::socket::{SocketSet, TcpSocket, TcpSocketBuffer};
 use smoltcp::time::Instant;
 
@@ -45,7 +45,7 @@ fn main() {
     let mut routes = Routes::new(&mut routes_storage[..]);
     routes.add_default_ipv4_route(default_v4_gw).unwrap();
     routes.add_default_ipv6_route(default_v6_gw).unwrap();
-    let mut iface = EthernetInterfaceBuilder::new(device)
+    let mut iface = InterfaceBuilder::new(device)
             .ethernet_addr(ethernet_addr)
             .neighbor_cache(neighbor_cache)
             .ip_addrs(ip_addrs)

+ 4 - 4
examples/loopback.rs

@@ -9,9 +9,9 @@ mod utils;
 use core::str;
 use log::{info, debug, error};
 
-use smoltcp::phy::Loopback;
+use smoltcp::phy::{Loopback, Medium};
 use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr};
-use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder};
+use smoltcp::iface::{NeighborCache, InterfaceBuilder};
 use smoltcp::socket::{SocketSet, TcpSocket, TcpSocketBuffer};
 use smoltcp::time::{Duration, Instant};
 
@@ -65,7 +65,7 @@ mod mock {
 
 fn main() {
     let clock = mock::Clock::new();
-    let device = Loopback::new();
+    let device = Loopback::new(Medium::Ethernet);
 
     #[cfg(feature = "std")]
     let device = {
@@ -83,7 +83,7 @@ fn main() {
     let mut neighbor_cache = NeighborCache::new(&mut neighbor_cache_entries[..]);
 
     let mut ip_addrs = [IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8)];
-    let mut iface = EthernetInterfaceBuilder::new(device)
+    let mut iface = InterfaceBuilder::new(device)
             .ethernet_addr(EthernetAddress::default())
             .neighbor_cache(neighbor_cache)
             .ip_addrs(ip_addrs)

+ 2 - 2
examples/multicast.rs

@@ -7,7 +7,7 @@ use log::debug;
 use smoltcp::phy::wait as phy_wait;
 use smoltcp::wire::{EthernetAddress, IpVersion, IpProtocol, IpAddress, IpCidr, Ipv4Address,
                     Ipv4Packet, IgmpPacket, IgmpRepr};
-use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder};
+use smoltcp::iface::{NeighborCache, InterfaceBuilder};
 use smoltcp::socket::{SocketSet,
                       RawSocket, RawSocketBuffer, RawPacketMetadata,
                       UdpSocket, UdpSocketBuffer, UdpPacketMetadata};
@@ -37,7 +37,7 @@ fn main() {
     let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
     let ip_addr = IpCidr::new(IpAddress::from(local_addr), 24);
     let mut ipv4_multicast_storage = [None; 1];
-    let mut iface = EthernetInterfaceBuilder::new(device)
+    let mut iface = InterfaceBuilder::new(device)
             .ethernet_addr(ethernet_addr)
             .neighbor_cache(neighbor_cache)
             .ip_addrs([ip_addr])

+ 2 - 2
examples/ping.rs

@@ -14,7 +14,7 @@ use smoltcp::phy::wait as phy_wait;
 use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr,
                     Ipv6Address, Icmpv6Repr, Icmpv6Packet,
                     Ipv4Address, Icmpv4Repr, Icmpv4Packet};
-use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder, Routes};
+use smoltcp::iface::{NeighborCache, InterfaceBuilder, Routes};
 use smoltcp::socket::{SocketSet, IcmpSocket, IcmpSocketBuffer, IcmpPacketMetadata, IcmpEndpoint};
 
 macro_rules! send_icmp_ping {
@@ -98,7 +98,7 @@ fn main() {
     let mut routes = Routes::new(&mut routes_storage[..]);
     routes.add_default_ipv4_route(default_v4_gw).unwrap();
     routes.add_default_ipv6_route(default_v6_gw).unwrap();
-    let mut iface = EthernetInterfaceBuilder::new(device)
+    let mut iface = InterfaceBuilder::new(device)
             .ethernet_addr(ethernet_addr)
             .ip_addrs(ip_addrs)
             .routes(routes)

+ 2 - 2
examples/server.rs

@@ -8,7 +8,7 @@ use log::debug;
 
 use smoltcp::phy::wait as phy_wait;
 use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr};
-use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder};
+use smoltcp::iface::{NeighborCache, InterfaceBuilder};
 use smoltcp::socket::SocketSet;
 use smoltcp::socket::{UdpSocket, UdpSocketBuffer, UdpPacketMetadata};
 use smoltcp::socket::{TcpSocket, TcpSocketBuffer};
@@ -54,7 +54,7 @@ fn main() {
         IpCidr::new(IpAddress::v6(0xfdaa, 0, 0, 0, 0, 0, 0, 1), 64),
         IpCidr::new(IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64)
     ];
-    let mut iface = EthernetInterfaceBuilder::new(device)
+    let mut iface = InterfaceBuilder::new(device)
             .ethernet_addr(ethernet_addr)
             .neighbor_cache(neighbor_cache)
             .ip_addrs(ip_addrs)

+ 4 - 4
fuzz/fuzz_targets/tcp_headers.rs

@@ -6,10 +6,10 @@ use std as core;
 extern crate getopts;
 
 use core::cmp;
-use smoltcp::phy::Loopback;
+use smoltcp::phy::{Loopback, Medium};
 use smoltcp::wire::{EthernetAddress, EthernetFrame, EthernetProtocol};
 use smoltcp::wire::{IpAddress, IpCidr, Ipv4Packet, Ipv6Packet, TcpPacket};
-use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder};
+use smoltcp::iface::{NeighborCache, InterfaceBuilder};
 use smoltcp::socket::{SocketSet, TcpSocket, TcpSocketBuffer};
 use smoltcp::time::{Duration, Instant};
 
@@ -118,7 +118,7 @@ fuzz_target!(|data: &[u8]| {
         utils::add_middleware_options(&mut opts, &mut free);
 
         let mut matches = utils::parse_options(&opts, free);
-        let device = utils::parse_middleware_options(&mut matches, Loopback::new(),
+        let device = utils::parse_middleware_options(&mut matches, Loopback::new(Medium::Ethernet),
                                                      /*loopback=*/true);
 
         smoltcp::phy::FuzzInjector::new(device,
@@ -130,7 +130,7 @@ fuzz_target!(|data: &[u8]| {
     let neighbor_cache = NeighborCache::new(&mut neighbor_cache_entries[..]);
 
     let ip_addrs = [IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8)];
-    let mut iface = EthernetInterfaceBuilder::new(device)
+    let mut iface = InterfaceBuilder::new(device)
             .ethernet_addr(EthernetAddress::default())
             .neighbor_cache(neighbor_cache)
             .ip_addrs(ip_addrs)

+ 1 - 1
src/dhcp/clientv4.rs

@@ -6,7 +6,7 @@ use crate::wire::{IpVersion, IpProtocol, IpEndpoint, IpAddress,
 use crate::wire::dhcpv4::field as dhcpv4_field;
 use crate::socket::{SocketSet, SocketHandle, RawSocket, RawSocketBuffer};
 use crate::phy::{Device, ChecksumCapabilities};
-use crate::iface::EthernetInterface as Interface;
+use crate::iface::Interface;
 use crate::time::{Instant, Duration};
 use super::{UDP_SERVER_PORT, UDP_CLIENT_PORT};
 

File diff suppressed because it is too large
+ 326 - 247
src/iface/interface.rs


+ 3 - 5
src/iface/mod.rs

@@ -7,8 +7,7 @@ provides lookup and caching of hardware addresses, and handles management packet
 #[cfg(feature = "ethernet")]
 mod neighbor;
 mod route;
-#[cfg(feature = "ethernet")]
-mod ethernet;
+mod interface;
 
 #[cfg(feature = "ethernet")]
 pub use self::neighbor::Neighbor as Neighbor;
@@ -17,6 +16,5 @@ pub(crate) use self::neighbor::Answer as NeighborAnswer;
 #[cfg(feature = "ethernet")]
 pub use self::neighbor::Cache as NeighborCache;
 pub use self::route::{Route, Routes};
-#[cfg(feature = "ethernet")]
-pub use self::ethernet::{Interface as EthernetInterface,
-                         InterfaceBuilder as EthernetInterfaceBuilder};
+
+pub use self::interface::{Interface, InterfaceBuilder};

+ 5 - 2
src/phy/loopback.rs

@@ -10,13 +10,14 @@ use alloc::collections::VecDeque;
 use alloc::VecDeque;
 
 use crate::Result;
-use crate::phy::{self, Device, DeviceCapabilities};
+use crate::phy::{self, Device, DeviceCapabilities, Medium};
 use crate::time::Instant;
 
 /// A loopback device.
 #[derive(Debug)]
 pub struct Loopback {
     queue: VecDeque<Vec<u8>>,
+    medium: Medium,
 }
 
 #[allow(clippy::new_without_default)]
@@ -25,9 +26,10 @@ impl Loopback {
     ///
     /// Every packet transmitted through this device will be received through it
     /// in FIFO order.
-    pub fn new() -> Loopback {
+    pub fn new(medium: Medium) -> Loopback {
         Loopback {
             queue: VecDeque::new(),
+            medium,
         }
     }
 }
@@ -39,6 +41,7 @@ impl<'a> Device<'a> for Loopback {
     fn capabilities(&self) -> DeviceCapabilities {
         DeviceCapabilities {
             max_transmission_unit: 65535,
+            medium: self.medium,
             ..DeviceCapabilities::default()
         }
     }

+ 39 - 3
src/phy/mod.rs

@@ -10,7 +10,8 @@ and implementations of it:
   * _adapters_ [RawSocket](struct.RawSocket.html) and
     [TapInterface](struct.TapInterface.html), to transmit and receive frames
     on the host OS.
-
+*/
+#![cfg_attr(feature = "ethernet", doc = r##"
 # Examples
 
 An implementation of the [Device](trait.Device.html) trait for a simple hardware
@@ -18,7 +19,7 @@ Ethernet controller could look as follows:
 
 ```rust
 use smoltcp::Result;
-use smoltcp::phy::{self, DeviceCapabilities, Device};
+use smoltcp::phy::{self, DeviceCapabilities, Device, Medium};
 use smoltcp::time::Instant;
 
 struct StmPhy {
@@ -52,6 +53,7 @@ impl<'a> phy::Device<'a> for StmPhy {
         let mut caps = DeviceCapabilities::default();
         caps.max_transmission_unit = 1536;
         caps.max_burst_size = Some(1);
+        caps.medium = Medium::Ethernet;
         caps
     }
 }
@@ -82,7 +84,7 @@ impl<'a> phy::TxToken for StmPhyTxToken<'a> {
     }
 }
 ```
-*/
+"##)]
 
 use crate::Result;
 use crate::time::Instant;
@@ -192,6 +194,13 @@ impl ChecksumCapabilities {
 #[derive(Debug, Clone, Default)]
 #[non_exhaustive]
 pub struct DeviceCapabilities {
+    /// Medium of the device.
+    ///
+    /// This indicates what kind of packet the sent/received bytes are, and determines
+    /// some behaviors of Interface. For example, ARP/NDISC address resolution is only done
+    /// for Ethernet mediums.
+    pub medium: Medium,
+
     /// Maximum transmission unit.
     ///
     /// The network device is unable to send or receive frames larger than the value returned
@@ -222,6 +231,33 @@ pub struct DeviceCapabilities {
     pub checksum: ChecksumCapabilities,
 }
 
+/// Type of medium of a device.
+#[derive(Debug, Eq, PartialEq, Copy, Clone)]
+pub enum Medium {
+    /// Ethernet medium. Devices of this type send and receive Ethernet frames,
+    /// and interfaces using it must do neighbor discovery via ARP or NDISC.
+    ///
+    /// Examples of devices of this type are Ethernet, WiFi (802.11), Linux `tap`, and VPNs in tap (layer 2) mode.
+    #[cfg(feature = "ethernet")]
+    Ethernet,
+
+    /// IP medium. Devices of this type send and receive IP frames, without an
+    /// Ethernet header. MAC addresses are not used, and no neighbor discovery (ARP, NDISC) is done.
+    ///
+    /// Examples of devices of this type are the Linux `tun`, PPP interfaces, VPNs in tun (layer 3) mode.
+    Ip,
+}
+
+
+impl Default for Medium {
+    fn default() -> Medium {
+        #[cfg(feature = "ethernet")]
+        return Medium::Ethernet;
+        #[cfg(not(feature = "ethernet"))]
+        return Medium::Ip;
+    }
+}
+
 /// An interface for sending and receiving raw network frames.
 ///
 /// The interface is based on _tokens_, which are types that allow to receive/transmit a

+ 2 - 1
src/phy/raw_socket.rs

@@ -5,7 +5,7 @@ use std::io;
 use std::os::unix::io::{RawFd, AsRawFd};
 
 use crate::Result;
-use crate::phy::{self, sys, DeviceCapabilities, Device};
+use crate::phy::{self, sys, DeviceCapabilities, Device, Medium};
 use crate::time::Instant;
 
 /// A socket that captures or transmits the complete frame.
@@ -44,6 +44,7 @@ impl<'a> Device<'a> for RawSocket {
     fn capabilities(&self) -> DeviceCapabilities {
         DeviceCapabilities {
             max_transmission_unit: self.mtu,
+            medium: Medium::Ethernet,
             ..DeviceCapabilities::default()
         }
     }

+ 2 - 1
src/phy/tap_interface.rs

@@ -5,7 +5,7 @@ use std::io;
 use std::os::unix::io::{RawFd, AsRawFd};
 
 use crate::Result;
-use crate::phy::{self, sys, DeviceCapabilities, Device};
+use crate::phy::{self, sys, DeviceCapabilities, Device, Medium};
 use crate::time::Instant;
 
 /// A virtual Ethernet interface.
@@ -45,6 +45,7 @@ impl<'a> Device<'a> for TapInterface {
     fn capabilities(&self) -> DeviceCapabilities {
         DeviceCapabilities {
             max_transmission_unit: self.mtu,
+            medium: Medium::Ethernet,
             ..DeviceCapabilities::default()
         }
     }

Some files were not shown because too many files changed in this diff