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