wlancfg_lib/client/roaming/local_roam_manager/
mod.rs1use crate::client::config_management::Credential;
6use crate::client::connection_selection::ConnectionSelectionRequester;
7use crate::client::roaming::lib::*;
8use crate::client::roaming::roam_monitor;
9use crate::client::types;
10use crate::config_management::SavedNetworksManagerApi;
11use crate::telemetry::TelemetrySender;
12use anyhow::Error;
13use futures::channel::mpsc;
14use futures::future::LocalBoxFuture;
15use futures::lock::Mutex;
16use futures::stream::FuturesUnordered;
17use futures::{select, StreamExt};
18use log::{debug, error};
19use std::convert::Infallible;
20use std::sync::Arc;
21
22fn create_roam_monitor(
24 roaming_policy: RoamingPolicy,
25 ap_state: types::ApState,
26 network_identifier: types::NetworkIdentifier,
27 credential: Credential,
28 telemetry_sender: TelemetrySender,
29 saved_networks: Arc<dyn SavedNetworksManagerApi>,
30 past_roams: Arc<Mutex<PastRoamList>>,
31) -> Box<dyn roam_monitor::RoamMonitorApi> {
32 match roaming_policy {
33 RoamingPolicy::Enabled { profile: RoamingProfile::Stationary, .. } => {
34 Box::new(roam_monitor::stationary_monitor::StationaryMonitor::new(
35 ap_state,
36 network_identifier,
37 credential,
38 telemetry_sender,
39 saved_networks,
40 past_roams,
41 ))
42 }
43 RoamingPolicy::Disabled => {
44 Box::new(roam_monitor::default_monitor::DefaultRoamMonitor::new())
45 }
46 }
47}
48
49#[cfg_attr(test, derive(Debug))]
51pub enum RoamServiceRequest {
52 InitializeRoamMonitor {
53 ap_state: types::ApState,
54 network_identifier: types::NetworkIdentifier,
55 credential: Credential,
56 roam_request_sender: mpsc::Sender<PolicyRoamRequest>,
57 roam_trigger_data_receiver: mpsc::Receiver<RoamTriggerData>,
58 },
59}
60
61#[derive(Clone)]
63pub struct RoamManager {
64 sender: mpsc::Sender<RoamServiceRequest>,
65}
66
67impl RoamManager {
68 pub fn new(sender: mpsc::Sender<RoamServiceRequest>) -> Self {
69 Self { sender }
70 }
71 pub fn initialize_roam_monitor(
73 &mut self,
74 ap_state: types::ApState,
75 network_identifier: types::NetworkIdentifier,
76 credential: Credential,
77 roam_request_sender: mpsc::Sender<PolicyRoamRequest>,
78 ) -> roam_monitor::RoamDataSender {
79 let (roam_trigger_data_sender, roam_trigger_data_receiver) =
80 mpsc::channel(ROAMING_CHANNEL_BUFFER_SIZE);
81 let _ = self
82 .sender
83 .try_send(RoamServiceRequest::InitializeRoamMonitor {
84 ap_state,
85 network_identifier,
86 credential,
87 roam_request_sender,
88 roam_trigger_data_receiver,
89 })
90 .inspect_err(|e| {
91 error!("Failed to request roam monitoring: {}. Proceeding without roaming.", e)
92 });
93 roam_monitor::RoamDataSender::new(roam_trigger_data_sender)
94 }
95}
96
97pub async fn serve_local_roam_manager_requests(
99 roaming_policy: RoamingPolicy,
100 mut roam_service_request_receiver: mpsc::Receiver<RoamServiceRequest>,
101 connection_selection_requester: ConnectionSelectionRequester,
102 telemetry_sender: TelemetrySender,
103 saved_networks: Arc<dyn SavedNetworksManagerApi>,
104) -> Result<Infallible, Error> {
105 let mut monitor_futs: FuturesUnordered<LocalBoxFuture<'static, Result<(), anyhow::Error>>> =
107 FuturesUnordered::new();
108 let past_roams = Arc::new(Mutex::new(PastRoamList::new(NUM_PLATFORM_MAX_ROAMS_PER_DAY)));
109
110 loop {
111 select! {
112 req = roam_service_request_receiver.select_next_some() => {
114 match req {
115 RoamServiceRequest::InitializeRoamMonitor { ap_state, network_identifier, credential, roam_request_sender, roam_trigger_data_receiver }=> {
118 let monitor = create_roam_monitor(roaming_policy, ap_state, network_identifier, credential, telemetry_sender.clone(), saved_networks.clone(), past_roams.clone());
119 let monitor_fut = roam_monitor::serve_roam_monitor(monitor, roaming_policy, roam_trigger_data_receiver, connection_selection_requester.clone(), roam_request_sender.clone(), telemetry_sender.clone(), past_roams.clone());
120 monitor_futs.push(Box::pin(monitor_fut));
121 }
122 }
123 }
124 _terminated_monitor = monitor_futs.select_next_some() => {
126 debug!("Roam monitor future closed.");
127 }
128 }
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135 use crate::telemetry::TelemetryEvent;
136 use crate::util::testing::{
137 generate_random_ap_state, generate_random_network_identifier, generate_random_password,
138 generate_random_roaming_connection_data, FakeSavedNetworksManager,
139 };
140 use assert_matches::assert_matches;
141 use fidl_fuchsia_wlan_internal::SignalReportIndication;
142 use fuchsia_async::TestExecutor;
143 use futures::task::Poll;
144 use std::pin::pin;
145 use test_case::test_case;
146
147 struct RoamManagerServiceTestValues {
148 telemetry_sender: TelemetrySender,
149 connection_selection_requester: ConnectionSelectionRequester,
150 roam_manager: RoamManager,
151 roam_service_request_receiver: mpsc::Receiver<RoamServiceRequest>,
152 saved_networks: Arc<FakeSavedNetworksManager>,
153 }
154
155 fn setup_test() -> RoamManagerServiceTestValues {
156 let (telemetry_sender, _) = mpsc::channel::<TelemetryEvent>(100);
157 let telemetry_sender = TelemetrySender::new(telemetry_sender);
158 let (connection_selection_request_sender, _) = mpsc::channel(5);
159 let connection_selection_requester =
160 ConnectionSelectionRequester::new(connection_selection_request_sender);
161 let (roam_service_request_sender, roam_service_request_receiver) = mpsc::channel(100);
162 let roam_manager = RoamManager::new(roam_service_request_sender);
163 let saved_networks = Arc::new(FakeSavedNetworksManager::new());
164 RoamManagerServiceTestValues {
165 telemetry_sender,
166 connection_selection_requester,
167 roam_manager,
168 roam_service_request_receiver,
169 saved_networks,
170 }
171 }
172
173 #[test_case(RoamingPolicy::Disabled; "disabled")]
174 #[test_case(RoamingPolicy::Enabled { profile: RoamingProfile::Stationary, mode: RoamingMode::CanRoam }; "enabled_stationary_can_roam")]
175 #[fuchsia::test(add_test_attr = false)]
176 fn test_create_roam_monitor(roaming_policy: RoamingPolicy) {
177 let _exec = TestExecutor::new();
178 let (telemetry_sender, _) = mpsc::channel::<TelemetryEvent>(100);
179 let telemetry_sender = TelemetrySender::new(telemetry_sender);
180 let saved_networks = Arc::new(FakeSavedNetworksManager::new());
181 let past_roams = Arc::new(Mutex::new(PastRoamList::new(NUM_PLATFORM_MAX_ROAMS_PER_DAY)));
182 let monitor = create_roam_monitor(
183 roaming_policy,
184 generate_random_ap_state(),
185 generate_random_network_identifier(),
186 generate_random_password(),
187 telemetry_sender.clone(),
188 saved_networks.clone(),
189 past_roams.clone(),
190 );
191 match roaming_policy {
192 RoamingPolicy::Disabled => {
193 let default_monitor: Box<dyn roam_monitor::RoamMonitorApi> =
194 Box::new(roam_monitor::default_monitor::DefaultRoamMonitor::new());
195 assert_eq!(default_monitor.type_id(), monitor.type_id());
196 }
197 RoamingPolicy::Enabled { profile: RoamingProfile::Stationary, .. } => {
198 let stationary_monitor: Box<dyn roam_monitor::RoamMonitorApi> =
199 Box::new(roam_monitor::stationary_monitor::StationaryMonitor::new(
200 generate_random_ap_state(),
201 generate_random_network_identifier(),
202 generate_random_password(),
203 telemetry_sender.clone(),
204 saved_networks,
205 past_roams.clone(),
206 ));
207 assert_eq!(stationary_monitor.type_id(), monitor.type_id());
208 }
209 }
210 }
211
212 #[test_case(RoamingPolicy::Disabled; "disabled")]
213 #[test_case(RoamingPolicy::Enabled { profile: RoamingProfile::Stationary, mode: RoamingMode::CanRoam }; "enabled_stationary_can_roam")]
214 #[fuchsia::test(add_test_attr = false)]
215 fn test_roam_manager_handles_get_roam_monitor_request(roaming_policy: RoamingPolicy) {
216 let mut exec = TestExecutor::new();
217 let mut test_values = setup_test();
218 let mut serve_fut = pin!(serve_local_roam_manager_requests(
219 roaming_policy,
220 test_values.roam_service_request_receiver,
221 test_values.connection_selection_requester.clone(),
222 test_values.telemetry_sender.clone(),
223 test_values.saved_networks,
224 ));
225 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
226
227 let connection_data = generate_random_roaming_connection_data();
229 let (sender, _) = mpsc::channel(ROAMING_CHANNEL_BUFFER_SIZE);
230 let mut roam_monitor_sender = test_values.roam_manager.initialize_roam_monitor(
231 connection_data.ap_state.clone(),
232 generate_random_network_identifier(),
233 generate_random_password(),
234 sender,
235 );
236
237 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
238
239 roam_monitor_sender
242 .send_signal_report_ind(SignalReportIndication { rssi_dbm: -60, snr_db: 30 })
243 .expect("error sending data via roam monitor sender");
244 }
245
246 #[test_case(RoamingPolicy::Disabled; "disabled")]
247 #[test_case(RoamingPolicy::Enabled { profile: RoamingProfile::Stationary, mode: RoamingMode::CanRoam }; "enabled_stationary_can_roam")]
248 #[fuchsia::test]
249 fn test_roam_manager_handles_terminated_roam_monitors(roaming_policy: RoamingPolicy) {
250 let mut exec = TestExecutor::new();
251 let mut test_values = setup_test();
252 let mut serve_fut = pin!(serve_local_roam_manager_requests(
253 roaming_policy,
254 test_values.roam_service_request_receiver,
255 test_values.connection_selection_requester.clone(),
256 test_values.telemetry_sender.clone(),
257 test_values.saved_networks,
258 ));
259 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
260
261 let connection_data = generate_random_roaming_connection_data();
263 let (sender, _) = mpsc::channel(ROAMING_CHANNEL_BUFFER_SIZE);
264 let mut roam_monitor_sender = test_values.roam_manager.initialize_roam_monitor(
265 connection_data.ap_state.clone(),
266 generate_random_network_identifier(),
267 generate_random_password(),
268 sender,
269 );
270
271 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
272
273 roam_monitor_sender
276 .send_signal_report_ind(SignalReportIndication { rssi_dbm: -60, snr_db: 30 })
277 .expect("error sending data via roam monitor sender");
278
279 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
280
281 std::mem::drop(roam_monitor_sender);
283
284 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
285 }
286}