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.
master
Dario Nieuwenhuis 2020-06-04 03:00:49 +02:00
parent bbecbf80c1
commit 9ac2cac075
16 changed files with 439 additions and 343 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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])

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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 Load Diff

View File

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

View File

@ -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()
}
}

View File

@ -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

View File

@ -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()
}
}

View File

@ -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()
}
}