瀏覽代碼

Add medium-ip, medium-ethernet feature flags.

Dario Nieuwenhuis 4 年之前
父節點
當前提交
4d8729088d
共有 9 個文件被更改,包括 119 次插入94 次删除
  1. 12 12
      .github/workflows/test.yml
  2. 3 2
      Cargo.toml
  3. 71 52
      src/iface/interface.rs
  4. 6 4
      src/iface/mod.rs
  5. 1 1
      src/lib.rs
  6. 5 5
      src/parsers.rs
  7. 8 5
      src/phy/mod.rs
  8. 5 5
      src/wire/icmpv6.rs
  9. 8 8
      src/wire/mod.rs

+ 12 - 12
.github/workflows/test.yml

@@ -26,23 +26,23 @@ jobs:
           - std proto-ipv4
 
           # Test features chosen to be as orthogonal as possible.
-          - std ethernet phy-raw_socket proto-ipv6 socket-udp
-          - std ethernet phy-tap_interface proto-ipv6 socket-udp
-          - std ethernet proto-ipv4 proto-igmp socket-raw
-          - std ethernet proto-ipv4 socket-udp socket-tcp
-          - std ethernet proto-ipv4 proto-dhcpv4 socket-udp
-          - std ethernet proto-ipv6 socket-udp
-          - std ethernet proto-ipv6 socket-tcp
-          - std ethernet proto-ipv4 socket-icmp socket-tcp
-          - std ethernet proto-ipv6 socket-icmp socket-tcp
+          - std medium-ethernet phy-raw_socket proto-ipv6 socket-udp
+          - std medium-ethernet phy-tap_interface proto-ipv6 socket-udp
+          - std medium-ethernet proto-ipv4 proto-igmp socket-raw
+          - std medium-ethernet proto-ipv4 socket-udp socket-tcp
+          - std medium-ethernet proto-ipv4 proto-dhcpv4 socket-udp
+          - std medium-ethernet proto-ipv6 socket-udp
+          - std medium-ethernet proto-ipv6 socket-tcp
+          - std medium-ethernet proto-ipv4 socket-icmp socket-tcp
+          - std medium-ethernet proto-ipv6 socket-icmp socket-tcp
 
           # Test features chosen to be as aggressive as possible.
-          - std ethernet proto-ipv4 proto-ipv6 socket-raw socket-udp socket-tcp socket-icmp async
+          - std medium-ethernet proto-ipv4 proto-ipv6 socket-raw socket-udp socket-tcp socket-icmp async
 
         include:
           # Test alloc feature which requires nightly.
           - rust: nightly
-            features: alloc ethernet proto-ipv4 proto-ipv6 socket-raw socket-udp socket-tcp socket-icmp
+            features: alloc medium-ethernet proto-ipv4 proto-ipv6 socket-raw socket-udp socket-tcp socket-icmp
           - rust: nightly
             features: alloc proto-ipv4 proto-ipv6 socket-raw socket-udp socket-tcp socket-icmp
     steps:
@@ -69,7 +69,7 @@ jobs:
 
         features:
           # These feature sets cannot run tests, so we only check they build.
-          - ethernet proto-ipv6 proto-ipv6 proto-igmp proto-dhcpv4 socket-raw socket-udp socket-tcp socket-icmp async
+          - medium-ip medium-ethernet proto-ipv6 proto-ipv6 proto-igmp proto-dhcpv4 socket-raw socket-udp socket-tcp socket-icmp async
 
     steps:
       - uses: actions/checkout@v2

+ 3 - 2
Cargo.toml

@@ -32,7 +32,8 @@ url = "1.0"
 std = ["managed/std"]
 alloc = ["managed/alloc"]
 verbose = []
-ethernet = ["socket"]
+"medium-ethernet" = ["socket"]
+"medium-ip" = ["socket"]
 "phy-raw_socket" = ["std", "libc", "ethernet"]
 "phy-tap_interface" = ["std", "libc", "ethernet"]
 "proto-ipv4" = []
