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::{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        // now send the response back
225        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            // iface query response
243            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                // ap sme proxy
253                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    // iface list contains an AP and a client. Test should pass
263    #[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    // iface list is empty. Test should fail
270    #[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    // iface list does not contain an ap. Test should fail
277    #[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}