blob: 931636ebea52ac4f38b98a120ff66ec8e926507f [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 crate::wlan::types::{ClientStatusResponse, MacRole, QueryIfaceResponse};
use anyhow::{Context as _, Error};
use fidl_fuchsia_wlan_device;
use fidl_fuchsia_wlan_device_service::{DeviceServiceMarker, DeviceServiceProxy};
use fidl_fuchsia_wlan_internal as fidl_internal;
use fuchsia_component::client::connect_to_service;
use fuchsia_zircon as zx;
use parking_lot::RwLock;
use std::collections::HashMap;
// WlanFacade: proxies commands from sl4f test to proper fidl APIs
//
// This object is shared among all threads created by server. The inner object is the facade
// itself. Callers interact with a wrapped version of the facade that enforces read/write
// protection.
//
// Use: Create once per server instantiation.
#[derive(Debug)]
struct InnerWlanFacade {
scan_results: bool,
}
#[derive(Debug)]
pub struct WlanFacade {
wlan_svc: DeviceServiceProxy,
inner: RwLock<InnerWlanFacade>,
}
impl WlanFacade {
pub fn new() -> Result<WlanFacade, Error> {
let wlan_svc = connect_to_service::<DeviceServiceMarker>()?;
Ok(WlanFacade { wlan_svc, inner: RwLock::new(InnerWlanFacade { scan_results: false }) })
}
/// Gets the list of wlan interface IDs.
pub async fn get_iface_id_list(&self) -> Result<Vec<u16>, Error> {
let wlan_iface_ids = wlan_service_util::get_iface_list(&self.wlan_svc)
.await
.context("Get Iface Id List: failed to get wlan iface list")?;
Ok(wlan_iface_ids)
}
/// Gets the list of wlan interface IDs.
pub async fn get_phy_id_list(&self) -> Result<Vec<u16>, Error> {
let wlan_phy_ids = wlan_service_util::get_phy_list(&self.wlan_svc)
.await
.context("Get Phy Id List: failed to get wlan phy list")?;
Ok(wlan_phy_ids)
}
pub async fn scan(&self) -> Result<Vec<String>, Error> {
// get the first client interface
let sme_proxy = wlan_service_util::client::get_first_sme(&self.wlan_svc)
.await
.context("Scan: failed to get client iface sme proxy")?;
// start the scan
let results =
wlan_service_util::client::passive_scan(&sme_proxy).await.context("Scan failed")?;
// send the ssids back to the test
let mut ssids = Vec::new();
for entry in &results {
let ssid = String::from_utf8_lossy(&entry.ssid).into_owned();
ssids.push(ssid);
}
Ok(ssids)
}
pub async fn scan_for_bss_info(
&self,
) -> Result<HashMap<Vec<u8>, Vec<Box<fidl_internal::BssDescription>>>, Error> {
// get the first client interface
let sme_proxy = wlan_service_util::client::get_first_sme(&self.wlan_svc)
.await
.context("Scan: failed to get client iface sme proxy")?;
// start the scan
let mut results =
wlan_service_util::client::passive_scan(&sme_proxy).await.context("Scan failed")?;
// send the bss descriptions back to the test
let mut hashmap = HashMap::new();
for bss in results.drain(..) {
if let Some(bss_desc) = bss.bss_desc {
let entry = hashmap.entry(bss.ssid).or_insert(vec![]);
entry.push(bss_desc);
}
}
Ok(hashmap)
}
pub async fn connect(
&self,
target_ssid: Vec<u8>,
target_pwd: Vec<u8>,
target_bss_desc: Option<Box<fidl_internal::BssDescription>>,
) -> Result<bool, Error> {
// get the first client interface
let sme_proxy = wlan_service_util::client::get_first_sme(&self.wlan_svc)
.await
.context("Connect: failed to get client iface sme proxy")?;
wlan_service_util::client::connect(&sme_proxy, target_ssid, target_pwd, target_bss_desc)
.await
}
/// Destroys a WLAN interface by input interface ID.
///
/// # Arguments
/// * `iface_id` - The u16 interface id.
pub async fn destroy_iface(&self, iface_id: u16) -> Result<(), Error> {
wlan_service_util::destroy_iface(&self.wlan_svc, iface_id)
.await
.context("Destroy: Failed to destroy iface")
}
pub async fn disconnect(&self) -> Result<(), Error> {
wlan_service_util::client::disconnect_all(&self.wlan_svc)
.await
.context("Disconnect: Failed to disconnect ifaces")
}
pub async fn status(&self) -> Result<ClientStatusResponse, Error> {
// get the first client interface
let sme_proxy = wlan_service_util::client::get_first_sme(&self.wlan_svc)
.await
.context("Status: failed to get iface sme proxy")?;
let rsp = sme_proxy.status().await.context("failed to get status from sme_proxy")?;
Ok(ClientStatusResponse::from(rsp))
}
pub async fn query_iface(&self, iface_id: u16) -> Result<QueryIfaceResponse, Error> {
let (status, iface_info) = self
.wlan_svc
.query_iface(iface_id)
.await
.context("Failed to query iface information")?;
zx::ok(status)?;
let iface_info = match iface_info {
Some(iface_info) => iface_info,
None => return Err(format_err!("no iface information for ID: {}", iface_id)),
};
let mac_role = match iface_info.role {
fidl_fuchsia_wlan_device::MacRole::Client => MacRole::Client,
fidl_fuchsia_wlan_device::MacRole::Ap => MacRole::Ap,
fidl_fuchsia_wlan_device::MacRole::Mesh => MacRole::Mesh,
};
Ok(QueryIfaceResponse {
role: mac_role,
id: iface_info.id,
phy_id: iface_info.phy_id,
phy_assigned_id: iface_info.phy_assigned_id,
mac_addr: iface_info.mac_addr,
})
}
}