wlancfg_lib/client/roaming/
lib.rs

1// Copyright 2024 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::client::config_management::Credential;
6use crate::client::types;
7use crate::util::historical_list::{HistoricalList, Timestamped};
8use crate::util::pseudo_energy::{EwmaSignalData, RssiVelocity};
9use log::error;
10use wlan_common::sequestered::Sequestered;
11use {
12    fidl_fuchsia_wlan_common as fidl_common, fidl_fuchsia_wlan_internal as fidl_internal,
13    fidl_fuchsia_wlan_sme as fidl_sme, fuchsia_async as fasync,
14};
15
16pub const ROAMING_CHANNEL_BUFFER_SIZE: usize = 100;
17/// This is how many past roam events will be remembered for limiting roams per day. Each roam
18/// monitor implementation decides how to limit roams per day, and this number must be greater
19/// than or equal to all of them.
20pub const NUM_PLATFORM_MAX_ROAMS_PER_DAY: usize = 5;
21pub const TIMESPAN_TO_LIMIT_SCANS: zx::MonotonicDuration = zx::MonotonicDuration::from_hours(24);
22
23// LINT.IfChange
24#[derive(Clone, Copy, Debug)]
25pub enum RoamingPolicy {
26    Disabled,
27    Enabled { profile: RoamingProfile, mode: RoamingMode },
28}
29
30#[derive(Clone, Copy, Debug)]
31pub enum RoamingProfile {
32    Stationary,
33}
34#[derive(Clone, Copy, Default, Debug, PartialEq)]
35pub enum RoamingMode {
36    MetricsOnly,
37    #[default]
38    CanRoam,
39}
40
41impl From<String> for RoamingPolicy {
42    fn from(string: String) -> Self {
43        match string.as_str() {
44            "enabled_stationary_can_roam" => RoamingPolicy::Enabled {
45                profile: RoamingProfile::Stationary,
46                mode: RoamingMode::CanRoam,
47            },
48            "enabled_stationary_metrics_only" => RoamingPolicy::Enabled {
49                profile: RoamingProfile::Stationary,
50                mode: RoamingMode::MetricsOnly,
51            },
52            "disabled" => RoamingPolicy::Disabled,
53            _ => {
54                error!(
55                    "Unknown roaming profile string ({}). Continuing with roaming disabled.",
56                    string
57                );
58                RoamingPolicy::Disabled
59            }
60        }
61    }
62}
63// LINT.ThenChange(//src/lib/assembly/config_schema/src/platform_config/connectivity_config.rs)
64
65/// Data tracked about a connection used to make roaming decisions.
66#[derive(Clone)]
67#[cfg_attr(test, derive(Debug, PartialEq))]
68pub struct RoamingConnectionData {
69    pub ap_state: types::ApState,
70    pub network_identifier: types::NetworkIdentifier,
71    pub credential: Credential,
72    pub signal_data: EwmaSignalData,
73    pub rssi_velocity: RssiVelocity,
74    pub previous_roam_scan_data: PreviousRoamScanData,
75}
76impl RoamingConnectionData {
77    pub fn new(
78        ap_state: types::ApState,
79        network_identifier: types::NetworkIdentifier,
80        credential: Credential,
81        signal_data: EwmaSignalData,
82    ) -> Self {
83        Self {
84            ap_state: ap_state.clone(),
85            network_identifier,
86            credential,
87            signal_data,
88            rssi_velocity: RssiVelocity::new(signal_data.ewma_rssi.get()),
89            previous_roam_scan_data: PreviousRoamScanData::new(ap_state.tracked.signal.rssi_dbm),
90        }
91    }
92}
93// Metadata related to the previous roam scan event.
94#[derive(Clone)]
95#[cfg_attr(test, derive(Debug, PartialEq))]
96pub struct PreviousRoamScanData {
97    pub(crate) time: fasync::MonotonicInstant,
98    /// This is the EWMA value, hence why it is an f64
99    pub rssi: f64,
100}
101impl PreviousRoamScanData {
102    pub fn new(rssi: impl Into<f64>) -> Self {
103        Self { time: fasync::MonotonicInstant::now(), rssi: rssi.into() }
104    }
105}
106
107// Data that could trigger roaming actions to occur. Roam monitor implementations
108// MUST read all trigger data types from the channel, even if they ignore/drop it.
109#[derive(Clone, Debug)]
110pub enum RoamTriggerData {
111    SignalReportInd(fidl_internal::SignalReportIndication),
112}
113
114// Actions that could be taken after handling new roam trigger data.
115#[derive(Clone)]
116#[cfg_attr(test, derive(Debug, PartialEq))]
117pub enum RoamTriggerDataOutcome {
118    Noop,
119    RoamSearch {
120        scan_type: fidl_common::ScanType,
121        network_identifier: types::NetworkIdentifier,
122        credential: Credential,
123        current_security: types::SecurityTypeDetailed,
124        reasons: Vec<RoamReason>,
125    },
126}
127
128#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
129pub enum RoamReason {
130    RssiBelowThreshold,
131    SnrBelowThreshold,
132}
133
134#[derive(Clone)]
135#[cfg_attr(test, derive(Debug, PartialEq))]
136pub struct PolicyRoamRequest {
137    pub candidate: types::ScannedCandidate,
138    pub reasons: Vec<RoamReason>,
139}
140impl From<PolicyRoamRequest> for fidl_sme::RoamRequest {
141    fn from(item: PolicyRoamRequest) -> Self {
142        fidl_sme::RoamRequest {
143            bss_description: Sequestered::release(item.candidate.bss.bss_description),
144        }
145    }
146}
147
148/// Only used for recording when the last roam attempts happened in order to limit their frequency.
149#[derive(Clone)]
150pub struct RoamEvent {
151    time: fasync::MonotonicInstant,
152}
153
154impl RoamEvent {
155    pub fn new_roam_now() -> Self {
156        Self { time: fasync::MonotonicInstant::now() }
157    }
158
159    #[cfg(test)]
160    pub fn new(time: fasync::MonotonicInstant) -> Self {
161        Self { time }
162    }
163}
164
165impl Timestamped for RoamEvent {
166    fn time(&self) -> fasync::MonotonicInstant {
167        self.time
168    }
169}
170
171pub type PastRoamList = HistoricalList<RoamEvent>;