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::Bandwidth::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 primary: wlan_common::channel::Channel::new(
154 channel,
155 wlan_common::channel::Bandwidth::Cbw20,
156 band,
157 )
158 .into(),
159 bandwidth: fidl_ieee80211::ChannelBandwidth::Cbw20,
160 },
161 };
162
163 let fut = start(&ap_sme, target_ssid, target_password, channel, band);
164 let mut fut = pin!(fut);
165 assert!(exec.run_until_stalled(&mut fut).is_pending());
166
167 send_start_ap_response(&mut exec, &mut ap_sme_req, config, result_code);
168
169 let complete = exec.run_until_stalled(&mut fut);
170
171 let ap_start_result = match complete {
172 Poll::Ready(result) => result,
173 _ => panic!("Expected a start response"),
174 };
175
176 let returned_start_ap_code = match ap_start_result {
177 Ok(response) => response,
178 _ => panic!("Expected a valid start result"),
179 };
180
181 returned_start_ap_code
182 }
183
184 fn create_ap_sme_proxy() -> (fidl_sme::ApSmeProxy, ApSmeRequestStream) {
185 let (proxy, server) = endpoints::create_proxy::<ApSmeMarker>();
186 let server = server.into_stream();
187 (proxy, server)
188 }
189
190 fn send_start_ap_response(
191 exec: &mut fasync::TestExecutor,
192 server: &mut StreamFuture<ApSmeRequestStream>,
193 expected_config: fidl_sme::ApConfig,
194 result_code: StartApResultCode,
195 ) {
196 let rsp = match poll_ap_sme_request(exec, server) {
197 Poll::Ready(ApSmeRequest::Start { config, responder }) => {
198 assert_eq!(expected_config, config);
199 responder
200 }
201 Poll::Pending => panic!("Expected AP Start Request"),
202 _ => panic!("Expected AP Start Request"),
203 };
204
205 rsp.send(result_code).expect("Failed to send AP start response.");
206 }
207
208 fn poll_ap_sme_request(
209 exec: &mut fasync::TestExecutor,
210 next_ap_sme_req: &mut StreamFuture<ApSmeRequestStream>,
211 ) -> Poll<ApSmeRequest> {
212 exec.run_until_stalled(next_ap_sme_req).map(|(req, stream)| {
213 *next_ap_sme_req = stream.into_future();
214 req.expect("did not expect the ApSmeRequestStream to end")
215 .expect("error polling ap sme request stream")
216 })
217 }
218
219 fn respond_to_get_ap_sme_request(
220 exec: &mut fasync::TestExecutor,
221 req_stream: &mut DeviceMonitorRequestStream,
222 result: Result<(), zx::Status>,
223 ) {
224 let req = exec.run_until_stalled(&mut req_stream.next());
225
226 let responder = assert_matches!(
227 req,
228 Poll::Ready(Some(Ok(DeviceMonitorRequest::GetApSme { responder, .. }))) => responder
229 );
230
231 responder
233 .send(result.map_err(|e| e.into_raw()))
234 .expect("fake sme proxy response: send failed")
235 }
236
237 fn test_get_first_sme(iface_list: &[WlanMacRole]) -> Result<(), Error> {
238 let (mut exec, proxy, mut req_stream) =
239 crate::tests::setup_fake_service::<DeviceMonitorMarker>();
240 let fut = get_first_sme(&proxy);
241 let mut fut = pin!(fut);
242
243 let ifaces = (0..iface_list.len() as u16).collect();
244
245 assert!(exec.run_until_stalled(&mut fut).is_pending());
246 crate::tests::respond_to_query_iface_list_request(&mut exec, &mut req_stream, ifaces);
247
248 for mac_role in iface_list {
249 assert!(exec.run_until_stalled(&mut fut).is_pending());
251 crate::tests::respond_to_query_iface_request(
252 &mut exec,
253 &mut req_stream,
254 *mac_role,
255 Some([1, 2, 3, 4, 5, 6]),
256 );
257
258 if *mac_role == WlanMacRole::Ap {
259 assert!(exec.run_until_stalled(&mut fut).is_pending());
261 respond_to_get_ap_sme_request(&mut exec, &mut req_stream, Ok(()));
262 break;
263 }
264 }
265
266 let _proxy = exec.run_singlethreaded(&mut fut)?;
267 Ok(())
268 }
269 #[test]
271 fn check_get_ap_sme_success() {
272 let iface_list: Vec<WlanMacRole> = vec![WlanMacRole::Client, WlanMacRole::Ap];
273 test_get_first_sme(&iface_list).expect("expect success but failed");
274 }
275
276 #[test]
278 fn check_get_ap_sme_no_devices() {
279 let iface_list: Vec<WlanMacRole> = Vec::new();
280 test_get_first_sme(&iface_list).expect_err("expect fail but succeeded");
281 }
282
283 #[test]
285 fn check_get_ap_sme_no_aps() {
286 let iface_list: Vec<WlanMacRole> = vec![WlanMacRole::Client, WlanMacRole::Client];
287 test_get_first_sme(&iface_list).expect_err("expect fail but succeeded");
288 }
289}