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