Skip to main content

wlan_service_util/
ap.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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        // now send the response back
231        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            // iface query response
249            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                // ap sme proxy
259                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    // iface list contains an AP and a client. Test should pass
269    #[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    // iface list is empty. Test should fail
276    #[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    // iface list does not contain an ap. Test should fail
283    #[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}