diff --git a/fuzz/fuzz_targets/tcp_headers.rs b/fuzz/fuzz_targets/tcp_headers.rs index 86a274dfb..5c285d89d 100644 --- a/fuzz/fuzz_targets/tcp_headers.rs +++ b/fuzz/fuzz_targets/tcp_headers.rs @@ -20,7 +20,7 @@ mod utils { mod mock { use std::sync::Arc; use std::sync::atomic::{Ordering, AtomicUsize}; - use smoltcp::time::{Duration, Instant}; + use smoltcp::time::{Duration, Instant}; // should be AtomicU64 but that's unstable #[derive(Debug, Clone)] @@ -119,8 +119,8 @@ 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(Medium::Ethernet), - /*loopback=*/true); + let loopback = Loopback::new(Medium::Ethernet); + let device = utils::parse_middleware_options(&mut matches, loopback, /*loopback=*/ true); smoltcp::phy::FuzzInjector::new(device, EmptyFuzzer(), @@ -165,6 +165,9 @@ fuzz_target!(|data: &[u8]| { let mut did_listen = false; let mut did_connect = false; let mut done = false; + + iface.up().expect("Failed to set device up"); + while !done && clock.elapsed() < Instant::from_millis(4_000) { let _ = iface.poll(&mut socket_set, clock.elapsed()); diff --git a/fuzz/utils.rs b/fuzz/utils.rs index 26763c23a..8ad8d349a 100644 --- a/fuzz/utils.rs +++ b/fuzz/utils.rs @@ -11,7 +11,7 @@ use std::env; use std::process; use getopts::{Options, Matches}; -use smoltcp::phy::{Device, EthernetTracer, FaultInjector}; +use smoltcp::phy::{Device, Tracer, FaultInjector}; use smoltcp::phy::{PcapWriter, PcapSink, PcapMode, PcapLinkType}; use smoltcp::time::Duration; @@ -52,7 +52,7 @@ pub fn add_middleware_options(opts: &mut Options, _free: &mut Vec<&str>) { } pub fn parse_middleware_options(matches: &mut Matches, device: D, loopback: bool) - -> FaultInjector>>> + -> FaultInjector>>> where D: for<'a> Device<'a> { let drop_chance = matches.opt_str("drop-chance").map(|s| u8::from_str(&s).unwrap()) @@ -78,9 +78,8 @@ pub fn parse_middleware_options(matches: &mut Matches, device: D, loopback: b let seed = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().subsec_nanos(); let device = PcapWriter::new(device, Rc::new(RefCell::new(pcap_writer)) as Rc, - if loopback { PcapMode::TxOnly } else { PcapMode::Both }, - PcapLinkType::Ethernet); - let device = EthernetTracer::new(device, |_timestamp, _printer| { + if loopback { PcapMode::TxOnly } else { PcapMode::Both }); + let device = Tracer::new(device, |_timestamp, _printer| { #[cfg(feature = "log")] trace!("{}", _printer); }); diff --git a/src/iface/interface.rs b/src/iface/interface.rs index 314192359..f6d1e8548 100644 --- a/src/iface/interface.rs +++ b/src/iface/interface.rs @@ -568,6 +568,24 @@ where &mut self.inner.routes } + /// Trigger the startup sequence for the interface. + /// + /// This method will call [Device::up] on the backing device. + /// + /// [Device::up]: ../phy/trait.Device.html#method.up + pub fn up(&mut self) -> Result<()> { + self.device.up() + } + + /// Trigger the shutdown sequence for the interface. + /// + /// This method will call [Device::down] on the backing device. + /// + /// [Device::down]: ../phy/trait.Device.html#method.down + pub fn down(&mut self) -> Result<()> { + self.device.down() + } + /// Transmit packets queued in the given sockets, and receive packets queued /// in the device. /// @@ -2107,7 +2125,9 @@ mod test { let iface_builder = InterfaceBuilder::new(device).ip_addrs(ip_addrs); #[cfg(feature = "proto-igmp")] let iface_builder = iface_builder.ipv4_multicast_groups(BTreeMap::new()); - let iface = iface_builder.finalize(); + let mut iface = iface_builder.finalize(); + + iface.up().expect("Failed to bring device up!"); (iface, SocketSet::new(vec![])) } @@ -2131,7 +2151,9 @@ mod test { .ip_addrs(ip_addrs); #[cfg(feature = "proto-igmp")] let iface_builder = iface_builder.ipv4_multicast_groups(BTreeMap::new()); - let iface = iface_builder.finalize(); + let mut iface = iface_builder.finalize(); + + iface.up().expect("Failed to bring device up!"); (iface, SocketSet::new(vec![])) } @@ -2169,6 +2191,36 @@ mod test { InterfaceBuilder::new(Loopback::new(Medium::Ethernet)).finalize(); } + #[test] + #[cfg(feature = "medium-ethernet")] + fn test_iface_updown() { + let (mut iface, _) = create_loopback_ethernet(); + + iface.down().unwrap(); + + assert!(iface.device_mut().transmit().is_none()); + + iface.up().unwrap(); + + let tx_token = match iface.device_mut().transmit() { + Some(token) => token, + None => panic!("Failed to bring up device!"), + }; + + let buf = [0x00; 42]; + + tx_token + .consume(Instant::from_millis(0), buf.len(), |tx_buf| { + tx_buf.copy_from_slice(&buf[..]); + Ok(()) + }) + .unwrap(); + + iface.down().unwrap(); + + assert!(iface.device_mut().receive().is_none()); + } + #[test] #[cfg(feature = "proto-ipv4")] fn test_no_icmp_no_unicast_ipv4() { diff --git a/src/phy/loopback.rs b/src/phy/loopback.rs index 9b39aed33..54f06c601 100644 --- a/src/phy/loopback.rs +++ b/src/phy/loopback.rs @@ -11,7 +11,7 @@ use crate::Result; /// A loopback device. #[derive(Debug)] pub struct Loopback { - queue: VecDeque>, + queue: Option>>, medium: Medium, } @@ -23,7 +23,7 @@ impl Loopback { /// in FIFO order. pub fn new(medium: Medium) -> Loopback { Loopback { - queue: VecDeque::new(), + queue: None, medium, } } @@ -42,19 +42,31 @@ impl<'a> Device<'a> for Loopback { } fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { - self.queue.pop_front().map(move |buffer| { - let rx = RxToken { buffer }; - let tx = TxToken { - queue: &mut self.queue, - }; - (rx, tx) - }) + match self.queue { + Some(ref mut queue) => queue.pop_front().map(move |buffer| { + let rx = RxToken { buffer }; + let tx = TxToken { queue: queue }; + (rx, tx) + }), + None => None, + } } fn transmit(&'a mut self) -> Option { - Some(TxToken { - queue: &mut self.queue, - }) + match self.queue { + Some(ref mut queue) => Some(TxToken { queue: queue }), + None => None, + } + } + + fn up(&'a mut self) -> Result<()> { + self.queue = Some(VecDeque::new()); + Ok(()) + } + + fn down(&'a mut self) -> Result<()> { + self.queue = None; + Ok(()) } } diff --git a/src/phy/mod.rs b/src/phy/mod.rs index c156d58b9..4fcdd2370 100644 --- a/src/phy/mod.rs +++ b/src/phy/mod.rs @@ -310,6 +310,16 @@ pub trait Device<'a> { /// Get a description of device capabilities. fn capabilities(&self) -> DeviceCapabilities; + + /// Place the device in a on or running state. + fn up(&'a mut self) -> Result<()> { + Ok(()) + } + + /// Place the device in a off or idle state. + fn down(&'a mut self) -> Result<()> { + Ok(()) + } } /// A token to receive a single network packet.