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