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::Bandwidth::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                primary: wlan_common::channel::Channel::new(
154                    channel,
155                    wlan_common::channel::Bandwidth::Cbw20,
156                    band,
157                )
158                .into(),
159                bandwidth: fidl_ieee80211::ChannelBandwidth::Cbw20,
160            },
161        };
162
163        let fut = start(&ap_sme, target_ssid, target_password, channel, band);
164        let mut fut = pin!(fut);
165        assert!(exec.run_until_stalled(&mut fut).is_pending());
166
167        send_start_ap_response(&mut exec, &mut ap_sme_req, config, result_code);
168
169        let complete = exec.run_until_stalled(&mut fut);
170
171        let ap_start_result = match complete {
172            Poll::Ready(result) => result,
173            _ => panic!("Expected a start response"),
174        };
175
176        let returned_start_ap_code = match ap_start_result {
177            Ok(response) => response,
178            _ => panic!("Expected a valid start result"),
179        };
180
181        returned_start_ap_code
182    }
183
184    fn create_ap_sme_proxy() -> (fidl_sme::ApSmeProxy, ApSmeRequestStream) {
185        let (proxy, server) = endpoints::create_proxy::<ApSmeMarker>();
186        let server = server.into_stream();
187        (proxy, server)
188    }
189
190    fn send_start_ap_response(
191        exec: &mut fasync::TestExecutor,
192        server: &mut StreamFuture<ApSmeRequestStream>,
193        expected_config: fidl_sme::ApConfig,
194        result_code: StartApResultCode,
195    ) {
196        let rsp = match poll_ap_sme_request(exec, server) {
197            Poll::Ready(ApSmeRequest::Start { config, responder }) => {
198                assert_eq!(expected_config, config);
199                responder
200            }
201            Poll::Pending => panic!("Expected AP Start Request"),
202            _ => panic!("Expected AP Start Request"),
203        };
204
205        rsp.send(result_code).expect("Failed to send AP start response.");
206    }
207
208    fn poll_ap_sme_request(
209        exec: &mut fasync::TestExecutor,
210        next_ap_sme_req: &mut StreamFuture<ApSmeRequestStream>,
211    ) -> Poll<ApSmeRequest> {
212        exec.run_until_stalled(next_ap_sme_req).map(|(req, stream)| {
213            *next_ap_sme_req = stream.into_future();
214            req.expect("did not expect the ApSmeRequestStream to end")
215                .expect("error polling ap sme request stream")
216        })
217    }
218
219    fn respond_to_get_ap_sme_request(
220        exec: &mut fasync::TestExecutor,
221        req_stream: &mut DeviceMonitorRequestStream,
222        result: Result<(), zx::Status>,
223    ) {
224        let req = exec.run_until_stalled(&mut req_stream.next());
225
226        let responder = assert_matches!(
227            req,
228            Poll::Ready(Some(Ok(DeviceMonitorRequest::GetApSme { responder, .. }))) => responder
229        );
230
231        // now send the response back
232        responder
233            .send(result.map_err(|e| e.into_raw()))
234            .expect("fake sme proxy response: send failed")
235    }
236
237    fn test_get_first_sme(iface_list: &[WlanMacRole]) -> Result<(), Error> {
238        let (mut exec, proxy, mut req_stream) =
239            crate::tests::setup_fake_service::<DeviceMonitorMarker>();
240        let fut = get_first_sme(&proxy);
241        let mut fut = pin!(fut);
242
243        let ifaces = (0..iface_list.len() as u16).collect();
244
245        assert!(exec.run_until_stalled(&mut fut).is_pending());
246        crate::tests::respond_to_query_iface_list_request(&mut exec, &mut req_stream, ifaces);
247
248        for mac_role in iface_list {
249            // iface query response
250            assert!(exec.run_until_stalled(&mut fut).is_pending());
251            crate::tests::respond_to_query_iface_request(
252                &mut exec,
253                &mut req_stream,
254                *mac_role,
255                Some([1, 2, 3, 4, 5, 6]),
256            );
257
258            if *mac_role == WlanMacRole::Ap {
259                // ap sme proxy
260                assert!(exec.run_until_stalled(&mut fut).is_pending());
261                respond_to_get_ap_sme_request(&mut exec, &mut req_stream, Ok(()));
262                break;
263            }
264        }
265
266        let _proxy = exec.run_singlethreaded(&mut fut)?;
267        Ok(())
268    }
269    // iface list contains an AP and a client. Test should pass
270    #[test]
271    fn check_get_ap_sme_success() {
272        let iface_list: Vec<WlanMacRole> = vec![WlanMacRole::Client, WlanMacRole::Ap];
273        test_get_first_sme(&iface_list).expect("expect success but failed");
274    }
275
276    // iface list is empty. Test should fail
277    #[test]
278    fn check_get_ap_sme_no_devices() {
279        let iface_list: Vec<WlanMacRole> = Vec::new();
280        test_get_first_sme(&iface_list).expect_err("expect fail but succeeded");
281    }
282
283    // iface list does not contain an ap. Test should fail
284    #[test]
285    fn check_get_ap_sme_no_aps() {
286        let iface_list: Vec<WlanMacRole> = vec![WlanMacRole::Client, WlanMacRole::Client];
287        test_get_first_sme(&iface_list).expect_err("expect fail but succeeded");
288    }
289}