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) -> 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        // now send the response back
224        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            // iface query response
242            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                // ap sme proxy
252                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    // iface list contains an AP and a client. Test should pass
262    #[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    // iface list is empty. Test should fail
269    #[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    // iface list does not contain an ap. Test should fail
276    #[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}