1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use crate::wlan::types;
use anyhow::{Context as _, Error};
use fidl_fuchsia_wlan_common as fidl_common;
use fidl_fuchsia_wlan_device_service::{DeviceMonitorMarker, DeviceMonitorProxy};
use fidl_fuchsia_wlan_internal as fidl_internal;
use fuchsia_component::client::connect_to_protocol;
use fuchsia_sync::RwLock;
use fuchsia_zircon as zx;
use ieee80211::{MacAddr, Ssid};
use std::collections::HashMap;
use wlan_common::scan::ScanResult;

// WlanFacade: proxies commands from sl4f test to proper fidl APIs
//
// This object is shared among all threads created by server.  The inner object is the facade
// itself.  Callers interact with a wrapped version of the facade that enforces read/write
// protection.
//
// Use: Create once per server instantiation.
#[derive(Debug)]
struct InnerWlanFacade {
    // TODO(https://fxbug.dev/42165549)
    #[allow(unused)]
    scan_results: bool,
}

#[derive(Debug)]
pub(crate) struct WlanFacade {
    monitor_svc: DeviceMonitorProxy,
    // TODO(https://fxbug.dev/42165549)
    #[allow(unused)]
    inner: RwLock<InnerWlanFacade>,
}

impl WlanFacade {
    pub fn new() -> Result<WlanFacade, Error> {
        let monitor_svc = connect_to_protocol::<DeviceMonitorMarker>()?;

        Ok(WlanFacade { monitor_svc, inner: RwLock::new(InnerWlanFacade { scan_results: false }) })
    }

    /// Gets the list of wlan interface IDs.
    pub async fn get_iface_id_list(&self) -> Result<Vec<u16>, Error> {
        let wlan_iface_ids = wlan_service_util::get_iface_list(&self.monitor_svc)
            .await
            .context("Get Iface Id List: failed to get wlan iface list")?;
        Ok(wlan_iface_ids)
    }

    /// Gets the list of wlan interface IDs.
    pub async fn get_phy_id_list(&self) -> Result<Vec<u16>, Error> {
        let wlan_phy_ids = wlan_service_util::get_phy_list(&self.monitor_svc)
            .await
            .context("Get Phy Id List: failed to get wlan phy list")?;
        Ok(wlan_phy_ids)
    }

    pub async fn scan(&self) -> Result<Vec<String>, Error> {
        // get the first client interface
        let sme_proxy = wlan_service_util::client::get_first_sme(&self.monitor_svc)
            .await
            .context("Scan: failed to get client iface sme proxy")?;

        // start the scan
        let scan_result_list =
            wlan_service_util::client::passive_scan(&sme_proxy).await.context("Scan failed")?;

        // send the ssids back to the test
        let mut ssid_list = Vec::new();
        for scan_result in &scan_result_list {
            let scan_result: ScanResult = scan_result.clone().try_into()?;
            let ssid = String::from_utf8_lossy(&scan_result.bss_description.ssid).into_owned();
            ssid_list.push(ssid);
        }
        Ok(ssid_list)
    }

    async fn passive_scan(
        &self,
    ) -> Result<impl IntoIterator<Item = Result<ScanResult, Error>>, Error> {
        // get the first client interface
        let sme_proxy = wlan_service_util::client::get_first_sme(&self.monitor_svc)
            .await
            .context("Scan: failed to get client iface sme proxy")?;
        // start the scan
        Ok(wlan_service_util::client::passive_scan(&sme_proxy)
            .await
            .context("Scan failed")?
            .into_iter()
            .map(ScanResult::try_from))
    }

    pub async fn scan_for_bss_info(
        &self,
    ) -> Result<HashMap<String, Vec<Box<types::BssDescriptionDef>>>, Error> {
        let mut scan_results_by_ssid_string = HashMap::new();
        for scan_result in self.passive_scan().await? {
            let scan_result = scan_result.context("Failed to convert scan result")?;
            let entry = scan_results_by_ssid_string
                .entry(String::from(scan_result.bss_description.ssid.to_string_not_redactable()))
                .or_insert(vec![]);

            let fidl_bss_desc: fidl_internal::BssDescription = scan_result.bss_description.into();
            entry.push(Box::new(fidl_bss_desc.into()));
        }
        Ok(scan_results_by_ssid_string)
    }

    pub async fn connect(
        &self,
        target_ssid: Ssid,
        target_pwd: Vec<u8>,
        target_bss_desc: fidl_internal::BssDescription,
    ) -> Result<bool, Error> {
        let sme_proxy = wlan_service_util::client::get_first_sme(&self.monitor_svc)
            .await
            .context("Connect: failed to get client iface sme proxy")?;
        wlan_service_util::client::connect(&sme_proxy, target_ssid, target_pwd, target_bss_desc)
            .await
    }

    pub async fn create_iface(
        &self,
        phy_id: u16,
        role: fidl_common::WlanMacRole,
        sta_addr: MacAddr,
    ) -> Result<u16, Error> {
        let iface_id = wlan_service_util::create_iface(&self.monitor_svc, phy_id, role, sta_addr)
            .await
            .context("Create: Failed to create iface")?;

        Ok(iface_id)
    }

    /// Destroys a WLAN interface by input interface ID.
    ///
    /// # Arguments
    /// * `iface_id` - The u16 interface id.
    pub async fn destroy_iface(&self, iface_id: u16) -> Result<(), Error> {
        wlan_service_util::destroy_iface(&self.monitor_svc, iface_id)
            .await
            .context("Destroy: Failed to destroy iface")
    }

    pub async fn disconnect(&self) -> Result<(), Error> {
        wlan_service_util::client::disconnect_all(&self.monitor_svc)
            .await
            .context("Disconnect: Failed to disconnect ifaces")
    }

    pub async fn status(&self) -> Result<types::ClientStatusResponseDef, Error> {
        // get the first client interface
        let sme_proxy = wlan_service_util::client::get_first_sme(&self.monitor_svc)
            .await
            .context("Status: failed to get iface sme proxy")?;

        let rsp = sme_proxy.status().await.context("failed to get status from sme_proxy")?;

        Ok(rsp.into())
    }

    pub async fn query_iface(
        &self,
        iface_id: u16,
    ) -> Result<types::QueryIfaceResponseWrapper, Error> {
        let iface_info = self
            .monitor_svc
            .query_iface(iface_id)
            .await
            .context("Failed to query iface information")?
            .map_err(|e| zx::Status::from_raw(e));

        match iface_info {
            Ok(info) => Ok(types::QueryIfaceResponseWrapper(info.into())),
            Err(zx::Status::NOT_FOUND) => {
                Err(format_err!("no iface information for ID: {}", iface_id))
            }
            Err(e) => Err(e.into()),
        }
    }
}