Skip to content

Commit

Permalink
Add the up/down Device and Interface methods
Browse files Browse the repository at this point in the history
Add up/down methods to Device and Interface for placing the underlying
device in a up or down state. This interface will also be handy when
adding support for MLDv2.
  • Loading branch information
dlrobertson committed Jun 17, 2021
1 parent 027f255 commit a9bbd53
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 21 deletions.
2 changes: 1 addition & 1 deletion examples/loopback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ mod mock {
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)]
Expand Down
9 changes: 6 additions & 3 deletions fuzz/fuzz_targets/tcp_headers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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());

Expand Down
9 changes: 4 additions & 5 deletions fuzz/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -52,7 +52,7 @@ pub fn add_middleware_options(opts: &mut Options, _free: &mut Vec<&str>) {
}

pub fn parse_middleware_options<D>(matches: &mut Matches, device: D, loopback: bool)
-> FaultInjector<EthernetTracer<PcapWriter<D, Rc<PcapSink>>>>
-> FaultInjector<Tracer<PcapWriter<D, Rc<PcapSink>>>>
where D: for<'a> Device<'a>
{
let drop_chance = matches.opt_str("drop-chance").map(|s| u8::from_str(&s).unwrap())
Expand All @@ -78,9 +78,8 @@ pub fn parse_middleware_options<D>(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<PcapSink>,
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);
});
Expand Down
54 changes: 52 additions & 2 deletions src/iface/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,24 @@ impl<'a, DeviceT> Interface<'a, DeviceT>
&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.
///
Expand Down Expand Up @@ -1862,9 +1880,11 @@ mod test {
#[cfg(feature = "proto-igmp")]
let iface_builder = iface_builder
.ipv4_multicast_groups(BTreeMap::new());
let iface = iface_builder
let mut iface = iface_builder
.finalize();

iface.up().expect("Failed to bring device up!");

(iface, SocketSet::new(vec![]))
}

Expand All @@ -1888,9 +1908,11 @@ mod test {
#[cfg(feature = "proto-igmp")]
let iface_builder = iface_builder
.ipv4_multicast_groups(BTreeMap::new());
let iface = iface_builder
let mut iface = iface_builder
.finalize();

iface.up().expect("Failed to bring device up!");

(iface, SocketSet::new(vec![]))
}

Expand Down Expand Up @@ -1924,6 +1946,34 @@ 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() {
Expand Down
36 changes: 26 additions & 10 deletions src/phy/loopback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::time::Instant;
/// A loopback device.
#[derive(Debug)]
pub struct Loopback {
queue: VecDeque<Vec<u8>>,
queue: Option<VecDeque<Vec<u8>>>,
medium: Medium,
}

Expand All @@ -23,7 +23,7 @@ impl Loopback {
/// in FIFO order.
pub fn new(medium: Medium) -> Loopback {
Loopback {
queue: VecDeque::new(),
queue: None,
medium,
}
}
Expand All @@ -42,17 +42,33 @@ 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<Self::TxToken> {
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(())
}
}

Expand Down
10 changes: 10 additions & 0 deletions src/phy/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,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.
Expand Down

0 comments on commit a9bbd53

Please sign in to comment.