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 {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        // now send the response back
222        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            // iface query response
240            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                // ap sme proxy
250                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    // iface list contains an AP and a client. Test should pass
260    #[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    // iface list is empty. Test should fail
267    #[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    // iface list does not contain an ap. Test should fail
274    #[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}