Skip to main content

wlancfg_lib/client/
types.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 crate::config_management::{self};
6use fidl_fuchsia_wlan_policy as fidl_policy;
7use fidl_fuchsia_wlan_sme as fidl_sme;
8use fuchsia_async::MonotonicInstant;
9use wlan_common::bss::BssDescription;
10use wlan_common::channel::Channel;
11use wlan_common::historical_list::Timestamped;
12use wlan_common::security::SecurityAuthenticator;
13use wlan_common::sequestered::Sequestered;
14use wlan_metrics_registry::{
15    PolicyConnectionAttemptMigratedMetricDimensionReason,
16    PolicyDisconnectionMigratedMetricDimensionReason,
17};
18
19pub(crate) use crate::regulatory_manager::CountryCode;
20
21pub type NetworkIdentifier = config_management::network_config::NetworkIdentifier;
22pub type SecurityTypeDetailed = fidl_sme::Protection;
23pub type SecurityType = config_management::network_config::SecurityType;
24pub type ConnectionState = fidl_policy::ConnectionState;
25pub type ClientState = fidl_policy::WlanClientState;
26pub type DisconnectStatus = fidl_policy::DisconnectStatus;
27pub type Compatibility = fidl_policy::Compatibility;
28pub type WlanChan = wlan_common::channel::Channel;
29pub type Bandwidth = wlan_common::channel::Bandwidth;
30pub use ieee80211::{Bssid, Ssid};
31pub type DisconnectReason = PolicyDisconnectionMigratedMetricDimensionReason;
32pub type ConnectReason = PolicyConnectionAttemptMigratedMetricDimensionReason;
33pub type ScanError = fidl_policy::ScanErrorCode;
34
35pub fn convert_to_sme_disconnect_reason(
36    disconnect_reason: PolicyDisconnectionMigratedMetricDimensionReason,
37) -> fidl_sme::UserDisconnectReason {
38    match disconnect_reason {
39        PolicyDisconnectionMigratedMetricDimensionReason::Unknown => {
40            fidl_sme::UserDisconnectReason::Unknown
41        }
42        PolicyDisconnectionMigratedMetricDimensionReason::FailedToConnect => {
43            fidl_sme::UserDisconnectReason::FailedToConnect
44        }
45        PolicyDisconnectionMigratedMetricDimensionReason::FidlConnectRequest => {
46            fidl_sme::UserDisconnectReason::FidlConnectRequest
47        }
48        PolicyDisconnectionMigratedMetricDimensionReason::FidlStopClientConnectionsRequest => {
49            fidl_sme::UserDisconnectReason::FidlStopClientConnectionsRequest
50        }
51        PolicyDisconnectionMigratedMetricDimensionReason::ProactiveNetworkSwitch => {
52            fidl_sme::UserDisconnectReason::ProactiveNetworkSwitch
53        }
54        PolicyDisconnectionMigratedMetricDimensionReason::DisconnectDetectedFromSme => {
55            fidl_sme::UserDisconnectReason::DisconnectDetectedFromSme
56        }
57        PolicyDisconnectionMigratedMetricDimensionReason::RegulatoryRegionChange => {
58            fidl_sme::UserDisconnectReason::RegulatoryRegionChange
59        }
60        PolicyDisconnectionMigratedMetricDimensionReason::Startup => {
61            fidl_sme::UserDisconnectReason::Startup
62        }
63        PolicyDisconnectionMigratedMetricDimensionReason::NetworkUnsaved => {
64            fidl_sme::UserDisconnectReason::NetworkUnsaved
65        }
66        PolicyDisconnectionMigratedMetricDimensionReason::NetworkConfigUpdated => {
67            fidl_sme::UserDisconnectReason::NetworkConfigUpdated
68        }
69    }
70}
71
72// An internal version of fidl_policy::ScanResult that can be cloned
73// To avoid printing PII, only allow Debug in tests, runtime logging should use Display
74#[cfg_attr(test, derive(Debug))]
75#[derive(Clone, PartialEq)]
76pub struct ScanResult {
77    /// Network properties used to distinguish between networks and to group
78    /// individual APs.
79    pub ssid: Ssid,
80    pub security_type_detailed: SecurityTypeDetailed,
81    /// Individual access points offering the specified network.
82    pub entries: Vec<Bss>,
83    /// Indication if the detected network is supported by the implementation.
84    pub compatibility: Compatibility,
85}
86
87// Only derive(Debug) in tests, we should never directly print this in non-test code
88#[cfg_attr(test, derive(Debug, PartialOrd, Ord, Clone))]
89#[derive(Hash, PartialEq, Eq)]
90pub struct NetworkIdentifierDetailed {
91    pub ssid: Ssid,
92    pub security_type: SecurityTypeDetailed,
93}
94
95#[derive(Clone, Copy, Debug, PartialEq)]
96pub enum ScanObservation {
97    Passive,
98    Active,
99    Unknown,
100}
101
102// An internal version of fidl_policy::Bss with extended information
103// To avoid printing PII, only allow Debug in tests, runtime logging should use Display
104#[cfg_attr(test, derive(Debug))]
105#[derive(Clone, PartialEq)]
106pub struct Bss {
107    /// MAC address for the AP interface.
108    pub bssid: Bssid,
109    /// Signal strength for the beacon/probe response.
110    pub signal: Signal,
111    /// Channel for this network.
112    pub channel: WlanChan,
113    /// Realtime timestamp for this scan result entry.
114    pub timestamp: zx::MonotonicInstant,
115    /// The scanning mode used to observe the BSS.
116    pub observation: ScanObservation,
117    /// Compatibility with this device's network stack.
118    pub compatibility: wlan_common::scan::Compatibility,
119    /// The BSS description with information that SME needs for connecting.
120    pub bss_description: Sequestered<fidl_fuchsia_wlan_ieee80211::BssDescription>,
121}
122
123impl Bss {
124    pub fn is_compatible(&self) -> bool {
125        self.compatibility.is_ok()
126    }
127
128    pub fn is_same_bssid_and_security(&self, other: &Bss) -> bool {
129        self.bssid == other.bssid && self.compatibility == other.compatibility
130    }
131}
132
133// TODO(https://fxbug.dev/42065250): Move this into `wlan_common::bss` and use it in place of signal fields
134//                         in `BssDescription`.
135#[derive(Clone, Copy, Debug, Eq, PartialEq)]
136pub struct Signal {
137    /// Calculated received signal strength for the beacon/probe response.
138    pub rssi_dbm: i8,
139    /// Signal to noise ratio  for the beacon/probe response.
140    pub snr_db: i8,
141}
142
143// For tracking the past signal reports
144#[derive(Clone, Debug, PartialEq)]
145pub struct TimestampedSignal {
146    pub signal: Signal,
147    pub time: MonotonicInstant,
148}
149impl Timestamped for TimestampedSignal {
150    fn time(&self) -> fuchsia_async::MonotonicInstant {
151        self.time
152    }
153}
154
155/// BSS information tracked by the client state machine.
156///
157/// While connected to an AP, some important BSS configuration may change, such as the channel and
158/// signal quality statistics. `TrackedBss` provides fields for this configuration that are managed
159/// by the client state machine.
160#[derive(Clone, Copy, Debug, Eq, PartialEq)]
161pub struct TrackedBss {
162    pub signal: Signal,
163    pub channel: Channel,
164}
165
166impl TrackedBss {
167    /// Snapshots a BSS description.
168    ///
169    /// A snapshot copies configuration from the given BSS description into a `TrackedBss`.
170    pub fn snapshot(original: &BssDescription) -> Self {
171        TrackedBss {
172            signal: Signal { rssi_dbm: original.rssi_dbm, snr_db: original.snr_db },
173            channel: original.channel,
174        }
175    }
176}
177
178impl PartialEq<BssDescription> for TrackedBss {
179    fn eq(&self, bss: &BssDescription) -> bool {
180        // This implementation is robust in the face of changes to `BssDescription` and
181        // `TrackedBss`, but must copy fields. This could be deceptively expensive for an
182        // equivalence query if `TrackedBss` has many congruent fields with respect to
183        // `BssDescription`.
184        *self == TrackedBss::snapshot(bss)
185    }
186}
187
188impl PartialEq<TrackedBss> for BssDescription {
189    fn eq(&self, tracked: &TrackedBss) -> bool {
190        tracked == self
191    }
192}
193
194/// Candidate BSS observed in a scan.
195#[derive(Debug, Clone)]
196#[cfg_attr(test, derive(PartialEq))]
197pub struct InternalSavedNetworkData {
198    pub has_ever_connected: bool,
199    pub recent_failures: Vec<config_management::ConnectFailure>,
200    pub past_connections: std::collections::HashMap<Bssid, config_management::PastConnectionList>,
201}
202#[derive(Clone)]
203// To avoid printing PII, only allow Debug in tests, runtime logging should use Display
204#[cfg_attr(test, derive(Debug, PartialEq))]
205pub struct ScannedCandidate {
206    pub network: NetworkIdentifier,
207    pub security_type_detailed: SecurityTypeDetailed,
208    pub credential: config_management::Credential,
209    pub bss: Bss,
210    pub network_has_multiple_bss: bool,
211    pub authenticator: SecurityAuthenticator,
212    pub saved_network_info: InternalSavedNetworkData,
213}
214
215impl ScannedCandidate {
216    // Returns if the two candidates represent the same BSS, ignore scan time variables.
217    pub fn is_same_bss_security_and_credential(&self, other: &ScannedCandidate) -> bool {
218        self.network == other.network
219            && self.security_type_detailed == other.security_type_detailed
220            && self.credential == other.credential
221            && self.bss.is_same_bssid_and_security(&other.bss)
222    }
223}
224
225/// Selected network candidate for a connection.
226///
227/// This type is a promotion of a scanned candidate and provides the necessary data required to
228/// establish a connection.
229#[derive(Clone)]
230// To avoid printing PII, only allow Debug in tests, runtime logging should use Display
231#[cfg_attr(test, derive(Debug))]
232#[cfg_attr(test, derive(PartialEq))]
233pub struct ConnectSelection {
234    pub target: ScannedCandidate,
235    pub reason: ConnectReason,
236}
237
238/// The state of a remote AP.
239///
240/// `ApState` describes the configuration of a BSS to which a client is connected. The state is
241/// comprised of an initial BSS description as well as tracked configuration. The tracked
242/// configuration may change while a client is connected and is managed by the client state
243/// machine. The initial BSS description is immutable.
244///
245/// See `TrackedBss`.
246#[derive(Clone, Debug, PartialEq)]
247pub struct ApState {
248    /// The initial configuration of the BSS (e.g., as seen from a scan).
249    original: BssDescription,
250    /// Tracked BSS configuration.
251    ///
252    /// This subset of the initial BSS description is managed by the client state machine and may
253    /// change while connected to an AP.
254    pub tracked: TrackedBss,
255}
256
257impl ApState {
258    /// Gets the initial BSS description for the AP to which a client is connected.
259    pub fn original(&self) -> &BssDescription {
260        &self.original
261    }
262
263    /// Returns `true` if the tracked BSS configuration differs from the initial BSS description.
264    pub fn has_changes(&self) -> bool {
265        self.original != self.tracked
266    }
267}
268
269impl From<BssDescription> for ApState {
270    fn from(original: BssDescription) -> Self {
271        let tracked = TrackedBss::snapshot(&original);
272        ApState { original, tracked }
273    }
274}