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