blob: 8c0246b720ae42c9bb07ab68dbb9e83ec548f910 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! The special-purpose event loop used by the recovery netstack.
use ethernet as eth;
use fuchsia_async as fasync;
use fuchsia_zircon as zx;
use std::env;
use std::fs::File;
use failure::ResultExt;
use futures::prelude::*;
use netstack_core::{
receive_frame, set_ip_addr, Context, DeviceId, DeviceLayerEventDispatcher, EventDispatcher,
Ipv4Addr, Mac, StackState, Subnet, TimerId, TransportLayerEventDispatcher, UdpEventDispatcher,
};
/// The event loop.
pub struct EventLoop {
ctx: Context<EventLoopInner>,
}
impl EventLoop {
/// Run a dummy event loop.
///
/// This function hard-codes way too many things, and will soon be replaced
/// with a more general-purpose mechanism.
pub async fn dummy_run() -> Result<(), failure::Error> {
const DEFAULT_ETH: &str = "/dev/class/ethernet/000";
// Hardcoded IPv4 address: if you use something other than a /24, update the subnet below
// as well.
const FIXED_IPADDR: Ipv4Addr = Ipv4Addr::new([192, 168, 1, 39]);
let vmo = zx::Vmo::create_with_opts(
zx::VmoOptions::NON_RESIZABLE,
256 * eth::DEFAULT_BUFFER_SIZE as u64,
)?;
let path = env::args()
.nth(1)
.unwrap_or_else(|| String::from(DEFAULT_ETH));
let dev = File::open(path)?;
let eth_client = await!(eth::Client::new(
dev,
vmo,
eth::DEFAULT_BUFFER_SIZE,
"recovery-ns"
))?;
let mac = await!(eth_client.info())?.mac;
let mut state = StackState::default();
let eth_id = state.add_ethernet_device(Mac::new(mac.octets));
let mut event_loop = EventLoop {
ctx: Context::new(
state,
EventLoopInner {
device_id: eth_id,
eth_client,
},
),
};
await!(event_loop.ctx.dispatcher().eth_client.start())?;
// Hardcoded subnet: if you update the IPADDR above to use a network that's not /24, update
// this as well.
let fixed_subnet = Subnet::new(Ipv4Addr::new([192, 168, 1, 0]), 24);
set_ip_addr(&mut event_loop.ctx, eth_id, FIXED_IPADDR, fixed_subnet);
let mut buf = [0; 2048];
let mut events = event_loop.ctx.dispatcher().eth_client.get_stream();
while let Some(evt) = await!(events.try_next())? {
match evt {
eth::Event::StatusChanged => {
let status = await!(event_loop.ctx.dispatcher().eth_client.get_status())?;
println!("ethernet status: {:?}", status);
}
eth::Event::Receive(rx) => {
let len = rx.read(&mut buf);
receive_frame(&mut event_loop.ctx, eth_id, &mut buf[..len]);
}
}
}
Ok(())
}
}
struct EventLoopInner {
device_id: DeviceId,
eth_client: eth::Client,
}
impl EventDispatcher for EventLoopInner {
fn schedule_timeout(
&mut self, _duration: std::time::Duration, _id: TimerId,
) -> Option<std::time::Instant> {
unimplemented!()
}
fn schedule_timeout_instant(
&mut self, _time: std::time::Instant, _id: TimerId,
) -> Option<std::time::Instant> {
unimplemented!()
}
fn cancel_timeout(&mut self, id: TimerId) -> Option<std::time::Instant> {
unimplemented!()
}
}
impl DeviceLayerEventDispatcher for EventLoopInner {
fn send_frame(&mut self, device: DeviceId, frame: &[u8]) {
// TODO(joshlf): Handle more than one device
assert_eq!(device, self.device_id);
self.eth_client.send(&frame);
}
}
impl UdpEventDispatcher for EventLoopInner {
type UdpConn = ();
type UdpListener = ();
}
impl TransportLayerEventDispatcher for EventLoopInner {}