@@ -47,7 +48,7 @@ ethernet = ["socket"]
 "async" = []
 default = [
   "std", "log", # needed for `cargo test --no-default-features --features default` :/
-  "ethernet",
+  "medium-ethernet", "medium-ip",
   "phy-raw_socket", "phy-tap_interface",
   "proto-ipv4", "proto-igmp", "proto-dhcpv4", "proto-ipv6",
   "socket-raw", "socket-icmp", "socket-udp", "socket-tcp",

+ 71 - 52
src/iface/interface.rs

@@ -10,7 +10,7 @@ use crate::phy::{Device, DeviceCapabilities, RxToken, TxToken, Medium};
 use crate::time::{Duration, Instant};
 use crate::wire::*;
 use crate::socket::*;
-#[cfg(feature = "ethernet")]
+#[cfg(feature = "medium-ethernet")]
 use crate::iface::{NeighborCache, NeighborAnswer};
 use crate::iface::Routes;
 
@@ -32,9 +32,9 @@ pub struct Interface<'a, DeviceT: for<'d> Device<'d>> {
 /// methods on the `Interface` in this time (since its `device` field is borrowed
 /// exclusively). However, it is still possible to call methods on its `inner` field.
 struct InterfaceInner<'a> {
-    #[cfg(feature = "ethernet")]
+    #[cfg(feature = "medium-ethernet")]
     neighbor_cache:         Option<NeighborCache<'a>>,
-    #[cfg(feature = "ethernet")]
+    #[cfg(feature = "medium-ethernet")]
     ethernet_addr:          Option<EthernetAddress>,
     ip_addrs:               ManagedSlice<'a, IpCidr>,
     #[cfg(feature = "proto-ipv4")]
@@ -51,9 +51,9 @@ struct InterfaceInner<'a> {
 /// A builder structure used for creating a network interface.
 pub struct InterfaceBuilder <'a, DeviceT: for<'d> Device<'d>> {
     device:                 DeviceT,
-    #[cfg(feature = "ethernet")]
+    #[cfg(feature = "medium-ethernet")]
     ethernet_addr:          Option<EthernetAddress>,
-    #[cfg(feature = "ethernet")]
+    #[cfg(feature = "medium-ethernet")]
     neighbor_cache:         Option<NeighborCache<'a>>,
     ip_addrs:               ManagedSlice<'a, IpCidr>,
     #[cfg(feature = "proto-ipv4")]
@@ -68,7 +68,7 @@ impl<'a, DeviceT> InterfaceBuilder<'a, DeviceT>
         where DeviceT: for<'d> Device<'d> {
     /// Create a builder used for creating a network interface using the
     /// given device and address.
-    #[cfg_attr(feature = "ethernet", doc = r##"
+    #[cfg_attr(feature = "medium-ethernet", doc = r##"
 # Examples
 
 ```
@@ -95,9 +95,9 @@ let iface = InterfaceBuilder::new(device)
     pub fn new(device: DeviceT) -> Self {
         InterfaceBuilder {
             device:              device,
-            #[cfg(feature = "ethernet")]
+            #[cfg(feature = "medium-ethernet")]
             ethernet_addr:       None,
-            #[cfg(feature = "ethernet")]
+            #[cfg(feature = "medium-ethernet")]
             neighbor_cache:      None,
             ip_addrs:            ManagedSlice::Borrowed(&mut []),
             #[cfg(feature = "proto-ipv4")]
@@ -115,7 +115,7 @@ let iface = InterfaceBuilder::new(device)
     /// This function panics if the address is not unicast.
     ///
     /// [ethernet_addr]: struct.Interface.html#method.ethernet_addr
-    #[cfg(feature = "ethernet")]
+    #[cfg(feature = "medium-ethernet")]
     pub fn ethernet_addr(mut self, addr: EthernetAddress) -> Self {
         InterfaceInner::check_ethernet_addr(&addr);
         self.ethernet_addr = Some(addr);
@@ -187,7 +187,7 @@ let iface = InterfaceBuilder::new(device)
     }
 
     /// Set the Neighbor Cache the interface will use.
-    #[cfg(feature = "ethernet")]
+    #[cfg(feature = "medium-ethernet")]
     pub fn neighbor_cache(mut self, neighbor_cache: NeighborCache<'a>) -> Self {
         self.neighbor_cache = Some(neighbor_cache);
         self
@@ -207,35 +207,31 @@ let iface = InterfaceBuilder::new(device)
     pub fn finalize(self) -> Interface<'a, DeviceT> {
         let device_capabilities = self.device.capabilities();
 
-        #[cfg(feature = "ethernet")]
-        let mut ethernet_addr = None;
-        #[cfg(feature = "ethernet")]
-        let mut neighbor_cache = None;
-        match device_capabilities.medium {
-            #[cfg(feature = "ethernet")]
-            Medium::Ethernet => {
-                ethernet_addr = Some(self.ethernet_addr.expect("ethernet_addr required option was not set"));
-                neighbor_cache = Some(self.neighbor_cache.expect("neighbor_cache required option was not set"));
-            }
+        #[cfg(feature = "medium-ethernet")]
+        let (ethernet_addr, neighbor_cache) = match device_capabilities.medium {
+            Medium::Ethernet => (
+                Some(self.ethernet_addr.expect("ethernet_addr required option was not set")),
+                Some(self.neighbor_cache.expect("neighbor_cache required option was not set"))
+            ),
+            #[cfg(feature = "medium-ip")]
             Medium::Ip => {
-                #[cfg(feature = "ethernet")]
                 assert!(self.ethernet_addr.is_none(), "ethernet_addr is set, but device medium is IP");
-                #[cfg(feature = "ethernet")]
                 assert!(self.neighbor_cache.is_none(), "neighbor_cache is set, but device medium is IP");
+                (None, None)
             }
-        }
+        };
 
         Interface {
             device: self.device,
             inner: InterfaceInner {
-                #[cfg(feature = "ethernet")]
+                #[cfg(feature = "medium-ethernet")]
                 ethernet_addr,
                 ip_addrs: self.ip_addrs,
                 #[cfg(feature = "proto-ipv4")]
                 any_ip: self.any_ip,
                 routes: self.routes,
                 device_capabilities,
-                #[cfg(feature = "ethernet")]
+                #[cfg(feature = "medium-ethernet")]
                 neighbor_cache,
                 #[cfg(feature = "proto-igmp")]
                 ipv4_multicast_groups: self.ipv4_multicast_groups,
@@ -247,7 +243,7 @@ let iface = InterfaceBuilder::new(device)
 }
 
 #[derive(Debug, PartialEq)]
-#[cfg(feature = "ethernet")]
+#[cfg(feature = "medium-ethernet")]
 enum EthernetPacket<'a> {
     #[cfg(feature = "proto-ipv4")]
     Arp(ArpRepr),
@@ -371,7 +367,7 @@ impl<'a, DeviceT> Interface<'a, DeviceT>
     /// # Panics
     /// This function panics if if the interface's medium is not Ethernet.
 
-    #[cfg(feature = "ethernet")]
+    #[cfg(feature = "medium-ethernet")]
     pub fn ethernet_addr(&self) -> EthernetAddress {
         self.inner.ethernet_addr.unwrap()
     }
@@ -381,7 +377,7 @@ impl<'a, DeviceT> Interface<'a, DeviceT>
     /// # Panics
     /// This function panics if the address is not unicast, or if the
     /// interface's medium is not Ethernet.
-    #[cfg(feature = "ethernet")]
+    #[cfg(feature = "medium-ethernet")]
     pub fn set_ethernet_addr(&mut self, addr: EthernetAddress) {
         assert!(self.device.capabilities().medium == Medium::Ethernet);
         InterfaceInner::check_ethernet_addr(&addr);
@@ -591,7 +587,7 @@ impl<'a, DeviceT> Interface<'a, DeviceT>
             };
             rx_token.consume(timestamp, |frame| {
                 match inner.device_capabilities.medium {
-                    #[cfg(feature = "ethernet")]
+                    #[cfg(feature = "medium-ethernet")]
                     Medium::Ethernet => {
                         inner.process_ethernet(sockets, timestamp, &frame).map_err(|err| {
                             net_debug!("cannot process ingress packet: {}", err);
@@ -611,6 +607,7 @@ impl<'a, DeviceT> Interface<'a, DeviceT>
                             }
                         })
                     }
+                    #[cfg(feature = "medium-ip")]
                     Medium::Ip => {
                         inner.process_ip(sockets, timestamp, &frame).map_err(|err| {
                             net_debug!("cannot process ingress packet: {}", err);
@@ -638,12 +635,12 @@ impl<'a, DeviceT> Interface<'a, DeviceT>
 
     fn socket_egress(&mut self, sockets: &mut SocketSet, timestamp: Instant) -> Result<bool> {
         let mut caps = self.device.capabilities();
-        match caps.medium {
-            #[cfg(feature = "ethernet")]
-            Medium::Ethernet => 
-                caps.max_transmission_unit -= EthernetFrame::<&[u8]>::header_len(),
-            _ => {}
-        }
+        caps.max_transmission_unit = match caps.medium {
+            #[cfg(feature = "medium-ethernet")]
+            Medium::Ethernet => caps.max_transmission_unit - EthernetFrame::<&[u8]>::header_len(),
+            #[cfg(feature = "medium-ip")]
+            Medium::Ip => caps.max_transmission_unit,
+        };
 
         let mut emitted_any = false;
         for mut socket in sockets.iter_mut() {
@@ -768,7 +765,7 @@ impl<'a, DeviceT> Interface<'a, DeviceT>
 }
 
 impl<'a> InterfaceInner<'a> {
-    #[cfg(feature = "ethernet")]
+    #[cfg(feature = "medium-ethernet")]
     fn check_ethernet_addr(addr: &EthernetAddress) {
         if addr.is_multicast() {
             panic!("Ethernet address {} is not unicast", addr)
@@ -836,7 +833,7 @@ impl<'a> InterfaceInner<'a> {
         }
     }
 
-    #[cfg(feature = "ethernet")]
+    #[cfg(feature = "medium-ethernet")]
     fn process_ethernet<'frame, T: AsRef<[u8]>>
                        (&mut self, sockets: &mut SocketSet, timestamp: Instant, frame: &'frame T) ->
                        Result<Option<EthernetPacket<'frame>>>
@@ -887,6 +884,7 @@ impl<'a> InterfaceInner<'a> {
         }
     }
 
+    #[cfg(feature = "medium-ip")]
     fn process_ip<'frame, T: AsRef<[u8]>>
                   (&mut self, sockets: &mut SocketSet, timestamp: Instant, ip_payload: &'frame T) ->
                   Result<Option<IpPacket<'frame>>>
@@ -907,7 +905,7 @@ impl<'a> InterfaceInner<'a> {
         }
     }
 
-    #[cfg(all(feature = "ethernet", feature = "proto-ipv4"))]
+    #[cfg(all(feature = "medium-ethernet", feature = "proto-ipv4"))]
     fn process_arp<'frame, T: AsRef<[u8]>>
                   (&mut self, timestamp: Instant, eth_frame: &EthernetFrame<&'frame T>) ->
                   Result<Option<EthernetPacket<'frame>>>
@@ -1215,7 +1213,7 @@ impl<'a> InterfaceInner<'a> {
             Icmpv6Repr::EchoReply { .. } => Ok(None),
 
             // Forward any NDISC packets to the ndisc packet handler
-            #[cfg(feature = "ethernet")]
+            #[cfg(feature = "medium-ethernet")]
             Icmpv6Repr::Ndisc(repr) if ip_repr.hop_limit() == 0xff => match ip_repr {
                 IpRepr::Ipv6(ipv6_repr) => self.process_ndisc(_timestamp, ipv6_repr, repr),
                 _ => Ok(None)
@@ -1231,7 +1229,7 @@ impl<'a> InterfaceInner<'a> {
         }
     }
 
-    #[cfg(all(feature = "ethernet", feature = "proto-ipv6"))]
+    #[cfg(all(feature = "medium-ethernet", feature = "proto-ipv6"))]
     fn process_ndisc<'frame>(&mut self, timestamp: Instant, ip_repr: Ipv6Repr,
                              repr: NdiscRepr<'frame>) -> Result<Option<IpPacket<'frame>>> {
         match repr {
@@ -1503,7 +1501,7 @@ impl<'a> InterfaceInner<'a> {
         }
     }
 
-    #[cfg(feature = "ethernet")]
+    #[cfg(feature = "medium-ethernet")]
     fn dispatch<Tx>(&mut self, tx_token: Tx, timestamp: Instant,
                     packet: EthernetPacket) -> Result<()>
         where Tx: TxToken
@@ -1530,7 +1528,7 @@ impl<'a> InterfaceInner<'a> {
         }
     }
 
-    #[cfg(feature = "ethernet")]
+    #[cfg(feature = "medium-ethernet")]
     fn dispatch_ethernet<Tx, F>(&mut self, tx_token: Tx, timestamp: Instant,
                                 buffer_len: usize, f: F) -> Result<()>
         where Tx: TxToken, F: FnOnce(EthernetFrame<&mut [u8]>)
@@ -1570,10 +1568,11 @@ impl<'a> InterfaceInner<'a> {
         match self.route(addr, timestamp) {
             Ok(_routed_addr) => {
                 match self.device_capabilities.medium {
-                    #[cfg(feature = "ethernet")]
+                    #[cfg(feature = "medium-ethernet")]
                     Medium::Ethernet => self.neighbor_cache.as_ref().unwrap()
                         .lookup(&_routed_addr, timestamp)
                         .found(),
+                    #[cfg(feature = "medium-ip")]
                     Medium::Ip => true,
                 }
             }
@@ -1581,7 +1580,7 @@ impl<'a> InterfaceInner<'a> {
         }
     }
 
-    #[cfg(feature = "ethernet")]
+    #[cfg(feature = "medium-ethernet")]
     fn lookup_hardware_addr<Tx>(&mut self, tx_token: Tx, timestamp: Instant,
                                 src_addr: &IpAddress, dst_addr: &IpAddress) ->
                                Result<(EthernetAddress, Tx)>
@@ -1682,7 +1681,7 @@ impl<'a> InterfaceInner<'a> {
         let caps = self.device_capabilities.clone();
 
         match self.device_capabilities.medium {
-            #[cfg(feature = "ethernet")]
+            #[cfg(feature = "medium-ethernet")]
             Medium::Ethernet => {
                 let (dst_hardware_addr, tx_token) =
                     self.lookup_hardware_addr(tx_token, timestamp,
@@ -1704,6 +1703,7 @@ impl<'a> InterfaceInner<'a> {
                     packet.emit_payload(ip_repr, payload, &caps);
                 })
             }
+            #[cfg(feature = "medium-ip")]
             Medium::Ip => {
                 let tx_len = ip_repr.total_len();
                 tx_token.consume(timestamp, tx_len, |mut tx_buffer| {
@@ -1773,6 +1773,15 @@ mod test {
     use crate::phy::{Loopback, ChecksumCapabilities};
 
     fn create_loopback<'a>() -> (Interface<'a, Loopback>, SocketSet<'a>) {
+        #[cfg(feature = "medium-ethernet")]
+        return create_loopback_ethernet();
+        #[cfg(not(feature = "medium-ethernet"))]
+        return create_loopback_ip();
+    }
+
+    #[cfg(all(feature = "medium-ip"))]
+    #[allow(unused)]
+    fn create_loopback_ip<'a>() -> (Interface<'a, Loopback>, SocketSet<'a>) {
         // Create a basic device
         let device = Loopback::new(Medium::Ip);
         let ip_addrs = [
@@ -1795,7 +1804,7 @@ mod test {
         (iface, SocketSet::new(vec![]))
     }
 
-    #[cfg(all(feature = "ethernet"))]
+    #[cfg(all(feature = "medium-ethernet"))]
     fn create_loopback_ethernet<'a>() -> (Interface<'a, Loopback>, SocketSet<'a>) {
         // Create a basic device
         let device = Loopback::new(Medium::Ethernet);
@@ -1845,7 +1854,7 @@ mod test {
 
     #[test]
     #[should_panic(expected = "ethernet_addr required option was not set")]
-    #[cfg(all(feature = "ethernet"))]
+    #[cfg(all(feature = "medium-ethernet"))]
     fn test_builder_initialization_panic() {
         InterfaceBuilder::new(Loopback::new(Medium::Ethernet)).finalize();
     }
@@ -2300,7 +2309,7 @@ mod test {
     }
 
     #[test]
-    #[cfg(all(feature = "ethernet", feature = "proto-ipv4"))]
+    #[cfg(all(feature = "medium-ethernet", feature = "proto-ipv4"))]
     fn test_handle_valid_arp_request() {
         let (mut iface, mut socket_set) = create_loopback_ethernet();
 
@@ -2345,7 +2354,7 @@ mod test {
     }
 
     #[test]
-    #[cfg(all(feature = "ethernet", feature = "proto-ipv6"))]
+    #[cfg(all(feature = "medium-ethernet", feature = "proto-ipv6"))]
     fn test_handle_valid_ndisc_request() {
         let (mut iface, mut socket_set) = create_loopback_ethernet();
 
@@ -2405,7 +2414,7 @@ mod test {
     }
 
     #[test]
-    #[cfg(all(feature = "ethernet", feature = "proto-ipv4"))]
+    #[cfg(all(feature = "medium-ethernet", feature = "proto-ipv4"))]
     fn test_handle_other_arp_request() {
         let (mut iface, mut socket_set) = create_loopback_ethernet();
 
@@ -2589,11 +2598,21 @@ mod test {
     #[cfg(feature = "proto-igmp")]
     fn test_handle_igmp() {
         fn recv_igmp(mut iface: &mut Interface<'_, Loopback>, timestamp: Instant) -> Vec<(Ipv4Repr, IgmpRepr)> {
-            let checksum_caps = &iface.device.capabilities().checksum;
+            let caps = iface.device.capabilities();
+            let checksum_caps = &caps.checksum;
             recv_all(&mut iface, timestamp)
                 .iter()
                 .filter_map(|frame| {
-                    let ipv4_packet = Ipv4Packet::new_checked(frame).ok()?;
+                    
+                    let ipv4_packet = match caps.medium {
+                        #[cfg(feature = "medium-ethernet")]
+                        Medium::Ethernet => {
+                            let eth_frame = EthernetFrame::new_checked(frame).ok()?;
+                            Ipv4Packet::new_checked(eth_frame.payload()).ok()?
+                        }
+                        #[cfg(feature = "medium-ip")]
+                        Medium::Ip => Ipv4Packet::new_checked(&frame[..]).ok()?
+                    };
                     let ipv4_repr = Ipv4Repr::parse(&ipv4_packet, &checksum_caps).ok()?;
                     let ip_payload = ipv4_packet.payload();
                     let igmp_packet = IgmpPacket::new_checked(ip_payload).ok()?;

+ 6 - 4
src/iface/mod.rs

@@ -4,17 +4,19 @@ The `iface` module deals with the *network interfaces*. It filters incoming fram
 provides lookup and caching of hardware addresses, and handles management packets.
 */
 
-#[cfg(feature = "ethernet")]
+#[cfg(feature = "medium-ethernet")]
 mod neighbor;
 mod route;
+#[cfg(any(feature = "medium-ethernet", feature = "medium-ip"))]
 mod interface;
 
-#[cfg(feature = "ethernet")]
+#[cfg(feature = "medium-ethernet")]
 pub use self::neighbor::Neighbor as Neighbor;
-#[cfg(feature = "ethernet")]
+#[cfg(feature = "medium-ethernet")]
 pub(crate) use self::neighbor::Answer as NeighborAnswer;
-#[cfg(feature = "ethernet")]
+#[cfg(feature = "medium-ethernet")]
 pub use self::neighbor::Cache as NeighborCache;
 pub use self::route::{Route, Routes};
 
+#[cfg(any(feature = "medium-ethernet", feature = "medium-ip"))]
 pub use self::interface::{Interface, InterfaceBuilder};

+ 1 - 1
src/lib.rs

@@ -1,6 +1,6 @@
 #![cfg_attr(not(any(test, feature = "std")), no_std)]
 #![deny(unsafe_code)]
-#![cfg_attr(all(any(feature = "proto-ipv4", feature = "proto-ipv6"), feature = "ethernet"), deny(unused))]
+#![cfg_attr(all(any(feature = "proto-ipv4", feature = "proto-ipv6"), feature = "medium-ethernet"), deny(unused))]
 
 //! The _smoltcp_ library is built in a layered structure, with the layers corresponding
 //! to the levels of API abstraction. Only the highest layers would be used by a typical

+ 5 - 5
src/parsers.rs

@@ -3,7 +3,7 @@
 use core::str::FromStr;
 use core::result;
 
-#[cfg(feature = "ethernet")]
+#[cfg(feature = "medium-ethernet")]
 use crate::wire::EthernetAddress;
 use crate::wire::{IpAddress, IpCidr, IpEndpoint};
 #[cfg(feature = "proto-ipv4")]
@@ -118,7 +118,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    #[cfg(feature = "ethernet")]
+    #[cfg(feature = "medium-ethernet")]
     fn accept_mac_joined_with(&mut self, separator: u8) -> Result<EthernetAddress> {
         let mut octets = [0u8; 6];
         for (n, octet) in octets.iter_mut().enumerate() {
@@ -130,7 +130,7 @@ impl<'a> Parser<'a> {
         Ok(EthernetAddress(octets))
     }
 
-    #[cfg(feature = "ethernet")]
+    #[cfg(feature = "medium-ethernet")]
     fn accept_mac(&mut self) -> Result<EthernetAddress> {
         if let Some(mac) = self.try_do(|p| p.accept_mac_joined_with(b'-')) {
             return Ok(mac)
@@ -352,7 +352,7 @@ impl<'a> Parser<'a> {
     }
 }
 
-#[cfg(feature = "ethernet")]
+#[cfg(feature = "medium-ethernet")]
 impl FromStr for EthernetAddress {
     type Err = ();
 
@@ -473,7 +473,7 @@ mod test {
     }
 
     #[test]
-    #[cfg(all(feature = "proto-ipv4", feature = "ethernet"))]
+    #[cfg(all(feature = "proto-ipv4", feature = "medium-ethernet"))]
     fn test_mac() {
         assert_eq!(EthernetAddress::from_str(""), Err(()));
         assert_eq!(EthernetAddress::from_str("02:00:00:00:00:00"),

+ 8 - 5
src/phy/mod.rs

@@ -11,7 +11,7 @@ and implementations of it:
     [TapInterface](struct.TapInterface.html), to transmit and receive frames
     on the host OS.
 */
-#![cfg_attr(feature = "ethernet", doc = r##"
+#![cfg_attr(feature = "medium-ethernet", doc = r##"
 # Examples
 
 An implementation of the [Device](trait.Device.html) trait for a simple hardware
@@ -117,7 +117,7 @@ pub use self::raw_socket::RawSocket;
 #[cfg(all(feature = "phy-tap_interface", any(target_os = "linux", target_os = "android")))]
 pub use self::tap_interface::TapInterface;
 
-#[cfg(feature = "ethernet")]
+#[cfg(feature = "medium-ethernet")]
 /// A tracer device for Ethernet frames.
 pub type EthernetTracer<T> = Tracer<T, super::wire::EthernetFrame<&'static [u8]>>;
 
@@ -238,23 +238,26 @@ pub enum Medium {
     /// 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")]
+    #[cfg(feature = "medium-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.
+    #[cfg(feature = "medium-ip")]
     Ip,
 }
 
 
 impl Default for Medium {
     fn default() -> Medium {
-        #[cfg(feature = "ethernet")]
+        #[cfg(feature = "medium-ethernet")]
         return Medium::Ethernet;
-        #[cfg(not(feature = "ethernet"))]
+        #[cfg(all(feature = "medium-ip", not(feature = "medium-ethernet")))]
         return Medium::Ip;
+        #[cfg(all(not(feature = "medium-ip"), not(feature = "medium-ethernet")))]
+        panic!("No medium enabled");
     }
 }
 

+ 5 - 5
src/wire/icmpv6.rs

@@ -6,7 +6,7 @@ use crate::phy::ChecksumCapabilities;
 use crate::wire::ip::checksum;
 use crate::wire::{IpAddress, IpProtocol, Ipv6Packet, Ipv6Repr};
 use crate::wire::MldRepr;
-#[cfg(feature = "ethernet")]
+#[cfg(feature = "medium-ethernet")]
 use crate::wire::NdiscRepr;
 
 enum_with_unknown! {
@@ -536,7 +536,7 @@ pub enum Repr<'a> {
         seq_no: u16,
         data:   &'a [u8]
     },
-    #[cfg(feature = "ethernet")]
+    #[cfg(feature = "medium-ethernet")]
     Ndisc(NdiscRepr<'a>),
     Mld(MldRepr<'a>),
 }
@@ -617,7 +617,7 @@ impl<'a> Repr<'a> {
                     data:   packet.payload()
                 })
             },
-            #[cfg(feature = "ethernet")]
+            #[cfg(feature = "medium-ethernet")]
             (msg_type, 0) if msg_type.is_ndisc() => {
                 NdiscRepr::parse(packet).map(Repr::Ndisc)
             },
@@ -639,7 +639,7 @@ impl<'a> Repr<'a> {
             &Repr::EchoReply { data, .. } => {
                 field::ECHO_SEQNO.end + data.len()
             },
-            #[cfg(feature = "ethernet")]
+            #[cfg(feature = "medium-ethernet")]
             &Repr::Ndisc(ndisc) => {
                 ndisc.buffer_len()
             },
@@ -710,7 +710,7 @@ impl<'a> Repr<'a> {
                 packet.payload_mut()[..data_len].copy_from_slice(&data[..data_len])
             },
 
-            #[cfg(feature = "ethernet")]
+            #[cfg(feature = "medium-ethernet")]
             Repr::Ndisc(ndisc) => {
                 ndisc.emit(packet)
             },

+ 8 - 8
src/wire/mod.rs

@@ -77,9 +77,9 @@ mod field {
 
 pub mod pretty_print;
 
-#[cfg(feature = "ethernet")]
+#[cfg(feature = "medium-ethernet")]
 mod ethernet;
-#[cfg(all(feature = "proto-ipv4", feature = "ethernet"))]
+#[cfg(all(feature = "proto-ipv4", feature = "medium-ethernet"))]
 mod arp;
 pub(crate) mod ip;
 #[cfg(feature = "proto-ipv4")]
@@ -102,9 +102,9 @@ mod icmpv6;
 mod icmp;
 #[cfg(feature = "proto-igmp")]
 mod igmp;
-#[cfg(all(feature = "proto-ipv6", feature = "ethernet"))]
+#[cfg(all(feature = "proto-ipv6", feature = "medium-ethernet"))]
 mod ndisc;
-#[cfg(all(feature = "proto-ipv6", feature = "ethernet"))]
+#[cfg(all(feature = "proto-ipv6", feature = "medium-ethernet"))]
 mod ndiscoption;
 #[cfg(feature = "proto-ipv6")]
 mod mld;
@@ -115,14 +115,14 @@ pub(crate) mod dhcpv4;
 
 pub use self::pretty_print::PrettyPrinter;
 
-#[cfg(feature = "ethernet")]
+#[cfg(feature = "medium-ethernet")]
 pub use self::ethernet::{EtherType as EthernetProtocol,
                          Address as EthernetAddress,
                          Frame as EthernetFrame,
                          HEADER_LEN as ETHERNET_HEADER_LEN,
                          Repr as EthernetRepr};
 
-#[cfg(all(feature = "proto-ipv4", feature = "ethernet"))]
+#[cfg(all(feature = "proto-ipv4", feature = "medium-ethernet"))]
 pub use self::arp::{Hardware as ArpHardware,
                     Operation as ArpOperation,
                     Packet as ArpPacket,
@@ -193,12 +193,12 @@ pub use self::icmpv6::{Message as Icmpv6Message,
 pub use self::icmp::Repr as IcmpRepr;
 
 
-#[cfg(all(feature = "proto-ipv6", feature = "ethernet"))]
+#[cfg(all(feature = "proto-ipv6", feature = "medium-ethernet"))]
 pub use self::ndisc::{Repr as NdiscRepr,
                       RouterFlags as NdiscRouterFlags,
                       NeighborFlags as NdiscNeighborFlags};
 
-#[cfg(all(feature = "proto-ipv6", feature = "ethernet"))]
+#[cfg(all(feature = "proto-ipv6", feature = "medium-ethernet"))]
 pub use self::ndiscoption::{NdiscOption,
                             Repr as NdiscOptionRepr,
                             Type as NdiscOptionType,