wlancfg_lib/mode_management/
mod.rs1use crate::client::connection_selection::ConnectionSelectionRequester;
6use crate::client::roaming::local_roam_manager::RoamManager;
7use crate::config_management::SavedNetworksManagerApi;
8use crate::telemetry::TelemetrySender;
9use crate::util::listener;
10use anyhow::Error;
11use fuchsia_async as fasync;
12use fuchsia_inspect::Node as InspectNode;
13use fuchsia_inspect_contrib::inspect_insert;
14use fuchsia_inspect_contrib::log::WriteInspect;
15use futures::Future;
16use futures::channel::mpsc;
17use futures::lock::Mutex;
18use std::borrow::Cow;
19use std::convert::Infallible;
20use std::sync::Arc;
21use wlan_telemetry::TimeoutSource;
22
23pub mod device_monitor;
24mod iface_manager;
25pub mod iface_manager_api;
26mod iface_manager_types;
27pub mod phy_manager;
28pub mod recovery;
29
30pub const DEFECT_CHANNEL_SIZE: usize = 100;
31
32pub fn create_iface_manager(
33 phy_manager: Arc<Mutex<dyn phy_manager::PhyManagerApi>>,
34 client_update_sender: listener::ClientListenerMessageSender,
35 ap_update_sender: listener::ApListenerMessageSender,
36 dev_monitor_proxy: fidl_fuchsia_wlan_device_service::DeviceMonitorProxy,
37 saved_networks: Arc<dyn SavedNetworksManagerApi>,
38 connection_selection_requester: ConnectionSelectionRequester,
39 roam_manager: RoamManager,
40 telemetry_sender: TelemetrySender,
41 defect_sender: mpsc::Sender<Defect>,
42 defect_receiver: mpsc::Receiver<Defect>,
43 recovery_receiver: recovery::RecoveryActionReceiver,
44 node: fuchsia_inspect::Node,
45) -> (Arc<Mutex<iface_manager_api::IfaceManager>>, impl Future<Output = Result<Infallible, Error>>)
46{
47 let (sender, receiver) = mpsc::channel(0);
48 let iface_manager_sender = Arc::new(Mutex::new(iface_manager_api::IfaceManager { sender }));
49 let iface_manager = iface_manager::IfaceManagerService::new(
50 phy_manager,
51 client_update_sender,
52 ap_update_sender,
53 dev_monitor_proxy,
54 saved_networks,
55 connection_selection_requester,
56 roam_manager,
57 telemetry_sender,
58 defect_sender,
59 node,
60 );
61 let iface_manager_service = iface_manager::serve_iface_manager_requests(
62 iface_manager,
63 receiver,
64 defect_receiver,
65 recovery_receiver,
66 );
67
68 (iface_manager_sender, iface_manager_service)
69}
70
71#[derive(Clone, Copy, Debug, PartialEq)]
72pub enum PhyFailure {
73 IfaceCreationFailure { phy_id: u16 },
74 IfaceDestructionFailure { phy_id: u16 },
75}
76
77#[derive(Clone, Copy, Debug)]
78pub enum IfaceFailure {
79 CanceledScan { iface_id: u16 },
80 FailedScan { iface_id: u16 },
81 EmptyScanResults { iface_id: u16 },
82 ApStartFailure { iface_id: u16 },
83 ConnectionFailure { iface_id: u16 },
84 Timeout { iface_id: u16, source: TimeoutSource },
85}
86
87impl PartialEq for IfaceFailure {
93 fn eq(&self, other: &Self) -> bool {
94 #[allow(
95 clippy::match_like_matches_macro,
96 reason = "mass allow for https://fxbug.dev/381896734"
97 )]
98 match (*self, *other) {
99 (IfaceFailure::CanceledScan { .. }, IfaceFailure::CanceledScan { .. }) => true,
100 (IfaceFailure::FailedScan { .. }, IfaceFailure::FailedScan { .. }) => true,
101 (IfaceFailure::EmptyScanResults { .. }, IfaceFailure::EmptyScanResults { .. }) => true,
102 (IfaceFailure::ApStartFailure { .. }, IfaceFailure::ApStartFailure { .. }) => true,
103 (IfaceFailure::ConnectionFailure { .. }, IfaceFailure::ConnectionFailure { .. }) => {
104 true
105 }
106 (IfaceFailure::Timeout { .. }, IfaceFailure::Timeout { .. }) => true,
107 _ => false,
108 }
109 }
110}
111
112#[derive(Clone, Copy, Debug, PartialEq)]
113pub enum Defect {
114 Phy(PhyFailure),
115 Iface(IfaceFailure),
116}
117
118impl WriteInspect for Defect {
119 fn write_inspect<'a>(&self, writer: &InspectNode, key: impl Into<Cow<'a, str>>) {
120 match self {
121 Defect::Phy(PhyFailure::IfaceCreationFailure { phy_id }) => {
122 inspect_insert!(writer, var key: {IfaceCreationFailure: {phy_id: phy_id}})
123 }
124 Defect::Phy(PhyFailure::IfaceDestructionFailure { phy_id }) => {
125 inspect_insert!(writer, var key: {IfaceDestructionFailure: {phy_id: phy_id}})
126 }
127 Defect::Iface(IfaceFailure::CanceledScan { iface_id }) => {
128 inspect_insert!(writer, var key: {CanceledScan: {iface_id: iface_id}})
129 }
130 Defect::Iface(IfaceFailure::FailedScan { iface_id }) => {
131 inspect_insert!(writer, var key: {FailedScan: {iface_id: iface_id}})
132 }
133 Defect::Iface(IfaceFailure::EmptyScanResults { iface_id }) => {
134 inspect_insert!(writer, var key: {EmptyScanResults: {iface_id: iface_id}})
135 }
136 Defect::Iface(IfaceFailure::ApStartFailure { iface_id }) => {
137 inspect_insert!(writer, var key: {ApStartFailure: {iface_id: iface_id}})
138 }
139 Defect::Iface(IfaceFailure::ConnectionFailure { iface_id }) => {
140 inspect_insert!(writer, var key: {ConnectionFailure: {iface_id: iface_id}})
141 }
142 Defect::Iface(IfaceFailure::Timeout { iface_id, .. }) => {
143 inspect_insert!(writer, var key: {Timeout: {iface_id: iface_id}})
144 }
145 }
146 }
147}
148
149#[derive(Debug, PartialEq)]
150struct Event<T: PartialEq> {
151 value: T,
152 time: fasync::MonotonicInstant,
153}
154
155impl<T: PartialEq> Event<T> {
156 fn new(value: T, time: fasync::MonotonicInstant) -> Self {
157 Event { value, time }
158 }
159}
160
161#[derive(Debug)]
162pub struct EventHistory<T: PartialEq> {
163 events: Vec<Event<T>>,
164 retention_time: zx::MonotonicDuration,
165}
166
167impl<T: PartialEq> EventHistory<T> {
168 fn new(retention_seconds: u32) -> Self {
169 EventHistory {
170 events: Vec::new(),
171 retention_time: zx::MonotonicDuration::from_seconds(retention_seconds as i64),
172 }
173 }
174
175 fn add_event(&mut self, value: T) {
176 let curr_time = fasync::MonotonicInstant::now();
177 self.events.push(Event::new(value, curr_time));
178 self.retain_unexpired_events(curr_time);
179 }
180
181 fn event_count(&mut self, value: T) -> usize {
182 let curr_time = fasync::MonotonicInstant::now();
183 self.retain_unexpired_events(curr_time);
184 self.events.iter().filter(|event| event.value == value).count()
185 }
186
187 fn time_since_last_event(&mut self, value: T) -> Option<zx::MonotonicDuration> {
188 let curr_time = fasync::MonotonicInstant::now();
189 self.retain_unexpired_events(curr_time);
190
191 for event in self.events.iter().rev() {
192 if event.value == value {
193 return Some(curr_time - event.time);
194 }
195 }
196 None
197 }
198
199 fn retain_unexpired_events(&mut self, curr_time: fasync::MonotonicInstant) {
200 let oldest_allowed_time = curr_time - self.retention_time;
201 self.events.retain(|event| event.time > oldest_allowed_time)
202 }
203}
204
205#[cfg(test)]
206mod tests {
207 use super::*;
208 use fuchsia_async::TestExecutor;
209 use rand::Rng;
210 use test_util::{assert_gt, assert_lt};
211
212 #[fuchsia::test]
213 fn test_event_retention() {
214 let mut event_history = EventHistory::<()>::new(1);
216
217 event_history.events = vec![
219 Event::<()> { value: (), time: fasync::MonotonicInstant::from_nanos(0) },
220 Event::<()> { value: (), time: fasync::MonotonicInstant::from_nanos(1_000_000_000) },
221 Event::<()> { value: (), time: fasync::MonotonicInstant::from_nanos(2_000_000_000) },
222 Event::<()> { value: (), time: fasync::MonotonicInstant::from_nanos(2_000_000_001) },
223 Event::<()> { value: (), time: fasync::MonotonicInstant::from_nanos(3_000_000_000) },
224 ];
225
226 event_history.retain_unexpired_events(fasync::MonotonicInstant::from_nanos(3_000_000_000));
228
229 assert_eq!(
232 event_history.events,
233 vec![
234 Event::<()> {
235 value: (),
236 time: fasync::MonotonicInstant::from_nanos(2_000_000_001)
237 },
238 Event::<()> {
239 value: (),
240 time: fasync::MonotonicInstant::from_nanos(3_000_000_000)
241 },
242 ]
243 );
244 }
245
246 #[derive(Debug, PartialEq)]
247 enum TestEnum {
248 Foo,
249 Bar,
250 }
251
252 #[fuchsia::test]
253 fn test_time_since_last_event() {
254 let _exec = TestExecutor::new();
256
257 let mut event_history = EventHistory::<TestEnum>::new(u32::MAX);
260
261 let foo_time: i64 = 1_123_123_123;
263 let bar_time: i64 = 2_222_222_222;
264 event_history.events = vec![
265 Event { value: TestEnum::Foo, time: fasync::MonotonicInstant::from_nanos(foo_time) },
266 Event { value: TestEnum::Bar, time: fasync::MonotonicInstant::from_nanos(bar_time) },
267 ];
268
269 let start_time = fasync::MonotonicInstant::now().into_nanos();
272 let time_since_foo =
273 event_history.time_since_last_event(TestEnum::Foo).expect("Foo was not retained");
274 let time_since_bar =
275 event_history.time_since_last_event(TestEnum::Bar).expect("Bar was not retained");
276 let end_time = fasync::MonotonicInstant::now().into_nanos();
277
278 assert_lt!(time_since_foo.into_nanos(), end_time - foo_time);
280 assert_gt!(time_since_foo.into_nanos(), start_time - foo_time);
281
282 assert_lt!(time_since_bar.into_nanos(), end_time - bar_time);
283 assert_gt!(time_since_bar.into_nanos(), start_time - bar_time);
284 }
285
286 #[fuchsia::test]
287 fn test_time_since_last_event_retention() {
288 let _exec = TestExecutor::new();
290
291 let curr_time_seconds = fasync::MonotonicInstant::now().into_nanos() / 1_000_000_000;
294 let mut event_history = EventHistory::<()>::new((curr_time_seconds - 1) as u32);
295
296 event_history
299 .events
300 .push(Event::<()> { value: (), time: fasync::MonotonicInstant::from_nanos(0) });
301
302 assert_eq!(event_history.time_since_last_event(()), None);
303 }
304 #[fuchsia::test]
305 fn test_add_event() {
306 let _exec = TestExecutor::new();
308 let mut event_history = EventHistory::<()>::new(u32::MAX);
309
310 let num_events = 3;
312 let start_time = fasync::MonotonicInstant::now().into_nanos();
313 for _ in 0..num_events {
314 event_history.add_event(());
315 }
316 let end_time = fasync::MonotonicInstant::now().into_nanos();
317
318 assert_eq!(event_history.events.len(), num_events);
320
321 for event in event_history.events {
323 let event_time = event.time.into_nanos();
324 assert_lt!(event_time, end_time);
325 assert_gt!(event_time, start_time);
326 }
327 }
328
329 #[fuchsia::test]
330 fn test_add_event_retention() {
331 let _exec = TestExecutor::new();
333
334 let curr_time_seconds = fasync::MonotonicInstant::now().into_nanos() / 1_000_000_000;
337 let mut event_history = EventHistory::<()>::new((curr_time_seconds - 1) as u32);
338
339 event_history
342 .events
343 .push(Event::<()> { value: (), time: fasync::MonotonicInstant::from_nanos(0) });
344
345 let start_time = fasync::MonotonicInstant::now().into_nanos();
347 event_history.add_event(());
348 assert_eq!(event_history.events.len(), 1);
349
350 event_history.add_event(());
352 event_history.add_event(());
353 let end_time = fasync::MonotonicInstant::now().into_nanos();
354
355 assert_eq!(event_history.events.len(), 3);
357
358 for event in event_history.events {
360 let event_time = event.time.into_nanos();
361 assert_lt!(event_time, end_time);
362 assert_gt!(event_time, start_time);
363 }
364 }
365
366 #[fuchsia::test]
367 fn test_event_count() {
368 let _exec = TestExecutor::new();
370 let mut event_history = EventHistory::<TestEnum>::new(u32::MAX);
371
372 event_history.events = vec![
373 Event { value: TestEnum::Foo, time: fasync::MonotonicInstant::from_nanos(0) },
374 Event { value: TestEnum::Foo, time: fasync::MonotonicInstant::from_nanos(1) },
375 Event { value: TestEnum::Bar, time: fasync::MonotonicInstant::from_nanos(2) },
376 Event { value: TestEnum::Bar, time: fasync::MonotonicInstant::from_nanos(3) },
377 Event { value: TestEnum::Foo, time: fasync::MonotonicInstant::from_nanos(4) },
378 ];
379
380 assert_eq!(event_history.event_count(TestEnum::Foo), 3);
381 assert_eq!(event_history.event_count(TestEnum::Bar), 2);
382 }
383
384 #[fuchsia::test]
385 fn test_event_count_retention() {
386 let _exec = TestExecutor::new();
388
389 let curr_time_seconds = fasync::MonotonicInstant::now().into_nanos() / 1_000_000_000;
392 let mut event_history = EventHistory::<TestEnum>::new((curr_time_seconds - 1) as u32);
393
394 event_history.events = vec![
395 Event { value: TestEnum::Foo, time: fasync::MonotonicInstant::from_nanos(0) },
396 Event { value: TestEnum::Foo, time: fasync::MonotonicInstant::from_nanos(0) },
397 Event { value: TestEnum::Bar, time: fasync::MonotonicInstant::now() },
398 Event { value: TestEnum::Bar, time: fasync::MonotonicInstant::now() },
399 Event { value: TestEnum::Foo, time: fasync::MonotonicInstant::now() },
400 ];
401
402 assert_eq!(event_history.event_count(TestEnum::Foo), 1);
403 assert_eq!(event_history.event_count(TestEnum::Bar), 2);
404 }
405
406 #[fuchsia::test]
407 fn test_failure_equality() {
408 let mut rng = rand::rng();
409 assert_eq!(
410 IfaceFailure::CanceledScan { iface_id: rng.random() },
411 IfaceFailure::CanceledScan { iface_id: rng.random() }
412 );
413 assert_eq!(
414 IfaceFailure::FailedScan { iface_id: rng.random() },
415 IfaceFailure::FailedScan { iface_id: rng.random() }
416 );
417 assert_eq!(
418 IfaceFailure::EmptyScanResults { iface_id: rng.random() },
419 IfaceFailure::EmptyScanResults { iface_id: rng.random() }
420 );
421 assert_eq!(
422 IfaceFailure::ApStartFailure { iface_id: rng.random() },
423 IfaceFailure::ApStartFailure { iface_id: rng.random() }
424 );
425 assert_eq!(
426 IfaceFailure::ConnectionFailure { iface_id: rng.random() },
427 IfaceFailure::ConnectionFailure { iface_id: rng.random() }
428 );
429 assert_eq!(
430 IfaceFailure::Timeout { iface_id: rng.random(), source: TimeoutSource::Scan },
431 IfaceFailure::Timeout { iface_id: rng.random(), source: TimeoutSource::ApStart }
432 );
433 }
434}