blob: 20a0b82fb00c0f9294d6090069b6339098964e6a [file] [log] [blame]
// Copyright 2019 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 network manager.
//!
//! This event loop takes in events from Admin and State FIDL,
//! and implements handlers for FIDL calls.
//!
//! This is implemented with a single mpsc queue for all event types - `EventLoop` holds the
//! consumer, and any event handling that requires state within `EventLoop` holds a producer,
//! allowing it to delegate work to the `EventLoop` by sending a message. In this documentation, we
//! call anything that holds a producer a "worker".
//!
//! Having a single queue for all of the message types is beneficial, since in guarantees a FIFO
//! ordering for all messages - whichever messages arrive first, will be handled first.
//!
//! We'll look at each type of message, to see how each one is handled - starting with FIDL
//! messages, since they can be thought of as the entrypoint for the whole loop (as nothing happens
//! until a FIDL call is made).
//!
//! # FIDL Worker
//!
//! The FIDL part of the event loop implements the fuchsia.router.config Admin and State
//! interfaces. The type of the event loop message for a FIDL call is
//! simply the generated FIDL type. When the event loop starts up, we use `fuchsia_app` to start a
//! FIDL server that simply sends all of the events it receives to the event loop (via the sender
//! end of the mpsc queue). When `EventLoop` receives this message, it calls the
//! `handle_fidl_router_admin_request` or `handle_fidl_router_state_request` method, which,
//! depending on what the request is, either:
//!
//! * Responds with the requested information.
//! * Modifies the router state byt accessinc netcfg.
//! * Updates local state.
use fidl_fuchsia_net as fnet;
use fidl_fuchsia_net_name as fnet_name;
use fidl_fuchsia_router_config::{
Id, Lif, Port, RouterAdminRequest, RouterStateGetPortsResponder, RouterStateRequest,
SecurityFeatures,
};
use fuchsia_component::server::ServiceFs;
use anyhow::{Context as _, Error};
use dns_server_watcher::{DnsServers, DnsServersUpdateSource, DEFAULT_DNS_PORT};
use futures::future;
use futures::stream::{self, StreamExt as _, TryStreamExt as _};
use network_manager_core::{
hal::NetCfg, lifmgr::LIFType, packet_filter::PacketFilter, portmgr::PortId, DeviceState,
};
use crate::fidl_worker::IncomingFidlRequestStream;
macro_rules! router_error {
($code:ident, $desc:expr) => {
Some(&mut fidl_fuchsia_router_config::Error {
code: fidl_fuchsia_router_config::ErrorCode::$code,
description: $desc,
})
};
}
macro_rules! not_supported {
() => {
router_error!(NotSupported, None)
};
}
macro_rules! not_found {
() => {
router_error!(NotFound, None)
};
}
macro_rules! internal_error {
($s:expr) => {
router_error!(Internal, Some($s.to_string()))
};
}
fn dns_sockaddr_from_ip(ip: fnet::IpAddress) -> fnet::SocketAddress {
match ip {
fnet::IpAddress::Ipv4(addr) => fnet::SocketAddress::Ipv4(fnet::Ipv4SocketAddress {
address: addr,
port: DEFAULT_DNS_PORT,
}),
fnet::IpAddress::Ipv6(addr) => fnet::SocketAddress::Ipv6(fnet::Ipv6SocketAddress {
address: addr,
port: DEFAULT_DNS_PORT,
zone_index: 0,
}),
}
}
/// The event loop.
pub struct EventLoop {
device: DeviceState,
dns_servers: DnsServers,
}
impl EventLoop {
pub fn new() -> Result<Self, Error> {
let netcfg = NetCfg::new()?;
let packet_filter = PacketFilter::start().context("failed to start packet filter")?;
let device = DeviceState::new(netcfg, packet_filter);
Ok(EventLoop { device, dns_servers: Default::default() })
}
pub async fn run(mut self) -> Result<(), Error> {
if let Err(e) = self.device.load_config().await {
// TODO(cgibson): Kick off some sort of recovery process here: Prompt the user to
// download a recovery app, set a static IP on the first interface and set everything
// else down, restructure packet filter rules, etc.
error!("Failed to load a device config: {}", e);
}
self.device.setup_services().await.context("setup_services")?;
self.device.populate_state().await.context("populate_state")?;
let (stack_stream, netstack_stream) = self.device.take_event_streams();
let stack_stream = stack_stream.map(|r| r.context("Stack event stream")).fuse();
let netstack_stream = netstack_stream.map(|r| r.context("Netstack event stream")).fuse();
let netstack_dns_stream = dns_server_watcher::new_dns_server_stream(
DnsServersUpdateSource::Netstack,
self.device
.get_netstack_dns_server_watcher()
.context("failed to get DNS server watcher")?,
)
.fuse();
let oir_stream = crate::oir_worker::new_stream()
.await
.context("starting OIR")?
.map(|r| r.context("OIR event stream"))
.fuse();
let mut fs = ServiceFs::new_local();
let fidl_server_stream = crate::fidl_worker::new_stream(&mut fs)
.context("setting up FIDL services")?
.then(futures::future::ok::<_, anyhow::Error>);
// Make sure errors encountered when setting up overnet services do not cause
// NetworkManager to exit as overnet may not be available on all builds.
let overnet_stream = match crate::overnet_worker::new_stream().await {
Err(e) => {
error!("error setting up overnet services: {}", e);
// We use a stream that is always pending so that the loop below may
// assume that `overnet_stream` is not expected to end (which is the
// case when we successfully setup and publish overnet services).
future::Either::Left(stream::pending())
}
Ok(o) => future::Either::Right(o.map(|r| r.context("overnet service request stream"))),
};
let fidl_req_stream = stream::select(fidl_server_stream, overnet_stream).fuse();
let mut router_admin_streams = stream::SelectAll::new();
let mut router_state_streams = stream::SelectAll::new();
futures::pin_mut!(
stack_stream,
netstack_stream,
netstack_dns_stream,
oir_stream,
fidl_req_stream
);
loop {
// Currently, if any of the workers encounters an error, the event loop
// will return with the worker's error immediately.
// TODO(fxbug.dev/52740): Gracefully handle worker errors.
let () = futures::select! {
stack_res = stack_stream.try_next() => {
let event = stack_res?.ok_or(anyhow::anyhow!("Stack event stream unexpectedly ended"))?;
self.handle_stack_event(event).await
}
netstack_res = netstack_stream.try_next() => {
let event = netstack_res?.ok_or(anyhow::anyhow!("Netstack event stream unexpectedly ended"))?;
self.handle_netstack_event(event).await
}
netstack_dns_res = netstack_dns_stream.next() => {
let (source, res) = netstack_dns_res.ok_or(anyhow::anyhow!("Netstack DNS Server watcher stream unexpectedly ended"))?;
self.handle_dns_server_watcher_event(source, res.context("error getting next DNS server event from netstack")?).await
}
oir_res = oir_stream.try_next() => {
let event = oir_res?.ok_or(anyhow::anyhow!("OIR stream unexpectedly ended"))?;
self.handle_oir_event(event).await
}
fidl_req_res = fidl_req_stream.try_next() => {
let req = fidl_req_res?.ok_or(anyhow::anyhow!("FIDL service request stream unexpectedly ended"))?;
match req {
IncomingFidlRequestStream::RouterAdmin(r) => router_admin_streams.push(r),
IncomingFidlRequestStream::RouterState(r) => router_state_streams.push(r),
}
}
router_admin_req_res = router_admin_streams.try_next() => {
// We may receive `None` just once if there are no longer any active streams
// in the `Stream` set. This is expected for the initial state, or after the
// streams are run to completion. Note, the `Stream` set will start to yield
// values again (as they become available) once a new `Stream` is added.
if let Some(req) = router_admin_req_res? {
self.handle_fidl_router_admin_request(req).await
}
}
router_state_req_res = router_state_streams.try_next() => {
// We may receive `None` just once if there are no longer any active streams
// in the `Stream` set. This is expected for the initial state, or after the
// streams are run to completion. Note, the `Stream` set will start to yield
// values again (as they become available) once a new `Stream` is added.
if let Some(req) = router_state_req_res? {
self.handle_fidl_router_state_request(req).await
}
}
complete => break,
};
}
Ok(())
}
async fn handle_dns_server_watcher_event(
&mut self,
source: DnsServersUpdateSource,
servers: Vec<fnet_name::DnsServer_>,
) {
trace!("got DNS server event from source = {:?} with servers = {:?}", source, servers);
let () = self.dns_servers.set_servers_from_source(source, servers);
let () = self
.device
.set_dns_resolvers(self.dns_servers.consolidated())
.await
.map(|_: network_manager_core::ElementId| ())
.unwrap_or_else(|err| warn!("error setting dns servers: {:?}", err));
}
async fn handle_stack_event(&mut self, event: fidl_fuchsia_net_stack::StackEvent) {
self.device
.update_state_for_stack_event(event)
.await
.unwrap_or_else(|err| warn!("error updating state: {:?}", err));
}
async fn handle_netstack_event(&mut self, event: fidl_fuchsia_netstack::NetstackEvent) {
self.device
.update_state_for_netstack_event(event)
.await
.unwrap_or_else(|err| warn!("error updating state: {:?}", err));
}
async fn handle_oir_event(&mut self, event: network_manager_core::oir::OIRInfo) {
self.device
.oir_event(event)
.await
.unwrap_or_else(|err| warn!("error processing oir event: {:?}", err));
}
async fn handle_fidl_router_admin_request(&mut self, req: RouterAdminRequest) {
match req {
RouterAdminRequest::CreateWan { name, vlan, ports, responder } => {
let r = self
.fidl_create_lif(
LIFType::WAN,
name,
vlan,
ports.iter().map(|x| PortId::from(u64::from(*x))).collect(),
)
.await;
match r {
Ok(mut id) => responder.send(Some(&mut id), None),
Err(mut e) => responder.send(None, Some(&mut e)),
}
}
RouterAdminRequest::CreateLan { name, vlan, ports, responder } => {
let r = self
.fidl_create_lif(
LIFType::LAN,
name,
vlan,
ports.iter().map(|x| PortId::from(u64::from(*x))).collect(),
)
.await;
match r {
Ok(mut id) => responder.send(Some(&mut id), None),
Err(mut e) => responder.send(None, Some(&mut e)),
}
}
RouterAdminRequest::RemoveWan { wan_id, responder } => {
let mut r = self.fidl_delete_lif(wan_id).await;
responder.send(r.as_mut()).or_else(|e| {
error!("Error sending response: {:?}", e);
Err(e)
})
}
RouterAdminRequest::RemoveLan { lan_id, responder } => {
let mut r = self.fidl_delete_lif(lan_id).await;
responder.send(r.as_mut()).or_else(|e| {
error!("Error sending response: {:?}", e);
Err(e)
})
}
RouterAdminRequest::SetWanProperties { wan_id, properties, responder } => {
let properties = fidl_fuchsia_router_config::LifProperties::Wan(properties);
if self
.device
.update_lif_properties_fidl(u128::from_ne_bytes(wan_id.uuid), &properties)
.await
.is_err()
{
warn!("WAN {:?} found but failed to update properties", wan_id);
responder.send(not_found!())
} else {
info!("WAN properties updated");
responder.send(None)
}
}
RouterAdminRequest::SetLanProperties { lan_id, properties, responder } => {
let properties = fidl_fuchsia_router_config::LifProperties::Lan(properties);
if self
.device
.update_lif_properties_fidl(u128::from_ne_bytes(lan_id.uuid), &properties)
.await
.is_err()
{
warn!("failed to update LAN properties");
responder.send(not_found!())
} else {
info!("LAN properties updated");
responder.send(None)
}
}
RouterAdminRequest::SetDhcpServerOptions { lan_id, options, responder } => {
info!("{:?}, {:?}", lan_id, options);
responder.send(not_supported!())
}
RouterAdminRequest::SetDhcpAddressPool { lan_id, pool, responder } => {
info!("{:?}, {:?}", lan_id, pool);
responder.send(not_supported!())
}
RouterAdminRequest::SetDhcpReservation { lan_id, reservation, responder } => {
info!("{:?}, {:?}", lan_id, reservation);
responder.send(None, not_supported!())
}
RouterAdminRequest::DeleteDhcpReservation { reservation_id, responder } => {
info!("{:?}", reservation_id);
responder.send(not_supported!())
}
RouterAdminRequest::SetDnsResolver { config, responder } => {
info!("{:?}", config);
match self
.device
.set_dns_resolvers(
config.search.servers.into_iter().map(dns_sockaddr_from_ip).collect(),
)
.await
{
Ok(i) => responder.send(
Some(&mut Id { uuid: i.uuid().to_ne_bytes(), version: i.version() }),
None,
),
Err(e) => responder.send(None, internal_error!(e.to_string())),
}
}
RouterAdminRequest::SetDnsForwarder { config, responder } => {
info!("{:?}", config);
responder.send(not_supported!())
}
RouterAdminRequest::AddDnsEntry { entry, responder } => {
info!("{:?}", entry);
responder.send(None, not_supported!())
}
RouterAdminRequest::DeleteDnsEntry { entry_id, responder } => {
info!("{:?}", entry_id);
responder.send(not_supported!())
}
RouterAdminRequest::SetRoute { route, responder } => {
info!("{:?}", route);
responder.send(None, not_supported!())
}
RouterAdminRequest::UpdateRouteMetric { route_id, metric, responder } => {
info!("{:?} {:?}", route_id, metric);
responder.send(not_supported!())
}
RouterAdminRequest::DeleteRoute { route_id, responder } => {
info!("{:?}", route_id);
responder.send(not_supported!())
}
RouterAdminRequest::SetSecurityFeatures { features, responder } => {
info!("Updating SecurityFeatures: {:?}", features);
match self.update_security_features(&features).await {
Ok(_) => responder.send(None),
Err(e) => responder.send(internal_error!(e.to_string())),
}
}
RouterAdminRequest::SetPortForward { rule, responder } => {
info!("{:?}", rule);
responder.send(None, not_supported!())
}
RouterAdminRequest::DeletePortForward { rule_id, responder } => {
info!("{:?}", rule_id);
responder.send(not_supported!())
}
RouterAdminRequest::SetPortTrigger { rule, responder } => {
info!("{:?}", rule);
responder.send(None, not_supported!())
}
RouterAdminRequest::DeletePortTrigger { rule_id, responder } => {
info!("{:?}", rule_id);
responder.send(not_supported!())
}
RouterAdminRequest::SetFilter { rule, responder } => {
let r = self
.device
// TODO(fxbug.dev/45024): The Router Config FIDL API doesn't have a way to provide a
// specific interface identifier.
.set_filter_on_interface(&rule, 0u32)
.await
.context("Error installing new packet filter on all interfaces");
match r {
Ok(()) => responder.send(None, None),
Err(e) => responder.send(None, internal_error!(e.to_string())),
}
}
RouterAdminRequest::DeleteFilter { rule_id, responder } => {
info!("{:?}", rule_id);
let r = self
.device
.delete_filter(rule_id)
.await
.context("Error deleting packet filter rule");
match r {
Ok(()) => responder.send(None),
Err(e) => responder.send(internal_error!(e.to_string())),
}
}
RouterAdminRequest::SetIpv6PinHole { rule, responder } => {
info!("{:?}", rule);
responder.send(None, not_supported!())
}
RouterAdminRequest::DeleteIpv6PinHole { rule_id, responder } => {
info!("{:?}", rule_id);
responder.send(not_supported!())
}
RouterAdminRequest::SetDmzHost { rule, responder } => {
info!("{:?}", rule);
responder.send(None, not_supported!())
}
RouterAdminRequest::DeleteDmzHost { rule_id, responder } => {
info!("{:?}", rule_id);
responder.send(not_supported!())
}
RouterAdminRequest::SetSystemConfig { config, responder } => {
info!("{:?}", config);
responder.send(None, not_supported!())
}
RouterAdminRequest::CreateWlanNetwork { responder, .. } => {
// TODO(guzt): implement
responder.send(None, not_supported!())
}
RouterAdminRequest::DeleteWlanNetwork { responder, .. } => {
// TODO(guzt): implement
responder.send(not_supported!())
}
}
.unwrap_or_else(|e| error!("Error sending response {}", e))
}
async fn fidl_create_lif(
&mut self,
lif_type: LIFType,
name: String,
vlan: u16,
ports: Vec<PortId>,
) -> Result<Id, fidl_fuchsia_router_config::Error> {
let lif = self.device.create_lif(lif_type, name, Some(vlan), &ports).await;
match lif {
Err(e) => {
error!("Error creating lif {:?}", e);
Err(fidl_fuchsia_router_config::Error {
code: fidl_fuchsia_router_config::ErrorCode::AlreadyExists,
description: None,
})
}
Ok(l) => {
let i = l.id();
Ok(Id { uuid: i.uuid().to_ne_bytes(), version: i.version() })
}
}
}
async fn fidl_delete_lif(&mut self, id: Id) -> Option<fidl_fuchsia_router_config::Error> {
let lif = self.device.delete_lif(u128::from_ne_bytes(id.uuid)).await;
match lif {
Err(e) => {
error!("Error deleting lif {:?}", e);
Some(fidl_fuchsia_router_config::Error {
code: fidl_fuchsia_router_config::ErrorCode::NotFound,
description: None,
})
}
Ok(()) => None,
}
}
async fn update_security_features(
&mut self,
security_features: &SecurityFeatures,
) -> Result<(), Error> {
if let Some(nat) = security_features.nat {
if nat {
self.device.enable_nat();
} else {
self.device.disable_nat();
}
}
// TODO(cgibson): Handle additional SecurityFeatures.
Ok(())
}
async fn handle_fidl_router_state_request(&mut self, req: RouterStateRequest) {
match req {
RouterStateRequest::GetWanPorts { wan_id, responder } => {
let lif = self.device.lif(u128::from_ne_bytes(wan_id.uuid));
match lif {
None => {
warn!("WAN {:?} not found", wan_id);
responder.send(&[], not_found!())
}
Some(l) => {
responder.send(&l.ports().map(|p| p.to_u32()).collect::<Vec<_>>(), None)
}
}
}
RouterStateRequest::GetLanPorts { lan_id, responder } => {
let lif = self.device.lif(u128::from_ne_bytes(lan_id.uuid));
match lif {
None => {
warn!("LAN {:?} not found", lan_id);
responder.send(&[], not_found!())
}
Some(l) => {
responder.send(&l.ports().map(|p| p.to_u32()).collect::<Vec<_>>(), None)
}
}
}
RouterStateRequest::GetWan { wan_id, responder } => {
let lif = self.device.lif(u128::from_ne_bytes(wan_id.uuid));
info!("lifs {:?}", lif);
match lif {
None => {
warn!("WAN {:?} not found", wan_id);
responder.send(
fidl_fuchsia_router_config::Lif {
element: None,
name: None,
port_ids: None,
properties: None,
vlan: None,
type_: None,
..fidl_fuchsia_router_config::Lif::EMPTY
},
not_found!(),
)
}
Some(l) => {
let ll = l.into();
responder.send(ll, None)
}
}
}
RouterStateRequest::GetLan { lan_id, responder } => {
let lif = self.device.lif(u128::from_ne_bytes(lan_id.uuid));
match lif {
None => {
warn!("LAN {:?} not found", lan_id);
responder.send(
fidl_fuchsia_router_config::Lif {
element: None,
name: None,
port_ids: None,
properties: None,
vlan: None,
type_: None,
..fidl_fuchsia_router_config::Lif::EMPTY
},
not_found!(),
)
}
Some(l) => {
let ll = l.into();
responder.send(ll, None)
}
}
}
RouterStateRequest::GetWans { responder } => {
let lifs: Vec<Lif> = self.device.lifs(LIFType::WAN).map(|l| l.into()).collect();
info!("result: {:?} ", lifs);
responder.send(&mut lifs.into_iter())
}
RouterStateRequest::GetLans { responder } => {
let lifs: Vec<Lif> = self.device.lifs(LIFType::LAN).map(|l| l.into()).collect();
info!("result: {:?} ", lifs);
responder.send(&mut lifs.into_iter())
}
RouterStateRequest::GetWanProperties { wan_id, responder } => {
info!("{:?}", wan_id);
let properties = fidl_fuchsia_router_config::WanProperties {
connection_type: None,
connection_parameters: None,
address_method: None,
address_v4: None,
gateway_v4: None,
connection_v6_mode: None,
address_v6: None,
gateway_v6: None,
hostname: None,
clone_mac: None,
mtu: None,
enable: None,
metric: None,
..fidl_fuchsia_router_config::WanProperties::EMPTY
};
responder.send(properties, not_supported!())
}
RouterStateRequest::GetLanProperties { lan_id, responder } => {
info!("{:?}", lan_id);
let properties = fidl_fuchsia_router_config::LanProperties {
address_v4: None,
enable_dhcp_server: None,
dhcp_config: None,
address_v6: None,
enable_dns_forwarder: None,
enable: None,
..fidl_fuchsia_router_config::LanProperties::EMPTY
};
responder.send(properties, not_supported!())
}
RouterStateRequest::GetDhcpConfig { lan_id, responder } => {
info!("{:?}", lan_id);
responder.send(None, not_supported!())
}
RouterStateRequest::GetDnsResolver { responder } => {
let mut resolver = self.device.get_dns_resolver().await;
responder.send(&mut resolver)
}
RouterStateRequest::GetDnsForwarder { responder } => {
let config = fidl_fuchsia_router_config::DnsForwarderConfig {
element: Id {
uuid: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
version: 0,
},
search: fidl_fuchsia_router_config::DnsSearch {
domain_name: None,
servers: vec![],
},
};
let mut forwarder = fidl_fuchsia_router_config::DnsForwarder {
config,
interfaces: vec![],
resolver: vec![],
};
responder.send(&mut forwarder)
}
RouterStateRequest::GetRoutes { responder } => responder.send(&mut [].iter_mut()),
RouterStateRequest::GetRoute { route_id, responder } => {
info!("{:?}", route_id);
responder.send(None, not_supported!())
}
RouterStateRequest::GetSecurityFeatures { responder } => {
let security_features = fidl_fuchsia_router_config::SecurityFeatures {
allow_multicast: None,
drop_icmp_echo: None,
firewall: None,
h323_passthru: None,
ipsec_passthru: None,
l2_tp_passthru: None,
nat: Some(self.device.is_nat_enabled()),
pptp_passthru: None,
rtsp_passthru: None,
sip_passthru: None,
upnp: None,
v6_firewall: None,
..fidl_fuchsia_router_config::SecurityFeatures::EMPTY
};
responder.send(security_features)
}
RouterStateRequest::GetPortForwards { responder } => responder.send(&mut [].iter_mut()),
RouterStateRequest::GetPortForward { rule_id, responder } => {
info!("{:?}", rule_id);
responder.send(None, not_supported!())
}
RouterStateRequest::GetPorts { responder } => {
self.fidl_get_ports(responder).await;
Ok(())
}
RouterStateRequest::GetPort { port_id, responder } => {
info!("{:?}", port_id);
responder.send(None, not_supported!())
}
RouterStateRequest::GetPortTrigger { rule_id, responder } => {
info!("{:?}", rule_id);
responder.send(None, not_supported!())
}
RouterStateRequest::GetPortTriggers { responder } => responder.send(&mut [].iter_mut()),
RouterStateRequest::GetFilter { rule_id, responder } => {
info!("{:?}", rule_id);
responder.send(None, not_supported!())
}
RouterStateRequest::GetFilters { responder } => {
let result = self.device.get_filters().await.context("Error getting filters");
let mut filter_rules = Vec::new();
match result {
Ok(f) => {
filter_rules = f.into_iter().collect();
info!("Filter rules returned: {:?}", filter_rules.len());
}
Err(e) => error!("Failed parsing filter rules: {}", e),
}
responder.send(&mut filter_rules.iter_mut())
}
RouterStateRequest::GetIpv6PinHole { rule_id, responder } => {
info!("{:?}", rule_id);
responder.send(None, not_supported!())
}
RouterStateRequest::GetIpv6PinHoles { responder } => responder.send(&mut [].iter_mut()),
RouterStateRequest::GetDmzHost { rule_id, responder } => {
info!("{:?}", rule_id);
responder.send(None, not_supported!())
}
RouterStateRequest::GetSystemConfig { responder } => {
let config = fidl_fuchsia_router_config::SystemConfig {
element: None,
timezone: None,
daylight_savings_time_enabled: None,
leds_enabled: None,
hostname: None,
..fidl_fuchsia_router_config::SystemConfig::EMPTY
};
responder.send(config)
}
RouterStateRequest::GetDevice { responder } => {
let device = fidl_fuchsia_router_config::Device {
version: None,
topology: None,
config: None,
..fidl_fuchsia_router_config::Device::EMPTY
};
responder.send(device)
}
RouterStateRequest::GetWlanNetworks { responder } => {
responder.send(&mut vec![].into_iter())
}
RouterStateRequest::GetRadios { responder } => responder.send(&mut vec![].into_iter()),
}
.unwrap_or_else(|e| error!("Error sending response {}", e))
}
async fn fidl_get_ports(&mut self, responder: RouterStateGetPortsResponder) {
let ps = self.device.ports();
let mut ports: Vec<Port> = ps
.map(|p| Port {
element: Id { uuid: p.e_id.uuid().to_ne_bytes(), version: p.e_id.version() },
id: p.port_id.to_u32(),
path: p.path.clone(),
})
.collect();
responder.send(&mut ports.iter_mut()).context("Error sending a response").unwrap();
}
}