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