1use 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 power_manager: Arc<dyn wlan_power_manager::PowerManager>,
46) -> (Arc<Mutex<iface_manager_api::IfaceManager>>, impl Future<Output = Result<Infallible, Error>>)
47{
48 let (sender, receiver) = mpsc::channel(0);
49 let iface_manager_sender = Arc::new(Mutex::new(iface_manager_api::IfaceManager { sender }));
50 let iface_manager = iface_manager::IfaceManagerService::new(
51 phy_manager,
52 client_update_sender,
53 ap_update_sender,
54 dev_monitor_proxy,
55 saved_networks,
56 connection_selection_requester,
57 roam_manager,
58 telemetry_sender,
59 defect_sender,
60 node,
61 power_manager,
62 );
63 let iface_manager_service = iface_manager::serve_iface_manager_requests(
64 iface_manager,
65 receiver,
66 defect_receiver,
67 recovery_receiver,
68 );
69
70 (iface_manager_sender, iface_manager_service)
71}
72
73#[derive(Clone, Copy, Debug, PartialEq)]
74pub enum PhyFailure {
75 IfaceCreationFailure { phy_id: u16 },
76 IfaceDestructionFailure { phy_id: u16 },
77}
78
79#[derive(Clone, Copy, Debug)]
80pub enum IfaceFailure {
81 CanceledScan { iface_id: u16 },
82 FailedScan { iface_id: u16 },
83 EmptyScanResults { iface_id: u16 },
84 ApStartFailure { iface_id: u16 },
85 ConnectionFailure { iface_id: u16 },
86 Timeout { iface_id: u16, source: TimeoutSource },
87}
88
89impl PartialEq for IfaceFailure {
95 fn eq(&self, other: &Self) -> bool {
96 #[allow(
97 clippy::match_like_matches_macro,
98 reason = "mass allow for https://fxbug.dev/381896734"
99 )]
100 match (*self, *other) {
101 (IfaceFailure::CanceledScan { .. }, IfaceFailure::CanceledScan { .. }) => true,
102 (IfaceFailure::FailedScan { .. }, IfaceFailure::FailedScan { .. }) => true,
103 (IfaceFailure::EmptyScanResults { .. }, IfaceFailure::EmptyScanResults { .. }) => true,
104 (IfaceFailure::ApStartFailure { .. }, IfaceFailure::ApStartFailure { .. }) => true,
105 (IfaceFailure::ConnectionFailure { .. }, IfaceFailure::ConnectionFailure { .. }) => {
106 true
107 }
108 (IfaceFailure::Timeout { .. }, IfaceFailure::Timeout { .. }) => true,
109 _ => false,
110 }
111 }
112}
113
114#[derive(Clone, Copy, Debug, PartialEq)]
115pub enum Defect {
116 Phy(PhyFailure),
117 Iface(IfaceFailure),
118}
119
120impl WriteInspect for Defect {
121 fn write_inspect<'a>(&self, writer: &InspectNode, key: impl Into<Cow<'a, str>>) {
122 match self {
123 Defect::Phy(PhyFailure::IfaceCreationFailure { phy_id }) => {
124 inspect_insert!(writer, var key: {IfaceCreationFailure: {phy_id: phy_id}})
125 }
126 Defect::Phy(PhyFailure::IfaceDestructionFailure { phy_id }) => {
127 inspect_insert!(writer, var key: {IfaceDestructionFailure: {phy_id: phy_id}})
128 }
129 Defect::Iface(IfaceFailure::CanceledScan { iface_id }) => {
130 inspect_insert!(writer, var key: {CanceledScan: {iface_id: iface_id}})
131 }
132 Defect::Iface(IfaceFailure::FailedScan { iface_id }) => {
133 inspect_insert!(writer, var key: {FailedScan: {iface_id: iface_id}})
134 }
135 Defect::Iface(IfaceFailure::EmptyScanResults { iface_id }) => {
136 inspect_insert!(writer, var key: {EmptyScanResults: {iface_id: iface_id}})
137 }
138 Defect::Iface(IfaceFailure::ApStartFailure { iface_id }) => {
139 inspect_insert!(writer, var key: {ApStartFailure: {iface_id: iface_id}})
140 }
141 Defect::Iface(IfaceFailure::ConnectionFailure { iface_id }) => {
142 inspect_insert!(writer, var key: {ConnectionFailure: {iface_id: iface_id}})
143 }
144 Defect::Iface(IfaceFailure::Timeout { iface_id, .. }) => {
145 inspect_insert!(writer, var key: {Timeout: {iface_id: iface_id}})
146 }
147 }
148 }
149}
150
151#[derive(Debug, PartialEq)]
152struct Event<T: PartialEq> {
153 value: T,
154 time: fasync::MonotonicInstant,
155}
156
157impl<T: PartialEq> Event<T> {
158 fn new(value: T, time: fasync::MonotonicInstant) -> Self {
159 Event { value, time }
160 }
161}
162
163#[derive(Debug)]
164pub struct EventHistory<T: PartialEq> {
165 events: Vec<Event<T>>,
166 retention_time: zx::MonotonicDuration,
167}
168
169impl<T: PartialEq> EventHistory<T> {
170 fn new(retention_seconds: u32) -> Self {
171 EventHistory {
172 events: Vec::new(),
173 retention_time: zx::MonotonicDuration::from_seconds(retention_seconds as i64),
174 }
175 }
176
177 fn add_event(&mut self, value: T) {
178 let curr_time = fasync::MonotonicInstant::now();
179 self.events.push(Event::new(value, curr_time));
180 self.retain_unexpired_events(curr_time);
181 }
182
183 fn event_count(&mut self, value: T) -> usize {
184 let curr_time = fasync::MonotonicInstant::now();
185 self.retain_unexpired_events(curr_time);
186 self.events.iter().filter(|event| event.value == value).count()
187 }
188
189 fn time_since_last_event(&mut self, value: T) -> Option<zx::MonotonicDuration> {
190 let curr_time = fasync::MonotonicInstant::now();
191 self.retain_unexpired_events(curr_time);
192
193 for event in self.events.iter().rev() {
194 if event.value == value {
195 return Some(curr_time - event.time);
196 }
197 }
198 None
199 }
200
201 fn retain_unexpired_events(&mut self, curr_time: fasync::MonotonicInstant) {
202 let oldest_allowed_time = curr_time - self.retention_time;
203 self.events.retain(|event| event.time > oldest_allowed_time)
204 }
205}
206
207#[cfg(test)]
208mod tests {
209 use super::*;
210 use fuchsia_async::TestExecutor;
211 use rand::RngExt as _;
212 use test_util::{assert_gt, assert_lt};
213
214 #[fuchsia::test]
215 fn test_event_retention() {
216 let mut event_history = EventHistory::<()>::new(1);
218
219 event_history.events = vec![
221 Event::<()> { value: (), time: fasync::MonotonicInstant::from_nanos(0) },
222 Event::<()> { value: (), time: fasync::MonotonicInstant::from_nanos(1_000_000_000) },
223 Event::<()> { value: (), time: fasync::MonotonicInstant::from_nanos(2_000_000_000) },
224 Event::<()> { value: (), time: fasync::MonotonicInstant::from_nanos(2_000_000_001) },
225 Event::<()> { value: (), time: fasync::MonotonicInstant::from_nanos(3_000_000_000) },
226 ];
227
228 event_history.retain_unexpired_events(fasync::MonotonicInstant::from_nanos(3_000_000_000));
230
231 assert_eq!(
234 event_history.events,
235 vec![
236 Event::<()> {
237 value: (),
238 time: fasync::MonotonicInstant::from_nanos(2_000_000_001)
239 },
240 Event::<()> {
241 value: (),
242 time: fasync::MonotonicInstant::from_nanos(3_000_000_000)
243 },
244 ]
245 );
246 }
247
248 #[derive(Debug, PartialEq)]
249 enum TestEnum {
250 Foo,
251 Bar,
252 }
253
254 #[fuchsia::test]
255 fn test_time_since_last_event() {
256 let _exec = TestExecutor::new();
258
259 let mut event_history = EventHistory::<TestEnum>::new(u32::MAX);
262
263 let foo_time: i64 = 1_123_123_123;
265 let bar_time: i64 = 2_222_222_222;
266 event_history.events = vec![
267 Event { value: TestEnum::Foo, time: fasync::MonotonicInstant::from_nanos(foo_time) },
268 Event { value: TestEnum::Bar, time: fasync::MonotonicInstant::from_nanos(bar_time) },
269 ];
270
271 let start_time = fasync::MonotonicInstant::now().into_nanos();
274 let time_since_foo =
275 event_history.time_since_last_event(TestEnum::Foo).expect("Foo was not retained");
276 let time_since_bar =
277 event_history.time_since_last_event(TestEnum::Bar).expect("Bar was not retained");
278 let end_time = fasync::MonotonicInstant::now().into_nanos();
279
280 assert_lt!(time_since_foo.into_nanos(), end_time - foo_time);
282 assert_gt!(time_since_foo.into_nanos(), start_time - foo_time);
283
284 assert_lt!(time_since_bar.into_nanos(), end_time - bar_time);
285 assert_gt!(time_since_bar.into_nanos(), start_time - bar_time);
286 }
287
288 #[fuchsia::test]
289 fn test_time_since_last_event_retention() {
290 let _exec = TestExecutor::new();
292
293 let curr_time_seconds = fasync::MonotonicInstant::now().into_nanos() / 1_000_000_000;
296 let mut event_history = EventHistory::<()>::new((curr_time_seconds - 1) as u32);
297
298 event_history
301 .events
302 .push(Event::<()> { value: (), time: fasync::MonotonicInstant::from_nanos(0) });
303
304 assert_eq!(event_history.time_since_last_event(()), None);
305 }
306 #[fuchsia::test]
307 fn test_add_event() {
308 let _exec = TestExecutor::new();
310 let mut event_history = EventHistory::<()>::new(u32::MAX);
311
312 let num_events = 3;
314 let start_time = fasync::MonotonicInstant::now().into_nanos();
315 for _ in 0..num_events {
316 event_history.add_event(());
317 }
318 let end_time = fasync::MonotonicInstant::now().into_nanos();
319
320 assert_eq!(event_history.events.len(), num_events);
322
323 for event in event_history.events {
325 let event_time = event.time.into_nanos();
326 assert_lt!(event_time, end_time);
327 assert_gt!(event_time, start_time);
328 }
329 }
330
331 #[fuchsia::test]
332 fn test_add_event_retention() {
333 let _exec = TestExecutor::new();
335
336 let curr_time_seconds = fasync::MonotonicInstant::now().into_nanos() / 1_000_000_000;
339 let mut event_history = EventHistory::<()>::new((curr_time_seconds - 1) as u32);
340
341 event_history
344 .events
345 .push(Event::<()> { value: (), time: fasync::MonotonicInstant::from_nanos(0) });
346
347 let start_time = fasync::MonotonicInstant::now().into_nanos();
349 event_history.add_event(());
350 assert_eq!(event_history.events.len(), 1);
351
352 event_history.add_event(());
354 event_history.add_event(());
355 let end_time = fasync::MonotonicInstant::now().into_nanos();
356
357 assert_eq!(event_history.events.len(), 3);
359
360 for event in event_history.events {
362 let event_time = event.time.into_nanos();
363 assert_lt!(event_time, end_time);
364 assert_gt!(event_time, start_time);
365 }
366 }
367
368 #[fuchsia::test]
369 fn test_event_count() {
370 let _exec = TestExecutor::new();
372 let mut event_history = EventHistory::<TestEnum>::new(u32::MAX);
373
374 event_history.events = vec![
375 Event { value: TestEnum::Foo, time: fasync::MonotonicInstant::from_nanos(0) },
376 Event { value: TestEnum::Foo, time: fasync::MonotonicInstant::from_nanos(1) },
377 Event { value: TestEnum::Bar, time: fasync::MonotonicInstant::from_nanos(2) },
378 Event { value: TestEnum::Bar, time: fasync::MonotonicInstant::from_nanos(3) },
379 Event { value: TestEnum::Foo, time: fasync::MonotonicInstant::from_nanos(4) },
380 ];
381
382 assert_eq!(event_history.event_count(TestEnum::Foo), 3);
383 assert_eq!(event_history.event_count(TestEnum::Bar), 2);
384 }
385
386 #[fuchsia::test]
387 fn test_event_count_retention() {
388 let _exec = TestExecutor::new();
390
391 let curr_time_seconds = fasync::MonotonicInstant::now().into_nanos() / 1_000_000_000;
394 let mut event_history = EventHistory::<TestEnum>::new((curr_time_seconds - 1) as u32);
395
396 event_history.events = vec![
397 Event { value: TestEnum::Foo, time: fasync::MonotonicInstant::from_nanos(0) },
398 Event { value: TestEnum::Foo, time: fasync::MonotonicInstant::from_nanos(0) },
399 Event { value: TestEnum::Bar, time: fasync::MonotonicInstant::now() },
400 Event { value: TestEnum::Bar, time: fasync::MonotonicInstant::now() },
401 Event { value: TestEnum::Foo, time: fasync::MonotonicInstant::now() },
402 ];
403
404 assert_eq!(event_history.event_count(TestEnum::Foo), 1);
405 assert_eq!(event_history.event_count(TestEnum::Bar), 2);
406 }
407
408 #[fuchsia::test]
409 fn test_failure_equality() {
410 let mut rng = rand::rng();
411 assert_eq!(
412 IfaceFailure::CanceledScan { iface_id: rng.random() },
413 IfaceFailure::CanceledScan { iface_id: rng.random() }
414 );
415 assert_eq!(
416 IfaceFailure::FailedScan { iface_id: rng.random() },
417 IfaceFailure::FailedScan { iface_id: rng.random() }
418 );
419 assert_eq!(
420 IfaceFailure::EmptyScanResults { iface_id: rng.random() },
421 IfaceFailure::EmptyScanResults { iface_id: rng.random() }
422 );
423 assert_eq!(
424 IfaceFailure::ApStartFailure { iface_id: rng.random() },
425 IfaceFailure::ApStartFailure { iface_id: rng.random() }
426 );
427 assert_eq!(
428 IfaceFailure::ConnectionFailure { iface_id: rng.random() },
429 IfaceFailure::ConnectionFailure { iface_id: rng.random() }
430 );
431 assert_eq!(
432 IfaceFailure::Timeout { iface_id: rng.random(), source: TimeoutSource::Scan },
433 IfaceFailure::Timeout { iface_id: rng.random(), source: TimeoutSource::ApStart }
434 );
435 }
436}