sl4f_lib/wlan_policy/
ap_facade.rsuse crate::wlan_policy::types::AccessPointState;
use anyhow::Error;
use fidl::endpoints::{create_endpoints, create_proxy};
use fidl_fuchsia_wlan_policy::{
AccessPointControllerMarker, AccessPointControllerProxy, AccessPointListenerMarker,
AccessPointProviderMarker, AccessPointStateUpdatesMarker, AccessPointStateUpdatesRequestStream,
ConnectivityMode, Credential, NetworkConfig, NetworkIdentifier, OperatingBand, OperatingState,
RequestStatus, SecurityType,
};
use fuchsia_component::client::connect_to_protocol;
use futures::TryStreamExt;
use std::cell::Cell;
use std::fmt::{self, Debug};
pub struct WlanApPolicyFacade {
ap_controller: AccessPointControllerProxy,
update_listener: Cell<Option<AccessPointStateUpdatesRequestStream>>,
}
impl Debug for WlanApPolicyFacade {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let listener = self.update_listener.take();
let update_listener =
if listener.is_some() { "Some(AccessPointStateUpdatesRequestStream)" } else { "None" }
.to_string();
self.update_listener.set(listener);
f.debug_struct("WlanApPolicyFacade")
.field("controller", &self.ap_controller)
.field("update_listener", &update_listener)
.finish()
}
}
impl WlanApPolicyFacade {
pub fn new() -> Result<WlanApPolicyFacade, Error> {
let policy_provider = connect_to_protocol::<AccessPointProviderMarker>()?;
let (ap_controller, server_end) = create_proxy::<AccessPointControllerMarker>();
let (update_client_end, update_listener) =
create_endpoints::<AccessPointStateUpdatesMarker>();
let () = policy_provider.get_controller(server_end, update_client_end)?;
let update_stream = update_listener.into_stream();
Ok(WlanApPolicyFacade { ap_controller, update_listener: Cell::new(Some(update_stream)) })
}
pub async fn start_access_point(
&self,
target_ssid: Vec<u8>,
type_: SecurityType,
credential: Credential,
mode: ConnectivityMode,
band: OperatingBand,
) -> Result<(), Error> {
let listener = connect_to_protocol::<AccessPointListenerMarker>()?;
let (client_end, server_end) = create_endpoints::<AccessPointStateUpdatesMarker>();
listener.get_listener(client_end)?;
let mut server_stream = server_end.into_stream();
match server_stream.try_next().await? {
Some(update) => {
let update = update.into_on_access_point_state_update();
let (_, responder) = match update {
Some((update, responder)) => (update, responder),
None => return Err(format_err!("AP provider produced invalid update.")),
};
let _ = responder.send();
}
None => return Err(format_err!("initial steam already busted")),
}
let network_id = NetworkIdentifier { ssid: target_ssid.clone(), type_: type_ };
match self
.ap_controller
.start_access_point(
&NetworkConfig {
id: Some(network_id),
credential: Some(credential),
..Default::default()
},
mode,
band,
)
.await?
{
RequestStatus::Acknowledged => {}
RequestStatus::RejectedNotSupported => {
return Err(format_err!("failed to start AP (not supported)"))
}
RequestStatus::RejectedIncompatibleMode => {
return Err(format_err!("failed to start AP (incompatible mode)"))
}
RequestStatus::RejectedAlreadyInUse => {
return Err(format_err!("failed to start AP (already in use)"))
}
RequestStatus::RejectedDuplicateRequest => {
return Err(format_err!("failed to start AP (duplicate request)"))
}
}
while let Some(update_request) = server_stream.try_next().await.unwrap() {
let update = update_request.into_on_access_point_state_update();
let (updates, responder) = match update {
Some((update, responder)) => (update, responder),
None => return Err(format_err!("AP provider produced invalid update.")),
};
let _ = responder.send();
for update in updates {
match update.state {
Some(state) => match state {
OperatingState::Failed => {
return Err(format_err!("Failed to start AP."));
}
OperatingState::Starting => {
continue;
}
OperatingState::Active => return Ok(()),
},
None => continue,
}
}
}
return Err(format_err!("AP update stream failed unexpectedly"));
}
pub async fn stop_access_point(
&self,
target_ssid: Vec<u8>,
type_: SecurityType,
credential: Credential,
) -> Result<(), Error> {
let network_id = NetworkIdentifier { ssid: target_ssid.clone(), type_: type_ };
match self
.ap_controller
.stop_access_point(&NetworkConfig {
id: Some(network_id),
credential: Some(credential),
..Default::default()
})
.await?
{
RequestStatus::Acknowledged => Ok(()),
RequestStatus::RejectedNotSupported => {
Err(format_err!("Failed to stop AP (not supported)"))
}
RequestStatus::RejectedIncompatibleMode => {
Err(format_err!("Failed to stop AP (incompatible mode)"))
}
RequestStatus::RejectedAlreadyInUse => {
Err(format_err!("Failed to stop AP (already in use)"))
}
RequestStatus::RejectedDuplicateRequest => {
Err(format_err!("Failed to stop AP (duplicate request)"))
}
}
}
pub async fn stop_all_access_points(&self) -> Result<(), Error> {
self.ap_controller.stop_all_access_points()?;
Ok(())
}
fn init_listener() -> Result<AccessPointStateUpdatesRequestStream, Error> {
let listener = connect_to_protocol::<AccessPointListenerMarker>()?;
let (client_end, server_end) =
fidl::endpoints::create_endpoints::<AccessPointStateUpdatesMarker>();
listener.get_listener(client_end)?;
Ok(server_end.into_stream())
}
pub fn set_new_listener(&self) -> Result<(), Error> {
self.update_listener.set(Some(Self::init_listener()?));
Ok(())
}
pub async fn get_update(&self) -> Result<Vec<AccessPointState>, Error> {
let listener = self.update_listener.take();
let mut update_listener = if listener.is_none() {
Self::init_listener()
} else {
listener.ok_or_else(|| format_err!("failed to set update listener of facade"))
}?;
if let Some(update_request) = update_listener.try_next().await? {
let update = update_request.into_on_access_point_state_update();
let (update, responder) = match update {
Some((update, responder)) => (update, responder),
None => return Err(format_err!("Client provider produced invalid update.")).into(),
};
responder.send().map_err(|e| format_err!("failed to ack update: {}", e))?;
self.update_listener.set(Some(update_listener));
let update = update.into_iter().map(|update| AccessPointState::from(update)).collect();
Ok(update)
} else {
self.update_listener.set(Some(update_listener));
Err(format_err!("update listener's next update is None"))
}
}
}