blob: 3ee7f1af4945293ad2905d176105adfd9c68b097 [file] [log] [blame]
// Copyright 2017 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.
//! System service for wireless networking
#![deny(missing_docs)]
#![recursion_limit = "256"]
mod device;
mod device_watch;
mod future_util;
mod inspect;
mod logger;
mod mlme_query_proxy;
mod service;
mod station;
mod stats_scheduler;
mod telemetry;
mod watchable_map;
mod watcher_service;
use anyhow::{Context, Error};
use argh::FromArgs;
use fidl_fuchsia_wlan_device_service::DeviceServiceRequestStream;
use fuchsia_async as fasync;
use fuchsia_cobalt::{CobaltConnector, CobaltSender, ConnectionType};
use fuchsia_component::server::{ServiceFs, ServiceObjLocal};
use fuchsia_inspect::Inspector;
use futures::future::try_join5;
use futures::prelude::*;
use log::{error, info};
use std::sync::Arc;
use wlan_sme;
use crate::device::{IfaceDevice, IfaceMap, PhyDevice, PhyMap};
use crate::watcher_service::WatcherService;
const MAX_LOG_LEVEL: log::LevelFilter = log::LevelFilter::Info;
const CONCURRENT_LIMIT: usize = 1000;
static LOGGER: logger::Logger = logger::Logger;
/// Configuration for wlanstack service.
/// This configuration is a super set of individual component configurations such as SME.
#[derive(FromArgs, Clone, Debug, Default)]
pub struct ServiceCfg {
/// if WEP should be supported by the service instance.
#[argh(switch)]
pub wep_supported: bool,
/// if legacy WPA1 should be supported by the service instance.
#[argh(switch)]
pub wpa1_supported: bool,
/// if devices are spawned in an isolated devmgr and device_watcher should watch devices
/// in the isolated devmgr (for wlan-hw-sim based tests)
#[argh(switch)]
pub isolated_devmgr: bool,
}
impl From<ServiceCfg> for wlan_sme::Config {
fn from(cfg: ServiceCfg) -> Self {
Self { wep_supported: cfg.wep_supported, wpa1_supported: cfg.wpa1_supported }
}
}
#[fasync::run_singlethreaded]
async fn main() -> Result<(), Error> {
log::set_logger(&LOGGER)?;
log::set_max_level(MAX_LOG_LEVEL);
info!("Starting");
let cfg: ServiceCfg = argh::from_env();
info!("{:?}", cfg);
let mut fs = ServiceFs::new_local();
let inspector = Inspector::new_with_size(inspect::VMO_SIZE_BYTES);
inspector.serve(&mut fs)?;
let inspect_tree = Arc::new(inspect::WlanstackTree::new(inspector));
fs.dir("svc").add_fidl_service(IncomingServices::Device);
let (phys, phy_events) = device::PhyMap::new();
let (ifaces, iface_events) = device::IfaceMap::new();
let phys = Arc::new(phys);
let ifaces = Arc::new(ifaces);
// TODO(fxbug.dev/45790): this should not depend on isolated_devmgr; the two functionalities should
// live in separate binaries to avoid leaking test dependencies into production builds.
let phy_server = if cfg.isolated_devmgr {
device::serve_phys::<isolated_devmgr::IsolatedDeviceEnv>(phys.clone(), inspect_tree.clone())
.left_future()
} else {
device::serve_phys::<wlan_dev::RealDeviceEnv>(phys.clone(), inspect_tree.clone())
.right_future()
};
let cobalt_1dot1_svc = fuchsia_component::client::connect_to_service::<
fidl_fuchsia_metrics::MetricEventLoggerFactoryMarker,
>()
.context("failed to connect to metrics service")?;
let (cobalt_1dot1_proxy, cobalt_1dot1_server) =
fidl::endpoints::create_proxy::<fidl_fuchsia_metrics::MetricEventLoggerMarker>()
.context("failed to create MetricEventLoggerMarker endponts")?;
let project_spec = fidl_fuchsia_metrics::ProjectSpec {
customer_id: None, // defaults to fuchsia
project_id: Some(wlan_metrics_registry::PROJECT_ID),
..fidl_fuchsia_metrics::ProjectSpec::EMPTY
};
if let Err(e) =
cobalt_1dot1_svc.create_metric_event_logger(project_spec, cobalt_1dot1_server).await
{
error!("create_metric_event_logger failure: {}", e);
}
let (cobalt_sender, cobalt_reporter) = CobaltConnector::default()
.serve(ConnectionType::project_id(wlan_metrics_registry::PROJECT_ID));
let telemetry_server = telemetry::report_telemetry_periodically(
ifaces.clone(),
cobalt_sender.clone(),
inspect_tree.clone(),
);
let (watcher_service, watcher_fut) =
watcher_service::serve_watchers(phys.clone(), ifaces.clone(), phy_events, iface_events);
let serve_fidl_fut = serve_fidl(
cfg,
fs,
phys,
ifaces,
watcher_service,
inspect_tree,
cobalt_sender,
cobalt_1dot1_proxy,
);
let ((), (), (), (), ()) = try_join5(
serve_fidl_fut,
watcher_fut.map_ok(|_: void::Void| ()),
phy_server.map_ok(|_: void::Void| ()),
cobalt_reporter.map(Ok),
telemetry_server.map(Ok),
)
.await?;
info!("Exiting");
Ok(())
}
enum IncomingServices {
Device(DeviceServiceRequestStream),
}
async fn serve_fidl(
cfg: ServiceCfg,
mut fs: ServiceFs<ServiceObjLocal<'_, IncomingServices>>,
phys: Arc<PhyMap>,
ifaces: Arc<IfaceMap>,
watcher_service: WatcherService<PhyDevice, IfaceDevice>,
inspect_tree: Arc<inspect::WlanstackTree>,
cobalt_sender: CobaltSender,
cobalt_1dot1_proxy: fidl_fuchsia_metrics::MetricEventLoggerProxy,
) -> Result<(), Error> {
fs.take_and_serve_directory_handle()?;
let iface_counter = Arc::new(service::IfaceCounter::new());
let fdio_server = fs.for_each_concurrent(CONCURRENT_LIMIT, move |s| {
let phys = phys.clone();
let ifaces = ifaces.clone();
let watcher_service = watcher_service.clone();
let cobalt_sender = cobalt_sender.clone();
let cobalt_1dot1_proxy = cobalt_1dot1_proxy.clone();
let cfg = cfg.clone();
let inspect_tree = inspect_tree.clone();
let iface_counter = iface_counter.clone();
async move {
match s {
IncomingServices::Device(stream) => {
service::serve_device_requests(
iface_counter,
cfg,
phys,
ifaces,
watcher_service,
stream,
inspect_tree,
cobalt_sender,
cobalt_1dot1_proxy,
)
.unwrap_or_else(|e| println!("{:?}", e))
.await
}
}
}
});
fdio_server.await;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_svc_cfg_wep() {
let cfg = ServiceCfg::from_args(&["bin/app"], &["--wep-supported"]).unwrap();
assert!(cfg.wep_supported);
}
#[test]
fn parse_svc_cfg_default() {
let cfg = ServiceCfg::from_args(&["bin/app"], &[]).unwrap();
assert!(!cfg.wep_supported);
}
#[test]
fn svc_to_sme_cfg() {
let svc_cfg = ServiceCfg::from_args(&["bin/app"], &[]).unwrap();
let sme_cfg: wlan_sme::Config = svc_cfg.into();
assert!(!sme_cfg.wep_supported);
let svc_cfg = ServiceCfg::from_args(&["bin/app"], &["--wep-supported"]).unwrap();
let sme_cfg: wlan_sme::Config = svc_cfg.into();
assert!(sme_cfg.wep_supported);
}
}