1use anyhow::{Context as _, Error, format_err};
6use fidl::endpoints;
7
8use fidl_fuchsia_wlan_common::WlanMacRole;
9use fidl_fuchsia_wlan_device_service::DeviceMonitorProxy;
10use fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211;
11use fidl_fuchsia_wlan_sme as fidl_sme;
12use ieee80211::Ssid;
13
14type WlanService = DeviceMonitorProxy;
15
16pub async fn get_sme_proxy(
17 wlan_svc: &WlanService,
18 iface_id: u16,
19) -> Result<fidl_sme::ApSmeProxy, Error> {
20 let (sme_proxy, sme_remote) = endpoints::create_proxy();
21 let result = wlan_svc
22 .get_ap_sme(iface_id, sme_remote)
23 .await
24 .context("error sending GetApSme request")?;
25 match result {
26 Ok(()) => Ok(sme_proxy),
27 Err(e) => Err(format_err!(
28 "Failed to get AP sme proxy for interface id {} with error {}",
29 iface_id,
30 e
31 )),
32 }
33}
34
35pub async fn get_first_sme(wlan_svc: &WlanService) -> Result<fidl_sme::ApSmeProxy, Error> {
36 let iface_id =
37 super::get_first_iface(wlan_svc, WlanMacRole::Ap).await.context("failed to get iface")?;
38 get_sme_proxy(&wlan_svc, iface_id).await
39}
40
41pub async fn stop(
42 iface_sme_proxy: &fidl_sme::ApSmeProxy,
43) -> Result<fidl_sme::StopApResultCode, Error> {
44 let stop_ap_result_code = iface_sme_proxy.stop().await;
45
46 match stop_ap_result_code {
47 Ok(result_code) => Ok(result_code),
48 _ => Err(format_err!("AP stop failure: {:?}", stop_ap_result_code)),
49 }
50}
51
52pub async fn start(
53 iface_sme_proxy: &fidl_sme::ApSmeProxy,
54 target_ssid: Ssid,
55 target_pwd: Vec<u8>,
56 channel: u8,
57 band: fidl_ieee80211::WlanBand,
58) -> Result<fidl_sme::StartApResultCode, Error> {
59 let config = fidl_sme::ApConfig {
60 ssid: target_ssid.into(),
61 password: target_pwd,
62 radio_cfg: fidl_sme::RadioConfig {
63 phy: fidl_ieee80211::WlanPhyType::Ht,
64 primary: wlan_common::channel::Channel::new(
65 channel,
66 wlan_common::channel::Cbw::Cbw20,
67 band,
68 )
69 .into(),
70 bandwidth: fidl_ieee80211::ChannelBandwidth::Cbw20,
71 },
72 };
73 let start_ap_result_code = iface_sme_proxy.start(&config).await;
74
75 match start_ap_result_code {
76 Ok(result_code) => Ok(result_code),
77 _ => Err(format_err!("AP start failure: {:?}", start_ap_result_code)),
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use assert_matches::assert_matches;
85 use fidl_fuchsia_wlan_device_service::{
86 DeviceMonitorMarker, DeviceMonitorRequest, DeviceMonitorRequestStream,
87 };
88 use fidl_fuchsia_wlan_sme::{ApSmeMarker, ApSmeRequest, ApSmeRequestStream, StartApResultCode};
89 use fidl_ieee80211::WlanBand::TwoGhz;
90 use fuchsia_async as fasync;
91 use futures::stream::{StreamExt, StreamFuture};
92 use futures::task::Poll;
93 use ieee80211::Ssid;
94 use std::pin::pin;
95
96 #[test]
97 fn start_ap_success_returns_true() {
98 let start_ap_result = test_ap_start("TestAp", "", 6, TwoGhz, StartApResultCode::Success);
99 assert!(start_ap_result == StartApResultCode::Success);
100 }
101
102 #[test]
103 fn start_ap_already_started_returns_false() {
104 let start_ap_result =
105 test_ap_start("TestAp", "", 6, TwoGhz, StartApResultCode::AlreadyStarted);
106 assert!(start_ap_result == StartApResultCode::AlreadyStarted);
107 }
108
109 #[test]
110 fn start_ap_internal_error_returns_false() {
111 let start_ap_result =
112 test_ap_start("TestAp", "", 6, TwoGhz, StartApResultCode::InternalError);
113 assert!(start_ap_result == StartApResultCode::InternalError);
114 }
115
116 #[test]
117 fn start_ap_canceled_returns_false() {
118 let start_ap_result = test_ap_start("TestAp", "", 6, TwoGhz, StartApResultCode::Canceled);
119 assert!(start_ap_result == StartApResultCode::Canceled);
120 }
121
122 #[test]
123 fn start_ap_timedout_returns_false() {
124 let start_ap_result = test_ap_start("TestAp", "", 6, TwoGhz, StartApResultCode::TimedOut);
125 assert!(start_ap_result == StartApResultCode::TimedOut);
126 }
127
128 #[test]
129 fn start_ap_in_progress_returns_false() {
130 let start_ap_result =
131 test_ap_start("TestAp", "", 6, TwoGhz, StartApResultCode::PreviousStartInProgress);
132 assert!(start_ap_result == StartApResultCode::PreviousStartInProgress);
133 }
134
135 fn test_ap_start(
136 ssid: &str,
137 password: &str,
138 channel: u8,
139 band: fidl_ieee80211::WlanBand,
140 result_code: StartApResultCode,
141 ) -> StartApResultCode {
142 let mut exec = fasync::TestExecutor::new();
143 let (ap_sme, server) = create_ap_sme_proxy();
144 let mut ap_sme_req = server.into_future();
145 let target_ssid = Ssid::try_from(ssid).unwrap();
146 let target_password = password.as_bytes().to_vec();
147
148 let config = fidl_sme::ApConfig {
149 ssid: target_ssid.to_vec(),
150 password: target_password.to_vec(),
151 radio_cfg: fidl_sme::RadioConfig {
152 phy: fidl_ieee80211::WlanPhyType::Ht,
153 channel: wlan_common::channel::Channel::new(
154 channel,
155 wlan_common::channel::Cbw::Cbw20,
156 band,
157 )
158 .into(),
159 },
160 };
161
162 let fut = start(&ap_sme, target_ssid, target_password, channel, band);
163 let mut fut = pin!(fut);
164 assert!(exec.run_until_stalled(&mut fut).is_pending());
165
166 send_start_ap_response(&mut exec, &mut ap_sme_req, config, result_code);
167
168 let complete = exec.run_until_stalled(&mut fut);
169
170 let ap_start_result = match complete {
171 Poll::Ready(result) => result,
172 _ => panic!("Expected a start response"),
173 };
174
175 let returned_start_ap_code = match ap_start_result {
176 Ok(response) => response,
177 _ => panic!("Expected a valid start result"),
178 };
179
180 returned_start_ap_code
181 }
182
183 fn create_ap_sme_proxy() -> (fidl_sme::ApSmeProxy, ApSmeRequestStream) {
184 let (proxy, server) = endpoints::create_proxy::<ApSmeMarker>();
185 let server = server.into_stream();
186 (proxy, server)
187 }
188
189 fn send_start_ap_response(
190 exec: &mut fasync::TestExecutor,
191 server: &mut StreamFuture<ApSmeRequestStream>,
192 expected_config: fidl_sme::ApConfig,
193 result_code: StartApResultCode,
194 ) {
195 let rsp = match poll_ap_sme_request(exec, server) {
196 Poll::Ready(ApSmeRequest::Start { config, responder }) => {
197 assert_eq!(expected_config, config);
198 responder
199 }
200 Poll::Pending => panic!("Expected AP Start Request"),
201 _ => panic!("Expected AP Start Request"),
202 };
203
204 rsp.send(result_code).expect("Failed to send AP start response.");
205 }
206
207 fn poll_ap_sme_request(
208 exec: &mut fasync::TestExecutor,
209 next_ap_sme_req: &mut StreamFuture<ApSmeRequestStream>,
210 ) -> Poll<ApSmeRequest> {
211 exec.run_until_stalled(next_ap_sme_req).map(|(req, stream)| {
212 *next_ap_sme_req = stream.into_future();
213 req.expect("did not expect the ApSmeRequestStream to end")
214 .expect("error polling ap sme request stream")
215 })
216 }
217
218 fn respond_to_get_ap_sme_request(
219 exec: &mut fasync::TestExecutor,
220 req_stream: &mut DeviceMonitorRequestStream,
221 result: Result<(), zx::Status>,
222 ) {
223 let req = exec.run_until_stalled(&mut req_stream.next());
224
225 let responder = assert_matches!(
226 req,
227 Poll::Ready(Some(Ok(DeviceMonitorRequest::GetApSme { responder, .. }))) => responder
228 );
229
230 responder
232 .send(result.map_err(|e| e.into_raw()))
233 .expect("fake sme proxy response: send failed")
234 }
235
236 fn test_get_first_sme(iface_list: &[WlanMacRole]) -> Result<(), Error> {
237 let (mut exec, proxy, mut req_stream) =
238 crate::tests::setup_fake_service::<DeviceMonitorMarker>();
239 let fut = get_first_sme(&proxy);
240 let mut fut = pin!(fut);
241
242 let ifaces = (0..iface_list.len() as u16).collect();
243
244 assert!(exec.run_until_stalled(&mut fut).is_pending());
245 crate::tests::respond_to_query_iface_list_request(&mut exec, &mut req_stream, ifaces);
246
247 for mac_role in iface_list {
248 assert!(exec.run_until_stalled(&mut fut).is_pending());
250 crate::tests::respond_to_query_iface_request(
251 &mut exec,
252 &mut req_stream,
253 *mac_role,
254 Some([1, 2, 3, 4, 5, 6]),
255 );
256
257 if *mac_role == WlanMacRole::Ap {
258 assert!(exec.run_until_stalled(&mut fut).is_pending());
260 respond_to_get_ap_sme_request(&mut exec, &mut req_stream, Ok(()));
261 break;
262 }
263 }
264
265 let _proxy = exec.run_singlethreaded(&mut fut)?;
266 Ok(())
267 }
268 #[test]
270 fn check_get_ap_sme_success() {
271 let iface_list: Vec<WlanMacRole> = vec![WlanMacRole::Client, WlanMacRole::Ap];
272 test_get_first_sme(&iface_list).expect("expect success but failed");
273 }
274
275 #[test]
277 fn check_get_ap_sme_no_devices() {
278 let iface_list: Vec<WlanMacRole> = Vec::new();
279 test_get_first_sme(&iface_list).expect_err("expect fail but succeeded");
280 }
281
282 #[test]
284 fn check_get_ap_sme_no_aps() {
285 let iface_list: Vec<WlanMacRole> = vec![WlanMacRole::Client, WlanMacRole::Client];
286 test_get_first_sme(&iface_list).expect_err("expect fail but succeeded");
287 }
288}