blob: 71607ae8c00cf72f27e2502e15c511dfc4a4b448 [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.
use anyhow::Context as _;
use core::sync::atomic::AtomicUsize;
use fidl::endpoints::create_proxy;
use fidl_fuchsia_wlan_device as fidl_wlan_dev;
use fidl_fuchsia_wlan_device_service::{self as fidl_svc, DeviceServiceRequest};
use fidl_fuchsia_wlan_mlme::{self as fidl_mlme, MinstrelStatsResponse, MlmeMarker};
use fuchsia_async as fasync;
use fuchsia_cobalt::{self, CobaltSender};
use fuchsia_inspect_contrib::inspect_log;
use fuchsia_zircon as zx;
use futures::prelude::*;
use log::{error, info};
use std::sync::{atomic::Ordering, Arc};
use crate::device::{self, IfaceDevice, IfaceMap, NewIface, PhyDevice, PhyMap};
use crate::inspect;
use crate::station;
use crate::stats_scheduler::StatsRef;
use crate::watcher_service::WatcherService;
use crate::ServiceCfg;
/// Thread-safe counter for spawned ifaces.
pub struct IfaceCounter(AtomicUsize);
impl IfaceCounter {
pub fn new() -> Self {
Self(AtomicUsize::new(0))
}
/// Provides the caller with a new unique id.
pub fn next_iface_id(&self) -> usize {
self.0.fetch_add(1, Ordering::SeqCst)
}
#[cfg(test)]
pub fn new_with_value(v: usize) -> Self {
Self(AtomicUsize::new(v))
}
}
pub async fn serve_device_requests(
iface_counter: Arc<IfaceCounter>,
cfg: ServiceCfg,
phys: Arc<PhyMap>,
ifaces: Arc<IfaceMap>,
watcher_service: WatcherService<PhyDevice, IfaceDevice>,
mut req_stream: fidl_svc::DeviceServiceRequestStream,
inspect_tree: Arc<inspect::WlanstackTree>,
cobalt_sender: CobaltSender,
) -> Result<(), anyhow::Error> {
while let Some(req) = req_stream.try_next().await.context("error running DeviceService")? {
// Note that errors from responder.send() are propagated intentionally.
// If we fail to send a response, the only way to recover is to stop serving the
// client and close the channel. Otherwise, the client would be left hanging
// forever.
match req {
DeviceServiceRequest::ListPhys { responder } => responder.send(&mut list_phys(&phys)),
DeviceServiceRequest::QueryPhy { req, responder } => {
let result = query_phy(&phys, req.phy_id).await;
let (status, mut response) = into_status_and_opt(result);
responder.send(status.into_raw(), response.as_mut())
}
DeviceServiceRequest::ListIfaces { responder } => {
responder.send(&mut list_ifaces(&ifaces))
}
DeviceServiceRequest::QueryIface { iface_id, responder } => {
let result = query_iface(&ifaces, iface_id);
let (status, mut response) = into_status_and_opt(result);
responder.send(status.into_raw(), response.as_mut())
}
DeviceServiceRequest::CreateIface { req, responder } => {
match create_iface(&iface_counter, &phys, req).await {
Ok(new_iface) => {
info!("iface #{} started ({:?})", new_iface.id, new_iface.phy_ownership);
let iface_id = new_iface.id;
let inspect_tree = inspect_tree.clone();
let iface_tree_holder = inspect_tree.create_iface_child(iface_id);
let device_info = match new_iface.mlme_channel.query_device_info().await {
Ok(device_info) => device_info,
Err(e) => {
responder.send(zx::sys::ZX_ERR_PEER_CLOSED, None.as_mut())?;
return Err(e.into());
}
};
let serve_sme_fut = device::create_and_serve_sme(
cfg.clone(),
iface_id,
new_iface.phy_ownership,
new_iface.mlme_channel,
ifaces.clone(),
inspect_tree.clone(),
iface_tree_holder,
cobalt_sender.clone(),
device_info,
)?;
let resp = fidl_svc::CreateIfaceResponse { iface_id };
responder.send(zx::sys::ZX_OK, Some(resp).as_mut())?;
let serve_sme_fut = serve_sme_fut.map(move |result| {
let msg = match result {
Ok(()) => {
let msg = format!("iface {} shutdown gracefully", iface_id);
info!("{}", msg);
msg
}
Err(e) => {
let msg = format!("error serving iface {}: {}", iface_id, e);
error!("{}", msg);
msg
}
};
inspect_log!(inspect_tree.device_events.lock(), msg: msg);
inspect_tree.notify_iface_removed(iface_id);
});
fasync::Task::spawn(serve_sme_fut).detach();
Ok(())
}
Err(status) => responder.send(status.into_raw(), None),
}
}
DeviceServiceRequest::DestroyIface { req, responder } => {
let result = destroy_iface(&phys, &ifaces, req.iface_id).await;
let status = into_status_and_opt(result).0;
responder.send(status.into_raw())
}
DeviceServiceRequest::GetClientSme { iface_id, sme, responder } => {
let status = get_client_sme(&ifaces, iface_id, sme);
responder.send(status.into_raw())
}
DeviceServiceRequest::GetApSme { iface_id, sme, responder } => {
let status = get_ap_sme(&ifaces, iface_id, sme);
responder.send(status.into_raw())
}
DeviceServiceRequest::GetMeshSme { iface_id, sme, responder } => {
let status = get_mesh_sme(&ifaces, iface_id, sme);
responder.send(status.into_raw())
}
DeviceServiceRequest::GetIfaceStats { iface_id, responder } => {
match get_iface_stats(&ifaces, iface_id).await {
Ok(stats_ref) => {
let mut stats = stats_ref.lock();
responder.send(zx::sys::ZX_OK, Some(&mut stats))
}
Err(status) => responder.send(status.into_raw(), None),
}
}
DeviceServiceRequest::GetMinstrelList { iface_id, responder } => {
let (status, mut peers) = list_minstrel_peers(&ifaces, iface_id).await;
responder.send(status.into_raw(), &mut peers)
}
DeviceServiceRequest::GetMinstrelStats { iface_id, peer_addr, responder } => {
let (status, mut peer) = get_minstrel_stats(&ifaces, iface_id, peer_addr).await;
responder.send(status.into_raw(), peer.as_deref_mut())
}
DeviceServiceRequest::WatchDevices { watcher, control_handle: _ } => {
watcher_service
.add_watcher(watcher)
.unwrap_or_else(|e| error!("error registering a device watcher: {}", e));
Ok(())
}
DeviceServiceRequest::GetCountry { phy_id, responder } => responder
.send(&mut get_country(&phys, phy_id).await.map_err(|status| status.into_raw())),
DeviceServiceRequest::SetCountry { req, responder } => {
let status = set_country(&phys, req).await;
responder.send(status.into_raw())
}
DeviceServiceRequest::ClearCountry { req, responder } => {
let status = clear_country(&phys, req).await;
responder.send(status.into_raw())
}
}?;
}
Ok(())
}
fn into_status_and_opt<T>(r: Result<T, zx::Status>) -> (zx::Status, Option<T>) {
match r {
Ok(x) => (zx::Status::OK, Some(x)),
Err(status) => (status, None),
}
}
fn list_phys(phys: &PhyMap) -> fidl_svc::ListPhysResponse {
let list = phys
.get_snapshot()
.iter()
.map(|(phy_id, phy)| fidl_svc::PhyListItem {
phy_id: *phy_id,
path: phy.device.path().to_string_lossy().into_owned(),
})
.collect();
fidl_svc::ListPhysResponse { phys: list }
}
async fn query_phy(phys: &PhyMap, id: u16) -> Result<fidl_svc::QueryPhyResponse, zx::Status> {
info!("query_phy(id = {})", id);
let phy = phys.get(&id).ok_or(zx::Status::NOT_FOUND)?;
let query_result = phy.proxy.query().await.map_err(move |e| {
error!("query_phy(id = {}): error sending 'Query' request to phy: {}", id, e);
zx::Status::INTERNAL
})?;
info!("query_phy(id = {}): received a 'QueryResult' from device", id);
zx::Status::ok(query_result.status)?;
let mut info = query_result.info;
info.id = id;
info.dev_path = Some(phy.device.path().to_string_lossy().into_owned());
Ok(fidl_svc::QueryPhyResponse { info })
}
fn list_ifaces(ifaces: &IfaceMap) -> fidl_svc::ListIfacesResponse {
let list = ifaces
.get_snapshot()
.iter()
.map(|(iface_id, _iface)| fidl_svc::IfaceListItem { iface_id: *iface_id })
.collect();
fidl_svc::ListIfacesResponse { ifaces: list }
}
async fn destroy_iface<'a>(
phys: &'a PhyMap,
ifaces: &'a IfaceMap,
id: u16,
) -> Result<(), zx::Status> {
info!("destroy_iface(id = {})", id);
let iface = ifaces.get(&id).ok_or(zx::Status::NOT_FOUND)?;
let phy_ownership = &iface.phy_ownership;
// Shutdown the corresponding SME first. We don't want to send requests to MLME while we're mid-shutdown.
if let Err(e) = iface.shutdown_sender.clone().send(()).await {
error!("Error shutting down SME before iface removal: {:?}", e);
}
let phy = phys.get(&phy_ownership.phy_id).ok_or(zx::Status::NOT_FOUND)?;
let mut phy_req = fidl_wlan_dev::DestroyIfaceRequest { id: phy_ownership.phy_assigned_id };
let r = phy.proxy.destroy_iface(&mut phy_req).await.map_err(move |e| {
error!("Error sending 'DestroyIface' request to phy {:?}: {}", phy_ownership, e);
zx::Status::INTERNAL
})?;
let () = zx::Status::ok(r.status)?;
ifaces.remove(&id);
Ok(())
}
fn query_iface(ifaces: &IfaceMap, id: u16) -> Result<fidl_svc::QueryIfaceResponse, zx::Status> {
info!("query_iface(id = {})", id);
let iface = ifaces.get(&id).ok_or(zx::Status::NOT_FOUND)?;
let role = match iface.device_info.role {
fidl_mlme::MacRole::Client => fidl_wlan_dev::MacRole::Client,
fidl_mlme::MacRole::Ap => fidl_wlan_dev::MacRole::Ap,
fidl_mlme::MacRole::Mesh => fidl_wlan_dev::MacRole::Mesh,
};
let phy_id = iface.phy_ownership.phy_id;
let phy_assigned_id = iface.phy_ownership.phy_assigned_id;
let mac_addr = iface.device_info.mac_addr;
Ok(fidl_svc::QueryIfaceResponse { role, id, mac_addr, phy_id, phy_assigned_id })
}
async fn get_country(
phys: &PhyMap,
phy_id: u16,
) -> Result<fidl_svc::GetCountryResponse, zx::Status> {
let phy = phys.get(&phy_id).ok_or(Err(zx::Status::NOT_FOUND))?;
match phy.proxy.get_country().await {
Ok(result) => match result {
Ok(country_code) => Ok(fidl_svc::GetCountryResponse { alpha2: country_code.alpha2 }),
Err(status) => Err(zx::Status::from_raw(status)),
},
Err(e) => {
error!("Error sending 'GetCountry' request to phy #{}: {}", phy_id, e);
Err(zx::Status::INTERNAL)
}
}
}
async fn set_country(phys: &PhyMap, req: fidl_svc::SetCountryRequest) -> zx::Status {
let phy_id = req.phy_id;
let phy = match phys.get(&req.phy_id) {
None => return zx::Status::NOT_FOUND,
Some(p) => p,
};
let mut phy_req = fidl_wlan_dev::CountryCode { alpha2: req.alpha2 };
match phy.proxy.set_country(&mut phy_req).await {
Ok(status) => zx::Status::from_raw(status),
Err(e) => {
error!("Error sending SetCountry set_country request to phy #{}: {}", phy_id, e);
zx::Status::INTERNAL
}
}
}
async fn clear_country(phys: &PhyMap, req: fidl_svc::ClearCountryRequest) -> zx::Status {
let phy = match phys.get(&req.phy_id) {
None => return zx::Status::NOT_FOUND,
Some(p) => p,
};
match phy.proxy.clear_country().await {
Ok(status) => zx::Status::from_raw(status),
Err(e) => {
error!(
"Error sending ClearCountry clear_country request to phy #{}: {}",
req.phy_id, e
);
zx::Status::INTERNAL
}
}
}
async fn create_iface<'a>(
iface_counter: &'a IfaceCounter,
phys: &'a PhyMap,
req: fidl_svc::CreateIfaceRequest,
) -> Result<NewIface, zx::Status> {
let phy_id = req.phy_id;
let phy = phys.get(&req.phy_id).ok_or(zx::Status::NOT_FOUND)?;
let (mlme_channel, sme_channel) = create_proxy::<MlmeMarker>()
.map_err(|e| {
error!("failed to create MlmeProxy: {}", e);
zx::Status::INTERNAL
})
.map(|(p, c)| (p, Some(c.into_channel())))?;
let mut phy_req = fidl_wlan_dev::CreateIfaceRequest {
role: req.role,
sme_channel,
init_mac_addr: req.mac_addr,
};
let r = phy.proxy.create_iface(&mut phy_req).await.map_err(move |e| {
error!("Error sending 'CreateIface' request to phy #{}: {}", phy_id, e);
zx::Status::INTERNAL
})?;
zx::Status::ok(r.status)?;
Ok(NewIface {
id: iface_counter.next_iface_id() as u16,
phy_ownership: device::PhyOwnership { phy_id, phy_assigned_id: r.iface_id },
mlme_channel,
})
}
fn get_client_sme(
ifaces: &IfaceMap,
iface_id: u16,
endpoint: station::client::Endpoint,
) -> zx::Status {
let iface = ifaces.get(&iface_id);
let server = match iface {
None => return zx::Status::NOT_FOUND,
Some(ref iface) => match iface.sme_server {
device::SmeServer::Client(ref server) => server,
_ => return zx::Status::NOT_SUPPORTED,
},
};
match server.unbounded_send(endpoint) {
Ok(()) => zx::Status::OK,
Err(e) => {
error!("error sending an endpoint to the SME server future: {}", e);
zx::Status::INTERNAL
}
}
}
fn get_ap_sme(ifaces: &IfaceMap, iface_id: u16, endpoint: station::ap::Endpoint) -> zx::Status {
let iface = ifaces.get(&iface_id);
let server = match iface {
None => return zx::Status::NOT_FOUND,
Some(ref iface) => match iface.sme_server {
device::SmeServer::Ap(ref server) => server,
_ => return zx::Status::NOT_SUPPORTED,
},
};
match server.unbounded_send(endpoint) {
Ok(()) => zx::Status::OK,
Err(e) => {
error!("error sending an endpoint to the SME server future: {}", e);
zx::Status::INTERNAL
}
}
}
fn get_mesh_sme(ifaces: &IfaceMap, iface_id: u16, endpoint: station::mesh::Endpoint) -> zx::Status {
let iface = ifaces.get(&iface_id);
let server = match iface {
None => return zx::Status::NOT_FOUND,
Some(ref iface) => match iface.sme_server {
device::SmeServer::Mesh(ref server) => server,
_ => return zx::Status::NOT_SUPPORTED,
},
};
match server.unbounded_send(endpoint) {
Ok(()) => zx::Status::OK,
Err(e) => {
error!("error sending an endpoint to the SME server future: {}", e);
zx::Status::INTERNAL
}
}
}
pub async fn get_iface_stats(ifaces: &IfaceMap, iface_id: u16) -> Result<StatsRef, zx::Status> {
let iface = ifaces.get(&iface_id).ok_or(zx::Status::NOT_FOUND)?;
iface.stats_sched.get_stats().await
}
async fn list_minstrel_peers(
ifaces: &IfaceMap,
iface_id: u16,
) -> (zx::Status, fidl_fuchsia_wlan_minstrel::Peers) {
let empty_peer_list = fidl_fuchsia_wlan_minstrel::Peers { peers: vec![] };
let iface = match ifaces.get(&iface_id) {
Some(iface) => iface,
None => return (zx::Status::NOT_FOUND, empty_peer_list),
};
match iface.mlme_query.get_minstrel_list().await {
Ok(resp) => (zx::Status::OK, resp.peers),
Err(_) => (zx::Status::INTERNAL, empty_peer_list),
}
}
async fn get_minstrel_stats(
ifaces: &IfaceMap,
iface_id: u16,
mac_addr: [u8; 6],
) -> (zx::Status, Option<Box<fidl_fuchsia_wlan_minstrel::Peer>>) {
let iface = match ifaces.get(&iface_id) {
Some(iface) => iface,
None => return (zx::Status::NOT_FOUND, None),
};
match iface.mlme_query.get_minstrel_peer(mac_addr).await {
Ok(MinstrelStatsResponse { peer }) => (zx::Status::OK, peer),
Err(_) => (zx::Status::INTERNAL, None),
}
}
#[cfg(test)]
mod tests {
use super::*;
use fidl::endpoints::ServerEnd;
use fidl_fuchsia_wlan_device::{self as fidl_dev, PhyRequest, PhyRequestStream};
use fidl_fuchsia_wlan_device_service::{IfaceListItem, PhyListItem};
use fidl_fuchsia_wlan_mlme::{self as fidl_mlme, MlmeMarker};
use fidl_fuchsia_wlan_sme as fidl_sme;
use fuchsia_async as fasync;
use fuchsia_inspect::Inspector;
use fuchsia_zircon as zx;
use futures::channel::mpsc;
use futures::future::BoxFuture;
use futures::task::Poll;
use pin_utils::pin_mut;
use wlan_common::{
assert_variant,
channel::{Cbw, Phy},
RadioConfig,
};
use wlan_dev::DeviceEnv;
use crate::{
mlme_query_proxy::MlmeQueryProxy,
stats_scheduler::{self, StatsRequest},
watcher_service,
};
#[test]
fn iface_counter() {
let iface_counter = IfaceCounter::new();
assert_eq!(0, iface_counter.next_iface_id());
assert_eq!(1, iface_counter.next_iface_id());
assert_eq!(2, iface_counter.next_iface_id());
assert_eq!(3, iface_counter.next_iface_id());
}
#[test]
fn list_two_phys() {
let _exec = fasync::Executor::new().expect("Failed to create an executor");
let (phy_map, _phy_map_events) = PhyMap::new();
let phy_map = Arc::new(phy_map);
let (phy_null, _phy_null_stream) = fake_phy("/dev/null");
let (phy_zero, _phy_zero_stream) = fake_phy("/dev/zero");
phy_map.insert(10u16, phy_null);
phy_map.insert(20u16, phy_zero);
let mut list = super::list_phys(&phy_map).phys;
list.sort_by_key(|p| p.phy_id);
assert_eq!(
vec![
PhyListItem { phy_id: 10u16, path: "/dev/null".to_string() },
PhyListItem { phy_id: 20u16, path: "/dev/zero".to_string() },
],
list
)
}
#[test]
fn query_phy_success() {
let mut exec = fasync::Executor::new().expect("Failed to create an executor");
let (phy_map, _phy_map_events) = PhyMap::new();
let phy_map = Arc::new(phy_map);
let (phy, mut phy_stream) = fake_phy("/dev/null");
phy_map.insert(10u16, phy);
// Initiate a QueryPhy request. The returned future should not be able
// to produce a result immediately
let query_fut = super::query_phy(&phy_map, 10u16);
pin_mut!(query_fut);
assert_eq!(Poll::Pending, exec.run_until_stalled(&mut query_fut));
// The call above should trigger a Query message to the phy.
// Pretend that we are the phy and read the message from the other side.
let responder = assert_variant!(exec.run_until_stalled(&mut phy_stream.next()),
Poll::Ready(Some(Ok(PhyRequest::Query { responder }))) => responder
);
// Reply with a fake phy info
responder
.send(&mut fidl_wlan_dev::QueryResponse {
status: zx::sys::ZX_OK,
info: fake_phy_info(),
})
.expect("failed to send QueryResponse");
// Our original future should complete now, and return the same phy info
let response = assert_variant!(exec.run_until_stalled(&mut query_fut),
Poll::Ready(Ok(response)) => response
);
assert_eq!(fake_phy_info(), response.info);
}
#[test]
fn query_phy_not_found() {
let mut exec = fasync::Executor::new().expect("Failed to create an executor");
let (phy_map, _phy_map_events) = PhyMap::new();
let phy_map = Arc::new(phy_map);
let query_fut = super::query_phy(&phy_map, 10u16);
pin_mut!(query_fut);
assert_eq!(Poll::Ready(Err(zx::Status::NOT_FOUND)), exec.run_until_stalled(&mut query_fut));
}
#[test]
fn list_two_ifaces() {
let _exec = fasync::Executor::new().expect("Failed to create an executor");
let (iface_map, _iface_map_events) = IfaceMap::new();
let iface_map = Arc::new(iface_map);
let iface_null = fake_client_iface();
let iface_zero = fake_client_iface();
iface_map.insert(10u16, iface_null.iface);
iface_map.insert(20u16, iface_zero.iface);
let mut list = super::list_ifaces(&iface_map).ifaces;
list.sort_by_key(|p| p.iface_id);
assert_eq!(
vec![IfaceListItem { iface_id: 10u16 }, IfaceListItem { iface_id: 20u16 },],
list
)
}
#[test]
fn query_iface_success() {
let _exec = fasync::Executor::new().expect("Failed to create an executor");
let (iface_map, _iface_map_events) = IfaceMap::new();
let iface_map = Arc::new(iface_map);
let iface = fake_client_iface();
iface_map.insert(10, iface.iface);
let response = super::query_iface(&iface_map, 10).expect("querying iface failed");
let expected = fake_device_info();
assert_eq!(response.role, fidl_dev::MacRole::Client);
assert_eq!(response.mac_addr, expected.mac_addr);
assert_eq!(response.id, 10);
}
#[test]
fn destroy_iface_success() {
let mut exec = fasync::Executor::new().expect("Failed to create an executor");
let (mut phy_map, _phy_map_events) = PhyMap::new();
let (mut iface_map, _iface_map_events) = IfaceMap::new();
let mut phy_stream = fake_destroy_iface_env(&mut phy_map, &mut iface_map);
let destroy_fut = super::destroy_iface(&phy_map, &iface_map, 42);
pin_mut!(destroy_fut);
assert_eq!(Poll::Pending, exec.run_until_stalled(&mut destroy_fut));
let (req, responder) = assert_variant!(exec.run_until_stalled(&mut phy_stream.next()),
Poll::Ready(Some(Ok(PhyRequest::DestroyIface { req, responder }))) => (req, responder)
);
// Verify the destroy iface request to the corresponding PHY is correct.
assert_eq!(13, req.id);
responder
.send(&mut fidl_wlan_dev::DestroyIfaceResponse { status: zx::sys::ZX_OK })
.expect("failed to send DestroyIfaceResponse");
assert_eq!(Poll::Ready(Ok(())), exec.run_until_stalled(&mut destroy_fut));
// Verify iface was removed from available ifaces.
assert!(iface_map.get(&42u16).is_none(), "iface expected to be deleted");
}
#[test]
fn destroy_iface_failure() {
let mut exec = fasync::Executor::new().expect("Failed to create an executor");
let (mut phy_map, _phy_map_events) = PhyMap::new();
let (mut iface_map, _iface_map_events) = IfaceMap::new();
let mut phy_stream = fake_destroy_iface_env(&mut phy_map, &mut iface_map);
let destroy_fut = super::destroy_iface(&phy_map, &iface_map, 42);
pin_mut!(destroy_fut);
assert_eq!(Poll::Pending, exec.run_until_stalled(&mut destroy_fut));
let (req, responder) = assert_variant!(exec.run_until_stalled(&mut phy_stream.next()),
Poll::Ready(Some(Ok(PhyRequest::DestroyIface { req, responder }))) => (req, responder)
);
// Verify the destroy iface request to the corresponding PHY is correct.
assert_eq!(13, req.id);
responder
.send(&mut fidl_wlan_dev::DestroyIfaceResponse { status: zx::sys::ZX_ERR_INTERNAL })
.expect("failed to send DestroyIfaceResponse");
assert_eq!(
Poll::Ready(Err(zx::Status::INTERNAL)),
exec.run_until_stalled(&mut destroy_fut)
);
// Verify iface was not removed from available ifaces.
assert!(iface_map.get(&42u16).is_some(), "iface expected to not be deleted");
}
#[test]
fn destroy_iface_not_found() {
let mut exec = fasync::Executor::new().expect("Failed to create an executor");
let (mut phy_map, _phy_map_events) = PhyMap::new();
let (mut iface_map, _iface_map_events) = IfaceMap::new();
let _phy_stream = fake_destroy_iface_env(&mut phy_map, &mut iface_map);
let fut = super::destroy_iface(&phy_map, &iface_map, 43);
pin_mut!(fut);
assert_eq!(Poll::Ready(Err(zx::Status::NOT_FOUND)), exec.run_until_stalled(&mut fut));
}
#[test]
fn query_iface_not_found() {
let (iface_map, _iface_map_events) = IfaceMap::new();
let iface_map = Arc::new(iface_map);
let status = super::query_iface(&iface_map, 10u16).expect_err("querying iface succeeded");
assert_eq!(zx::Status::NOT_FOUND, status);
}
#[test]
fn create_iface_without_mac_success() {
let mut exec = fasync::Executor::new().expect("Failed to create an executor");
let (phy_map, _phy_map_events) = PhyMap::new();
let phy_map = Arc::new(phy_map);
let (phy, mut phy_stream) = fake_phy("/dev/null");
phy_map.insert(10, phy);
// Initiate a CreateIface request. The returned future should not be able
// to produce a result immediately
let iface_counter = IfaceCounter::new_with_value(5);
let create_fut = super::create_iface(
&iface_counter,
&phy_map,
fidl_svc::CreateIfaceRequest {
phy_id: 10,
role: fidl_wlan_dev::MacRole::Client,
mac_addr: None,
},
);
pin_mut!(create_fut);
let fut_result = exec.run_until_stalled(&mut create_fut);
assert_variant!(fut_result, Poll::Pending);
// Continue running create iface request.
let fut_result = exec.run_until_stalled(&mut create_fut);
assert_variant!(fut_result, Poll::Pending);
let (req, responder) = assert_variant!(exec.run_until_stalled(&mut phy_stream.next()),
Poll::Ready(Some(Ok(PhyRequest::CreateIface { req, responder }))) => (req, responder)
);
// Since we requested the Client role, the request to the phy should also have
// the Client role
assert_eq!(fidl_wlan_dev::MacRole::Client, req.role);
// Pretend that the interface was created with local id 123.
responder
.send(&mut fidl_wlan_dev::CreateIfaceResponse { status: zx::sys::ZX_OK, iface_id: 123 })
.expect("failed to send CreateIfaceResponse");
// The original future should resolve into a response.
let response = assert_variant!(exec.run_until_stalled(&mut create_fut),
Poll::Ready(Ok(response)) => response
);
assert_eq!(5, response.id);
assert_eq!(
device::PhyOwnership { phy_id: 10, phy_assigned_id: 123 },
response.phy_ownership
);
// TODO(fxbug.dev/29547): response.mlme_channel use and talk to it
}
#[test]
fn create_iface_with_mac_success() {
let mut exec = fasync::Executor::new().expect("Failed to create an executor");
let (phy_map, _phy_map_events) = PhyMap::new();
let phy_map = Arc::new(phy_map);
let (phy, mut phy_stream) = fake_phy("/dev/null");
phy_map.insert(10, phy);
// Initiate a CreateIface request. The returned future should not be able
// to produce a result immediately
let iface_counter = IfaceCounter::new_with_value(5);
let mac_addr = Some(vec![1, 2, 3, 4, 5, 6]);
let create_fut = super::create_iface(
&iface_counter,
&phy_map,
fidl_svc::CreateIfaceRequest { phy_id: 10, role: fidl_wlan_dev::MacRole::Ap, mac_addr },
);
pin_mut!(create_fut);
assert_variant!(exec.run_until_stalled(&mut create_fut), Poll::Pending);
// Continue running create iface request.
assert_variant!(exec.run_until_stalled(&mut create_fut), Poll::Pending);
let (req, responder) = assert_variant!(exec.run_until_stalled(&mut phy_stream.next()),
Poll::Ready(Some(Ok(PhyRequest::CreateIface { req, responder }))) => (req, responder)
);
// Since we requested the Ap role, the request to the phy should also have
// the Ap role
assert_eq!(fidl_wlan_dev::MacRole::Ap, req.role);
let res = match req.init_mac_addr {
None => false,
Some(mac_addr) => {
assert_eq!(mac_addr, [1, 2, 3, 4, 5, 6]);
true
}
};
assert!(res);
// Pretend that the interface was created with local id 123.
responder
.send(&mut fidl_wlan_dev::CreateIfaceResponse { status: zx::sys::ZX_OK, iface_id: 123 })
.expect("failed to send CreateIfaceResponse");
// The original future should resolve into a response.
let response = assert_variant!(exec.run_until_stalled(&mut create_fut),
Poll::Ready(Ok(response)) => response
);
assert_eq!(5, response.id);
assert_eq!(
device::PhyOwnership { phy_id: 10, phy_assigned_id: 123 },
response.phy_ownership
);
}
#[test]
fn create_iface_not_found() {
let mut exec = fasync::Executor::new().expect("Failed to create an executor");
let (phy_map, _phy_map_events) = PhyMap::new();
let phy_map = Arc::new(phy_map);
let iface_counter = IfaceCounter::new_with_value(2);
let fut = super::create_iface(
&iface_counter,
&phy_map,
fidl_svc::CreateIfaceRequest {
phy_id: 10,
role: fidl_wlan_dev::MacRole::Client,
mac_addr: None,
},
);
pin_mut!(fut);
assert_variant!(
exec.run_until_stalled(&mut fut),
Poll::Ready(Err(zx::Status::NOT_FOUND)),
"expected failure on invalid PHY"
);
}
#[test]
fn get_client_sme_success() {
let mut exec = fasync::Executor::new().expect("Failed to create an executor");
let (iface_map, _iface_map_events) = IfaceMap::new();
let iface_map = Arc::new(iface_map);
let mut iface = fake_client_iface();
iface_map.insert(10, iface.iface);
let (proxy, server) = create_proxy().expect("failed to create a pair of SME endpoints");
assert_eq!(zx::Status::OK, super::get_client_sme(&iface_map, 10, server));
// Expect to get a new FIDL client in the stream
let endpoint = iface
.new_sme_clients
.try_next()
.expect("expected a message in new_sme_clients")
.expect("didn't expect new_sme_clients stream to end");
let mut sme_stream = endpoint.into_stream().expect("failed to create stream for endpoint");
// Verify that `proxy` is indeed connected to `sme_stream`
let (_scan_proxy, scan_txn) =
create_proxy().expect("failed to create a pair of scan txn endpoints");
proxy.scan(&mut fake_scan_request(), scan_txn).expect("failed to send a scan request");
assert_variant!(exec.run_until_stalled(&mut sme_stream.next()),
Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan { req, .. }))) => {
assert_eq!(fake_scan_request(), req)
}
);
}
#[test]
fn get_client_sme_not_found() {
let mut _exec = fasync::Executor::new().expect("Failed to create an executor");
let (iface_map, _iface_map_events) = IfaceMap::new();
let iface_map = Arc::new(iface_map);
let (_proxy, server) = create_proxy().expect("failed to create a pair of SME endpoints");
assert_eq!(zx::Status::NOT_FOUND, super::get_client_sme(&iface_map, 10, server));
}
#[test]
fn get_client_sme_wrong_role() {
let mut _exec = fasync::Executor::new().expect("Failed to create an executor");
let (iface_map, _iface_map_events) = IfaceMap::new();
let iface_map = Arc::new(iface_map);
let iface = fake_ap_iface();
iface_map.insert(10, iface.iface);
let (_proxy, server) = create_proxy().expect("failed to create a pair of SME endpoints");
assert_eq!(zx::Status::NOT_SUPPORTED, super::get_client_sme(&iface_map, 10, server));
}
#[test]
fn get_ap_sme_success() {
let mut exec = fasync::Executor::new().expect("Failed to create an executor");
let (iface_map, _iface_map_events) = IfaceMap::new();
let iface_map = Arc::new(iface_map);
let mut iface = fake_ap_iface();
iface_map.insert(10, iface.iface);
let (proxy, server) = create_proxy().expect("failed to create a pair of SME endpoints");
assert_eq!(zx::Status::OK, super::get_ap_sme(&iface_map, 10, server));
// Expect to get a new FIDL client in the stream
let endpoint = iface
.new_sme_clients
.try_next()
.expect("expected a message in new_sme_clients")
.expect("didn't expect new_sme_clients stream to end");
let mut sme_stream = endpoint.into_stream().expect("failed to create stream for endpoint");
// Verify that `proxy` is indeed connected to `sme_stream`
let mut fut = fidl_sme::ApSmeProxyInterface::start(&proxy, &mut fake_ap_config());
assert_variant!(exec.run_until_stalled(&mut sme_stream.next()),
Poll::Ready(Some(Ok(fidl_sme::ApSmeRequest::Start { config, responder }))) => {
assert_eq!(fake_ap_config(), config);
responder
.send(fidl_sme::StartApResultCode::Success)
.expect("failed to send response");
}
);
let fut_result = exec.run_until_stalled(&mut fut);
assert_variant!(fut_result, Poll::Ready(Ok(fidl_sme::StartApResultCode::Success)));
}
#[test]
fn get_ap_sme_not_found() {
let mut _exec = fasync::Executor::new().expect("Failed to create an executor");
let (iface_map, _iface_map_events) = IfaceMap::new();
let iface_map = Arc::new(iface_map);
let (_proxy, server) = create_proxy().expect("failed to create a pair of SME endpoints");
assert_eq!(zx::Status::NOT_FOUND, super::get_ap_sme(&iface_map, 10, server));
}
#[test]
fn get_ap_sme_wrong_role() {
let mut _exec = fasync::Executor::new().expect("Failed to create an executor");
let (iface_map, _iface_map_events) = IfaceMap::new();
let iface_map = Arc::new(iface_map);
let iface = fake_client_iface();
iface_map.insert(10, iface.iface);
let (_proxy, server) = create_proxy().expect("failed to create a pair of SME endpoints");
assert_eq!(zx::Status::NOT_SUPPORTED, super::get_ap_sme(&iface_map, 10, server));
}
#[test]
fn test_set_country() {
// Setup environment
let mut exec = fasync::Executor::new().expect("Failed to create an executor");
let (phy_map, _phy_map_events) = PhyMap::new();
let phy_map = Arc::new(phy_map);
let (phy, mut phy_stream) = fake_phy("/dev/null");
let phy_id = 10u16;
phy_map.insert(phy_id, phy);
let alpha2 = fake_alpha2();
// Initiate a QueryPhy request. The returned future should not be able
// to produce a result immediately
// Issue service.fidl::SetCountryRequest()
let req_msg = fidl_svc::SetCountryRequest { phy_id, alpha2: alpha2.clone() };
let req_fut = super::set_country(&phy_map, req_msg);
pin_mut!(req_fut);
assert_eq!(Poll::Pending, exec.run_until_stalled(&mut req_fut));
assert_variant!(exec.run_until_stalled(&mut phy_stream.next()),
Poll::Ready(Some(Ok(PhyRequest::SetCountry { req, responder }))) => {
assert_eq!(req.alpha2, alpha2.clone());
// Pretend to be a WLAN PHY to return the result.
responder.send(zx::Status::OK.into_raw())
.expect("failed to send the response to SetCountry");
}
);
// req_fut should have completed by now. Test the result.
assert_eq!(exec.run_until_stalled(&mut req_fut), Poll::Ready(zx::Status::OK));
}
#[test]
fn test_set_country_failure() {
// Setup environment
let mut exec = fasync::Executor::new().expect("Failed to create an executor");
let (phy_map, _phy_map_events) = PhyMap::new();
let phy_map = Arc::new(phy_map);
let (phy, mut phy_stream) = fake_phy("/dev/null");
let phy_id = 10u16;
phy_map.insert(phy_id, phy);
let alpha2 = fake_alpha2();
// Initiate a QueryPhy request. The returned future should not be able
// to produce a result immediately
// Issue service.fidl::SetCountryRequest()
let req_msg = fidl_svc::SetCountryRequest { phy_id, alpha2: alpha2.clone() };
let req_fut = super::set_country(&phy_map, req_msg);
pin_mut!(req_fut);
assert_eq!(Poll::Pending, exec.run_until_stalled(&mut req_fut));
let (req, responder) = assert_variant!(exec.run_until_stalled(&mut phy_stream.next()),
Poll::Ready(Some(Ok(PhyRequest::SetCountry { req, responder }))) => (req, responder)
);
assert_eq!(req.alpha2, alpha2.clone());
// Failure case #1: WLAN PHY not responding
assert_eq!(Poll::Pending, exec.run_until_stalled(&mut req_fut));
// Failure case #2: WLAN PHY has not implemented the feature.
assert_eq!(Poll::Pending, exec.run_until_stalled(&mut req_fut));
let resp = zx::Status::NOT_SUPPORTED.into_raw();
responder.send(resp).expect("failed to send the response to SetCountry");
assert_eq!(Poll::Ready(zx::Status::NOT_SUPPORTED), exec.run_until_stalled(&mut req_fut));
}
#[test]
fn test_get_country() {
// Setup environment
let mut exec = fasync::Executor::new().expect("Failed to create an executor");
let (phy_map, _phy_map_events) = PhyMap::new();
let phy_map = Arc::new(phy_map);
let (phy, mut phy_stream) = fake_phy("/dev/null");
let phy_id = 10u16;
phy_map.insert(phy_id, phy);
let alpha2 = fake_alpha2();
// Initiate a QueryPhy request. The returned future should not be able
// to produce a result immediately
// Issue service.fidl::SetCountryRequest()
let req_fut = super::get_country(&phy_map, phy_id);
pin_mut!(req_fut);
assert_eq!(Poll::Pending, exec.run_until_stalled(&mut req_fut));
assert_variant!(exec.run_until_stalled(&mut phy_stream.next()),
Poll::Ready(Some(Ok(PhyRequest::GetCountry { responder }))) => {
// Pretend to be a WLAN PHY to return the result.
responder.send(
&mut Ok(fidl_wlan_dev::CountryCode { alpha2 })
).expect("failed to send the response to SetCountry");
}
);
assert_eq!(
exec.run_until_stalled(&mut req_fut),
Poll::Ready(Ok(fidl_svc::GetCountryResponse { alpha2 }))
);
}
#[test]
fn test_get_country_failure() {
// Setup environment
let mut exec = fasync::Executor::new().expect("Failed to create an executor");
let (phy_map, _phy_map_events) = PhyMap::new();
let phy_map = Arc::new(phy_map);
let (phy, mut phy_stream) = fake_phy("/dev/null");
let phy_id = 10u16;
phy_map.insert(phy_id, phy);
// Initiate a QueryPhy request. The returned future should not be able
// to produce a result immediately
// Issue service.fidl::GetCountryRequest()
let req_fut = super::get_country(&phy_map, phy_id);
pin_mut!(req_fut);
assert_eq!(Poll::Pending, exec.run_until_stalled(&mut req_fut));
assert_variant!(exec.run_until_stalled(&mut phy_stream.next()),
Poll::Ready(Some(Ok(PhyRequest::GetCountry { responder }))) => {
// Pretend to be a WLAN PHY to return the result.
// Right now the returned country code is not optional, so we just return garbage.
responder.send(&mut Err(zx::Status::NOT_SUPPORTED.into_raw()))
.expect("failed to send the response to SetCountry");
}
);
assert_variant!(exec.run_until_stalled(&mut req_fut), Poll::Ready(Err(_)));
}
#[test]
fn test_clear_country() {
// Setup environment
let mut exec = fasync::Executor::new().expect("Failed to create an executor");
let (phy_map, _phy_map_events) = PhyMap::new();
let phy_map = Arc::new(phy_map);
let (phy, mut phy_stream) = fake_phy("/dev/null");
let phy_id = 10u16;
phy_map.insert(phy_id, phy);
// Initiate a QueryPhy request. The returned future should not be able
// to produce a result immediately
// Issue service.fidl::ClearCountryRequest()
let req_msg = fidl_svc::ClearCountryRequest { phy_id };
let req_fut = super::clear_country(&phy_map, req_msg);
pin_mut!(req_fut);
assert_eq!(Poll::Pending, exec.run_until_stalled(&mut req_fut));
assert_variant!(exec.run_until_stalled(&mut phy_stream.next()),
Poll::Ready(Some(Ok(PhyRequest::ClearCountry { responder }))) => {
// Pretend to be a WLAN PHY to return the result.
responder.send(zx::Status::OK.into_raw())
.expect("failed to send the response to ClearCountry");
}
);
// req_fut should have completed by now. Test the result.
assert_eq!(exec.run_until_stalled(&mut req_fut), Poll::Ready(zx::Status::OK));
}
#[test]
fn test_clear_country_failure() {
// Setup environment
let mut exec = fasync::Executor::new().expect("Failed to create an executor");
let (phy_map, _phy_map_events) = PhyMap::new();
let phy_map = Arc::new(phy_map);
let (phy, mut phy_stream) = fake_phy("/dev/null");
let phy_id = 10u16;
phy_map.insert(phy_id, phy);
// Initiate a QueryPhy request. The returned future should not be able
// to produce a result immediately
// Issue service.fidl::ClearCountryRequest()
let req_msg = fidl_svc::ClearCountryRequest { phy_id };
let req_fut = super::clear_country(&phy_map, req_msg);
pin_mut!(req_fut);
assert_eq!(Poll::Pending, exec.run_until_stalled(&mut req_fut));
let responder = assert_variant!(exec.run_until_stalled(&mut phy_stream.next()),
Poll::Ready(Some(Ok(PhyRequest::ClearCountry { responder }))) => responder
);
// Failure case #1: WLAN PHY not responding
assert_eq!(Poll::Pending, exec.run_until_stalled(&mut req_fut));
// Failure case #2: WLAN PHY has not implemented the feature.
assert_eq!(Poll::Pending, exec.run_until_stalled(&mut req_fut));
let resp = zx::Status::NOT_SUPPORTED.into_raw();
responder.send(resp).expect("failed to send the response to ClearCountry");
assert_eq!(Poll::Ready(zx::Status::NOT_SUPPORTED), exec.run_until_stalled(&mut req_fut));
}
fn setup_create_iface_test() -> (
fasync::Executor,
BoxFuture<'static, Result<(), anyhow::Error>>,
BoxFuture<'static, Result<(i32, Option<Box<fidl_svc::CreateIfaceResponse>>), fidl::Error>>,
impl Future<Output = Result<void::Void, anyhow::Error>>,
fidl_wlan_dev::CreateIfaceRequest,
) {
let fake_phy_id = 10;
let mut exec = fasync::Executor::new().expect("Failed to create an executor");
let (phys, phy_events) = device::PhyMap::new();
let (ifaces, iface_events) = device::IfaceMap::new();
let iface_counter = Arc::new(IfaceCounter::new());
let cfg: ServiceCfg = argh::from_env();
let phys = Arc::new(phys);
let ifaces = Arc::new(ifaces);
let (watcher_service, watcher_fut) =
watcher_service::serve_watchers(phys.clone(), ifaces.clone(), phy_events, iface_events);
// Insert a fake PHY
let (phy, mut phy_stream) = fake_phy("/dev/null");
phys.insert(fake_phy_id, phy);
// Create a CobaltSender with a dangling receiver end.
let (cobalt_sender, _cobalt_receiver) = mpsc::channel(1);
let cobalt_sender = CobaltSender::new(cobalt_sender);
// Create an inspector, but don't serve.
let inspect_tree = Arc::new(inspect::WlanstackTree::new(Inspector::new()));
let (proxy, marker) =
create_proxy::<fidl_svc::DeviceServiceMarker>().expect("failed to create proxy");
let req_stream = marker.into_stream().expect("could not create request stream");
let fut = serve_device_requests(
iface_counter,
cfg,
phys,
ifaces,
watcher_service,
req_stream,
inspect_tree,
cobalt_sender,
);
let mut fut = Box::pin(fut);
// Make the CreateIface request
let mut create_iface_request = fidl_svc::CreateIfaceRequest {
phy_id: fake_phy_id,
role: fidl_wlan_dev::MacRole::Ap,
mac_addr: None,
};
let create_iface_fut = proxy.create_iface(&mut create_iface_request);
let mut create_iface_fut = Box::pin(create_iface_fut);
assert_variant!(exec.run_until_stalled(&mut create_iface_fut), Poll::Pending);
// Advance the server so that it gets the CreateIfaceRequest
assert_variant!(exec.run_until_stalled(&mut fut), Poll::Pending);
// There should be a pending CreateIfaceRequest. Send it a response and capture its request
// so that the MLME channel associated with the request can be used to inject a successful
// MLME response when the PHY's information is queried.
assert_variant!(exec.run_until_stalled(&mut fut), Poll::Pending);
let (phy_create_iface_req, responder) = assert_variant!(
exec.run_until_stalled(&mut phy_stream.next()),
Poll::Ready(Some(Ok(PhyRequest::CreateIface { req, responder }))) => (req, responder)
);
responder
.send(&mut fidl_wlan_dev::CreateIfaceResponse { status: zx::sys::ZX_OK, iface_id: 0 })
.expect("failed to send CreateIfaceResponse");
(exec, fut, create_iface_fut, watcher_fut, phy_create_iface_req)
}
#[test]
fn test_query_device_info_succeeds() {
let (mut exec, mut fut, mut create_iface_fut, _watcher_fut, phy_create_iface_req) =
setup_create_iface_test();
// Use the channel that is included in the CreateIfaceRequest to create an MLME request
// stream.
let mlme_channel =
phy_create_iface_req.sme_channel.expect("no mlme stream found in iface request");
let mut mlme_stream = ServerEnd::<fidl_mlme::MlmeMarker>::new(mlme_channel)
.into_stream()
.expect("could not create MLME event stream");
// Run the server's future so that it can query device information.
assert_variant!(exec.run_until_stalled(&mut fut), Poll::Pending);
assert_variant!(
exec.run_until_stalled(&mut mlme_stream.next()),
Poll::Ready(Some(Ok(fidl_mlme::MlmeRequest::QueryDeviceInfo{ responder } ))) => {
assert!(responder.send(&mut fake_device_info()).is_ok());
}
);
// Run the query future to completion and expect an Ok result.
assert_variant!(exec.run_until_stalled(&mut fut), Poll::Pending);
assert_variant!(
exec.run_until_stalled(&mut create_iface_fut),
Poll::Ready(Ok((status, Some(response)))) => {
assert_eq!(status, zx::sys::ZX_OK);
assert_eq!(*response, fidl_svc::CreateIfaceResponse { iface_id: 0 });
}
);
}
#[test]
fn test_query_device_info_fails() {
// Drop the CreateIfaceRequest to terminate the serving end of the MLME transaction.
let (mut exec, mut fut, mut create_iface_fut, _watcher_fut, create_iface_req) =
setup_create_iface_test();
drop(create_iface_req);
// Run the server's future so that it can fail to query the device information.
assert_variant!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
assert_variant!(
exec.run_until_stalled(&mut create_iface_fut),
Poll::Ready(Ok((zx::sys::ZX_ERR_PEER_CLOSED, None)))
);
}
fn fake_destroy_iface_env(phy_map: &mut PhyMap, iface_map: &mut IfaceMap) -> PhyRequestStream {
let (phy, phy_stream) = fake_phy("/dev/null");
phy_map.insert(10, phy);
// Insert device which does not support destruction.
let iface = fake_client_iface();
iface_map.insert(10, iface.iface);
// Insert device which does support destruction.
let iface = fake_client_iface();
let iface = FakeClientIface {
iface: IfaceDevice {
phy_ownership: device::PhyOwnership { phy_id: 10, phy_assigned_id: 13 },
..iface.iface
},
..iface
};
iface_map.insert(42, iface.iface);
phy_stream
}
fn fake_phy(path: &str) -> (PhyDevice, PhyRequestStream) {
let (proxy, server) =
create_proxy::<fidl_wlan_dev::PhyMarker>().expect("fake_phy: create_proxy() failed");
let device = wlan_dev::RealDeviceEnv::device_from_path(path)
.expect(&format!("fake_phy: failed to open {}", path));
let stream = server.into_stream().expect("fake_phy: failed to create stream");
(PhyDevice { proxy, device }, stream)
}
struct FakeClientIface<St: Stream<Item = StatsRequest>> {
iface: IfaceDevice,
_stats_requests: St,
new_sme_clients: mpsc::UnboundedReceiver<station::client::Endpoint>,
}
fn fake_client_iface() -> FakeClientIface<impl Stream<Item = StatsRequest>> {
let (sme_sender, sme_receiver) = mpsc::unbounded();
let (stats_sched, stats_requests) = stats_scheduler::create_scheduler();
let (proxy, _server) = create_proxy::<MlmeMarker>().expect("Error creating proxy");
let (shutdown_sender, _) = mpsc::channel(1);
let mlme_query = MlmeQueryProxy::new(proxy);
let device_info = fake_device_info();
let iface = IfaceDevice {
phy_ownership: device::PhyOwnership { phy_id: 0, phy_assigned_id: 0 },
sme_server: device::SmeServer::Client(sme_sender),
stats_sched,
mlme_query,
device_info,
shutdown_sender,
};
FakeClientIface { iface, _stats_requests: stats_requests, new_sme_clients: sme_receiver }
}
struct FakeApIface<St: Stream<Item = StatsRequest>> {
iface: IfaceDevice,
_stats_requests: St,
new_sme_clients: mpsc::UnboundedReceiver<station::ap::Endpoint>,
}
fn fake_ap_iface() -> FakeApIface<impl Stream<Item = StatsRequest>> {
let (sme_sender, sme_receiver) = mpsc::unbounded();
let (stats_sched, stats_requests) = stats_scheduler::create_scheduler();
let (proxy, _server) = create_proxy::<MlmeMarker>().expect("Error creating proxy");
let mlme_query = MlmeQueryProxy::new(proxy);
let (shutdown_sender, _) = mpsc::channel(1);
let device_info = fake_device_info();
let iface = IfaceDevice {
phy_ownership: device::PhyOwnership { phy_id: 0, phy_assigned_id: 0 },
sme_server: device::SmeServer::Ap(sme_sender),
stats_sched,
mlme_query,
device_info,
shutdown_sender,
};
FakeApIface { iface, _stats_requests: stats_requests, new_sme_clients: sme_receiver }
}
fn fake_phy_info() -> fidl_wlan_dev::PhyInfo {
fidl_wlan_dev::PhyInfo {
id: 10,
dev_path: Some("/dev/null".to_string()),
hw_mac_address: [0x67, 0x62, 0x6f, 0x6e, 0x69, 0x6b],
supported_phys: Vec::new(),
driver_features: Vec::new(),
mac_roles: Vec::new(),
caps: Vec::new(),
bands: Vec::new(),
}
}
fn fake_device_info() -> fidl_mlme::DeviceInfo {
fidl_mlme::DeviceInfo {
role: fidl_mlme::MacRole::Client,
bands: vec![],
mac_addr: [0xAC; 6],
driver_features: vec![],
qos_capable: false,
}
}
fn fake_scan_request() -> fidl_sme::ScanRequest {
fidl_sme::ScanRequest::Passive(fidl_sme::PassiveScanRequest {})
}
fn fake_ap_config() -> fidl_sme::ApConfig {
fidl_sme::ApConfig {
ssid: b"qwerty".to_vec(),
password: vec![],
radio_cfg: RadioConfig::new(Phy::Ht, Cbw::Cbw20, 6).to_fidl(),
}
}
fn fake_alpha2() -> [u8; 2] {
let mut alpha2: [u8; 2] = [0, 0];
alpha2.copy_from_slice("MX".as_bytes());
alpha2
}
}