| // 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 failure::{bail, format_err}; |
| use fidl::encoding::OutOfLine; |
| use fidl::endpoints::RequestStream; |
| 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}; |
| use fuchsia_async as fasync; |
| use fuchsia_zircon as zx; |
| use futures::channel::mpsc::UnboundedReceiver; |
| use futures::prelude::*; |
| use futures::select; |
| use futures::stream::FuturesUnordered; |
| use log::{error, info}; |
| use pin_utils::pin_mut; |
| use std::marker::Unpin; |
| use std::sync::Arc; |
| |
| use crate::device::{self, IfaceDevice, IfaceMap, PhyDevice, PhyMap}; |
| use crate::station; |
| use crate::stats_scheduler::StatsRef; |
| use crate::watchable_map::MapEvent; |
| use crate::watcher_service::{self, WatcherService}; |
| use crate::Never; |
| |
| const CONCURRENT_LIMIT: usize = 1000; |
| |
| pub async fn device_service<S>( |
| phys: Arc<PhyMap>, |
| ifaces: Arc<IfaceMap>, |
| phy_events: UnboundedReceiver<MapEvent<u16, PhyDevice>>, |
| iface_events: UnboundedReceiver<MapEvent<u16, IfaceDevice>>, |
| new_clients: S, |
| ) -> Result<Never, failure::Error> |
| where |
| S: Stream<Item = fasync::Channel> + Unpin, |
| { |
| let (watcher_service, watcher_fut) = |
| watcher_service::serve_watchers(phys.clone(), ifaces.clone(), phy_events, iface_events); |
| pin_mut!(watcher_fut); |
| let mut watcher_fut = watcher_fut.fuse(); |
| let mut active_clients = FuturesUnordered::new(); |
| let mut new_clients = new_clients.fuse(); |
| loop { |
| select! { |
| watcher_res = watcher_fut => watcher_res |
| .map_err(|e| format_err!("watcher service has failed: {}", e))?.into_any(), |
| () = active_clients.select_next_some() => {}, |
| new_client = new_clients.next() => match new_client { |
| Some(channel) => { |
| active_clients.push(serve_channel( |
| Arc::clone(&phys), Arc::clone(&ifaces), watcher_service.clone(), channel)); |
| } |
| None => bail!("stream of new FIDL clients has ended unexpectedly"), |
| }, |
| } |
| } |
| } |
| |
| async fn serve_channel( |
| phys: Arc<PhyMap>, |
| ifaces: Arc<IfaceMap>, |
| watcher_service: WatcherService<PhyDevice, IfaceDevice>, |
| channel: fasync::Channel, |
| ) { |
| let r = await!(fidl_svc::DeviceServiceRequestStream::from_channel(channel) |
| .try_for_each_concurrent(CONCURRENT_LIMIT, move |request| handle_fidl_request( |
| request, |
| Arc::clone(&phys), |
| Arc::clone(&ifaces), |
| watcher_service.clone() |
| ))); |
| r.unwrap_or_else(|e| error!("error serving a DeviceService client: {}", e)) |
| } |
| |
| async fn handle_fidl_request( |
| request: fidl_svc::DeviceServiceRequest, |
| phys: Arc<PhyMap>, |
| ifaces: Arc<IfaceMap>, |
| watcher_service: WatcherService<PhyDevice, IfaceDevice>, |
| ) -> Result<(), fidl::Error> { |
| // 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 request { |
| DeviceServiceRequest::ListPhys { responder } => responder.send(&mut list_phys(&phys)), |
| DeviceServiceRequest::QueryPhy { req, responder } => { |
| let result = await!(query_phy(&phys, req.phy_id)); |
| let (status, mut response) = into_status_and_opt(result); |
| responder.send(status.into_raw(), response.as_mut().map(OutOfLine)) |
| } |
| 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().map(OutOfLine)) |
| } |
| DeviceServiceRequest::CreateIface { req, responder } => { |
| let result = await!(create_iface(&phys, req)); |
| let (status, mut response) = into_status_and_opt(result); |
| responder.send(status.into_raw(), response.as_mut().map(OutOfLine)) |
| } |
| DeviceServiceRequest::DestroyIface { req: _, responder: _ } => unimplemented!(), |
| 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 await!(get_iface_stats(&ifaces, iface_id)) { |
| Ok(stats_ref) => { |
| let mut stats = stats_ref.lock(); |
| responder.send(zx::sys::ZX_OK, Some(OutOfLine(&mut stats))) |
| } |
| Err(status) => responder.send(status.into_raw(), None), |
| } |
| } |
| DeviceServiceRequest::GetMinstrelList { iface_id, responder } => { |
| let (status, mut peers) = await!(list_minstrel_peers(&ifaces, iface_id)); |
| responder.send(status.into_raw(), &mut peers) |
| } |
| DeviceServiceRequest::GetMinstrelStats { iface_id, peer_addr, responder } => { |
| let (status, mut peer) = await!(get_minstrel_stats(&ifaces, iface_id, peer_addr)); |
| responder.send(status.into_raw(), peer.as_mut().map(|x| OutOfLine(x.as_mut()))) |
| } |
| DeviceServiceRequest::WatchDevices { watcher, control_handle: _ } => { |
| watcher_service |
| .add_watcher(watcher) |
| .unwrap_or_else(|e| error!("error registering a device watcher: {}", e)); |
| 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 = await!(phy.proxy.query()).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, |
| path: iface.device.path().to_string_lossy().into_owned(), |
| }) |
| .collect(); |
| fidl_svc::ListIfacesResponse { ifaces: list } |
| } |
| |
| 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 dev_path = iface.device.path().to_string_lossy().into_owned(); |
| let mac_addr = iface.device_info.mac_addr; |
| Ok(fidl_svc::QueryIfaceResponse { role, id, dev_path, mac_addr }) |
| } |
| |
| async fn create_iface( |
| phys: &PhyMap, |
| req: fidl_svc::CreateIfaceRequest, |
| ) -> Result<fidl_svc::CreateIfaceResponse, zx::Status> { |
| let phy = phys.get(&req.phy_id).ok_or(zx::Status::NOT_FOUND)?; |
| let mut phy_req = fidl_wlan_dev::CreateIfaceRequest { role: req.role }; |
| let r = await!(phy.proxy.create_iface(&mut phy_req)).map_err(move |e| { |
| error!("Error sending 'CreateIface' request to phy #{}: {}", req.phy_id, e); |
| zx::Status::INTERNAL |
| })?; |
| zx::Status::ok(r.status)?; |
| // TODO(gbonik): this is not the ID that we want to return |
| Ok(fidl_svc::CreateIfaceResponse { iface_id: r.iface_id }) |
| } |
| |
| 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 |
| } |
| } |
| } |
| |
| 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)?; |
| await!(iface.stats_sched.get_stats()) |
| } |
| |
| 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 await!(iface.mlme_query.get_minstrel_list()) { |
| 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 await!(iface.mlme_query.get_minstrel_peer(mac_addr)) { |
| Ok(MinstrelStatsResponse { peer }) => (zx::Status::OK, peer), |
| Err(_) => (zx::Status::INTERNAL, None), |
| } |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use super::*; |
| |
| use fidl::endpoints::create_proxy; |
| use fidl_fuchsia_wlan_common as fidl_common; |
| 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_wlan_dev as wlan_dev; |
| use futures::channel::mpsc; |
| use futures::task::Poll; |
| use pin_utils::pin_mut; |
| |
| use crate::{ |
| mlme_query_proxy::MlmeQueryProxy, |
| stats_scheduler::{self, StatsRequest}, |
| }; |
| |
| #[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 = match exec.run_until_stalled(&mut phy_stream.next()) { |
| Poll::Ready(Some(Ok(PhyRequest::Query { responder }))) => responder, |
| _ => panic!("phy_stream returned unexpected result"), |
| }; |
| |
| // 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 = match exec.run_until_stalled(&mut query_fut) { |
| Poll::Ready(Ok(response)) => response, |
| other => panic!("query_fut returned unexpected result: {:?}", other), |
| }; |
| 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("/dev/null"); |
| let iface_zero = fake_client_iface("/dev/zero"); |
| 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, path: "/dev/null".to_string() }, |
| IfaceListItem { iface_id: 20u16, path: "/dev/zero".to_string() }, |
| ], |
| 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("/dev/null"); |
| 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); |
| assert_eq!(response.dev_path, "/dev/null"); |
| } |
| |
| #[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_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 CreateIface request. The returned future should not be able |
| // to produce a result immediately |
| let create_fut = super::create_iface( |
| &phy_map, |
| fidl_svc::CreateIfaceRequest { phy_id: 10, role: fidl_wlan_dev::MacRole::Client }, |
| ); |
| pin_mut!(create_fut); |
| assert_eq!(Poll::Pending, exec.run_until_stalled(&mut create_fut)); |
| |
| // The call above should trigger a CreateIface message to the phy. |
| // Pretend that we are the phy and read the message from the other side. |
| let (req, responder) = match exec.run_until_stalled(&mut phy_stream.next()) { |
| Poll::Ready(Some(Ok(PhyRequest::CreateIface { req, responder }))) => (req, responder), |
| _ => panic!("phy_stream returned unexpected result"), |
| }; |
| |
| // 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 we created an interface device with id 123 and send a response |
| responder |
| .send(&mut fidl_wlan_dev::CreateIfaceResponse { status: zx::sys::ZX_OK, iface_id: 123 }) |
| .expect("failed to send CreateIfaceResponse"); |
| |
| // Now, our original future should resolve into a response |
| let response = match exec.run_until_stalled(&mut create_fut) { |
| Poll::Ready(Ok(response)) => response, |
| other => panic!("create_fut returned unexpected result: {:?}", other), |
| }; |
| // This assertion likely needs to change once we figure out a solution |
| // to the iface id problem. |
| assert_eq!(123, response.iface_id); |
| } |
| |
| #[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 fut = super::create_iface( |
| &phy_map, |
| fidl_svc::CreateIfaceRequest { phy_id: 10, role: fidl_wlan_dev::MacRole::Client }, |
| ); |
| pin_mut!(fut); |
| assert_eq!(Poll::Ready(Err(zx::Status::NOT_FOUND)), exec.run_until_stalled(&mut fut)); |
| } |
| |
| #[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("/dev/null"); |
| 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"); |
| |
| let req = match exec.run_until_stalled(&mut sme_stream.next()) { |
| Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan { req, .. }))) => req, |
| _ => panic!("sme_stream returned unexpected result"), |
| }; |
| 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("/dev/null"); |
| 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("/dev/null"); |
| 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()); |
| |
| match 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"); |
| } |
| _ => panic!("sme_stream returned unexpected result"), |
| }; |
| match exec.run_until_stalled(&mut fut) { |
| Poll::Ready(Ok(fidl_sme::StartApResultCode::Success)) => {} |
| other => panic!("expected a successful response, got {:?}", other), |
| } |
| } |
| |
| #[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("/dev/null"); |
| 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)); |
| } |
| |
| 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::Device::new(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(path: &str) -> FakeClientIface<impl Stream<Item = StatsRequest>> { |
| let device = wlan_dev::Device::new(path) |
| .expect(&format!("fake_client_iface: failed to open {}", path)); |
| 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 device_info = fake_device_info(); |
| let iface = IfaceDevice { |
| sme_server: device::SmeServer::Client(sme_sender), |
| stats_sched, |
| device, |
| mlme_query, |
| device_info, |
| }; |
| 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(path: &str) -> FakeApIface<impl Stream<Item = StatsRequest>> { |
| let device = wlan_dev::Device::new(path) |
| .expect(&format!("fake_client_iface: failed to open {}", path)); |
| 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 device_info = fake_device_info(); |
| let iface = IfaceDevice { |
| sme_server: device::SmeServer::Ap(sme_sender), |
| stats_sched, |
| device, |
| mlme_query, |
| device_info, |
| }; |
| 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], |
| } |
| } |
| |
| fn fake_scan_request() -> fidl_sme::ScanRequest { |
| fidl_sme::ScanRequest { timeout: 41, scan_type: fidl_common::ScanType::Passive } |
| } |
| |
| fn fake_ap_config() -> fidl_sme::ApConfig { |
| fidl_sme::ApConfig { ssid: b"qwerty".to_vec(), password: vec![], channel: 6 } |
| } |
| } |