1use crate::{ap as ap_sme, MlmeEventStream, MlmeSink, MlmeStream};
6use fuchsia_sync::Mutex;
7use futures::channel::mpsc;
8use futures::prelude::*;
9use futures::select;
10use ieee80211::Ssid;
11use log::error;
12use std::pin::pin;
13use std::sync::Arc;
14use wlan_common::RadioConfig;
15use {fidl_fuchsia_wlan_mlme as fidl_mlme, fidl_fuchsia_wlan_sme as fidl_sme};
16
17pub type Endpoint = fidl::endpoints::ServerEnd<fidl_sme::ApSmeMarker>;
18type Sme = ap_sme::ApSme;
19
20pub fn serve(
21 device_info: fidl_mlme::DeviceInfo,
22 event_stream: MlmeEventStream,
23 new_fidl_clients: mpsc::UnboundedReceiver<Endpoint>,
24) -> (MlmeSink, MlmeStream, impl Future<Output = Result<(), anyhow::Error>>) {
25 let (sme, mlme_sink, mlme_stream, time_stream) = Sme::new(device_info);
26 let fut = async move {
27 let sme = Arc::new(Mutex::new(sme));
28 let mlme_sme = super::serve_mlme_sme(event_stream, Arc::clone(&sme), time_stream);
29 let sme_fidl = super::serve_fidl(&*sme, new_fidl_clients, handle_fidl_request);
30 let mlme_sme = pin!(mlme_sme);
31 let sme_fidl = pin!(sme_fidl);
32 select! {
33 mlme_sme = mlme_sme.fuse() => mlme_sme?,
34 sme_fidl = sme_fidl.fuse() => match sme_fidl? {},
35 }
36 Ok(())
37 };
38 (mlme_sink, mlme_stream, fut)
39}
40
41async fn handle_fidl_request(
42 sme: &Mutex<Sme>,
43 request: fidl_sme::ApSmeRequest,
44) -> Result<(), ::fidl::Error> {
45 match request {
46 fidl_sme::ApSmeRequest::Start { config, responder } => {
47 let r = start(sme, config).await;
48 responder.send(r)?;
49 }
50 fidl_sme::ApSmeRequest::Stop { responder } => {
51 let r = stop(sme).await;
52 responder.send(r)?;
53 }
54 fidl_sme::ApSmeRequest::Status { responder } => {
55 let r = status(sme);
56 responder.send(&r)?;
57 }
58 }
59 Ok(())
60}
61
62async fn start(sme: &Mutex<Sme>, config: fidl_sme::ApConfig) -> fidl_sme::StartApResultCode {
63 let radio_cfg = match RadioConfig::try_from(config.radio_cfg) {
64 Ok(radio_cfg) => radio_cfg,
65 Err(e) => {
66 error!("Could not convert RadioConfig from ApConfig: {:?}", e);
67 return fidl_sme::StartApResultCode::InternalError;
68 }
69 };
70
71 let sme_config = ap_sme::Config {
72 ssid: Ssid::from_bytes_unchecked(config.ssid),
73 password: config.password,
74 radio_cfg,
75 };
76
77 let receiver = sme.lock().on_start_command(sme_config);
78 let r = receiver.await.unwrap_or_else(|_| {
79 error!("Responder for AP Start command was dropped without sending a response");
80 ap_sme::StartResult::InternalError
81 });
82
83 match r {
84 ap_sme::StartResult::Success => fidl_sme::StartApResultCode::Success,
85 ap_sme::StartResult::AlreadyStarted => fidl_sme::StartApResultCode::AlreadyStarted,
86 ap_sme::StartResult::InternalError => fidl_sme::StartApResultCode::InternalError,
87 ap_sme::StartResult::Canceled => fidl_sme::StartApResultCode::Canceled,
88 ap_sme::StartResult::TimedOut => fidl_sme::StartApResultCode::TimedOut,
89 ap_sme::StartResult::PreviousStartInProgress => {
90 fidl_sme::StartApResultCode::PreviousStartInProgress
91 }
92 ap_sme::StartResult::InvalidArguments(e) => {
93 error!("Invalid arguments for AP start: {}", e);
94 fidl_sme::StartApResultCode::InvalidArguments
95 }
96 }
97}
98
99async fn stop(sme: &Mutex<Sme>) -> fidl_sme::StopApResultCode {
100 let receiver = sme.lock().on_stop_command();
101 receiver.await.unwrap_or_else(|_| {
102 error!("Responder for AP Stop command was dropped without sending a response");
103 fidl_sme::StopApResultCode::InternalError
104 })
105}
106
107fn status(sme: &Mutex<Sme>) -> fidl_sme::ApStatusResponse {
108 fidl_sme::ApStatusResponse { running_ap: sme.lock().get_running_ap().map(Box::new) }
109}